]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteGraph.java
Ordering of RouteGraphs RouteLines is nondeterministic
[simantics/platform.git] / bundles / org.simantics.diagram.connection / src / org / simantics / diagram / connection / RouteGraph.java
index 1905cfe2b2c172969e2883a5659a0d807a106761..62d3de68fae5f110a6b08eb80dcc7558ca34df80 100644 (file)
@@ -24,7 +24,10 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
 
 import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;
 import org.simantics.diagram.connection.rendering.arrows.PlainLineEndStyle;
@@ -45,6 +48,13 @@ public class RouteGraph implements Serializable {
     boolean isSimpleConnection;
     boolean needsUpdate = false;
 
+    public void updateTerminals() {
+        boolean changed = false;
+        for(RouteTerminal terminal : terminals)
+            changed |= terminal.updateDynamicPosition();
+        if(changed) update();
+    }
+
     /**
      * Adds a route line to the graph.
      * @param isHorizontal true, if the line is horizontal
@@ -78,21 +88,31 @@ public class RouteGraph implements Serializable {
      * </pre>
      * @param style Tells what kind of line end is drawn 
      *        to the connection.
+     * @param position a provider for a dynamic position for the terminal or
+     *        <code>null</code> if terminal position is not dynamic
      * @return The new terminal.
      */
+    public RouteTerminal addTerminal(double x, double y, 
+            double minX, double minY,
+            double maxX, double maxY, 
+            int allowedDirections,
+            ILineEndStyle style, RouteTerminalPosition position) {
+        return addTerminal(x, y, minX, minY, maxX, maxY, allowedDirections, style, null, position);
+    }
+
     public RouteTerminal addTerminal(double x, double y, 
             double minX, double minY,
             double maxX, double maxY, 
             int allowedDirections,
             ILineEndStyle style) {
-       return addTerminal(x, y, minX, minY, maxX, maxY, allowedDirections, style, null);
-       
+        return addTerminal(x, y, minX, minY, maxX, maxY, allowedDirections, style, null, null);
     }
+
     public RouteTerminal addTerminal(double x, double y, 
             double minX, double minY,
             double maxX, double maxY, 
             int allowedDirections,
-            ILineEndStyle style, ILineEndStyle dynamicStyle) {
+            ILineEndStyle style, ILineEndStyle dynamicStyle, RouteTerminalPosition position) {
         if(CHECK_PARAMERS) {
             if(allowedDirections > 0x1f)
                 throw new IllegalArgumentException("Illegal allowedDirection flags.");
@@ -102,7 +122,7 @@ public class RouteGraph implements Serializable {
         if(style == null)
             style = PlainLineEndStyle.INSTANCE;
         RouteTerminal terminal = new RouteTerminal(x, y, minX, minY,
-                maxX, maxY, allowedDirections, false, style); 
+                maxX, maxY, allowedDirections, false, style, position); 
         terminal.setDynamicStyle(dynamicStyle);
         terminals.add(terminal);
         return terminal;
@@ -112,7 +132,7 @@ public class RouteGraph implements Serializable {
             double minX, double minY,
             double maxX, double maxY,
             ILineEndStyle style) {
-       return addBigTerminal(minX, minY, maxX, maxY, style, null);
+        return addBigTerminal(minX, minY, maxX, maxY, style, null);
     }
     public RouteTerminal addBigTerminal( 
             double minX, double minY,
@@ -124,7 +144,7 @@ public class RouteGraph implements Serializable {
                 0.5*(minX+maxX), 0.5*(minY+maxY),
                 minX, minY,
                 maxX, maxY, 
-                0xf, true, style); 
+                0xf, true, style, null); 
         terminal.setDynamicStyle(dynamicStyle);
         
         terminals.add(terminal);
@@ -142,7 +162,7 @@ public class RouteGraph implements Serializable {
             ILineEndStyle style) {
         return addTerminal(x, y, 
                 bounds.getMinX(), bounds.getMinY(), bounds.getMaxX(), bounds.getMaxY(), 
-                allowedDirections, style);
+                allowedDirections, style, null);
     }
 
     /**
@@ -152,7 +172,7 @@ public class RouteGraph implements Serializable {
         RouteTerminal newTerminal = addTerminal(terminal.x, terminal.y,
                 terminal.getMinX(), terminal.getMinY(),
                 terminal.getMaxX(), terminal.getMaxY(),
-                terminal.getAllowedDirections(), terminal.getStyle(), terminal.getDynamicStyle());
+                terminal.getAllowedDirections(), terminal.getStyle(), terminal.getDynamicStyle(), terminal.getDynamicPosition());
         newTerminal.setData(terminal.getData());
         return terminal;
     }
@@ -166,7 +186,7 @@ public class RouteGraph implements Serializable {
             double maxX, double maxY, 
             int allowedDirections) {
         return addTerminal(x, y, minX, minY, maxX, maxY, allowedDirections, 
-                PlainLineEndStyle.INSTANCE);
+                PlainLineEndStyle.INSTANCE, null);
     }
     
     /**
@@ -492,9 +512,9 @@ public class RouteGraph implements Serializable {
         for(RouteTerminal terminal : terminals)
             if((terminal.getAllowedDirections()&0x10) != 0) {     
                 try {
-                       RouteLine line = terminal.getLine();
-                       if(line == null)
-                               continue;
+                    RouteLine line = terminal.getLine();
+                    if(line == null)
+                        continue;
                     RoutePoint b = line.getBegin();
                     double distSq = Line2D.ptSegDistSq(terminal.x, terminal.y, b.x, b.y, x, y); 
                     if(distSq <= toleranceSq) {
@@ -625,7 +645,7 @@ public class RouteGraph implements Serializable {
         if((mask & PICK_POINTS) != 0) {
             Object point = pickPoint(x, y, tolerance, mask);
             if(point != null)
-               return point;
+                return point;
         }
         /*if((mask & PICK_DIRECT_LINES) != 0) {
             RouteTerminal terminal = pickDirectLine(x, y, tolerance);
@@ -900,12 +920,12 @@ public class RouteGraph implements Serializable {
              * 
              * Update 14.2.2014: With Sulca, there is a constant issue when line.terminal == null but point is RouteTerminal. 
              */
-               if (point instanceof RouteLink) {
-                   RouteLine l = ((RouteLink)point).getOther(line);
-                   l.points.remove(point);
-                   if(!l.isTransient())
-                       nLines.add(l);
-               }
+            if (point instanceof RouteLink) {
+                RouteLine l = ((RouteLink)point).getOther(line);
+                l.points.remove(point);
+                if(!l.isTransient())
+                    nLines.add(l);
+            }
         }
         
         if(nLines.isEmpty())
@@ -919,10 +939,10 @@ public class RouteGraph implements Serializable {
                  * 
                  * Update 16.10.2014: With Sulca, there is a constant issue when line.terminal == null but point is RouteTerminal. 
                  */
-               if (point instanceof RouteLink) {
-                       RouteLink link = (RouteLink)point;
-                       link.replace(l, merged);
-               }
+                if (point instanceof RouteLink) {
+                    RouteLink link = (RouteLink)point;
+                    link.replace(l, merged);
+                }
             }
         }
         THashSet<RouteLine> removedLines = new THashSet<RouteLine>();
@@ -1328,6 +1348,18 @@ public class RouteGraph implements Serializable {
         path.moveTo(x, y);
     }
     
+    private static final Comparator<RoutePoint> RG_COMP = (o1, o2) -> {
+        if (o1.getX() < o2.getX())
+            return -1;
+        else if (o1.getX() > o2.getX())
+            return 1;
+        if (o1.getY() < o2.getY())
+            return -1;
+        else if (o1.getY() > o2.getY())
+            return 1;
+        return 0;
+    };
+    
     private static void addPathEnd(Path2D path, RoutePoint cur, RouteLine line) {
         double x = cur.x, y = cur.y;
         if(cur instanceof RouteTerminal) {
@@ -1365,8 +1397,9 @@ public class RouteGraph implements Serializable {
         }
 
         // Analyze graph
-        THashMap<RoutePoint, RouteLine> begins = 
-                new THashMap<RoutePoint, RouteLine>();
+        Map<RoutePoint, RouteLine> begins = 
+//                new THashMap<RoutePoint, RouteLine>(); //The ordering of the coordinates in the path should be deterministic between scenegraphs
+                new TreeMap<RoutePoint, RouteLine>(RG_COMP);
         for(RouteLine line : lines) {
             add(begins, line);
         }
@@ -1386,7 +1419,7 @@ public class RouteGraph implements Serializable {
         }
     }
     
-    private void drawContinuousPath(Path2D path, THashMap<RoutePoint, RouteLine> begins,
+    private void drawContinuousPath(Path2D path, Map<RoutePoint, RouteLine> begins,
             RoutePoint cur, RouteLine curLine) {
         if(curLine == null)
             return;
@@ -1415,7 +1448,7 @@ public class RouteGraph implements Serializable {
         }
     }
 
-    private static void add(THashMap<RoutePoint, RouteLine> begins,
+    private static void add(Map<RoutePoint, RouteLine> begins,
             RouteLine line) { 
         if(line.points.size() > 1) {
             {
@@ -1541,8 +1574,8 @@ public class RouteGraph implements Serializable {
     }
     
     public void reclaimTransientMemory() {
-       removeTransientRouteLines();
-       needsUpdate = true;
+        removeTransientRouteLines();
+        needsUpdate = true;
     }
 
 }