Mercurial > projects > dwt-addons
diff dwtx/draw2d/Polyline.d @ 98:95307ad235d9
Added Draw2d code, still work in progress
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 03 Aug 2008 00:52:14 +0200 |
parents | |
children | 2d6540440fe6 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/draw2d/Polyline.d Sun Aug 03 00:52:14 2008 +0200 @@ -0,0 +1,317 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwtx.draw2d.Polyline; + +import dwt.dwthelper.utils; +import dwtx.dwtxhelper.Collection; + +import dwtx.draw2d.geometry.Point; +import dwtx.draw2d.geometry.PointList; +import dwtx.draw2d.geometry.Rectangle; +import dwtx.draw2d.Shape; +import dwtx.draw2d.Graphics; +import dwtx.draw2d.IFigure; +import dwtx.draw2d.Connection; + +/** + * Renders a {@link PointList} as a series of line segments. A Polyline figure should be + * positioned by manipulating its points, <EM>NOT</EM> by calling + * {@link Figure#setBounds(Rectangle)}. + * <P> + * A polyline's bounds will be calculated automatically based on its PointList. The + * bounds will be the smallest Rectangle large enough to render the line properly. + * Children should not be added to a Polyline and will not affect the bounds calculation. + */ +public class Polyline + : Shape +{ + +PointList points; +private int tolerance = 2; +private static const Rectangle LINEBOUNDS; + +static this(){ + LINEBOUNDS = Rectangle.SINGLETON; + assert( LINEBOUNDS !is null ); +} + +this(){ + points = new PointList(); + setFill(false); + bounds = null; +} + +/** + * Adds the passed point to the Polyline. + * + * @param pt the Point to be added to the Polyline + * @since 2.0 + */ +public void addPoint(Point pt) { + points.addPoint(pt); + bounds = null; + repaint(); +} + +/** + * @see dwtx.draw2d.IFigure#containsPoint(int, int) + */ +public bool containsPoint(int x, int y) { + int tolerance = Math.max(lineWidth / 2, this.tolerance); + LINEBOUNDS.setBounds(getBounds()); + LINEBOUNDS.expand(tolerance, tolerance); + if (!LINEBOUNDS.contains(x, y)) + return false; + int ints[] = points.toIntArray(); + for (int index = 0; index < ints.length - 3; index += 2) { + if (lineContainsPoint(ints[index], ints[index + 1], + ints[index + 2], ints[index + 3], x, y, tolerance)) + return true; + } + List children = getChildren(); + for (int i = 0; i < children.size(); i++) { + if ((cast(IFigure)children.get(i)).containsPoint(x, y)) + return true; + } + return false; +} + +private bool lineContainsPoint( + int x1, int y1, + int x2, int y2, + int px, int py, + int tolerance) { + LINEBOUNDS.setSize(0, 0); + LINEBOUNDS.setLocation(x1, y1); + LINEBOUNDS.union_(x2, y2); + LINEBOUNDS.expand(tolerance, tolerance); + if (!LINEBOUNDS.contains(px, py)) + return false; + + int v1x, v1y, v2x, v2y; + int numerator, denominator; + int result = 0; + + /** + * calculates the length squared of the cross product of two vectors, v1 & v2. + */ + if (x1 !is x2 && y1 !is y2) { + v1x = x2 - x1; + v1y = y2 - y1; + v2x = px - x1; + v2y = py - y1; + + numerator = v2x * v1y - v1x * v2y; + + denominator = v1x * v1x + v1y * v1y; + + result = cast(int)(cast(long)numerator * numerator / denominator); + } + + // if it is the same point, and it passes the bounding box test, + // the result is always true. + return result <= tolerance * tolerance; + +} + +/** + * Null implementation for a line. + * @see dwtx.draw2d.Shape#fillShape(Graphics) + */ +protected void fillShape(Graphics g) { } + +/** + * @see dwtx.draw2d.IFigure#getBounds() + */ +public Rectangle getBounds() { + if (bounds is null) { + bounds = getPoints() + .getBounds() + .getExpanded(lineWidth / 2, lineWidth / 2); + } + return bounds; +} + +/** + * Returns the last point in the Polyline. + * @since 2.0 + * @return the last point + */ +public Point getEnd() { + return points.getLastPoint(); +} + +/** + * Returns the points in this Polyline <B>by reference</B>. If the returned list is + * modified, this Polyline must be informed by calling {@link #setPoints(PointList)}. + * Failure to do so will result in layout and paint problems. + * + * @return this Polyline's points + * @since 2.0 + */ +public PointList getPoints() { + return points; +} + +/** + * @return the first point in the Polyline + * @since 2.0 + */ +public Point getStart() { + return points.getFirstPoint(); +} + +/** + * Inserts a given point at a specified index in the Polyline. + * + * @param pt the point to be added + * @param index the position in the Polyline where the point is to be added + * + * @since 2.0 + */ +public void insertPoint(Point pt, int index) { + bounds = null; + points.insertPoint(pt, index); + repaint(); +} + +/** + * @return <code>false</code> because Polyline's aren't filled + */ +public bool isOpaque() { + return false; +} + +/** + * @see Shape#outlineShape(Graphics) + */ +protected void outlineShape(Graphics g) { + g.drawPolyline(points); +} + +/** + * @see Figure#primTranslate(int, int) + */ +public void primTranslate(int x, int y) { } + +/** + * Erases the Polyline and removes all of its {@link Point Points}. + * + * @since 2.0 + */ +public void removeAllPoints() { + erase(); + bounds = null; + points.removeAllPoints(); +} + +/** + * Removes a point from the Polyline. + * + * @param index the position of the point to be removed + * @since 2.0 + */ +public void removePoint(int index) { + erase(); + bounds = null; + points.removePoint(index); +} + +/** + * Sets the end point of the Polyline + * + * @param end the point that will become the last point in the Polyline + * @since 2.0 + */ +public void setEnd(Point end) { + if (points.size() < 2) + addPoint(end); + else + setPoint(end, points.size() - 1); +} + +/** + * Sets the points at both extremes of the Polyline + * + * @param start the point to become the first point in the Polyline + * @param end the point to become the last point in the Polyline + * @since 2.0 + */ +public void setEndpoints(Point start, Point end) { + setStart(start); + setEnd(end); +} + +/** + * @see dwtx.draw2d.Shape#setLineWidth(int) + */ +public void setLineWidth(int w) { + if (lineWidth is w) + return; + if (w < lineWidth) //The bounds will become smaller, so erase must occur first. + erase(); + bounds = null; + super.setLineWidth(w); +} + +/** + * Sets the point at <code>index</code> to the Point <code>pt</code>. Calling this method + * results in a recalculation of the polyline's bounding box. If you're going to set + * multiple Points, use {@link #setPoints(PointList)}. + * @param pt the point + * @param index the index + */ +public void setPoint(Point pt, int index) { + erase(); + points.setPoint(pt, index); + bounds = null; + repaint(); +} + +/** + * Sets the list of points to be used by this polyline connection. Removes any previously + * existing points. The polyline will hold onto the given list by reference. + * + * @param points new set of points + * @since 2.0 + */ +public void setPoints(PointList points) { + erase(); + this.points = points; + bounds = null; + firePropertyChange(Connection.PROPERTY_POINTS, null, points); + repaint(); +} + +/** + * Sets the start point of the Polyline + * + * @param start the point that will become the first point in the Polyline + * @since 2.0 + */ +public void setStart(Point start) { + if (points.size() is 0) + addPoint(start); + else + setPoint(start, 0); +} + +/** + * Sets the tolerance + * + * @param tolerance the new tolerance value of the Polyline + */ +public void setTolerance(int tolerance) { + this.tolerance = tolerance; +} +}