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 }