]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/SimpleConnectionUtility.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.diagram.connection / src / org / simantics / diagram / connection / SimpleConnectionUtility.java
index 4f9b94f77e452df5e0756a4ed1874ccd75f04ecc..109f8fe735ed9cf1bb947530c290e618633ea842 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2011 Association for Decentralized Information Management in\r
- * 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.diagram.connection;\r
-\r
-/**\r
- * An internal utility class for routing simple connections \r
- * (a connection with two terminals without any route lines).\r
- * \r
- * @author Hannu Niemistö\r
- */\r
-class SimpleConnectionUtility {\r
-\r
-    public static boolean allowsDirection(RouteTerminal a, int dir) {\r
-        return Directions.isAllowed(a.getAllowedDirections(), dir);\r
-    }\r
-    \r
-    public static final int DIRECT_HORIZONTAL_CONNECTION = 0;\r
-    public static final int DIRECT_VERTICAL_CONNECTION = 1;\r
-    \r
-    public static final int ONE_BEND_HORIZONTAL_VERTICAL = 2;\r
-    public static final int ONE_BEND_VERTICAL_HORIZONTAL = 3;\r
-\r
-    public static final int MORE_BENDS_BBS_DONT_INTERSECT = 4;\r
-    public static final int MORE_BENDS_BBS_INTERSECT = 5;\r
-    \r
-    public static final int COMPLEX_CONNECTION = 6;\r
-    \r
-    public static int simpleConnectionCase(RouteTerminal a, RouteTerminal b) {\r
-        if(a.isRouteToBounds() && b.isRouteToBounds())\r
-            return simpleConnectionCaseRouteToBounds(a, b);\r
-                    \r
-        // Can connect terminals by one straight line?\r
-        if(a.y == b.y) {\r
-            if(a.x < b.x) {\r
-                if(allowsDirection(a, 0) && allowsDirection(b, 2))\r
-                    return DIRECT_HORIZONTAL_CONNECTION;\r
-            }\r
-            else {\r
-                if(allowsDirection(a, 2) && allowsDirection(b, 0))\r
-                    return DIRECT_HORIZONTAL_CONNECTION;\r
-            }\r
-        }\r
-        else if(a.x == b.x) {\r
-            if(a.y < b.y) {\r
-                if(allowsDirection(a, 1) && allowsDirection(b, 3))\r
-                    return DIRECT_VERTICAL_CONNECTION;\r
-            }\r
-            else {\r
-                if(allowsDirection(a, 3) && allowsDirection(b, 1))\r
-                    return DIRECT_VERTICAL_CONNECTION;\r
-            }\r
-        }\r
-        \r
-        // Can connect terminals by two lines?\r
-        if(a.x < b.x) {\r
-            if(a.y < b.y) {\r
-                if(allowsDirection(a, 0) && allowsDirection(b, 3)\r
-                        /*&& b.x >= a.getMaxX() && a.y <= b.getMinY()*/)\r
-                    return ONE_BEND_HORIZONTAL_VERTICAL;\r
-                else if(allowsDirection(a, 1) && allowsDirection(b, 2)\r
-                        /*&& b.y >= a.getMaxY() && a.x <= b.getMinX()*/)\r
-                    return ONE_BEND_VERTICAL_HORIZONTAL;\r
-            }\r
-            else {\r
-                if(allowsDirection(a, 0) && allowsDirection(b, 1)\r
-                        /*&& b.x >= a.getMaxX() && a.y >= b.getMaxY()*/)\r
-                    return ONE_BEND_HORIZONTAL_VERTICAL;\r
-                else if(allowsDirection(a, 3) && allowsDirection(b, 2)\r
-                        /*&& b.y <= a.getMinY() && a.x <= b.getMinX()*/)\r
-                    return ONE_BEND_VERTICAL_HORIZONTAL;\r
-            }\r
-        }\r
-        else {\r
-            if(a.y < b.y) {\r
-                if(allowsDirection(a, 2) && allowsDirection(b, 3)\r
-                        /*&& b.x <= a.getMinX() && a.y <= b.getMinY()*/)\r
-                    return ONE_BEND_HORIZONTAL_VERTICAL;\r
-                else if(allowsDirection(a, 1) && allowsDirection(b, 0)\r
-                        /*&& b.y >= a.getMaxY() && a.x >= b.getMaxX()*/)\r
-                    return ONE_BEND_VERTICAL_HORIZONTAL;\r
-            }\r
-            else {\r
-                if(allowsDirection(a, 2) && allowsDirection(b, 1)\r
-                        /*&& b.x <= a.getMinX() && a.y >= b.getMaxY()*/)\r
-                    return ONE_BEND_HORIZONTAL_VERTICAL;\r
-                else if(allowsDirection(a, 3) && allowsDirection(b, 0)\r
-                        /*&& b.y <= a.getMinY() && a.x >= b.getMaxX()*/)\r
-                    return ONE_BEND_VERTICAL_HORIZONTAL;\r
-            }\r
-        }\r
-        \r
-        // Do bounding boxes intersect each other?\r
-        boolean boundingBoxesIntersect = !(\r
-                a.getMaxX() < b.getMinX() ||\r
-                a.getMinX() > b.getMaxX() ||\r
-                a.getMaxY() < b.getMinY() ||\r
-                a.getMinY() > b.getMaxY() \r
-                );\r
-        \r
-        if(boundingBoxesIntersect) {\r
-            // Can connect terminals by two lines if we ignore bounding boxes?\r
-            if(a.x < b.x) {\r
-                if(a.y < b.y) {\r
-                    if(allowsDirection(a, 0) && allowsDirection(b, 3))\r
-                        return ONE_BEND_HORIZONTAL_VERTICAL;\r
-                    else if(allowsDirection(a, 1) && allowsDirection(b, 2))\r
-                        return ONE_BEND_VERTICAL_HORIZONTAL;\r
-                }\r
-                else {\r
-                    if(allowsDirection(a, 0) && allowsDirection(b, 1))\r
-                        return ONE_BEND_HORIZONTAL_VERTICAL;\r
-                    else if(allowsDirection(a, 3) && allowsDirection(b, 2))\r
-                        return ONE_BEND_VERTICAL_HORIZONTAL;\r
-                }\r
-            }\r
-            else {\r
-                if(a.y < b.y) {\r
-                    if(allowsDirection(a, 2) && allowsDirection(b, 3))\r
-                        return ONE_BEND_HORIZONTAL_VERTICAL;\r
-                    else if(allowsDirection(a, 1) && allowsDirection(b, 0))\r
-                        return ONE_BEND_VERTICAL_HORIZONTAL;\r
-                }\r
-                else {\r
-                    if(allowsDirection(a, 2) && allowsDirection(b, 1))\r
-                        return ONE_BEND_HORIZONTAL_VERTICAL;\r
-                    else if(allowsDirection(a, 3) && allowsDirection(b, 0))\r
-                        return ONE_BEND_VERTICAL_HORIZONTAL;\r
-                }\r
-            }\r
-            \r
-            // Otherwise\r
-            return MORE_BENDS_BBS_INTERSECT;\r
-        }        \r
-        \r
-        // Otherwise\r
-        return MORE_BENDS_BBS_DONT_INTERSECT;\r
-    }\r
-    \r
-    private static int simpleConnectionCaseRouteToBounds(RouteTerminal a,\r
-            RouteTerminal b) {\r
-        double aX = 0.5*(a.getMinX() + a.getMaxX());\r
-        double aY = 0.5*(a.getMinY() + a.getMaxY());\r
-        double bX = 0.5*(b.getMinX() + b.getMaxX());\r
-        double bY = 0.5*(b.getMinY() + b.getMaxY());\r
-        \r
-        double minY = Math.max(a.getMinY(), b.getMinY());\r
-        double maxY = Math.min(a.getMaxY(), b.getMaxY());\r
-        \r
-        if(minY <= maxY) {\r
-            double cY = 0.5*(minY+maxY);\r
-            a.setY(cY);\r
-            b.setY(cY);\r
-            if(aX < bX) {\r
-                a.setX(a.getMaxX());\r
-                b.setX(b.getMinX());\r
-            }\r
-            else {\r
-                a.setX(a.getMinX());\r
-                b.setX(b.getMaxX());\r
-            }\r
-            return DIRECT_HORIZONTAL_CONNECTION;\r
-        }\r
-        \r
-        double minX = Math.max(a.getMinX(), b.getMinX());\r
-        double maxX = Math.min(a.getMaxX(), b.getMaxX());\r
-        \r
-        if(minX <= maxX) {\r
-            double cX = 0.5*(minX+maxX);\r
-            a.setX(cX);\r
-            b.setX(cX);\r
-            if(aY < bY) {\r
-                a.setY(a.getMaxY());\r
-                b.setY(b.getMinY());\r
-            }\r
-            else {\r
-                a.setY(a.getMinY());\r
-                b.setY(b.getMaxY());\r
-            }\r
-            return DIRECT_VERTICAL_CONNECTION;\r
-        }\r
-        \r
-        {\r
-            a.setY(aY);\r
-            b.setX(bX);\r
-            if(aX < bX) {\r
-                a.setX(a.getMaxX());\r
-            }\r
-            else {\r
-                a.setX(a.getMinX());\r
-            }\r
-            if(aY < bY) {\r
-                b.setY(b.getMinY());\r
-            }\r
-            else {\r
-                b.setY(b.getMaxY());\r
-            }\r
-            return ONE_BEND_HORIZONTAL_VERTICAL;\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Finds a route line for two route terminals.\r
-     */\r
-    public static RouteLine findRouteLine(RouteTerminal a, RouteTerminal b, boolean terminalsIntersect) {\r
-        if(terminalsIntersect) {\r
-            if(a.x < b.x) {\r
-                if((a.getAllowedDirections() & RouteTerminal.DIR_RIGHT) != 0 \r
-                        && (b.getAllowedDirections() & RouteTerminal.DIR_LEFT) != 0) {\r
-                    return new RouteLine(false, 0.5 * (a.x + b.x));\r
-                }\r
-            }\r
-            else {\r
-                if((a.getAllowedDirections() & RouteTerminal.DIR_LEFT) != 0 \r
-                        && (b.getAllowedDirections() & RouteTerminal.DIR_RIGHT) != 0) {\r
-                    return new RouteLine(false, 0.5 * (a.x + b.x));\r
-                }\r
-            }\r
-            if(a.y < b.y) {\r
-                if((a.getAllowedDirections() & RouteTerminal.DIR_DOWN) != 0 \r
-                        && (b.getAllowedDirections() & RouteTerminal.DIR_UP) != 0) {\r
-                    return new RouteLine(true, 0.5 * (a.y + b.y));\r
-                }\r
-            }\r
-            else {\r
-                if((a.getAllowedDirections() & RouteTerminal.DIR_UP) != 0 \r
-                        && (b.getAllowedDirections() & RouteTerminal.DIR_DOWN) != 0) {\r
-                    return new RouteLine(true, 0.5 * (a.y + b.y));\r
-                }\r
-            }\r
-        }\r
-        \r
-        //int aDir = Directions.firstAllowedDirection(a.getAllowedDirections());\r
-        //int bDir = Directions.firstAllowedDirection(b.getAllowedDirections());\r
-        \r
-        boolean isHorizontal = true;\r
-        double position = 0.0;\r
-        \r
-        loop:\r
-        for(int aDir=0;aDir<4;++aDir)\r
-            if(Directions.isAllowed(a.getAllowedDirections(), aDir))\r
-                for(int bDir=0;bDir<4;++bDir)\r
-                    if(Directions.isAllowed(b.getAllowedDirections(), bDir)) {\r
-                        // Connection starts to the same direction from the both terminals\r
-                        if(aDir == bDir) {\r
-                            isHorizontal = !isHorizontal(aDir);\r
-                            if(!terminalsIntersect) {\r
-                                if(dist(aDir, a, b) > 0 && isIn(aDir+1, a.x, a.y, b)) {\r
-                                    position = middle(aDir, a, b);\r
-                                    break loop;\r
-                                }\r
-                                else if(dist(aDir, b, a) > 0 && isIn(aDir+1, b.x, b.y, a)) {\r
-                                    position = middle(aDir, b, a);\r
-                                    break loop;\r
-                                }\r
-                            }\r
-                            position = boundary(aDir, a, b);\r
-                        }\r
-                        // Connection starts horizontally from one terminal and\r
-                        // vertically from another terminal\r
-                        else if(((aDir ^ bDir)&1) == 1) {\r
-                            if(dist(aDir, a, b) >= 0) {\r
-                                isHorizontal = !isHorizontal(aDir);\r
-                                position = middle(aDir, a, b);\r
-                                break loop;\r
-                            }\r
-                            else if(dist(bDir, b, a) >= 0) {\r
-                                isHorizontal = isHorizontal(aDir);;\r
-                                position = middle(bDir, b, a);\r
-                                break loop;\r
-                            }\r
-                            else if(firstIsBoundary(bDir, a, b)) {\r
-                                isHorizontal = isHorizontal(aDir);\r
-                                position = boundary(bDir, b, a);\r
-                            }\r
-                            else {\r
-                                isHorizontal = !isHorizontal(aDir);\r
-                                position = boundary(aDir, a, b);\r
-                            }\r
-                        }\r
-                        // Connection starts to opposite directions from the terminals\r
-                        else {           \r
-                            if(dist(aDir, a, b) >= 0.0) {\r
-                                isHorizontal = !isHorizontal(aDir);\r
-                                position = middle(aDir, a, b);\r
-                                break loop;\r
-                            }\r
-                            else if(dist(aDir+1, a, b) >= 0.0) {\r
-                                isHorizontal = isHorizontal(aDir);\r
-                                position = middle(aDir+1, a, b);\r
-                                break loop;\r
-                            }\r
-                            else if(dist(aDir-1, a, b) >= 0.0) {\r
-                                isHorizontal = isHorizontal(aDir);\r
-                                position = middle(aDir+1, a, b);\r
-                                break loop;\r
-                            }\r
-                            else {\r
-                                isHorizontal = isHorizontal(aDir);\r
-                                double b1 = boundary(aDir+1, a, b);\r
-                                double b2 = boundary(aDir-1, a, b);\r
-                                double cost1, cost2;\r
-                                if(isHorizontal) {\r
-                                    double da1 = a.y - b1;\r
-                                    double db1 = b.y - b1;\r
-                                    cost1 = da1*da1 + db1*db1;\r
-                                    double da2 = a.y - b2;\r
-                                    double db2 = b.y - b2;\r
-                                    cost2 = da2*da2 + db1*db2;\r
-                                }\r
-                                else {\r
-                                    double da1 = a.x - b1;\r
-                                    double db1 = b.x - b1;\r
-                                    cost1 = da1*da1 + db1*db1;\r
-                                    double da2 = a.x - b2;\r
-                                    double db2 = b.x - b2;\r
-                                    cost2 = da2*da2 + db1*db2;\r
-                                }\r
-                                position = cost1 <= cost2 ? b1 : b2;\r
-                            }\r
-                        }\r
-                    }\r
-        return new RouteLine(isHorizontal, position);\r
-    }\r
-    \r
-    /**\r
-     * Computes the difference between two points to the given direction\r
-     */\r
-    public static double diff(int dir, double x1, double y1, double x2, double y2) {\r
-        switch(dir&3) {\r
-        case 0: return x1 - x2;\r
-        case 1: return y1 - y2;\r
-        case 2: return x2 - x1;\r
-        case 3: return y2 - y1;\r
-        default: throw new Error("Should not happen.");\r
-        }\r
-    }\r
-    \r
-    /**\r
-     * Computes the distance of the bounding boxes of the two route terminals\r
-     * to the given direction.\r
-     */\r
-    public static double dist(int dir, RouteTerminal a, RouteTerminal b) {\r
-        switch(dir&3) {\r
-        case 0: return b.getMinX() - a.getMaxX();\r
-        case 1: return b.getMinY() - a.getMaxY();\r
-        case 2: return a.getMinX() - b.getMaxX();\r
-        case 3: return a.getMinY() - b.getMaxY();\r
-        default: throw new Error("Should not happen.");\r
-        }\r
-    }\r
-    \r
-    /**\r
-     * Computes the middle point between two terminals in the given direction.\r
-     */\r
-    public static double middle(int dir, RouteTerminal a, RouteTerminal b) {\r
-        switch(dir&3) {\r
-        case 0: return 0.5*(b.getMinX() + a.getMaxX());\r
-        case 1: return 0.5*(b.getMinY() + a.getMaxY());\r
-        case 2: return 0.5*(a.getMinX() + b.getMaxX());\r
-        case 3: return 0.5*(a.getMinY() + b.getMaxY());\r
-        default: throw new Error("Should not happen.");\r
-        }\r
-    }\r
-    \r
-    /**\r
-     * Tests whether the point is inside the bounding box of the terminal\r
-     * in the given direction.\r
-     */\r
-    public static boolean isIn(int dir, double x, double y, RouteTerminal a) {\r
-        if((dir&1) == 0)\r
-            return a.getMinX() < x && x < a.getMaxX();\r
-        else\r
-            return a.getMinY() < y && y < a.getMaxY();\r
-    }\r
-    \r
-    public static boolean isHorizontal(int dir) {\r
-        return (dir&1) == 0;\r
-    }\r
-    \r
-    /**\r
-     * Gives the boundary of the route terminal in the given direction.\r
-     */\r
-    public static double boundary(int dir, RouteTerminal a) {\r
-        switch(dir&3) {\r
-        case 0: return a.getMaxX();\r
-        case 1: return a.getMaxY();\r
-        case 2: return a.getMinX();\r
-        case 3: return a.getMinY();\r
-        default: throw new Error("Should not happen.");\r
-        }\r
-    }\r
-    \r
-    /**\r
-     * Gives the boundary of two route terminals in the given direction.\r
-     */\r
-    public static double boundary(int dir, RouteTerminal a, RouteTerminal b) {\r
-        switch(dir&3) {\r
-        case 0: return Math.max(a.getMaxX(), b.getMaxX());\r
-        case 1: return Math.max(a.getMaxY(), b.getMaxY());\r
-        case 2: return Math.min(a.getMinX(), b.getMinX());\r
-        case 3: return Math.min(a.getMinY(), b.getMinY());\r
-        default: throw new Error("Should not happen.");\r
-        }\r
-    }\r
-    \r
-    /**\r
-     * Returns true if the first terminal is farther away in the given direction.\r
-     */\r
-    public static boolean firstIsBoundary(int dir, RouteTerminal a, RouteTerminal b) {\r
-        switch(dir&3) {\r
-        case 0: return a.getMaxX() >= b.getMaxX();\r
-        case 1: return a.getMaxY() >= b.getMaxY();\r
-        case 2: return a.getMinX() <= b.getMinX();\r
-        case 3: return a.getMinY() <= b.getMinY();\r
-        default: throw new Error("Should not happen.");\r
-        }\r
-    }\r
-        \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2011 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.diagram.connection;
+
+/**
+ * An internal utility class for routing simple connections 
+ * (a connection with two terminals without any route lines).
+ * 
+ * @author Hannu Niemist&ouml;
+ */
+class SimpleConnectionUtility {
+
+    public static boolean allowsDirection(RouteTerminal a, int dir) {
+        return Directions.isAllowed(a.getAllowedDirections(), dir);
+    }
+    
+    public static final int DIRECT_HORIZONTAL_CONNECTION = 0;
+    public static final int DIRECT_VERTICAL_CONNECTION = 1;
+    
+    public static final int ONE_BEND_HORIZONTAL_VERTICAL = 2;
+    public static final int ONE_BEND_VERTICAL_HORIZONTAL = 3;
+
+    public static final int MORE_BENDS_BBS_DONT_INTERSECT = 4;
+    public static final int MORE_BENDS_BBS_INTERSECT = 5;
+    
+    public static final int COMPLEX_CONNECTION = 6;
+    
+    public static int simpleConnectionCase(RouteTerminal a, RouteTerminal b) {
+        if(a.isRouteToBounds() && b.isRouteToBounds())
+            return simpleConnectionCaseRouteToBounds(a, b);
+                    
+        // Can connect terminals by one straight line?
+        if(a.y == b.y) {
+            if(a.x < b.x) {
+                if(allowsDirection(a, 0) && allowsDirection(b, 2))
+                    return DIRECT_HORIZONTAL_CONNECTION;
+            }
+            else {
+                if(allowsDirection(a, 2) && allowsDirection(b, 0))
+                    return DIRECT_HORIZONTAL_CONNECTION;
+            }
+        }
+        else if(a.x == b.x) {
+            if(a.y < b.y) {
+                if(allowsDirection(a, 1) && allowsDirection(b, 3))
+                    return DIRECT_VERTICAL_CONNECTION;
+            }
+            else {
+                if(allowsDirection(a, 3) && allowsDirection(b, 1))
+                    return DIRECT_VERTICAL_CONNECTION;
+            }
+        }
+        
+        // Can connect terminals by two lines?
+        if(a.x < b.x) {
+            if(a.y < b.y) {
+                if(allowsDirection(a, 0) && allowsDirection(b, 3)
+                        /*&& b.x >= a.getMaxX() && a.y <= b.getMinY()*/)
+                    return ONE_BEND_HORIZONTAL_VERTICAL;
+                else if(allowsDirection(a, 1) && allowsDirection(b, 2)
+                        /*&& b.y >= a.getMaxY() && a.x <= b.getMinX()*/)
+                    return ONE_BEND_VERTICAL_HORIZONTAL;
+            }
+            else {
+                if(allowsDirection(a, 0) && allowsDirection(b, 1)
+                        /*&& b.x >= a.getMaxX() && a.y >= b.getMaxY()*/)
+                    return ONE_BEND_HORIZONTAL_VERTICAL;
+                else if(allowsDirection(a, 3) && allowsDirection(b, 2)
+                        /*&& b.y <= a.getMinY() && a.x <= b.getMinX()*/)
+                    return ONE_BEND_VERTICAL_HORIZONTAL;
+            }
+        }
+        else {
+            if(a.y < b.y) {
+                if(allowsDirection(a, 2) && allowsDirection(b, 3)
+                        /*&& b.x <= a.getMinX() && a.y <= b.getMinY()*/)
+                    return ONE_BEND_HORIZONTAL_VERTICAL;
+                else if(allowsDirection(a, 1) && allowsDirection(b, 0)
+                        /*&& b.y >= a.getMaxY() && a.x >= b.getMaxX()*/)
+                    return ONE_BEND_VERTICAL_HORIZONTAL;
+            }
+            else {
+                if(allowsDirection(a, 2) && allowsDirection(b, 1)
+                        /*&& b.x <= a.getMinX() && a.y >= b.getMaxY()*/)
+                    return ONE_BEND_HORIZONTAL_VERTICAL;
+                else if(allowsDirection(a, 3) && allowsDirection(b, 0)
+                        /*&& b.y <= a.getMinY() && a.x >= b.getMaxX()*/)
+                    return ONE_BEND_VERTICAL_HORIZONTAL;
+            }
+        }
+        
+        // Do bounding boxes intersect each other?
+        boolean boundingBoxesIntersect = !(
+                a.getMaxX() < b.getMinX() ||
+                a.getMinX() > b.getMaxX() ||
+                a.getMaxY() < b.getMinY() ||
+                a.getMinY() > b.getMaxY() 
+                );
+        
+        if(boundingBoxesIntersect) {
+            // Can connect terminals by two lines if we ignore bounding boxes?
+            if(a.x < b.x) {
+                if(a.y < b.y) {
+                    if(allowsDirection(a, 0) && allowsDirection(b, 3))
+                        return ONE_BEND_HORIZONTAL_VERTICAL;
+                    else if(allowsDirection(a, 1) && allowsDirection(b, 2))
+                        return ONE_BEND_VERTICAL_HORIZONTAL;
+                }
+                else {
+                    if(allowsDirection(a, 0) && allowsDirection(b, 1))
+                        return ONE_BEND_HORIZONTAL_VERTICAL;
+                    else if(allowsDirection(a, 3) && allowsDirection(b, 2))
+                        return ONE_BEND_VERTICAL_HORIZONTAL;
+                }
+            }
+            else {
+                if(a.y < b.y) {
+                    if(allowsDirection(a, 2) && allowsDirection(b, 3))
+                        return ONE_BEND_HORIZONTAL_VERTICAL;
+                    else if(allowsDirection(a, 1) && allowsDirection(b, 0))
+                        return ONE_BEND_VERTICAL_HORIZONTAL;
+                }
+                else {
+                    if(allowsDirection(a, 2) && allowsDirection(b, 1))
+                        return ONE_BEND_HORIZONTAL_VERTICAL;
+                    else if(allowsDirection(a, 3) && allowsDirection(b, 0))
+                        return ONE_BEND_VERTICAL_HORIZONTAL;
+                }
+            }
+            
+            // Otherwise
+            return MORE_BENDS_BBS_INTERSECT;
+        }        
+        
+        // Otherwise
+        return MORE_BENDS_BBS_DONT_INTERSECT;
+    }
+    
+    private static int simpleConnectionCaseRouteToBounds(RouteTerminal a,
+            RouteTerminal b) {
+        double aX = 0.5*(a.getMinX() + a.getMaxX());
+        double aY = 0.5*(a.getMinY() + a.getMaxY());
+        double bX = 0.5*(b.getMinX() + b.getMaxX());
+        double bY = 0.5*(b.getMinY() + b.getMaxY());
+        
+        double minY = Math.max(a.getMinY(), b.getMinY());
+        double maxY = Math.min(a.getMaxY(), b.getMaxY());
+        
+        if(minY <= maxY) {
+            double cY = 0.5*(minY+maxY);
+            a.setY(cY);
+            b.setY(cY);
+            if(aX < bX) {
+                a.setX(a.getMaxX());
+                b.setX(b.getMinX());
+            }
+            else {
+                a.setX(a.getMinX());
+                b.setX(b.getMaxX());
+            }
+            return DIRECT_HORIZONTAL_CONNECTION;
+        }
+        
+        double minX = Math.max(a.getMinX(), b.getMinX());
+        double maxX = Math.min(a.getMaxX(), b.getMaxX());
+        
+        if(minX <= maxX) {
+            double cX = 0.5*(minX+maxX);
+            a.setX(cX);
+            b.setX(cX);
+            if(aY < bY) {
+                a.setY(a.getMaxY());
+                b.setY(b.getMinY());
+            }
+            else {
+                a.setY(a.getMinY());
+                b.setY(b.getMaxY());
+            }
+            return DIRECT_VERTICAL_CONNECTION;
+        }
+        
+        {
+            a.setY(aY);
+            b.setX(bX);
+            if(aX < bX) {
+                a.setX(a.getMaxX());
+            }
+            else {
+                a.setX(a.getMinX());
+            }
+            if(aY < bY) {
+                b.setY(b.getMinY());
+            }
+            else {
+                b.setY(b.getMaxY());
+            }
+            return ONE_BEND_HORIZONTAL_VERTICAL;
+        }
+    }
+
+    /**
+     * Finds a route line for two route terminals.
+     */
+    public static RouteLine findRouteLine(RouteTerminal a, RouteTerminal b, boolean terminalsIntersect) {
+        if(terminalsIntersect) {
+            if(a.x < b.x) {
+                if((a.getAllowedDirections() & RouteTerminal.DIR_RIGHT) != 0 
+                        && (b.getAllowedDirections() & RouteTerminal.DIR_LEFT) != 0) {
+                    return new RouteLine(false, 0.5 * (a.x + b.x));
+                }
+            }
+            else {
+                if((a.getAllowedDirections() & RouteTerminal.DIR_LEFT) != 0 
+                        && (b.getAllowedDirections() & RouteTerminal.DIR_RIGHT) != 0) {
+                    return new RouteLine(false, 0.5 * (a.x + b.x));
+                }
+            }
+            if(a.y < b.y) {
+                if((a.getAllowedDirections() & RouteTerminal.DIR_DOWN) != 0 
+                        && (b.getAllowedDirections() & RouteTerminal.DIR_UP) != 0) {
+                    return new RouteLine(true, 0.5 * (a.y + b.y));
+                }
+            }
+            else {
+                if((a.getAllowedDirections() & RouteTerminal.DIR_UP) != 0 
+                        && (b.getAllowedDirections() & RouteTerminal.DIR_DOWN) != 0) {
+                    return new RouteLine(true, 0.5 * (a.y + b.y));
+                }
+            }
+        }
+        
+        //int aDir = Directions.firstAllowedDirection(a.getAllowedDirections());
+        //int bDir = Directions.firstAllowedDirection(b.getAllowedDirections());
+        
+        boolean isHorizontal = true;
+        double position = 0.0;
+        
+        loop:
+        for(int aDir=0;aDir<4;++aDir)
+            if(Directions.isAllowed(a.getAllowedDirections(), aDir))
+                for(int bDir=0;bDir<4;++bDir)
+                    if(Directions.isAllowed(b.getAllowedDirections(), bDir)) {
+                        // Connection starts to the same direction from the both terminals
+                        if(aDir == bDir) {
+                            isHorizontal = !isHorizontal(aDir);
+                            if(!terminalsIntersect) {
+                                if(dist(aDir, a, b) > 0 && isIn(aDir+1, a.x, a.y, b)) {
+                                    position = middle(aDir, a, b);
+                                    break loop;
+                                }
+                                else if(dist(aDir, b, a) > 0 && isIn(aDir+1, b.x, b.y, a)) {
+                                    position = middle(aDir, b, a);
+                                    break loop;
+                                }
+                            }
+                            position = boundary(aDir, a, b);
+                        }
+                        // Connection starts horizontally from one terminal and
+                        // vertically from another terminal
+                        else if(((aDir ^ bDir)&1) == 1) {
+                            if(dist(aDir, a, b) >= 0) {
+                                isHorizontal = !isHorizontal(aDir);
+                                position = middle(aDir, a, b);
+                                break loop;
+                            }
+                            else if(dist(bDir, b, a) >= 0) {
+                                isHorizontal = isHorizontal(aDir);;
+                                position = middle(bDir, b, a);
+                                break loop;
+                            }
+                            else if(firstIsBoundary(bDir, a, b)) {
+                                isHorizontal = isHorizontal(aDir);
+                                position = boundary(bDir, b, a);
+                            }
+                            else {
+                                isHorizontal = !isHorizontal(aDir);
+                                position = boundary(aDir, a, b);
+                            }
+                        }
+                        // Connection starts to opposite directions from the terminals
+                        else {           
+                            if(dist(aDir, a, b) >= 0.0) {
+                                isHorizontal = !isHorizontal(aDir);
+                                position = middle(aDir, a, b);
+                                break loop;
+                            }
+                            else if(dist(aDir+1, a, b) >= 0.0) {
+                                isHorizontal = isHorizontal(aDir);
+                                position = middle(aDir+1, a, b);
+                                break loop;
+                            }
+                            else if(dist(aDir-1, a, b) >= 0.0) {
+                                isHorizontal = isHorizontal(aDir);
+                                position = middle(aDir+1, a, b);
+                                break loop;
+                            }
+                            else {
+                                isHorizontal = isHorizontal(aDir);
+                                double b1 = boundary(aDir+1, a, b);
+                                double b2 = boundary(aDir-1, a, b);
+                                double cost1, cost2;
+                                if(isHorizontal) {
+                                    double da1 = a.y - b1;
+                                    double db1 = b.y - b1;
+                                    cost1 = da1*da1 + db1*db1;
+                                    double da2 = a.y - b2;
+                                    double db2 = b.y - b2;
+                                    cost2 = da2*da2 + db1*db2;
+                                }
+                                else {
+                                    double da1 = a.x - b1;
+                                    double db1 = b.x - b1;
+                                    cost1 = da1*da1 + db1*db1;
+                                    double da2 = a.x - b2;
+                                    double db2 = b.x - b2;
+                                    cost2 = da2*da2 + db1*db2;
+                                }
+                                position = cost1 <= cost2 ? b1 : b2;
+                            }
+                        }
+                    }
+        return new RouteLine(isHorizontal, position);
+    }
+    
+    /**
+     * Computes the difference between two points to the given direction
+     */
+    public static double diff(int dir, double x1, double y1, double x2, double y2) {
+        switch(dir&3) {
+        case 0: return x1 - x2;
+        case 1: return y1 - y2;
+        case 2: return x2 - x1;
+        case 3: return y2 - y1;
+        default: throw new Error("Should not happen.");
+        }
+    }
+    
+    /**
+     * Computes the distance of the bounding boxes of the two route terminals
+     * to the given direction.
+     */
+    public static double dist(int dir, RouteTerminal a, RouteTerminal b) {
+        switch(dir&3) {
+        case 0: return b.getMinX() - a.getMaxX();
+        case 1: return b.getMinY() - a.getMaxY();
+        case 2: return a.getMinX() - b.getMaxX();
+        case 3: return a.getMinY() - b.getMaxY();
+        default: throw new Error("Should not happen.");
+        }
+    }
+    
+    /**
+     * Computes the middle point between two terminals in the given direction.
+     */
+    public static double middle(int dir, RouteTerminal a, RouteTerminal b) {
+        switch(dir&3) {
+        case 0: return 0.5*(b.getMinX() + a.getMaxX());
+        case 1: return 0.5*(b.getMinY() + a.getMaxY());
+        case 2: return 0.5*(a.getMinX() + b.getMaxX());
+        case 3: return 0.5*(a.getMinY() + b.getMaxY());
+        default: throw new Error("Should not happen.");
+        }
+    }
+    
+    /**
+     * Tests whether the point is inside the bounding box of the terminal
+     * in the given direction.
+     */
+    public static boolean isIn(int dir, double x, double y, RouteTerminal a) {
+        if((dir&1) == 0)
+            return a.getMinX() < x && x < a.getMaxX();
+        else
+            return a.getMinY() < y && y < a.getMaxY();
+    }
+    
+    public static boolean isHorizontal(int dir) {
+        return (dir&1) == 0;
+    }
+    
+    /**
+     * Gives the boundary of the route terminal in the given direction.
+     */
+    public static double boundary(int dir, RouteTerminal a) {
+        switch(dir&3) {
+        case 0: return a.getMaxX();
+        case 1: return a.getMaxY();
+        case 2: return a.getMinX();
+        case 3: return a.getMinY();
+        default: throw new Error("Should not happen.");
+        }
+    }
+    
+    /**
+     * Gives the boundary of two route terminals in the given direction.
+     */
+    public static double boundary(int dir, RouteTerminal a, RouteTerminal b) {
+        switch(dir&3) {
+        case 0: return Math.max(a.getMaxX(), b.getMaxX());
+        case 1: return Math.max(a.getMaxY(), b.getMaxY());
+        case 2: return Math.min(a.getMinX(), b.getMinX());
+        case 3: return Math.min(a.getMinY(), b.getMinY());
+        default: throw new Error("Should not happen.");
+        }
+    }
+    
+    /**
+     * Returns true if the first terminal is farther away in the given direction.
+     */
+    public static boolean firstIsBoundary(int dir, RouteTerminal a, RouteTerminal b) {
+        switch(dir&3) {
+        case 0: return a.getMaxX() >= b.getMaxX();
+        case 1: return a.getMaxY() >= b.getMaxY();
+        case 2: return a.getMinX() <= b.getMinX();
+        case 3: return a.getMinY() <= b.getMinY();
+        default: throw new Error("Should not happen.");
+        }
+    }
+        
+}