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