X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Frouting%2Falgorithm2%2FLocalRouter.java;h=e9063e0b19213424984b545eab29bae58a1c136e;hp=90d3e6d01f6ee9aa43124aaf6445257c6b5131f4;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hpb=24e2b34260f219f0d1644ca7a138894980e25b14 diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/routing/algorithm2/LocalRouter.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/routing/algorithm2/LocalRouter.java index 90d3e6d01..e9063e0b1 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/routing/algorithm2/LocalRouter.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/routing/algorithm2/LocalRouter.java @@ -1,447 +1,447 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.g2d.routing.algorithm2; - -import java.awt.geom.Path2D; - -import org.simantics.g2d.routing.Constants; - -public class LocalRouter { - - static final double CORNER_SIZE = 1.0; - - boolean roundCorners; - - double aMinX; - double aMinY; - double aMaxX; - double aMaxY; - - double bMinX; - double bMinY; - double bMaxX; - double bMaxY; - - double sx; - double sy; - - double tx; - double ty; - - int sourceDirection; - int targetDirection; - - Path2D path; - - public LocalRouter(boolean roundCorners) { - this.roundCorners = roundCorners; - } - - /** - * Case where both source and target connection directions - * are to east. - */ - void routeEast() { - if(bMinX >= aMaxX || tx >= 0 && !(bMaxY < aMinY || aMaxY < bMinY)) { - if(ty != 0.0) { - /* ______ ______ - * | | | | - * | |----\ | | - * | | \--->| | - * |______| |______| - */ - double mx = 0.5 * (aMaxX + bMinX); - point(mx, 0.0); - point(mx, ty); - } - else - ; // Just a straight line - } - else { - double x0 = bMinX; - double x1 = aMaxX; - double my; - /* ______ - * | | - * | | - * /->| | - * | |______| - * | - * \-------------\ - * ______ | - * | | | - * | |-/ - * | | - * |______| - * - * If the elements are separated in Y-direction, - * route between the elements (this is always the shortest path). - */ - if(bMaxY < aMinY) my = 0.5 * (aMinY + bMaxY); - else if(aMaxY < bMinY) my = 0.5 * (aMaxY + bMinY); - else { - /* - * /------------------------\ - * | ______ ______ | - * | | | | | | - * | | | | |--+ - * +->| | | | | - * | |______| |______| | - * | | - * \------------------------/ - * - * or - * - * /-----------\ - * | ______ | - * | | | | - * | | | | - * /--+->| | | - * | ___|______| | - * | | | | - * | | |-+---/ - * | | | | - * | |______| | - * | | - * \----------/ - * - * We may choose either lower or upper path. - */ - double upperX0 = bMinX; - double upperX1 = aMaxX; - double lowerX0 = bMinX; - double lowerX1 = aMaxX; - double upperY = Math.min(aMinY, bMinY); - double lowerY = Math.max(aMaxY, bMaxY); - - if(aMinX < bMinX) { - if(ty < 0.5 * (aMinY + aMaxY)) - lowerX0 = aMinX; - else - upperX0 = aMinX; - } - - if(bMaxX > aMaxX) { - if(ty < 0.5 * (aMinY + aMaxY)) - upperX1 = bMaxX; - else - lowerX1 = bMaxX; - } - - double upperLength = upperX1 - upperY + (upperX1 - upperX0) + (ty - upperY) + (tx - upperX0); - double lowerLength = lowerX1 + lowerY + (lowerX1 - lowerX0) + (lowerY - ty) + (tx - lowerX0); - - if(upperLength < lowerLength) { - x0 = upperX0; - x1 = upperX1; - my = upperY; - } - else { - x0 = lowerX0; - x1 = lowerX1; - my = lowerY; - } - } - point(x1, 0.0); - point(x1, my); - point(x0, my); - point(x0, ty); - } - } - - void routeWest() { - if(tx >= 0.0) { - double fx = Math.max(aMaxX, bMaxX); - double mx = 0.5 * (aMaxX + bMinX); - if(bMinY >= 0.0 || bMaxY <= 0.0 || mx < 0.0) { - /* ______ - * | | - * | | - * | |<-\ - * ______ |______| | - * | | | - * | |-------------------/ - * | | - * |______| - */ - point(fx, 0.0); - } - else { - /* /-------------\ - * | ______ | - * | | | | - * ______ | | | | - * | | | | |<-+ - * | |----+ |______| | - * | | | | - * |______| \-------------/ - * - * We may choose either upper or lower path - * by the path length. - */ - double my = - Math.abs(bMinY) + Math.abs(ty - bMinY) - < Math.abs(bMaxY) + Math.abs(ty - bMaxY) - ? bMinY : bMaxY; - point(mx, 0.0); - point(mx, my); - point(fx, my); - } - point(fx, ty); - } - else { - double fx = Math.max(aMaxX, bMaxX); - double mx = 0.5 * (aMinX + bMaxX); - point(fx, 0.0); - if(ty <= aMinY || ty >= aMaxY || (tx >= mx && ty >= aMinY && ty <= aMaxY)) { - /* ______ - * | | - * | | - * | |--\ - * ______ |______| | - * | | | - * | |<------------------/ - * | | - * |______| - */ - point(fx, ty); - } - else { - /* /-------------\ - * | ______ | - * | | | | - * ______ | | | | - * | | | | |--+ - * | |<---+ |______| | - * | | | | - * |______| \-------------/ - * - * We may choose either upper or lower path - * by the path length. - */ - double my = - Math.abs(aMinY) + Math.abs(ty - aMinY) - < Math.abs(aMaxY) + Math.abs(ty - aMaxY) - ? aMinY : aMaxY; - point(fx, my); - point(mx, my); - point(mx, ty); - } - } - } - - void routeSouth() { - if(tx > 0.0 && (bMinY >= 0.0 || (ty > 0.0 && bMinX <= aMaxX))) - point(tx, 0.0); - else if(bMinX > aMaxX) { - double mx = 0.5 * (aMaxX + bMinX); - point(mx, 0.0); - point(mx, bMinY); - point(tx, bMinY); - } - else { - double fx = aMaxX; - double my = 0.5 * (aMaxY + bMinY); - if(my < aMaxY && (tx < aMinX || ty < aMinY)) { - my = Math.min(aMinY, bMinY); - if(bMaxX > aMaxX) - fx = bMaxX; - } - point(fx, 0.0); - point(fx, my); - point(tx, my); - } - } - - double xx, xy, yx, yy; - void point(double x, double y) { - if (roundCorners) { - continuePath(x*xx + y*yx + sx, x*xy + y*yy + sy); - } else { - path.lineTo(x*xx + y*yx + sx, x*xy + y*yy + sy); - } - } - - double prevX, prevY, curX, curY, nextX, nextY; - boolean first; - void beginPath(double x, double y) { - path.moveTo(x, y); - nextX = x; - nextY = y; - first = true; - } - - static double dd(double d) { - if(Math.abs(d) < CORNER_SIZE*2.0) - return d*0.5; - else - return Math.signum(d)*CORNER_SIZE; - } - - void continuePath(double x, double y) { - prevX = curX; - prevY = curY; - curX = nextX; - curY = nextY; - nextX = x; - nextY = y; - - if(first) - first = false; - else { - double prevDeltaX = dd(prevX - curX); - double prevDeltaY = dd(prevY - curY); - double nextDeltaX = dd(nextX - curX); - double nextDeltaY = dd(nextY - curY); - - - path.lineTo(curX+prevDeltaX, curY+prevDeltaY); - path.quadTo( - curX, curY, - curX+nextDeltaX, curY+nextDeltaY); - //path.lineTo(curX+nextDeltaX, curY+nextDeltaY); - - //path.lineTo(curX, curY); - } - } - - void endPath() { - path.lineTo(nextX, nextY); - } - - void rotate() { - double temp; - - temp = tx; - tx = ty; - ty = -temp; - - temp = aMinX; - aMinX = aMinY; - aMinY = -aMaxX; - aMaxX = aMaxY; - aMaxY = -temp; - - temp = bMinX; - bMinX = bMinY; - bMinY = -bMaxX; - bMaxX = bMaxY; - bMaxY = -temp; - - temp = xx; - xx = -xy; - xy = temp; - - temp = yx; - yx = -yy; - yy = temp; - - --targetDirection; - if(targetDirection < 0) - targetDirection += 4; - --sourceDirection; - } - - void flip() { - double temp; - - ty = -ty; - - temp = aMinY; - aMinY = -aMaxY; - aMaxY = -temp; - - temp = bMinY; - bMinY = -bMaxY; - bMaxY = -temp; - - yx = -yx; - yy = -yy; - - targetDirection = (targetDirection + 2) % 4; - } - - /* - * Puts source terminal to origo and rotates the situation - * so that the connection leaves to east. Finally, the - * case where target direction is to south is eliminated - * by optionally flipping the situation. - */ - void canonicalize() { - aMinX -= sx; - aMinY -= sy; - aMaxX -= sx; - aMaxY -= sy; - bMinX -= sx; - bMinY -= sy; - bMaxX -= sx; - bMaxY -= sy; - tx -= sx; - ty -= sy; - xx = yy = 1.0; - xy = yx = 0.0; - while(sourceDirection > 0) - rotate(); - - if(targetDirection == Constants.SOUTH) - flip(); - } - - public void route() { - //System.out.println("route"); - //System.out.println(sourceDirection + " " + targetDirection); - - path = new Path2D.Double(); - - if (roundCorners) { - - beginPath(sx, sy); - - if(bMinX < sx && sx < bMaxX && bMinY < sy && sy < bMaxY) - targetDirection = (targetDirection+2)&3; - if(aMinX < tx && tx < aMaxX && aMinY < ty && ty < aMaxY) - sourceDirection = (sourceDirection+2)&3; - -// // Vertical and horizontal cases -// if(Math.abs(sx - tx) < 1e-5 || Math.abs(sy - ty) < 1e-5) { -// path.lineTo(tx, ty); -// return; -// } - - } else { - - path.moveTo(sx, sy); - - // Vertical and horizontal cases - // TODO Removed this seemingly incorrect code (they were already disabled in roundCorners case - /*if(Math.abs(sx - tx) < 1e-5 || Math.abs(sy - ty) < 1e-5) { - path.lineTo(tx, ty); - return; - }*/ - - } - - canonicalize(); - switch(targetDirection) { - case Constants.EAST: routeWest(); break; - case Constants.WEST: routeEast(); break; - case Constants.NORTH: routeSouth(); break; - } - point(tx, ty); - - if (roundCorners) { - endPath(); - } - //System.out.println(sourceDirection + " " + targetDirection); - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.g2d.routing.algorithm2; + +import java.awt.geom.Path2D; + +import org.simantics.g2d.routing.Constants; + +public class LocalRouter { + + static final double CORNER_SIZE = 1.0; + + boolean roundCorners; + + double aMinX; + double aMinY; + double aMaxX; + double aMaxY; + + double bMinX; + double bMinY; + double bMaxX; + double bMaxY; + + double sx; + double sy; + + double tx; + double ty; + + int sourceDirection; + int targetDirection; + + Path2D path; + + public LocalRouter(boolean roundCorners) { + this.roundCorners = roundCorners; + } + + /** + * Case where both source and target connection directions + * are to east. + */ + void routeEast() { + if(bMinX >= aMaxX || tx >= 0 && !(bMaxY < aMinY || aMaxY < bMinY)) { + if(ty != 0.0) { + /* ______ ______ + * | | | | + * | |----\ | | + * | | \--->| | + * |______| |______| + */ + double mx = 0.5 * (aMaxX + bMinX); + point(mx, 0.0); + point(mx, ty); + } + else + ; // Just a straight line + } + else { + double x0 = bMinX; + double x1 = aMaxX; + double my; + /* ______ + * | | + * | | + * /->| | + * | |______| + * | + * \-------------\ + * ______ | + * | | | + * | |-/ + * | | + * |______| + * + * If the elements are separated in Y-direction, + * route between the elements (this is always the shortest path). + */ + if(bMaxY < aMinY) my = 0.5 * (aMinY + bMaxY); + else if(aMaxY < bMinY) my = 0.5 * (aMaxY + bMinY); + else { + /* + * /------------------------\ + * | ______ ______ | + * | | | | | | + * | | | | |--+ + * +->| | | | | + * | |______| |______| | + * | | + * \------------------------/ + * + * or + * + * /-----------\ + * | ______ | + * | | | | + * | | | | + * /--+->| | | + * | ___|______| | + * | | | | + * | | |-+---/ + * | | | | + * | |______| | + * | | + * \----------/ + * + * We may choose either lower or upper path. + */ + double upperX0 = bMinX; + double upperX1 = aMaxX; + double lowerX0 = bMinX; + double lowerX1 = aMaxX; + double upperY = Math.min(aMinY, bMinY); + double lowerY = Math.max(aMaxY, bMaxY); + + if(aMinX < bMinX) { + if(ty < 0.5 * (aMinY + aMaxY)) + lowerX0 = aMinX; + else + upperX0 = aMinX; + } + + if(bMaxX > aMaxX) { + if(ty < 0.5 * (aMinY + aMaxY)) + upperX1 = bMaxX; + else + lowerX1 = bMaxX; + } + + double upperLength = upperX1 - upperY + (upperX1 - upperX0) + (ty - upperY) + (tx - upperX0); + double lowerLength = lowerX1 + lowerY + (lowerX1 - lowerX0) + (lowerY - ty) + (tx - lowerX0); + + if(upperLength < lowerLength) { + x0 = upperX0; + x1 = upperX1; + my = upperY; + } + else { + x0 = lowerX0; + x1 = lowerX1; + my = lowerY; + } + } + point(x1, 0.0); + point(x1, my); + point(x0, my); + point(x0, ty); + } + } + + void routeWest() { + if(tx >= 0.0) { + double fx = Math.max(aMaxX, bMaxX); + double mx = 0.5 * (aMaxX + bMinX); + if(bMinY >= 0.0 || bMaxY <= 0.0 || mx < 0.0) { + /* ______ + * | | + * | | + * | |<-\ + * ______ |______| | + * | | | + * | |-------------------/ + * | | + * |______| + */ + point(fx, 0.0); + } + else { + /* /-------------\ + * | ______ | + * | | | | + * ______ | | | | + * | | | | |<-+ + * | |----+ |______| | + * | | | | + * |______| \-------------/ + * + * We may choose either upper or lower path + * by the path length. + */ + double my = + Math.abs(bMinY) + Math.abs(ty - bMinY) + < Math.abs(bMaxY) + Math.abs(ty - bMaxY) + ? bMinY : bMaxY; + point(mx, 0.0); + point(mx, my); + point(fx, my); + } + point(fx, ty); + } + else { + double fx = Math.max(aMaxX, bMaxX); + double mx = 0.5 * (aMinX + bMaxX); + point(fx, 0.0); + if(ty <= aMinY || ty >= aMaxY || (tx >= mx && ty >= aMinY && ty <= aMaxY)) { + /* ______ + * | | + * | | + * | |--\ + * ______ |______| | + * | | | + * | |<------------------/ + * | | + * |______| + */ + point(fx, ty); + } + else { + /* /-------------\ + * | ______ | + * | | | | + * ______ | | | | + * | | | | |--+ + * | |<---+ |______| | + * | | | | + * |______| \-------------/ + * + * We may choose either upper or lower path + * by the path length. + */ + double my = + Math.abs(aMinY) + Math.abs(ty - aMinY) + < Math.abs(aMaxY) + Math.abs(ty - aMaxY) + ? aMinY : aMaxY; + point(fx, my); + point(mx, my); + point(mx, ty); + } + } + } + + void routeSouth() { + if(tx > 0.0 && (bMinY >= 0.0 || (ty > 0.0 && bMinX <= aMaxX))) + point(tx, 0.0); + else if(bMinX > aMaxX) { + double mx = 0.5 * (aMaxX + bMinX); + point(mx, 0.0); + point(mx, bMinY); + point(tx, bMinY); + } + else { + double fx = aMaxX; + double my = 0.5 * (aMaxY + bMinY); + if(my < aMaxY && (tx < aMinX || ty < aMinY)) { + my = Math.min(aMinY, bMinY); + if(bMaxX > aMaxX) + fx = bMaxX; + } + point(fx, 0.0); + point(fx, my); + point(tx, my); + } + } + + double xx, xy, yx, yy; + void point(double x, double y) { + if (roundCorners) { + continuePath(x*xx + y*yx + sx, x*xy + y*yy + sy); + } else { + path.lineTo(x*xx + y*yx + sx, x*xy + y*yy + sy); + } + } + + double prevX, prevY, curX, curY, nextX, nextY; + boolean first; + void beginPath(double x, double y) { + path.moveTo(x, y); + nextX = x; + nextY = y; + first = true; + } + + static double dd(double d) { + if(Math.abs(d) < CORNER_SIZE*2.0) + return d*0.5; + else + return Math.signum(d)*CORNER_SIZE; + } + + void continuePath(double x, double y) { + prevX = curX; + prevY = curY; + curX = nextX; + curY = nextY; + nextX = x; + nextY = y; + + if(first) + first = false; + else { + double prevDeltaX = dd(prevX - curX); + double prevDeltaY = dd(prevY - curY); + double nextDeltaX = dd(nextX - curX); + double nextDeltaY = dd(nextY - curY); + + + path.lineTo(curX+prevDeltaX, curY+prevDeltaY); + path.quadTo( + curX, curY, + curX+nextDeltaX, curY+nextDeltaY); + //path.lineTo(curX+nextDeltaX, curY+nextDeltaY); + + //path.lineTo(curX, curY); + } + } + + void endPath() { + path.lineTo(nextX, nextY); + } + + void rotate() { + double temp; + + temp = tx; + tx = ty; + ty = -temp; + + temp = aMinX; + aMinX = aMinY; + aMinY = -aMaxX; + aMaxX = aMaxY; + aMaxY = -temp; + + temp = bMinX; + bMinX = bMinY; + bMinY = -bMaxX; + bMaxX = bMaxY; + bMaxY = -temp; + + temp = xx; + xx = -xy; + xy = temp; + + temp = yx; + yx = -yy; + yy = temp; + + --targetDirection; + if(targetDirection < 0) + targetDirection += 4; + --sourceDirection; + } + + void flip() { + double temp; + + ty = -ty; + + temp = aMinY; + aMinY = -aMaxY; + aMaxY = -temp; + + temp = bMinY; + bMinY = -bMaxY; + bMaxY = -temp; + + yx = -yx; + yy = -yy; + + targetDirection = (targetDirection + 2) % 4; + } + + /* + * Puts source terminal to origo and rotates the situation + * so that the connection leaves to east. Finally, the + * case where target direction is to south is eliminated + * by optionally flipping the situation. + */ + void canonicalize() { + aMinX -= sx; + aMinY -= sy; + aMaxX -= sx; + aMaxY -= sy; + bMinX -= sx; + bMinY -= sy; + bMaxX -= sx; + bMaxY -= sy; + tx -= sx; + ty -= sy; + xx = yy = 1.0; + xy = yx = 0.0; + while(sourceDirection > 0) + rotate(); + + if(targetDirection == Constants.SOUTH) + flip(); + } + + public void route() { + //System.out.println("route"); + //System.out.println(sourceDirection + " " + targetDirection); + + path = new Path2D.Double(); + + if (roundCorners) { + + beginPath(sx, sy); + + if(bMinX < sx && sx < bMaxX && bMinY < sy && sy < bMaxY) + targetDirection = (targetDirection+2)&3; + if(aMinX < tx && tx < aMaxX && aMinY < ty && ty < aMaxY) + sourceDirection = (sourceDirection+2)&3; + +// // Vertical and horizontal cases +// if(Math.abs(sx - tx) < 1e-5 || Math.abs(sy - ty) < 1e-5) { +// path.lineTo(tx, ty); +// return; +// } + + } else { + + path.moveTo(sx, sy); + + // Vertical and horizontal cases + // TODO Removed this seemingly incorrect code (they were already disabled in roundCorners case + /*if(Math.abs(sx - tx) < 1e-5 || Math.abs(sy - ty) < 1e-5) { + path.lineTo(tx, ty); + return; + }*/ + + } + + canonicalize(); + switch(targetDirection) { + case Constants.EAST: routeWest(); break; + case Constants.WEST: routeEast(); break; + case Constants.NORTH: routeSouth(); break; + } + point(tx, ty); + + if (roundCorners) { + endPath(); + } + //System.out.println(sourceDirection + " " + targetDirection); + } + +}