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