]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteTerminal.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.diagram.connection / src / org / simantics / diagram / connection / RouteTerminal.java
index 31064adf1f1275abe8f3082986bea3bfee1a923e..2f3fc9f86ec7ce7668c0dc12e87f741a4ae4c74e 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
-import gnu.trove.map.hash.THashMap;\r
-\r
-import java.awt.geom.Rectangle2D;\r
-import java.io.PrintStream;\r
-import java.io.Serializable;\r
-import java.util.ArrayList;\r
-\r
-import org.simantics.diagram.connection.RouteGraph.Interval;\r
-import org.simantics.diagram.connection.RouteGraph.IntervalCache;\r
-import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;\r
-\r
-public class RouteTerminal extends RoutePoint implements RouteNode, Serializable {\r
-\r
-    private static final long serialVersionUID = -8839093950347737029L;\r
-\r
-    public static final int   DIR_RIGHT        = (1 << 0);\r
-    public static final int   DIR_DOWN         = (1 << 1);\r
-    public static final int   DIR_LEFT         = (1 << 2);\r
-    public static final int   DIR_UP           = (1 << 3);\r
-    public static final int   DIR_DIRECT       = (1 << 4);\r
-\r
-    private Object data;\r
-    private double minX, minY;\r
-    private double maxX, maxY;\r
-    private int allowedDirections;\r
-    private ILineEndStyle style;\r
-    private ILineEndStyle dynamicStyle;\r
-    private boolean routeToBounds;\r
-\r
-    RouteLine line;\r
-\r
-    RouteTerminal(double x, double y, double minX, double minY,\r
-            double maxX, double maxY, int allowedDirections,\r
-            boolean routeToBounds,\r
-            ILineEndStyle style) {\r
-        super(x, y);\r
-        this.minX = minX;\r
-        this.minY = minY;\r
-        this.maxX = maxX;\r
-        this.maxY = maxY;\r
-        this.allowedDirections = allowedDirections;\r
-        this.routeToBounds = routeToBounds;\r
-        this.style = style;\r
-    }\r
-    \r
-    @Override\r
-    public void setData(Object data) {\r
-        this.data = data;\r
-    }\r
-    \r
-    @Override\r
-    public Object getData() {\r
-        return data;\r
-    }\r
-    \r
-    public int getAllowedDirections() {\r
-               return allowedDirections;\r
-       }\r
-    \r
-    public double getMinX() {\r
-               return minX;\r
-       }\r
-    \r
-    public double getMinY() {\r
-               return minY;\r
-       }\r
-    \r
-    public double getMaxX() {\r
-               return maxX;\r
-       }\r
-    \r
-    public double getMaxY() {\r
-               return maxY;\r
-       }\r
-    \r
-    public Rectangle2D getBounds() {\r
-       return new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY);\r
-    }\r
-\r
-    /**\r
-     * Routes connection from the terminal to route line\r
-     * adding necessary transient route lines.\r
-     * @param cache \r
-     */\r
-    void route(ArrayList<RouteLine> lines, IntervalCache cache, boolean boundingBoxesIntersect) {\r
-        if(routeToBounds) {\r
-            int lineDir;\r
-            boolean routeLineDoesNotIntersectTerminal;\r
-            double linePosition = line.position;\r
-            if(line.isHorizontal) { \r
-                lineDir = linePosition < y ? 3 : 1;\r
-                routeLineDoesNotIntersectTerminal = \r
-                        linePosition <= minY || linePosition >= maxY;\r
-            }\r
-            else {\r
-                lineDir = linePosition < x ? 2 : 0;\r
-                routeLineDoesNotIntersectTerminal = \r
-                        linePosition <= minX || linePosition >= maxX;\r
-            }\r
-            \r
-            if(routeLineDoesNotIntersectTerminal) {\r
-                RouteLine line0 = createLine0(lineDir);\r
-                new RouteLink(line0, line);\r
-                lines.add(line0);\r
-                switch(lineDir) {\r
-                case 0:\r
-                    x = maxX;\r
-                    y = 0.5*(minY+maxY);\r
-                    break;\r
-                case 1:\r
-                    x = 0.5*(minX+maxX);\r
-                    y = maxY;\r
-                    break;\r
-                case 2:\r
-                    x = minX;\r
-                    y = 0.5*(minY+maxY);\r
-                    break;\r
-                case 3:\r
-                    x = 0.5*(minX+maxX);\r
-                    y = minY;\r
-                    break;\r
-                }\r
-                return;\r
-            }\r
-            else {\r
-                line.addPoint(this);\r
-                Interval interval = cache.get(line);\r
-                if(line.isHorizontal) {\r
-                    if(interval.min < minX)\r
-                        x = minX;\r
-                    else\r
-                        x = maxX;\r
-                    y = linePosition;\r
-                }\r
-                else {\r
-                    x = linePosition;\r
-                    if(interval.min < minY)\r
-                        y = minY;\r
-                    else\r
-                        y = maxY;\r
-                }\r
-            }\r
-        }\r
-        else {\r
-            // In which direction the route line is?\r
-            int lineDir;\r
-            boolean routeLineDoesNotIntersectTerminal;\r
-            double linePosition = line.position;\r
-            if(line.isHorizontal) { \r
-                lineDir = linePosition < y ? 3 : 1;\r
-                routeLineDoesNotIntersectTerminal = linePosition <= minY || linePosition >= maxY \r
-                        || boundingBoxesIntersect /* we ignore intersection in this case */;\r
-            }\r
-            else {\r
-                lineDir = linePosition < x ? 2 : 0;\r
-                routeLineDoesNotIntersectTerminal = linePosition <= minX || linePosition >= maxX\r
-                        || boundingBoxesIntersect /* we ignore intersection in this case */;\r
-            }\r
-                    \r
-            // We can route the connection directly to the right direction\r
-            if(routeLineDoesNotIntersectTerminal && \r
-                    Directions.isAllowed(allowedDirections, lineDir)) {           \r
-                RouteLine line0 = createLine0(lineDir);\r
-                new RouteLink(line0, line);\r
-                lines.add(line0);\r
-                return;\r
-            }\r
-            \r
-            // We must make one bend\r
-            oneBend: {\r
-                int dir = 1-(lineDir&1);\r
-                if(Directions.isAllowed(allowedDirections, dir)) {\r
-                    if(Directions.isAllowed(allowedDirections, dir+2)) {\r
-                        Interval interval = cache.get(line);\r
-                        if(dir == 0) {\r
-                            if(interval.max <= maxX)\r
-                                dir = 2;\r
-                        }\r
-                        else /* dir == 1 */ {\r
-                            if(interval.max <= maxY)\r
-                                dir = 3;\r
-                        }\r
-                    }\r
-                    else {\r
-                        // ok\r
-                    }\r
-                }\r
-                else {\r
-                    if(Directions.isAllowed(allowedDirections, dir+2)) {\r
-                        dir = dir + 2;\r
-                    }\r
-                    else {\r
-                        break oneBend;\r
-                    }\r
-                }\r
-    \r
-                RouteLine line0 = createLine0(dir);\r
-                RouteLine line1 = createLine1(dir);\r
-                new RouteLink(line0, line1);\r
-                new RouteLink(line1, line);\r
-                lines.add(line0);\r
-                lines.add(line1);\r
-                line0.nextTransient = line1;\r
-                return;\r
-            }\r
-            \r
-            // We can begin to the right direction but do two bends\r
-            if(!routeLineDoesNotIntersectTerminal && \r
-                    Directions.isAllowed(allowedDirections, lineDir)) {  \r
-                RouteLine line0 = createLine0(lineDir);\r
-                RouteLine line1 = createLine1(lineDir);\r
-                RouteLine line2 = createLine2(lineDir, cache);\r
-                new RouteLink(line0, line1);\r
-                new RouteLink(line1, line2);\r
-                new RouteLink(line2, line);\r
-                lines.add(line0);\r
-                lines.add(line1);\r
-                lines.add(line2);\r
-                line0.nextTransient = line1;\r
-                line1.nextTransient = line2;\r
-                return;\r
-            }\r
-            \r
-            // Only allowed direction is to completely wrong direction:\r
-            // we must make two bends\r
-            {\r
-                int dir = lineDir^2;\r
-                RouteLine line0 = createLine0(dir);\r
-                RouteLine line1 = createLine1(dir);\r
-                RouteLine line2 = createLine2(dir, cache);\r
-                new RouteLink(line0, line1);\r
-                new RouteLink(line1, line2);\r
-                new RouteLink(line2, line);\r
-                lines.add(line0);\r
-                lines.add(line1);\r
-                lines.add(line2);\r
-                line0.nextTransient = line1;\r
-                line1.nextTransient = line2;\r
-                return;\r
-            }\r
-        }\r
-    }\r
-    \r
-    private RouteLine createLine0(int dir) {\r
-        RouteLine line0 = (dir&1) == 0 \r
-                ? new RouteLine(true, y)\r
-                : new RouteLine(false, x)\r
-                ;\r
-        line0.addPoint(this);\r
-        line0.terminal = this;\r
-        return line0;\r
-    }\r
-    \r
-    private RouteLine createLine1(int dir) {\r
-        RouteLine line1 = (dir&1) == 0 \r
-                ? new RouteLine(false, (dir&2) == 0 ? maxX : minX)\r
-                : new RouteLine(true, (dir&2) == 0 ? maxY : minY)\r
-                ;\r
-        line1.terminal = this;\r
-        return line1;\r
-    }\r
-    \r
-    private RouteLine createLine2(int dir, IntervalCache cache) {\r
-        Interval interval = cache.get(line);\r
-        RouteLine line2;\r
-        if((dir&1) == 0) {\r
-            double position;\r
-            if(minY < interval.min) {\r
-                if(maxY > interval.max) {\r
-                    position = 2*maxY-y-interval.max < interval.min+y-2*minY ? maxY : minY;\r
-                }\r
-                else {\r
-                    position = maxY;\r
-                }\r
-            }\r
-            else {\r
-                if(maxY > interval.max) {\r
-                    position = minY;\r
-                }\r
-                else {\r
-                    position = maxY-y < y-minY ? maxY : minY;\r
-                }\r
-            }\r
-            line2 = new RouteLine(true, position);\r
-        }\r
-        else {\r
-            double position;\r
-            if(minX < interval.min) {\r
-                if(maxX > interval.max) {\r
-                    position = 2*maxX-x-interval.max < interval.min+x-2*minX ? maxX : minX;\r
-                }\r
-                else {\r
-                    position = maxX;\r
-                }\r
-            }\r
-            else {\r
-                if(maxX > interval.max) {\r
-                    position = minX;\r
-                }\r
-                else {\r
-                    position = maxX-x < x-minX ? maxX : minX;\r
-                }\r
-            }\r
-            line2 = new RouteLine(false, position);\r
-        }\r
-        line2.terminal = this;                \r
-        return line2;\r
-    }    \r
-\r
-    public boolean isNear(double x2, double y2) {\r
-        return minX <= x2 && x2 <= maxX && minY <= y2 && y2 <= maxY;\r
-    }\r
-\r
-    void setLocation(double x2, double y2) {\r
-        double dx = x2 - x;\r
-        double dy = y2 - y;\r
-        x = x2;\r
-        y = y2;\r
-        minX += dx;\r
-        minY += dy;\r
-        maxX += dx;\r
-        maxY += dy;\r
-    }\r
-\r
-    void rotate(int amount) {\r
-        amount %= 4;\r
-        if(amount < 0)\r
-            amount += 4;\r
-        \r
-        int temp = (allowedDirections&15) << amount;\r
-        allowedDirections = (temp&15) | (temp >> 4) | (allowedDirections&16);       \r
-    }\r
-\r
-    public double approximatePositionToLine() {\r
-        // In which direction the route line is?\r
-        int lineDir = line.isHorizontal \r
-                ? (line.position < y ? 3 : 1)\r
-                : (line.position < x ? 2 : 0)\r
-                ;\r
-                \r
-        // We can route the connection directly to the right direction\r
-        if(Directions.isAllowed(allowedDirections, lineDir))\r
-            return line.isHorizontal ? x : y;\r
-        \r
-        // We must make one bend \r
-        for(int dir = 0;dir < 4;++dir) {\r
-            if(Directions.isAllowed(allowedDirections, dir) && ((dir^lineDir)&1) == 1) {\r
-                switch(dir) {\r
-                case 0: return maxX;\r
-                case 1: return maxY;\r
-                case 2: return minX;\r
-                case 3: return minY;\r
-                }\r
-            }\r
-        }\r
-        // Only allowed direction is to completely wrong direction:\r
-        // we must make two bends\r
-        {\r
-            // Approximation\r
-            return line.isHorizontal ? x : y;\r
-        }\r
-    }\r
-\r
-    RouteTerminal copy(THashMap<Object, Object> map) {\r
-       RouteTerminal copy = (RouteTerminal)map.get(this);\r
-       if(copy == null) {      \r
-               copy = new RouteTerminal(x,  y, minX, minY, maxX, maxY, \r
-                               allowedDirections, routeToBounds, style);\r
-               copy.setDynamicStyle(dynamicStyle);\r
-               map.put(this, copy);\r
-               copy.data = data;\r
-               copy.line = line == null ? null : line.copy(map);\r
-       }\r
-        return copy;\r
-    }\r
-\r
-    public void print(PrintStream out) {\r
-        out.print("     (" + x + "," + y + ") " + allowedDirections + " -> ");\r
-        if (line != null)\r
-            line.print(out);\r
-        else\r
-            out.print("NO LINE");\r
-        out.print(" (data=" + data + ")");\r
-        out.println();\r
-    }\r
-\r
-    public ILineEndStyle getStyle() {\r
-        return style;\r
-    }\r
-    \r
-    public ILineEndStyle getRenderStyle() {\r
-       if (dynamicStyle != null)\r
-               return dynamicStyle;\r
-        return style;\r
-    }\r
-\r
-    public boolean hasDirectConnection() {\r
-        return (allowedDirections&16) == 16;\r
-    }\r
-    \r
-    public RouteLine getLine() {\r
-        return line;\r
-    }\r
-    \r
-    public void setMinX(double minX) {\r
-               this.minX = minX;\r
-       }\r
-    public void setMinY(double minY) {\r
-               this.minY = minY;\r
-       }\r
-    \r
-    public void setMaxX(double maxX) {\r
-               this.maxX = maxX;\r
-       }\r
-    \r
-    public void setMaxY(double maxY) {\r
-               this.maxY = maxY;\r
-       }\r
-\r
-    public void toggleDirectLines() {\r
-        this.allowedDirections ^= 16;\r
-    }\r
-    \r
-    public boolean isRouteToBounds() {\r
-        return routeToBounds;\r
-    }\r
-    \r
-    public void setStyle(ILineEndStyle style) {\r
-               this.style = style;\r
-       }\r
-    \r
-    public ILineEndStyle getDynamicStyle() {\r
-               return dynamicStyle;\r
-       }\r
-    \r
-    public void setDynamicStyle(ILineEndStyle dynamicStyle) {\r
-               this.dynamicStyle = dynamicStyle;\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;
+
+import gnu.trove.map.hash.THashMap;
+
+import java.awt.geom.Rectangle2D;
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+
+import org.simantics.diagram.connection.RouteGraph.Interval;
+import org.simantics.diagram.connection.RouteGraph.IntervalCache;
+import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;
+
+public class RouteTerminal extends RoutePoint implements RouteNode, Serializable {
+
+    private static final long serialVersionUID = -8839093950347737029L;
+
+    public static final int   DIR_RIGHT        = (1 << 0);
+    public static final int   DIR_DOWN         = (1 << 1);
+    public static final int   DIR_LEFT         = (1 << 2);
+    public static final int   DIR_UP           = (1 << 3);
+    public static final int   DIR_DIRECT       = (1 << 4);
+
+    private Object data;
+    private double minX, minY;
+    private double maxX, maxY;
+    private int allowedDirections;
+    private ILineEndStyle style;
+    private ILineEndStyle dynamicStyle;
+    private boolean routeToBounds;
+
+    RouteLine line;
+
+    RouteTerminal(double x, double y, double minX, double minY,
+            double maxX, double maxY, int allowedDirections,
+            boolean routeToBounds,
+            ILineEndStyle style) {
+        super(x, y);
+        this.minX = minX;
+        this.minY = minY;
+        this.maxX = maxX;
+        this.maxY = maxY;
+        this.allowedDirections = allowedDirections;
+        this.routeToBounds = routeToBounds;
+        this.style = style;
+    }
+    
+    @Override
+    public void setData(Object data) {
+        this.data = data;
+    }
+    
+    @Override
+    public Object getData() {
+        return data;
+    }
+    
+    public int getAllowedDirections() {
+               return allowedDirections;
+       }
+    
+    public double getMinX() {
+               return minX;
+       }
+    
+    public double getMinY() {
+               return minY;
+       }
+    
+    public double getMaxX() {
+               return maxX;
+       }
+    
+    public double getMaxY() {
+               return maxY;
+       }
+    
+    public Rectangle2D getBounds() {
+       return new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY);
+    }
+
+    /**
+     * Routes connection from the terminal to route line
+     * adding necessary transient route lines.
+     * @param cache 
+     */
+    void route(ArrayList<RouteLine> lines, IntervalCache cache, boolean boundingBoxesIntersect) {
+        if(routeToBounds) {
+            int lineDir;
+            boolean routeLineDoesNotIntersectTerminal;
+            double linePosition = line.position;
+            if(line.isHorizontal) { 
+                lineDir = linePosition < y ? 3 : 1;
+                routeLineDoesNotIntersectTerminal = 
+                        linePosition <= minY || linePosition >= maxY;
+            }
+            else {
+                lineDir = linePosition < x ? 2 : 0;
+                routeLineDoesNotIntersectTerminal = 
+                        linePosition <= minX || linePosition >= maxX;
+            }
+            
+            if(routeLineDoesNotIntersectTerminal) {
+                RouteLine line0 = createLine0(lineDir);
+                new RouteLink(line0, line);
+                lines.add(line0);
+                switch(lineDir) {
+                case 0:
+                    x = maxX;
+                    y = 0.5*(minY+maxY);
+                    break;
+                case 1:
+                    x = 0.5*(minX+maxX);
+                    y = maxY;
+                    break;
+                case 2:
+                    x = minX;
+                    y = 0.5*(minY+maxY);
+                    break;
+                case 3:
+                    x = 0.5*(minX+maxX);
+                    y = minY;
+                    break;
+                }
+                return;
+            }
+            else {
+                line.addPoint(this);
+                Interval interval = cache.get(line);
+                if(line.isHorizontal) {
+                    if(interval.min < minX)
+                        x = minX;
+                    else
+                        x = maxX;
+                    y = linePosition;
+                }
+                else {
+                    x = linePosition;
+                    if(interval.min < minY)
+                        y = minY;
+                    else
+                        y = maxY;
+                }
+            }
+        }
+        else {
+            // In which direction the route line is?
+            int lineDir;
+            boolean routeLineDoesNotIntersectTerminal;
+            double linePosition = line.position;
+            if(line.isHorizontal) { 
+                lineDir = linePosition < y ? 3 : 1;
+                routeLineDoesNotIntersectTerminal = linePosition <= minY || linePosition >= maxY 
+                        || boundingBoxesIntersect /* we ignore intersection in this case */;
+            }
+            else {
+                lineDir = linePosition < x ? 2 : 0;
+                routeLineDoesNotIntersectTerminal = linePosition <= minX || linePosition >= maxX
+                        || boundingBoxesIntersect /* we ignore intersection in this case */;
+            }
+                    
+            // We can route the connection directly to the right direction
+            if(routeLineDoesNotIntersectTerminal && 
+                    Directions.isAllowed(allowedDirections, lineDir)) {           
+                RouteLine line0 = createLine0(lineDir);
+                new RouteLink(line0, line);
+                lines.add(line0);
+                return;
+            }
+            
+            // We must make one bend
+            oneBend: {
+                int dir = 1-(lineDir&1);
+                if(Directions.isAllowed(allowedDirections, dir)) {
+                    if(Directions.isAllowed(allowedDirections, dir+2)) {
+                        Interval interval = cache.get(line);
+                        if(dir == 0) {
+                            if(interval.max <= maxX)
+                                dir = 2;
+                        }
+                        else /* dir == 1 */ {
+                            if(interval.max <= maxY)
+                                dir = 3;
+                        }
+                    }
+                    else {
+                        // ok
+                    }
+                }
+                else {
+                    if(Directions.isAllowed(allowedDirections, dir+2)) {
+                        dir = dir + 2;
+                    }
+                    else {
+                        break oneBend;
+                    }
+                }
+    
+                RouteLine line0 = createLine0(dir);
+                RouteLine line1 = createLine1(dir);
+                new RouteLink(line0, line1);
+                new RouteLink(line1, line);
+                lines.add(line0);
+                lines.add(line1);
+                line0.nextTransient = line1;
+                return;
+            }
+            
+            // We can begin to the right direction but do two bends
+            if(!routeLineDoesNotIntersectTerminal && 
+                    Directions.isAllowed(allowedDirections, lineDir)) {  
+                RouteLine line0 = createLine0(lineDir);
+                RouteLine line1 = createLine1(lineDir);
+                RouteLine line2 = createLine2(lineDir, cache);
+                new RouteLink(line0, line1);
+                new RouteLink(line1, line2);
+                new RouteLink(line2, line);
+                lines.add(line0);
+                lines.add(line1);
+                lines.add(line2);
+                line0.nextTransient = line1;
+                line1.nextTransient = line2;
+                return;
+            }
+            
+            // Only allowed direction is to completely wrong direction:
+            // we must make two bends
+            {
+                int dir = lineDir^2;
+                RouteLine line0 = createLine0(dir);
+                RouteLine line1 = createLine1(dir);
+                RouteLine line2 = createLine2(dir, cache);
+                new RouteLink(line0, line1);
+                new RouteLink(line1, line2);
+                new RouteLink(line2, line);
+                lines.add(line0);
+                lines.add(line1);
+                lines.add(line2);
+                line0.nextTransient = line1;
+                line1.nextTransient = line2;
+                return;
+            }
+        }
+    }
+    
+    private RouteLine createLine0(int dir) {
+        RouteLine line0 = (dir&1) == 0 
+                ? new RouteLine(true, y)
+                : new RouteLine(false, x)
+                ;
+        line0.addPoint(this);
+        line0.terminal = this;
+        return line0;
+    }
+    
+    private RouteLine createLine1(int dir) {
+        RouteLine line1 = (dir&1) == 0 
+                ? new RouteLine(false, (dir&2) == 0 ? maxX : minX)
+                : new RouteLine(true, (dir&2) == 0 ? maxY : minY)
+                ;
+        line1.terminal = this;
+        return line1;
+    }
+    
+    private RouteLine createLine2(int dir, IntervalCache cache) {
+        Interval interval = cache.get(line);
+        RouteLine line2;
+        if((dir&1) == 0) {
+            double position;
+            if(minY < interval.min) {
+                if(maxY > interval.max) {
+                    position = 2*maxY-y-interval.max < interval.min+y-2*minY ? maxY : minY;
+                }
+                else {
+                    position = maxY;
+                }
+            }
+            else {
+                if(maxY > interval.max) {
+                    position = minY;
+                }
+                else {
+                    position = maxY-y < y-minY ? maxY : minY;
+                }
+            }
+            line2 = new RouteLine(true, position);
+        }
+        else {
+            double position;
+            if(minX < interval.min) {
+                if(maxX > interval.max) {
+                    position = 2*maxX-x-interval.max < interval.min+x-2*minX ? maxX : minX;
+                }
+                else {
+                    position = maxX;
+                }
+            }
+            else {
+                if(maxX > interval.max) {
+                    position = minX;
+                }
+                else {
+                    position = maxX-x < x-minX ? maxX : minX;
+                }
+            }
+            line2 = new RouteLine(false, position);
+        }
+        line2.terminal = this;                
+        return line2;
+    }    
+
+    public boolean isNear(double x2, double y2) {
+        return minX <= x2 && x2 <= maxX && minY <= y2 && y2 <= maxY;
+    }
+
+    void setLocation(double x2, double y2) {
+        double dx = x2 - x;
+        double dy = y2 - y;
+        x = x2;
+        y = y2;
+        minX += dx;
+        minY += dy;
+        maxX += dx;
+        maxY += dy;
+    }
+
+    void rotate(int amount) {
+        amount %= 4;
+        if(amount < 0)
+            amount += 4;
+        
+        int temp = (allowedDirections&15) << amount;
+        allowedDirections = (temp&15) | (temp >> 4) | (allowedDirections&16);       
+    }
+
+    public double approximatePositionToLine() {
+        // In which direction the route line is?
+        int lineDir = line.isHorizontal 
+                ? (line.position < y ? 3 : 1)
+                : (line.position < x ? 2 : 0)
+                ;
+                
+        // We can route the connection directly to the right direction
+        if(Directions.isAllowed(allowedDirections, lineDir))
+            return line.isHorizontal ? x : y;
+        
+        // We must make one bend 
+        for(int dir = 0;dir < 4;++dir) {
+            if(Directions.isAllowed(allowedDirections, dir) && ((dir^lineDir)&1) == 1) {
+                switch(dir) {
+                case 0: return maxX;
+                case 1: return maxY;
+                case 2: return minX;
+                case 3: return minY;
+                }
+            }
+        }
+        // Only allowed direction is to completely wrong direction:
+        // we must make two bends
+        {
+            // Approximation
+            return line.isHorizontal ? x : y;
+        }
+    }
+
+    RouteTerminal copy(THashMap<Object, Object> map) {
+       RouteTerminal copy = (RouteTerminal)map.get(this);
+       if(copy == null) {      
+               copy = new RouteTerminal(x,  y, minX, minY, maxX, maxY, 
+                               allowedDirections, routeToBounds, style);
+               copy.setDynamicStyle(dynamicStyle);
+               map.put(this, copy);
+               copy.data = data;
+               copy.line = line == null ? null : line.copy(map);
+       }
+        return copy;
+    }
+
+    public void print(PrintStream out) {
+        out.print("     (" + x + "," + y + ") " + allowedDirections + " -> ");
+        if (line != null)
+            line.print(out);
+        else
+            out.print("NO LINE");
+        out.print(" (data=" + data + ")");
+        out.println();
+    }
+
+    public ILineEndStyle getStyle() {
+        return style;
+    }
+    
+    public ILineEndStyle getRenderStyle() {
+       if (dynamicStyle != null)
+               return dynamicStyle;
+        return style;
+    }
+
+    public boolean hasDirectConnection() {
+        return (allowedDirections&16) == 16;
+    }
+    
+    public RouteLine getLine() {
+        return line;
+    }
+    
+    public void setMinX(double minX) {
+               this.minX = minX;
+       }
+    public void setMinY(double minY) {
+               this.minY = minY;
+       }
+    
+    public void setMaxX(double maxX) {
+               this.maxX = maxX;
+       }
+    
+    public void setMaxY(double maxY) {
+               this.maxY = maxY;
+       }
+
+    public void toggleDirectLines() {
+        this.allowedDirections ^= 16;
+    }
+    
+    public boolean isRouteToBounds() {
+        return routeToBounds;
+    }
+    
+    public void setStyle(ILineEndStyle style) {
+               this.style = style;
+       }
+    
+    public ILineEndStyle getDynamicStyle() {
+               return dynamicStyle;
+       }
+    
+    public void setDynamicStyle(ILineEndStyle dynamicStyle) {
+               this.dynamicStyle = dynamicStyle;
+       }
+}