Mercurial > projects > dwt-addons
comparison dwtx/draw2d/ManhattanConnectionRouter.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, 2005 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.ManhattanConnectionRouter; | |
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.Ray; | |
21 import dwtx.draw2d.geometry.Rectangle; | |
22 import dwtx.draw2d.AbstractRouter; | |
23 import dwtx.draw2d.Connection; | |
24 import dwtx.draw2d.ConnectionAnchor; | |
25 | |
26 /** | |
27 * Provides a {@link Connection} with an orthogonal route between the Connection's source | |
28 * and target anchors. | |
29 */ | |
30 public final class ManhattanConnectionRouter | |
31 : AbstractRouter | |
32 { | |
33 | |
34 private Map rowsUsed; | |
35 private Map colsUsed; | |
36 //private Hashtable offsets = new Hashtable(7); | |
37 | |
38 private Map reservedInfo; | |
39 | |
40 private class ReservedInfo { | |
41 public List reservedRows; | |
42 public List reservedCols; | |
43 this(){ | |
44 reservedRows = new ArrayList(2); | |
45 reservedCols = new ArrayList(2); | |
46 } | |
47 } | |
48 | |
49 private static Ray UP, DOWN, LEFT, RIGHT; | |
50 | |
51 | |
52 static this(){ | |
53 UP = new Ray(0, -1); | |
54 DOWN = new Ray(0, 1); | |
55 LEFT = new Ray(-1, 0); | |
56 RIGHT = new Ray(1, 0); | |
57 } | |
58 | |
59 public this(){ | |
60 rowsUsed = new HashMap(); | |
61 colsUsed = new HashMap(); | |
62 reservedInfo = new HashMap(); | |
63 } | |
64 | |
65 /** | |
66 * @see ConnectionRouter#invalidate(Connection) | |
67 */ | |
68 public void invalidate(Connection connection) { | |
69 removeReservedLines(connection); | |
70 } | |
71 | |
72 private int getColumnNear(Connection connection, int r, int n, int x) { | |
73 int min = Math.min(n, x), | |
74 max = Math.max(n, x); | |
75 if (min > r) { | |
76 max = min; | |
77 min = r - (min - r); | |
78 } | |
79 if (max < r) { | |
80 min = max; | |
81 max = r + (r - max); | |
82 } | |
83 int proximity = 0; | |
84 int direction = -1; | |
85 if (r % 2 is 1) | |
86 r--; | |
87 Integer i; | |
88 while (proximity < r) { | |
89 i = new Integer(r + proximity * direction); | |
90 if (!colsUsed.containsKey(i)) { | |
91 colsUsed.put(i, i); | |
92 reserveColumn(connection, i); | |
93 return i.intValue(); | |
94 } | |
95 int j = i.intValue(); | |
96 if (j <= min) | |
97 return j + 2; | |
98 if (j >= max) | |
99 return j - 2; | |
100 if (direction is 1) | |
101 direction = -1; | |
102 else { | |
103 direction = 1; | |
104 proximity += 2; | |
105 } | |
106 } | |
107 return r; | |
108 } | |
109 | |
110 /** | |
111 * Returns the direction the point <i>p</i> is in relation to the given rectangle. | |
112 * Possible values are LEFT (-1,0), RIGHT (1,0), UP (0,-1) and DOWN (0,1). | |
113 * | |
114 * @param r the rectangle | |
115 * @param p the point | |
116 * @return the direction from <i>r</i> to <i>p</i> | |
117 */ | |
118 protected Ray getDirection(Rectangle r, Point p) { | |
119 int i, distance = Math.abs(r.x - p.x); | |
120 Ray direction; | |
121 | |
122 direction = LEFT; | |
123 | |
124 i = Math.abs(r.y - p.y); | |
125 if (i <= distance) { | |
126 distance = i; | |
127 direction = UP; | |
128 } | |
129 | |
130 i = Math.abs(r.bottom() - p.y); | |
131 if (i <= distance) { | |
132 distance = i; | |
133 direction = DOWN; | |
134 } | |
135 | |
136 i = Math.abs(r.right() - p.x); | |
137 if (i < distance) { | |
138 distance = i; | |
139 direction = RIGHT; | |
140 } | |
141 | |
142 return direction; | |
143 } | |
144 | |
145 protected Ray getEndDirection(Connection conn) { | |
146 ConnectionAnchor anchor = conn.getTargetAnchor(); | |
147 Point p = getEndPoint(conn); | |
148 Rectangle rect; | |
149 if (anchor.getOwner() is null) | |
150 rect = new Rectangle(p.x - 1, p.y - 1, 2, 2); | |
151 else { | |
152 rect = conn.getTargetAnchor().getOwner().getBounds().getCopy(); | |
153 conn.getTargetAnchor().getOwner().translateToAbsolute(rect); | |
154 } | |
155 return getDirection(rect, p); | |
156 } | |
157 | |
158 protected int getRowNear(Connection connection, int r, int n, int x) { | |
159 int min = Math.min(n, x), | |
160 max = Math.max(n, x); | |
161 if (min > r) { | |
162 max = min; | |
163 min = r - (min - r); | |
164 } | |
165 if (max < r) { | |
166 min = max; | |
167 max = r + (r - max); | |
168 } | |
169 | |
170 int proximity = 0; | |
171 int direction = -1; | |
172 if (r % 2 is 1) | |
173 r--; | |
174 Integer i; | |
175 while (proximity < r) { | |
176 i = new Integer(r + proximity * direction); | |
177 if (!rowsUsed.containsKey(i)) { | |
178 rowsUsed.put(i, i); | |
179 reserveRow(connection, i); | |
180 return i.intValue(); | |
181 } | |
182 int j = i.intValue(); | |
183 if (j <= min) | |
184 return j + 2; | |
185 if (j >= max) | |
186 return j - 2; | |
187 if (direction is 1) | |
188 direction = -1; | |
189 else { | |
190 direction = 1; | |
191 proximity += 2; | |
192 } | |
193 } | |
194 return r; | |
195 } | |
196 | |
197 protected Ray getStartDirection(Connection conn) { | |
198 ConnectionAnchor anchor = conn.getSourceAnchor(); | |
199 Point p = getStartPoint(conn); | |
200 Rectangle rect; | |
201 if (anchor.getOwner() is null) | |
202 rect = new Rectangle(p.x - 1, p.y - 1, 2, 2); | |
203 else { | |
204 rect = conn.getSourceAnchor().getOwner().getBounds().getCopy(); | |
205 conn.getSourceAnchor().getOwner().translateToAbsolute(rect); | |
206 } | |
207 return getDirection(rect, p); | |
208 } | |
209 | |
210 protected void processPositions(Ray start, Ray end, List positions, | |
211 bool horizontal, Connection conn) { | |
212 removeReservedLines(conn); | |
213 | |
214 int pos[] = new int[positions.size() + 2]; | |
215 if (horizontal) | |
216 pos[0] = start.x; | |
217 else | |
218 pos[0] = start.y; | |
219 int i; | |
220 for (i = 0; i < positions.size(); i++) { | |
221 pos[i + 1] = (cast(Integer)positions.get(i)).intValue(); | |
222 } | |
223 if (horizontal is (positions.size() % 2 is 1)) | |
224 pos[++i] = end.x; | |
225 else | |
226 pos[++i] = end.y; | |
227 | |
228 PointList points = new PointList(); | |
229 points.addPoint(new Point(start.x, start.y)); | |
230 Point p; | |
231 int current, prev, min, max; | |
232 bool adjust; | |
233 for (i = 2; i < pos.length - 1; i++) { | |
234 horizontal = !horizontal; | |
235 prev = pos[i - 1]; | |
236 current = pos[i]; | |
237 | |
238 adjust = (i !is pos.length - 2); | |
239 if (horizontal) { | |
240 if (adjust) { | |
241 min = pos[i - 2]; | |
242 max = pos[i + 2]; | |
243 pos[i] = current = getRowNear(conn, current, min, max); | |
244 } | |
245 p = new Point(prev, current); | |
246 } else { | |
247 if (adjust) { | |
248 min = pos[i - 2]; | |
249 max = pos[i + 2]; | |
250 pos[i] = current = getColumnNear(conn, current, min, max); | |
251 } | |
252 p = new Point(current, prev); | |
253 } | |
254 points.addPoint(p); | |
255 } | |
256 points.addPoint(new Point(end.x, end.y)); | |
257 conn.setPoints(points); | |
258 } | |
259 | |
260 /** | |
261 * @see ConnectionRouter#remove(Connection) | |
262 */ | |
263 public void remove(Connection connection) { | |
264 removeReservedLines(connection); | |
265 } | |
266 | |
267 protected void removeReservedLines(Connection connection) { | |
268 ReservedInfo rInfo = cast(ReservedInfo) reservedInfo.get(cast(Object)connection); | |
269 if (rInfo is null) | |
270 return; | |
271 | |
272 for (int i = 0; i < rInfo.reservedRows.size(); i++) { | |
273 rowsUsed.remove(rInfo.reservedRows.get(i)); | |
274 } | |
275 for (int i = 0; i < rInfo.reservedCols.size(); i++) { | |
276 colsUsed.remove(rInfo.reservedCols.get(i)); | |
277 } | |
278 reservedInfo.remove(cast(Object)connection); | |
279 } | |
280 | |
281 protected void reserveColumn(Connection connection, Integer column) { | |
282 ReservedInfo info = cast(ReservedInfo) reservedInfo.get(cast(Object)connection); | |
283 if (info is null) { | |
284 info = new ReservedInfo(); | |
285 reservedInfo.put(cast(Object)connection, info); | |
286 } | |
287 info.reservedCols.add(column); | |
288 } | |
289 | |
290 protected void reserveRow(Connection connection, Integer row) { | |
291 ReservedInfo info = cast(ReservedInfo) reservedInfo.get(cast(Object)connection); | |
292 if (info is null) { | |
293 info = new ReservedInfo(); | |
294 reservedInfo.put(cast(Object)connection, info); | |
295 } | |
296 info.reservedRows.add(row); | |
297 } | |
298 | |
299 /** | |
300 * @see ConnectionRouter#route(Connection) | |
301 */ | |
302 public void route(Connection conn) { | |
303 if ((conn.getSourceAnchor() is null) || (conn.getTargetAnchor() is null)) | |
304 return; | |
305 int i; | |
306 Point startPoint = getStartPoint(conn); | |
307 conn.translateToRelative(startPoint); | |
308 Point endPoint = getEndPoint(conn); | |
309 conn.translateToRelative(endPoint); | |
310 | |
311 Ray start = new Ray(startPoint); | |
312 Ray end = new Ray(endPoint); | |
313 Ray average = start.getAveraged(end); | |
314 | |
315 Ray direction = new Ray(start, end); | |
316 Ray startNormal = getStartDirection(conn); | |
317 Ray endNormal = getEndDirection(conn); | |
318 | |
319 List positions = new ArrayList(5); | |
320 bool horizontal = startNormal.isHorizontal(); | |
321 if (horizontal) | |
322 positions.add(new Integer(start.y)); | |
323 else | |
324 positions.add(new Integer(start.x)); | |
325 horizontal = !horizontal; | |
326 | |
327 if (startNormal.dotProduct(endNormal) is 0) { | |
328 if ((startNormal.dotProduct(direction) >= 0) | |
329 && (endNormal.dotProduct(direction) <= 0)) { | |
330 // 0 | |
331 } else { | |
332 // 2 | |
333 if (startNormal.dotProduct(direction) < 0) | |
334 i = startNormal.similarity(start.getAdded(startNormal.getScaled(10))); | |
335 else { | |
336 if (horizontal) | |
337 i = average.y; | |
338 else | |
339 i = average.x; | |
340 } | |
341 positions.add(new Integer(i)); | |
342 horizontal = !horizontal; | |
343 | |
344 if (endNormal.dotProduct(direction) > 0) | |
345 i = endNormal.similarity(end.getAdded(endNormal.getScaled(10))); | |
346 else { | |
347 if (horizontal) | |
348 i = average.y; | |
349 else | |
350 i = average.x; | |
351 } | |
352 positions.add(new Integer(i)); | |
353 horizontal = !horizontal; | |
354 } | |
355 } else { | |
356 if (startNormal.dotProduct(endNormal) > 0) { | |
357 //1 | |
358 if (startNormal.dotProduct(direction) >= 0) | |
359 i = startNormal.similarity(start.getAdded(startNormal.getScaled(10))); | |
360 else | |
361 i = endNormal.similarity(end.getAdded(endNormal.getScaled(10))); | |
362 positions.add(new Integer(i)); | |
363 horizontal = !horizontal; | |
364 } else { | |
365 //3 or 1 | |
366 if (startNormal.dotProduct(direction) < 0) { | |
367 i = startNormal.similarity(start.getAdded(startNormal.getScaled(10))); | |
368 positions.add(new Integer(i)); | |
369 horizontal = !horizontal; | |
370 } | |
371 | |
372 if (horizontal) | |
373 i = average.y; | |
374 else | |
375 i = average.x; | |
376 positions.add(new Integer(i)); | |
377 horizontal = !horizontal; | |
378 | |
379 if (startNormal.dotProduct(direction) < 0) { | |
380 i = endNormal.similarity(end.getAdded(endNormal.getScaled(10))); | |
381 positions.add(new Integer(i)); | |
382 horizontal = !horizontal; | |
383 } | |
384 } | |
385 } | |
386 if (horizontal) | |
387 positions.add(new Integer(end.y)); | |
388 else | |
389 positions.add(new Integer(end.x)); | |
390 | |
391 processPositions(start, end, positions, startNormal.isHorizontal(), conn); | |
392 } | |
393 | |
394 } |