Mercurial > projects > dwt-addons
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 } |