]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/delta/RouteGraphDelta.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.diagram.connection / src / org / simantics / diagram / connection / delta / RouteGraphDelta.java
diff --git a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/delta/RouteGraphDelta.java b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/delta/RouteGraphDelta.java
new file mode 100644 (file)
index 0000000..6288feb
--- /dev/null
@@ -0,0 +1,275 @@
+/*******************************************************************************\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.delta;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.simantics.diagram.connection.RouteGraph;\r
+import org.simantics.diagram.connection.RouteLine;\r
+import org.simantics.diagram.connection.RouteLink;\r
+import org.simantics.diagram.connection.RoutePoint;\r
+import org.simantics.diagram.connection.RouteTerminal;\r
+\r
+/**\r
+ * Calculates the delta between two route graphs. Only\r
+ * persistent lines are used in the computation. Lines,\r
+ * links and terminals are matched by their data attribute.\r
+ * If data is null, the node is not matched any node in\r
+ * the other node. Two lines differ, if they have a \r
+ * different orientation or position. Two terminals differ,\r
+ * if they are linked to different route lines ({@link RouteTerminal#getLine()}).  \r
+ * @author Hannu Niemistö\r
+ */\r
+public class RouteGraphDelta implements Serializable {\r
+\r
+    private static final long serialVersionUID = 5011201407852172263L;\r
+\r
+    ArrayList<RouteLine> linesOnlyInLeft = new ArrayList<RouteLine>();\r
+    ArrayList<RouteLine> linesOnlyInRight = new ArrayList<RouteLine>();\r
+    ArrayList<RouteLinePair> linesThatDiffer = new ArrayList<RouteLinePair>();\r
+    ArrayList<RouteLink> linksOnlyInLeft = new ArrayList<RouteLink>();\r
+    ArrayList<RouteLink> linksOnlyInRight = new ArrayList<RouteLink>();\r
+    ArrayList<RouteTerminal> terminalsOnlyInLeft = new ArrayList<RouteTerminal>();\r
+    ArrayList<RouteTerminal> terminalsOnlyInRight = new ArrayList<RouteTerminal>();\r
+    ArrayList<RouteTerminalPair> terminalsThatDiffer = new ArrayList<RouteTerminalPair>();\r
+    \r
+    public static class RouteLinePair implements Serializable {\r
+        private static final long serialVersionUID = 382349562756381086L;\r
+\r
+        public final RouteLine left;\r
+        public final RouteLine right;\r
+\r
+        public RouteLinePair(RouteLine left, RouteLine right) {\r
+            this.left = left;\r
+            this.right = right;\r
+        }\r
+    }\r
+    \r
+    public static class RouteTerminalPair implements Serializable {\r
+        private static final long serialVersionUID = 5286896101190626944L;\r
+\r
+        public final RouteTerminal left;\r
+        public final RouteTerminal right;\r
+\r
+        public RouteTerminalPair(RouteTerminal left, RouteTerminal right) {\r
+            this.left = left;\r
+            this.right = right;\r
+        }\r
+    }\r
+    \r
+    public Collection<RouteLine> getLinesOnlyInLeft() {\r
+        return linesOnlyInLeft;\r
+    }\r
+    \r
+    public Collection<RouteLine> getLinesOnlyInRight() {\r
+        return linesOnlyInRight;\r
+    }\r
+    \r
+    public ArrayList<RouteLinePair> getLinesThatDiffer() {\r
+        return linesThatDiffer;\r
+    }\r
+    \r
+    public Collection<RouteLink> getLinksOnlyInLeft() {\r
+        return linksOnlyInLeft;\r
+    }\r
+    \r
+    public Collection<RouteLink> getLinksOnlyInRight() {\r
+        return linksOnlyInRight;\r
+    }\r
+    \r
+    public ArrayList<RouteTerminal> getTerminalsOnlyInLeft() {\r
+        return terminalsOnlyInLeft;\r
+    }\r
+    \r
+    public ArrayList<RouteTerminal> getTerminalsOnlyInRight() {\r
+        return terminalsOnlyInRight;\r
+    }\r
+    \r
+    public ArrayList<RouteTerminalPair> getTerminalsThatDiffer() {\r
+        return terminalsThatDiffer;\r
+    }\r
+    \r
+    private static class KeyPair {\r
+        final Object a;\r
+        final Object b;\r
+        \r
+        public KeyPair(Object a, Object b) {\r
+            this.a = a;\r
+            this.b = b;\r
+        }\r
+        \r
+        @Override\r
+        public int hashCode() {\r
+            return 31*a.hashCode() + b.hashCode();\r
+        }\r
+        \r
+        @Override\r
+        public boolean equals(Object obj) {\r
+            if(obj == this)\r
+                return true;\r
+            if(obj == null || obj.getClass() != KeyPair.class)\r
+                return false;\r
+            KeyPair other = (KeyPair)obj;\r
+            return a.equals(other.a) && b.equals(other.b);\r
+        }\r
+    }\r
+    \r
+    public RouteGraphDelta(RouteGraph left, RouteGraph right) {\r
+        {\r
+            THashMap<Object, RouteLine> lineMap = \r
+                    new THashMap<Object, RouteLine>();\r
+            for(RouteLine line : left.getLines()) {\r
+                Object data = line.getData();\r
+                if(data == null)\r
+                    linesOnlyInLeft.add(line);\r
+                else\r
+                    lineMap.put(data, line);\r
+            }\r
+            for(RouteLine line : right.getLines()) {\r
+                Object data = line.getData();\r
+                if(data == null)\r
+                    linesOnlyInRight.add(line);\r
+                else {\r
+                    RouteLine other =lineMap.remove(data);\r
+                    if(other == null)\r
+                        linesOnlyInRight.add(line);\r
+                    else if(line.getPosition() != other.getPosition() ||\r
+                            line.isHorizontal() != other.isHorizontal())\r
+                        linesThatDiffer.add(new RouteLinePair(other, line));\r
+                }\r
+            }\r
+            linesOnlyInLeft.addAll(lineMap.values());\r
+        }\r
+        {\r
+            THashMap<KeyPair, RouteLink> linkMap = \r
+                    new THashMap<KeyPair, RouteLink>();\r
+            for(RouteLine a : left.getLines()) {\r
+                for(RoutePoint point : a.getPoints()) {\r
+                    if(!(point instanceof RouteLink))\r
+                        continue;\r
+                    RouteLink link = (RouteLink)point;\r
+                    RouteLine b = link.getB();\r
+                    if(a == link.getA() && !b.isTransient()) {\r
+                        Object dataA = a.getData();\r
+                        Object dataB = b.getData();\r
+                        if(dataA == null || dataB == null)\r
+                            linksOnlyInLeft.add(link);\r
+                        else\r
+                            linkMap.put(new KeyPair(dataA, dataB), link);\r
+                    }\r
+                }\r
+            }\r
+            for(RouteLine a : right.getLines()) {\r
+                for(RoutePoint point : a.getPoints()) {\r
+                    if(!(point instanceof RouteLink))\r
+                        continue;\r
+                    RouteLink link = (RouteLink)point;\r
+                    RouteLine b = link.getB();\r
+                    if(a == link.getA() && !b.isTransient()) {\r
+                        Object dataA = a.getData();\r
+                        Object dataB = b.getData();\r
+                        if(dataA == null || dataB == null\r
+                                || (linkMap.remove(new KeyPair(dataA, dataB)) == null\r
+                                 && linkMap.remove(new KeyPair(dataB, dataA)) == null))\r
+                            linksOnlyInRight.add(link);\r
+                    }\r
+                }\r
+            }\r
+            linksOnlyInLeft.addAll(linkMap.values());\r
+        }   \r
+        {\r
+            THashMap<Object, RouteTerminal> terminalMap = \r
+                    new THashMap<Object, RouteTerminal>();\r
+            for(RouteTerminal terminal : left.getTerminals()) {\r
+                Object data = terminal.getData();\r
+                if(data == null)\r
+                    terminalsOnlyInLeft.add(terminal);\r
+                else\r
+                    terminalMap.put(data, terminal);\r
+            }\r
+            for(RouteTerminal terminal : right.getTerminals()) {\r
+                Object data = terminal.getData();\r
+                if(data == null)\r
+                    terminalsOnlyInRight.add(terminal);\r
+                else {\r
+                    RouteTerminal other = terminalMap.remove(data);\r
+                    if(other == null)\r
+                        terminalsOnlyInRight.add(terminal);\r
+                    else if(!terminalsEqual(other, terminal))\r
+                        terminalsThatDiffer.add(new RouteTerminalPair(other, terminal));\r
+                }\r
+            }\r
+            terminalsOnlyInLeft.addAll(terminalMap.values());\r
+        }\r
+    }\r
+    \r
+    private static boolean terminalsEqual(RouteTerminal left, RouteTerminal right) {\r
+        if(left == null)\r
+            return right == null;\r
+        if(right == null)\r
+            return false;\r
+        RouteLine leftLine = left.getLine();\r
+        RouteLine rightLine = right.getLine();\r
+        if(leftLine == null)\r
+            return rightLine == null;\r
+        if(rightLine == null)\r
+            return false;\r
+        Object leftData = leftLine.getData();\r
+        Object rightData = rightLine.getData();\r
+        if(leftData == null || rightData == null) \r
+            return false; // if both lines have null data, they are still not equal\r
+        return leftData.equals(rightData);\r
+    }\r
+    \r
+    public void print() {\r
+        System.out.println("=== Delta ===");\r
+        if(!linesOnlyInLeft.isEmpty() || !linksOnlyInLeft.isEmpty()\r
+                || !terminalsOnlyInLeft.isEmpty()) {\r
+            System.out.println("Only in the left route graph:");\r
+            for(RouteLine line : linesOnlyInLeft)\r
+                System.out.println("    line " + line.getData());\r
+            for(RouteLink link : linksOnlyInLeft)\r
+                System.out.println("    <" + link.getA().getData() + "," + link.getB().getData() + ">");\r
+            for(RouteTerminal terminal : terminalsOnlyInLeft)\r
+                System.out.println("    terminal " + terminal.getData());\r
+        }\r
+        if(!linesOnlyInRight.isEmpty() || !linksOnlyInRight.isEmpty()\r
+                || !terminalsOnlyInRight.isEmpty()) {\r
+            System.out.println("Only in the right route graph:");\r
+            for(RouteLine line : linesOnlyInRight)\r
+                System.out.println("    line " + line.getData());\r
+            for(RouteLink link : linksOnlyInRight)\r
+                System.out.println("    <" + link.getA().getData() + "," + link.getB().getData() + ">");\r
+            for(RouteTerminal terminal : terminalsOnlyInRight)\r
+                System.out.println("    terminal " + terminal.getData());\r
+        }\r
+        if(!linesThatDiffer.isEmpty() || !terminalsThatDiffer.isEmpty()) {\r
+            System.out.println("Differing:");\r
+            for(RouteLinePair pair : linesThatDiffer)\r
+                System.out.println("    " + pair.left.getData() + " <> " + pair.right.getData());\r
+            for(RouteTerminalPair pair : terminalsThatDiffer)\r
+                System.out.println("    " + pair.left.getData() + " (" + pair.left.getX() + "," + pair.left.getY() + ") <> " + pair.right.getData() + " (" + pair.right.getX() + "," + pair.right.getY() + ")");\r
+        }\r
+    }\r
+\r
+    public boolean isEmpty() {\r
+        return\r
+                linesOnlyInLeft.isEmpty() && linksOnlyInLeft.isEmpty() && terminalsOnlyInLeft.isEmpty() &&\r
+                linesOnlyInRight.isEmpty() && linksOnlyInRight.isEmpty() && terminalsOnlyInRight.isEmpty() &&\r
+                linesThatDiffer.isEmpty() && terminalsThatDiffer.isEmpty();\r
+    }\r
+\r
+}\r