]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/delta/RouteGraphDelta.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.diagram.connection / src / org / simantics / diagram / connection / delta / RouteGraphDelta.java
1 /*******************************************************************************
2  * Copyright (c) 2011 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.connection.delta;
13
14 import gnu.trove.map.hash.THashMap;
15
16 import java.io.Serializable;
17 import java.util.ArrayList;
18 import java.util.Collection;
19
20 import org.simantics.diagram.connection.RouteGraph;
21 import org.simantics.diagram.connection.RouteLine;
22 import org.simantics.diagram.connection.RouteLink;
23 import org.simantics.diagram.connection.RoutePoint;
24 import org.simantics.diagram.connection.RouteTerminal;
25
26 /**
27  * Calculates the delta between two route graphs. Only
28  * persistent lines are used in the computation. Lines,
29  * links and terminals are matched by their data attribute.
30  * If data is null, the node is not matched any node in
31  * the other node. Two lines differ, if they have a 
32  * different orientation or position. Two terminals differ,
33  * if they are linked to different route lines ({@link RouteTerminal#getLine()}).  
34  * @author Hannu Niemistö
35  */
36 public class RouteGraphDelta implements Serializable {
37
38     private static final long serialVersionUID = 5011201407852172263L;
39
40     ArrayList<RouteLine> linesOnlyInLeft = new ArrayList<RouteLine>();
41     ArrayList<RouteLine> linesOnlyInRight = new ArrayList<RouteLine>();
42     ArrayList<RouteLinePair> linesThatDiffer = new ArrayList<RouteLinePair>();
43     ArrayList<RouteLink> linksOnlyInLeft = new ArrayList<RouteLink>();
44     ArrayList<RouteLink> linksOnlyInRight = new ArrayList<RouteLink>();
45     ArrayList<RouteTerminal> terminalsOnlyInLeft = new ArrayList<RouteTerminal>();
46     ArrayList<RouteTerminal> terminalsOnlyInRight = new ArrayList<RouteTerminal>();
47     ArrayList<RouteTerminalPair> terminalsThatDiffer = new ArrayList<RouteTerminalPair>();
48     
49     public static class RouteLinePair implements Serializable {
50         private static final long serialVersionUID = 382349562756381086L;
51
52         public final RouteLine left;
53         public final RouteLine right;
54
55         public RouteLinePair(RouteLine left, RouteLine right) {
56             this.left = left;
57             this.right = right;
58         }
59     }
60     
61     public static class RouteTerminalPair implements Serializable {
62         private static final long serialVersionUID = 5286896101190626944L;
63
64         public final RouteTerminal left;
65         public final RouteTerminal right;
66
67         public RouteTerminalPair(RouteTerminal left, RouteTerminal right) {
68             this.left = left;
69             this.right = right;
70         }
71     }
72     
73     public Collection<RouteLine> getLinesOnlyInLeft() {
74         return linesOnlyInLeft;
75     }
76     
77     public Collection<RouteLine> getLinesOnlyInRight() {
78         return linesOnlyInRight;
79     }
80     
81     public ArrayList<RouteLinePair> getLinesThatDiffer() {
82         return linesThatDiffer;
83     }
84     
85     public Collection<RouteLink> getLinksOnlyInLeft() {
86         return linksOnlyInLeft;
87     }
88     
89     public Collection<RouteLink> getLinksOnlyInRight() {
90         return linksOnlyInRight;
91     }
92     
93     public ArrayList<RouteTerminal> getTerminalsOnlyInLeft() {
94         return terminalsOnlyInLeft;
95     }
96     
97     public ArrayList<RouteTerminal> getTerminalsOnlyInRight() {
98         return terminalsOnlyInRight;
99     }
100     
101     public ArrayList<RouteTerminalPair> getTerminalsThatDiffer() {
102         return terminalsThatDiffer;
103     }
104     
105     private static class KeyPair {
106         final Object a;
107         final Object b;
108         
109         public KeyPair(Object a, Object b) {
110             this.a = a;
111             this.b = b;
112         }
113         
114         @Override
115         public int hashCode() {
116             return 31*a.hashCode() + b.hashCode();
117         }
118         
119         @Override
120         public boolean equals(Object obj) {
121             if(obj == this)
122                 return true;
123             if(obj == null || obj.getClass() != KeyPair.class)
124                 return false;
125             KeyPair other = (KeyPair)obj;
126             return a.equals(other.a) && b.equals(other.b);
127         }
128     }
129     
130     public RouteGraphDelta(RouteGraph left, RouteGraph right) {
131         {
132             THashMap<Object, RouteLine> lineMap = 
133                     new THashMap<Object, RouteLine>();
134             for(RouteLine line : left.getLines()) {
135                 Object data = line.getData();
136                 if(data == null)
137                     linesOnlyInLeft.add(line);
138                 else
139                     lineMap.put(data, line);
140             }
141             for(RouteLine line : right.getLines()) {
142                 Object data = line.getData();
143                 if(data == null)
144                     linesOnlyInRight.add(line);
145                 else {
146                     RouteLine other =lineMap.remove(data);
147                     if(other == null)
148                         linesOnlyInRight.add(line);
149                     else if(line.getPosition() != other.getPosition() ||
150                             line.isHorizontal() != other.isHorizontal())
151                         linesThatDiffer.add(new RouteLinePair(other, line));
152                 }
153             }
154             linesOnlyInLeft.addAll(lineMap.values());
155         }
156         {
157             THashMap<KeyPair, RouteLink> linkMap = 
158                     new THashMap<KeyPair, RouteLink>();
159             for(RouteLine a : left.getLines()) {
160                 for(RoutePoint point : a.getPoints()) {
161                     if(!(point instanceof RouteLink))
162                         continue;
163                     RouteLink link = (RouteLink)point;
164                     RouteLine b = link.getB();
165                     if(a == link.getA() && !b.isTransient()) {
166                         Object dataA = a.getData();
167                         Object dataB = b.getData();
168                         if(dataA == null || dataB == null)
169                             linksOnlyInLeft.add(link);
170                         else
171                             linkMap.put(new KeyPair(dataA, dataB), link);
172                     }
173                 }
174             }
175             for(RouteLine a : right.getLines()) {
176                 for(RoutePoint point : a.getPoints()) {
177                     if(!(point instanceof RouteLink))
178                         continue;
179                     RouteLink link = (RouteLink)point;
180                     RouteLine b = link.getB();
181                     if(a == link.getA() && !b.isTransient()) {
182                         Object dataA = a.getData();
183                         Object dataB = b.getData();
184                         if(dataA == null || dataB == null
185                                 || (linkMap.remove(new KeyPair(dataA, dataB)) == null
186                                  && linkMap.remove(new KeyPair(dataB, dataA)) == null))
187                             linksOnlyInRight.add(link);
188                     }
189                 }
190             }
191             linksOnlyInLeft.addAll(linkMap.values());
192         }   
193         {
194             THashMap<Object, RouteTerminal> terminalMap = 
195                     new THashMap<Object, RouteTerminal>();
196             for(RouteTerminal terminal : left.getTerminals()) {
197                 Object data = terminal.getData();
198                 if(data == null)
199                     terminalsOnlyInLeft.add(terminal);
200                 else
201                     terminalMap.put(data, terminal);
202             }
203             for(RouteTerminal terminal : right.getTerminals()) {
204                 Object data = terminal.getData();
205                 if(data == null)
206                     terminalsOnlyInRight.add(terminal);
207                 else {
208                     RouteTerminal other = terminalMap.remove(data);
209                     if(other == null)
210                         terminalsOnlyInRight.add(terminal);
211                     else if(!terminalsEqual(other, terminal))
212                         terminalsThatDiffer.add(new RouteTerminalPair(other, terminal));
213                 }
214             }
215             terminalsOnlyInLeft.addAll(terminalMap.values());
216         }
217     }
218     
219     private static boolean terminalsEqual(RouteTerminal left, RouteTerminal right) {
220         if(left == null)
221             return right == null;
222         if(right == null)
223             return false;
224         RouteLine leftLine = left.getLine();
225         RouteLine rightLine = right.getLine();
226         if(leftLine == null)
227             return rightLine == null;
228         if(rightLine == null)
229             return false;
230         Object leftData = leftLine.getData();
231         Object rightData = rightLine.getData();
232         if(leftData == null || rightData == null) 
233             return false; // if both lines have null data, they are still not equal
234         return leftData.equals(rightData);
235     }
236     
237     public void print() {
238         System.out.println("=== Delta ===");
239         if(!linesOnlyInLeft.isEmpty() || !linksOnlyInLeft.isEmpty()
240                 || !terminalsOnlyInLeft.isEmpty()) {
241             System.out.println("Only in the left route graph:");
242             for(RouteLine line : linesOnlyInLeft)
243                 System.out.println("    line " + line.getData());
244             for(RouteLink link : linksOnlyInLeft)
245                 System.out.println("    <" + link.getA().getData() + "," + link.getB().getData() + ">");
246             for(RouteTerminal terminal : terminalsOnlyInLeft)
247                 System.out.println("    terminal " + terminal.getData());
248         }
249         if(!linesOnlyInRight.isEmpty() || !linksOnlyInRight.isEmpty()
250                 || !terminalsOnlyInRight.isEmpty()) {
251             System.out.println("Only in the right route graph:");
252             for(RouteLine line : linesOnlyInRight)
253                 System.out.println("    line " + line.getData());
254             for(RouteLink link : linksOnlyInRight)
255                 System.out.println("    <" + link.getA().getData() + "," + link.getB().getData() + ">");
256             for(RouteTerminal terminal : terminalsOnlyInRight)
257                 System.out.println("    terminal " + terminal.getData());
258         }
259         if(!linesThatDiffer.isEmpty() || !terminalsThatDiffer.isEmpty()) {
260             System.out.println("Differing:");
261             for(RouteLinePair pair : linesThatDiffer)
262                 System.out.println("    " + pair.left.getData() + " <> " + pair.right.getData());
263             for(RouteTerminalPair pair : terminalsThatDiffer)
264                 System.out.println("    " + pair.left.getData() + " (" + pair.left.getX() + "," + pair.left.getY() + ") <> " + pair.right.getData() + " (" + pair.right.getX() + "," + pair.right.getY() + ")");
265         }
266     }
267
268     public boolean isEmpty() {
269         return
270                 linesOnlyInLeft.isEmpty() && linksOnlyInLeft.isEmpty() && terminalsOnlyInLeft.isEmpty() &&
271                 linesOnlyInRight.isEmpty() && linksOnlyInRight.isEmpty() && terminalsOnlyInRight.isEmpty() &&
272                 linesThatDiffer.isEmpty() && terminalsThatDiffer.isEmpty();
273     }
274
275 }