comparison 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
comparison
equal deleted inserted replaced
96:b492ba44e44d 98:95307ad235d9
1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module dwtx.draw2d.Polyline;
14
15 import dwt.dwthelper.utils;
16 import dwtx.dwtxhelper.Collection;
17
18 import dwtx.draw2d.geometry.Point;
19 import dwtx.draw2d.geometry.PointList;
20 import dwtx.draw2d.geometry.Rectangle;
21 import dwtx.draw2d.Shape;
22 import dwtx.draw2d.Graphics;
23 import dwtx.draw2d.IFigure;
24 import dwtx.draw2d.Connection;
25
26 /**
27 * Renders a {@link PointList} as a series of line segments. A Polyline figure should be
28 * positioned by manipulating its points, <EM>NOT</EM> by calling
29 * {@link Figure#setBounds(Rectangle)}.
30 * <P>
31 * A polyline's bounds will be calculated automatically based on its PointList. The
32 * bounds will be the smallest Rectangle large enough to render the line properly.
33 * Children should not be added to a Polyline and will not affect the bounds calculation.
34 */
35 public class Polyline
36 : Shape
37 {
38
39 PointList points;
40 private int tolerance = 2;
41 private static const Rectangle LINEBOUNDS;
42
43 static this(){
44 LINEBOUNDS = Rectangle.SINGLETON;
45 assert( LINEBOUNDS !is null );
46 }
47
48 this(){
49 points = new PointList();
50 setFill(false);
51 bounds = null;
52 }
53
54 /**
55 * Adds the passed point to the Polyline.
56 *
57 * @param pt the Point to be added to the Polyline
58 * @since 2.0
59 */
60 public void addPoint(Point pt) {
61 points.addPoint(pt);
62 bounds = null;
63 repaint();
64 }
65
66 /**
67 * @see dwtx.draw2d.IFigure#containsPoint(int, int)
68 */
69 public bool containsPoint(int x, int y) {
70 int tolerance = Math.max(lineWidth / 2, this.tolerance);
71 LINEBOUNDS.setBounds(getBounds());
72 LINEBOUNDS.expand(tolerance, tolerance);
73 if (!LINEBOUNDS.contains(x, y))
74 return false;
75 int ints[] = points.toIntArray();
76 for (int index = 0; index < ints.length - 3; index += 2) {
77 if (lineContainsPoint(ints[index], ints[index + 1],
78 ints[index + 2], ints[index + 3], x, y, tolerance))
79 return true;
80 }
81 List children = getChildren();
82 for (int i = 0; i < children.size(); i++) {
83 if ((cast(IFigure)children.get(i)).containsPoint(x, y))
84 return true;
85 }
86 return false;
87 }
88
89 private bool lineContainsPoint(
90 int x1, int y1,
91 int x2, int y2,
92 int px, int py,
93 int tolerance) {
94 LINEBOUNDS.setSize(0, 0);
95 LINEBOUNDS.setLocation(x1, y1);
96 LINEBOUNDS.union_(x2, y2);
97 LINEBOUNDS.expand(tolerance, tolerance);
98 if (!LINEBOUNDS.contains(px, py))
99 return false;
100
101 int v1x, v1y, v2x, v2y;
102 int numerator, denominator;
103 int result = 0;
104
105 /**
106 * calculates the length squared of the cross product of two vectors, v1 & v2.
107 */
108 if (x1 !is x2 && y1 !is y2) {
109 v1x = x2 - x1;
110 v1y = y2 - y1;
111 v2x = px - x1;
112 v2y = py - y1;
113
114 numerator = v2x * v1y - v1x * v2y;
115
116 denominator = v1x * v1x + v1y * v1y;
117
118 result = cast(int)(cast(long)numerator * numerator / denominator);
119 }
120
121 // if it is the same point, and it passes the bounding box test,
122 // the result is always true.
123 return result <= tolerance * tolerance;
124
125 }
126
127 /**
128 * Null implementation for a line.
129 * @see dwtx.draw2d.Shape#fillShape(Graphics)
130 */
131 protected void fillShape(Graphics g) { }
132
133 /**
134 * @see dwtx.draw2d.IFigure#getBounds()
135 */
136 public Rectangle getBounds() {
137 if (bounds is null) {
138 bounds = getPoints()
139 .getBounds()
140 .getExpanded(lineWidth / 2, lineWidth / 2);
141 }
142 return bounds;
143 }
144
145 /**
146 * Returns the last point in the Polyline.
147 * @since 2.0
148 * @return the last point
149 */
150 public Point getEnd() {
151 return points.getLastPoint();
152 }
153
154 /**
155 * Returns the points in this Polyline <B>by reference</B>. If the returned list is
156 * modified, this Polyline must be informed by calling {@link #setPoints(PointList)}.
157 * Failure to do so will result in layout and paint problems.
158 *
159 * @return this Polyline's points
160 * @since 2.0
161 */
162 public PointList getPoints() {
163 return points;
164 }
165
166 /**
167 * @return the first point in the Polyline
168 * @since 2.0
169 */
170 public Point getStart() {
171 return points.getFirstPoint();
172 }
173
174 /**
175 * Inserts a given point at a specified index in the Polyline.
176 *
177 * @param pt the point to be added
178 * @param index the position in the Polyline where the point is to be added
179 *
180 * @since 2.0
181 */
182 public void insertPoint(Point pt, int index) {
183 bounds = null;
184 points.insertPoint(pt, index);
185 repaint();
186 }
187
188 /**
189 * @return <code>false</code> because Polyline's aren't filled
190 */
191 public bool isOpaque() {
192 return false;
193 }
194
195 /**
196 * @see Shape#outlineShape(Graphics)
197 */
198 protected void outlineShape(Graphics g) {
199 g.drawPolyline(points);
200 }
201
202 /**
203 * @see Figure#primTranslate(int, int)
204 */
205 public void primTranslate(int x, int y) { }
206
207 /**
208 * Erases the Polyline and removes all of its {@link Point Points}.
209 *
210 * @since 2.0
211 */
212 public void removeAllPoints() {
213 erase();
214 bounds = null;
215 points.removeAllPoints();
216 }
217
218 /**
219 * Removes a point from the Polyline.
220 *
221 * @param index the position of the point to be removed
222 * @since 2.0
223 */
224 public void removePoint(int index) {
225 erase();
226 bounds = null;
227 points.removePoint(index);
228 }
229
230 /**
231 * Sets the end point of the Polyline
232 *
233 * @param end the point that will become the last point in the Polyline
234 * @since 2.0
235 */
236 public void setEnd(Point end) {
237 if (points.size() < 2)
238 addPoint(end);
239 else
240 setPoint(end, points.size() - 1);
241 }
242
243 /**
244 * Sets the points at both extremes of the Polyline
245 *
246 * @param start the point to become the first point in the Polyline
247 * @param end the point to become the last point in the Polyline
248 * @since 2.0
249 */
250 public void setEndpoints(Point start, Point end) {
251 setStart(start);
252 setEnd(end);
253 }
254
255 /**
256 * @see dwtx.draw2d.Shape#setLineWidth(int)
257 */
258 public void setLineWidth(int w) {
259 if (lineWidth is w)
260 return;
261 if (w < lineWidth) //The bounds will become smaller, so erase must occur first.
262 erase();
263 bounds = null;
264 super.setLineWidth(w);
265 }
266
267 /**
268 * Sets the point at <code>index</code> to the Point <code>pt</code>. Calling this method
269 * results in a recalculation of the polyline's bounding box. If you're going to set
270 * multiple Points, use {@link #setPoints(PointList)}.
271 * @param pt the point
272 * @param index the index
273 */
274 public void setPoint(Point pt, int index) {
275 erase();
276 points.setPoint(pt, index);
277 bounds = null;
278 repaint();
279 }
280
281 /**
282 * Sets the list of points to be used by this polyline connection. Removes any previously
283 * existing points. The polyline will hold onto the given list by reference.
284 *
285 * @param points new set of points
286 * @since 2.0
287 */
288 public void setPoints(PointList points) {
289 erase();
290 this.points = points;
291 bounds = null;
292 firePropertyChange(Connection.PROPERTY_POINTS, null, points);
293 repaint();
294 }
295
296 /**
297 * Sets the start point of the Polyline
298 *
299 * @param start the point that will become the first point in the Polyline
300 * @since 2.0
301 */
302 public void setStart(Point start) {
303 if (points.size() is 0)
304 addPoint(start);
305 else
306 setPoint(start, 0);
307 }
308
309 /**
310 * Sets the tolerance
311 *
312 * @param tolerance the new tolerance value of the Polyline
313 */
314 public void setTolerance(int tolerance) {
315 this.tolerance = tolerance;
316 }
317 }