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 }