Project

General

Profile

Download (9.41 KB) Statistics
| Branch: | Tag: | Revision:
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 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
 *******************************************************************************/
11
package org.eclipse.draw2d;
12

    
13
import java.util.ArrayList;
14
import java.util.HashMap;
15
import java.util.List;
16
import java.util.Map;
17

    
18
import org.eclipse.draw2d.geometry.Point;
19
import org.eclipse.draw2d.geometry.PointList;
20
import org.eclipse.draw2d.geometry.Ray;
21
import org.eclipse.draw2d.geometry.Rectangle;
22

    
23
/**
24
 * Provides a {@link Connection} with an orthogonal route between the
25
 * Connection's source and target anchors.
26
 */
27
public final class ManhattanConnectionRouter extends AbstractRouter {
28

    
29
	private Map rowsUsed = new HashMap();
30
	private Map colsUsed = new HashMap();
31
	// private Hashtable offsets = new Hashtable(7);
32

    
33
	private Map reservedInfo = new HashMap();
34

    
35
	private class ReservedInfo {
36
		public List reservedRows = new ArrayList(2);
37
		public List reservedCols = new ArrayList(2);
38
	}
39

    
40
	private static Ray UP = new Ray(0, -1), DOWN = new Ray(0, 1),
41
			LEFT = new Ray(-1, 0), RIGHT = new Ray(1, 0);
42

    
43
	/**
44
	 * @see ConnectionRouter#invalidate(Connection)
45
	 */
46
	public void invalidate(Connection connection) {
47
		removeReservedLines(connection);
48
	}
49

    
50
	private int getColumnNear(Connection connection, int r, int n, int x) {
51
		int min = Math.min(n, x), max = Math.max(n, x);
52
		if (min > r) {
53
			max = min;
54
			min = r - (min - r);
55
		}
56
		if (max < r) {
57
			min = max;
58
			max = r + (r - max);
59
		}
60
		int proximity = 0;
61
		int direction = -1;
62
		if (r % 2 == 1)
63
			r--;
64
		Integer i;
65
		while (proximity < r) {
66
			i = new Integer(r + proximity * direction);
67
			if (!colsUsed.containsKey(i)) {
68
				colsUsed.put(i, i);
69
				reserveColumn(connection, i);
70
				return i.intValue();
71
			}
72
			int j = i.intValue();
73
			if (j <= min)
74
				return j + 2;
75
			if (j >= max)
76
				return j - 2;
77
			if (direction == 1)
78
				direction = -1;
79
			else {
80
				direction = 1;
81
				proximity += 2;
82
			}
83
		}
84
		return r;
85
	}
86

    
87
	/**
88
	 * Returns the direction the point <i>p</i> is in relation to the given
89
	 * rectangle. Possible values are LEFT (-1,0), RIGHT (1,0), UP (0,-1) and
90
	 * DOWN (0,1).
91
	 * 
92
	 * @param r
93
	 *            the rectangle
94
	 * @param p
95
	 *            the point
96
	 * @return the direction from <i>r</i> to <i>p</i>
97
	 */
98
	protected Ray getDirection(Rectangle r, Point p) {
99
		int i, distance = Math.abs(r.x - p.x);
100
		Ray direction;
101

    
102
		direction = LEFT;
103

    
104
		i = Math.abs(r.y - p.y);
105
		if (i <= distance) {
106
			distance = i;
107
			direction = UP;
108
		}
109

    
110
		i = Math.abs(r.bottom() - p.y);
111
		if (i <= distance) {
112
			distance = i;
113
			direction = DOWN;
114
		}
115

    
116
		i = Math.abs(r.right() - p.x);
117
		if (i < distance) {
118
			distance = i;
119
			direction = RIGHT;
120
		}
121

    
122
		return direction;
123
	}
124

    
125
	protected Ray getEndDirection(Connection conn) {
126
		ConnectionAnchor anchor = conn.getTargetAnchor();
127
		Point p = getEndPoint(conn);
128
		Rectangle rect;
129
		if (anchor.getOwner() == null)
130
			rect = new Rectangle(p.x - 1, p.y - 1, 2, 2);
131
		else {
132
			rect = conn.getTargetAnchor().getOwner().getBounds().getCopy();
133
			conn.getTargetAnchor().getOwner().translateToAbsolute(rect);
134
		}
135
		return getDirection(rect, p);
136
	}
137

    
138
	protected int getRowNear(Connection connection, int r, int n, int x) {
139
		int min = Math.min(n, x), max = Math.max(n, x);
140
		if (min > r) {
141
			max = min;
142
			min = r - (min - r);
143
		}
144
		if (max < r) {
145
			min = max;
146
			max = r + (r - max);
147
		}
148

    
149
		int proximity = 0;
150
		int direction = -1;
151
		if (r % 2 == 1)
152
			r--;
153
		Integer i;
154
		while (proximity < r) {
155
			i = new Integer(r + proximity * direction);
156
			if (!rowsUsed.containsKey(i)) {
157
				rowsUsed.put(i, i);
158
				reserveRow(connection, i);
159
				return i.intValue();
160
			}
161
			int j = i.intValue();
162
			if (j <= min)
163
				return j + 2;
164
			if (j >= max)
165
				return j - 2;
166
			if (direction == 1)
167
				direction = -1;
168
			else {
169
				direction = 1;
170
				proximity += 2;
171
			}
172
		}
173
		return r;
174
	}
175

    
176
	protected Ray getStartDirection(Connection conn) {
177
		ConnectionAnchor anchor = conn.getSourceAnchor();
178
		Point p = getStartPoint(conn);
179
		Rectangle rect;
180
		if (anchor.getOwner() == null)
181
			rect = new Rectangle(p.x - 1, p.y - 1, 2, 2);
182
		else {
183
			rect = conn.getSourceAnchor().getOwner().getBounds().getCopy();
184
			conn.getSourceAnchor().getOwner().translateToAbsolute(rect);
185
		}
186
		return getDirection(rect, p);
187
	}
188

    
189
	protected void processPositions(Ray start, Ray end, List positions,
190
			boolean horizontal, Connection conn) {
191
		removeReservedLines(conn);
192

    
193
		int pos[] = new int[positions.size() + 2];
194
		if (horizontal)
195
			pos[0] = start.x;
196
		else
197
			pos[0] = start.y;
198
		int i;
199
		for (i = 0; i < positions.size(); i++) {
200
			pos[i + 1] = ((Integer) positions.get(i)).intValue();
201
		}
202
		if (horizontal == (positions.size() % 2 == 1))
203
			pos[++i] = end.x;
204
		else
205
			pos[++i] = end.y;
206

    
207
		PointList points = new PointList();
208
		points.addPoint(new Point(start.x, start.y));
209
		Point p;
210
		int current, prev, min, max;
211
		boolean adjust;
212
		for (i = 2; i < pos.length - 1; i++) {
213
			horizontal = !horizontal;
214
			prev = pos[i - 1];
215
			current = pos[i];
216

    
217
			adjust = (i != pos.length - 2);
218
			if (horizontal) {
219
				if (adjust) {
220
					min = pos[i - 2];
221
					max = pos[i + 2];
222
					pos[i] = current = getRowNear(conn, current, min, max);
223
				}
224
				p = new Point(prev, current);
225
			} else {
226
				if (adjust) {
227
					min = pos[i - 2];
228
					max = pos[i + 2];
229
					pos[i] = current = getColumnNear(conn, current, min, max);
230
				}
231
				p = new Point(current, prev);
232
			}
233
			points.addPoint(p);
234
		}
235
		points.addPoint(new Point(end.x, end.y));
236
		conn.setPoints(points);
237
	}
238

    
239
	/**
240
	 * @see ConnectionRouter#remove(Connection)
241
	 */
242
	public void remove(Connection connection) {
243
		removeReservedLines(connection);
244
	}
245

    
246
	protected void removeReservedLines(Connection connection) {
247
		ReservedInfo rInfo = (ReservedInfo) reservedInfo.get(connection);
248
		if (rInfo == null)
249
			return;
250

    
251
		for (int i = 0; i < rInfo.reservedRows.size(); i++) {
252
			rowsUsed.remove(rInfo.reservedRows.get(i));
253
		}
254
		for (int i = 0; i < rInfo.reservedCols.size(); i++) {
255
			colsUsed.remove(rInfo.reservedCols.get(i));
256
		}
257
		reservedInfo.remove(connection);
258
	}
259

    
260
	protected void reserveColumn(Connection connection, Integer column) {
261
		ReservedInfo info = (ReservedInfo) reservedInfo.get(connection);
262
		if (info == null) {
263
			info = new ReservedInfo();
264
			reservedInfo.put(connection, info);
265
		}
266
		info.reservedCols.add(column);
267
	}
268

    
269
	protected void reserveRow(Connection connection, Integer row) {
270
		ReservedInfo info = (ReservedInfo) reservedInfo.get(connection);
271
		if (info == null) {
272
			info = new ReservedInfo();
273
			reservedInfo.put(connection, info);
274
		}
275
		info.reservedRows.add(row);
276
	}
277

    
278
	/**
279
	 * @see ConnectionRouter#route(Connection)
280
	 */
281
	public void route(Connection conn) {
282
		if ((conn.getSourceAnchor() == null)
283
				|| (conn.getTargetAnchor() == null))
284
			return;
285
		int i;
286
		Point startPoint = getStartPoint(conn);
287
		conn.translateToRelative(startPoint);
288
		Point endPoint = getEndPoint(conn);
289
		conn.translateToRelative(endPoint);
290

    
291
		Ray start = new Ray(startPoint);
292
		Ray end = new Ray(endPoint);
293
		Ray average = start.getAveraged(end);
294

    
295
		Ray direction = new Ray(start, end);
296
		Ray startNormal = getStartDirection(conn);
297
		Ray endNormal = getEndDirection(conn);
298

    
299
		List positions = new ArrayList(5);
300
		boolean horizontal = startNormal.isHorizontal();
301
		if (horizontal)
302
			positions.add(new Integer(start.y));
303
		else
304
			positions.add(new Integer(start.x));
305
		horizontal = !horizontal;
306

    
307
		if (startNormal.dotProduct(endNormal) == 0) {
308
			if ((startNormal.dotProduct(direction) >= 0)
309
					&& (endNormal.dotProduct(direction) <= 0)) {
310
				// 0
311
			} else {
312
				// 2
313
				if (startNormal.dotProduct(direction) < 0)
314
					i = startNormal.similarity(start.getAdded(startNormal
315
							.getScaled(10)));
316
				else {
317
					if (horizontal)
318
						i = average.y;
319
					else
320
						i = average.x;
321
				}
322
				positions.add(new Integer(i));
323
				horizontal = !horizontal;
324

    
325
				if (endNormal.dotProduct(direction) > 0)
326
					i = endNormal.similarity(end.getAdded(endNormal
327
							.getScaled(10)));
328
				else {
329
					if (horizontal)
330
						i = average.y;
331
					else
332
						i = average.x;
333
				}
334
				positions.add(new Integer(i));
335
				horizontal = !horizontal;
336
			}
337
		} else {
338
			if (startNormal.dotProduct(endNormal) > 0) {
339
				// 1
340
				if (startNormal.dotProduct(direction) >= 0)
341
					i = startNormal.similarity(start.getAdded(startNormal
342
							.getScaled(10)));
343
				else
344
					i = endNormal.similarity(end.getAdded(endNormal
345
							.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
352
							.getScaled(10)));
353
					positions.add(new Integer(i));
354
					horizontal = !horizontal;
355
				}
356

    
357
				if (horizontal)
358
					i = average.y;
359
				else
360
					i = average.x;
361
				positions.add(new Integer(i));
362
				horizontal = !horizontal;
363

    
364
				if (startNormal.dotProduct(direction) < 0) {
365
					i = endNormal.similarity(end.getAdded(endNormal
366
							.getScaled(10)));
367
					positions.add(new Integer(i));
368
					horizontal = !horizontal;
369
				}
370
			}
371
		}
372
		if (horizontal)
373
			positions.add(new Integer(end.y));
374
		else
375
			positions.add(new Integer(end.x));
376

    
377
		processPositions(start, end, positions, startNormal.isHorizontal(),
378
				conn);
379
	}
380

    
381
}
(104-104/171)