1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.g2d.routing.algorithm2;
\r
14 import java.awt.geom.Path2D;
\r
16 import org.simantics.g2d.routing.Constants;
\r
18 public class LocalRouter {
\r
20 static final double CORNER_SIZE = 1.0;
\r
22 boolean roundCorners;
\r
40 int sourceDirection;
\r
41 int targetDirection;
\r
45 public LocalRouter(boolean roundCorners) {
\r
46 this.roundCorners = roundCorners;
\r
50 * Case where both source and target connection directions
\r
54 if(bMinX >= aMaxX || tx >= 0 && !(bMaxY < aMinY || aMaxY < bMinY)) {
\r
62 double mx = 0.5 * (aMaxX + bMinX);
\r
67 ; // Just a straight line
\r
86 * If the elements are separated in Y-direction,
\r
87 * route between the elements (this is always the shortest path).
\r
89 if(bMaxY < aMinY) my = 0.5 * (aMinY + bMaxY);
\r
90 else if(aMaxY < bMinY) my = 0.5 * (aMaxY + bMinY);
\r
93 * /------------------------\
\r
98 * | |______| |______| |
\r
100 * \------------------------/
\r
117 * We may choose either lower or upper path.
\r
119 double upperX0 = bMinX;
\r
120 double upperX1 = aMaxX;
\r
121 double lowerX0 = bMinX;
\r
122 double lowerX1 = aMaxX;
\r
123 double upperY = Math.min(aMinY, bMinY);
\r
124 double lowerY = Math.max(aMaxY, bMaxY);
\r
126 if(aMinX < bMinX) {
\r
127 if(ty < 0.5 * (aMinY + aMaxY))
\r
133 if(bMaxX > aMaxX) {
\r
134 if(ty < 0.5 * (aMinY + aMaxY))
\r
140 double upperLength = upperX1 - upperY + (upperX1 - upperX0) + (ty - upperY) + (tx - upperX0);
\r
141 double lowerLength = lowerX1 + lowerY + (lowerX1 - lowerX0) + (lowerY - ty) + (tx - lowerX0);
\r
143 if(upperLength < lowerLength) {
\r
163 double fx = Math.max(aMaxX, bMaxX);
\r
164 double mx = 0.5 * (aMaxX + bMinX);
\r
165 if(bMinY >= 0.0 || bMaxY <= 0.0 || mx < 0.0) {
\r
170 * ______ |______| |
\r
172 * | |-------------------/
\r
184 * | |----+ |______| |
\r
186 * |______| \-------------/
\r
188 * We may choose either upper or lower path
\r
189 * by the path length.
\r
192 Math.abs(bMinY) + Math.abs(ty - bMinY)
\r
193 < Math.abs(bMaxY) + Math.abs(ty - bMaxY)
\r
202 double fx = Math.max(aMaxX, bMaxX);
\r
203 double mx = 0.5 * (aMinX + bMaxX);
\r
205 if(ty <= aMinY || ty >= aMaxY || (tx >= mx && ty >= aMinY && ty <= aMaxY)) {
\r
210 * ______ |______| |
\r
212 * | |<------------------/
\r
224 * | |<---+ |______| |
\r
226 * |______| \-------------/
\r
228 * We may choose either upper or lower path
\r
229 * by the path length.
\r
232 Math.abs(aMinY) + Math.abs(ty - aMinY)
\r
233 < Math.abs(aMaxY) + Math.abs(ty - aMaxY)
\r
242 void routeSouth() {
\r
243 if(tx > 0.0 && (bMinY >= 0.0 || (ty > 0.0 && bMinX <= aMaxX)))
\r
245 else if(bMinX > aMaxX) {
\r
246 double mx = 0.5 * (aMaxX + bMinX);
\r
253 double my = 0.5 * (aMaxY + bMinY);
\r
254 if(my < aMaxY && (tx < aMinX || ty < aMinY)) {
\r
255 my = Math.min(aMinY, bMinY);
\r
265 double xx, xy, yx, yy;
\r
266 void point(double x, double y) {
\r
267 if (roundCorners) {
\r
268 continuePath(x*xx + y*yx + sx, x*xy + y*yy + sy);
\r
270 path.lineTo(x*xx + y*yx + sx, x*xy + y*yy + sy);
\r
274 double prevX, prevY, curX, curY, nextX, nextY;
\r
276 void beginPath(double x, double y) {
\r
283 static double dd(double d) {
\r
284 if(Math.abs(d) < CORNER_SIZE*2.0)
\r
287 return Math.signum(d)*CORNER_SIZE;
\r
290 void continuePath(double x, double y) {
\r
301 double prevDeltaX = dd(prevX - curX);
\r
302 double prevDeltaY = dd(prevY - curY);
\r
303 double nextDeltaX = dd(nextX - curX);
\r
304 double nextDeltaY = dd(nextY - curY);
\r
307 path.lineTo(curX+prevDeltaX, curY+prevDeltaY);
\r
310 curX+nextDeltaX, curY+nextDeltaY);
\r
311 //path.lineTo(curX+nextDeltaX, curY+nextDeltaY);
\r
313 //path.lineTo(curX, curY);
\r
318 path.lineTo(nextX, nextY);
\r
349 if(targetDirection < 0)
\r
350 targetDirection += 4;
\r
370 targetDirection = (targetDirection + 2) % 4;
\r
374 * Puts source terminal to origo and rotates the situation
\r
375 * so that the connection leaves to east. Finally, the
\r
376 * case where target direction is to south is eliminated
\r
377 * by optionally flipping the situation.
\r
379 void canonicalize() {
\r
392 while(sourceDirection > 0)
\r
395 if(targetDirection == Constants.SOUTH)
\r
399 public void route() {
\r
400 //System.out.println("route");
\r
401 //System.out.println(sourceDirection + " " + targetDirection);
\r
403 path = new Path2D.Double();
\r
405 if (roundCorners) {
\r
409 if(bMinX < sx && sx < bMaxX && bMinY < sy && sy < bMaxY)
\r
410 targetDirection = (targetDirection+2)&3;
\r
411 if(aMinX < tx && tx < aMaxX && aMinY < ty && ty < aMaxY)
\r
412 sourceDirection = (sourceDirection+2)&3;
\r
414 // // Vertical and horizontal cases
\r
415 // if(Math.abs(sx - tx) < 1e-5 || Math.abs(sy - ty) < 1e-5) {
\r
416 // path.lineTo(tx, ty);
\r
422 path.moveTo(sx, sy);
\r
424 // Vertical and horizontal cases
\r
425 // TODO Removed this seemingly incorrect code (they were already disabled in roundCorners case
\r
426 /*if(Math.abs(sx - tx) < 1e-5 || Math.abs(sy - ty) < 1e-5) {
\r
427 path.lineTo(tx, ty);
\r
434 switch(targetDirection) {
\r
435 case Constants.EAST: routeWest(); break;
\r
436 case Constants.WEST: routeEast(); break;
\r
437 case Constants.NORTH: routeSouth(); break;
\r
441 if (roundCorners) {
\r
444 //System.out.println(sourceDirection + " " + targetDirection);
\r