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