Don't create degenerated transient RouteLines to RouteGraph
[simantics/platform.git] / bundles / org.simantics.diagram.connection / src / org / simantics / diagram / connection / RouteLine.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;
13
14 import gnu.trove.map.hash.THashMap;
15
16 import java.io.PrintStream;
17 import java.io.Serializable;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.List;
22
23 import org.simantics.diagram.connection.segments.Segment;
24
25 public class RouteLine implements RouteNode, Serializable {
26     private static final long serialVersionUID = -7256429294500809465L;
27
28     Object data;
29     boolean isHorizontal;
30     double  position;
31     boolean hidden;
32     
33     ArrayList<RoutePoint> points = new ArrayList<RoutePoint>(4);
34     RouteLine nextTransient;
35     RouteTerminal terminal;
36     
37     public RouteLine(boolean isHorizontal, double position) {
38         this.isHorizontal = isHorizontal;
39         this.position = position;
40     }
41     
42     @Override
43     public void setData(Object data) {
44         this.data = data;
45     }
46     
47     @Override
48     public Object getData() {
49         return data;
50     }
51
52     public boolean isHorizontal() {
53         return isHorizontal;
54     }
55     
56     public boolean isHidden() {
57                 return hidden;
58         }
59     
60     public void setHidden(boolean hidden) {
61                 this.hidden = hidden;
62         }
63     
64     public double getPosition() {
65         return position;
66     }
67     
68     public List<RoutePoint> getPoints() {
69         if(RouteGraph.RETURN_UNMODIFIABLE_COLLECTIONS)
70                 return Collections.unmodifiableList(points);
71         else
72                 return points;
73     }
74     
75     public void addPoint(RoutePoint link) {
76         points.add(link);        
77     }
78
79     void remove() {
80         for(RoutePoint point : points)
81             point.removeFromOther(this);
82     }
83     
84     public void setPointPositions() {        
85         if(isHorizontal) {
86             for(RoutePoint point : points)
87                 point.y = position;
88         }
89         else {
90             for(RoutePoint point : points)
91                 point.x = position;
92         }
93     }
94
95     public void sortPoints() {
96         Collections.sort(points, isHorizontal 
97                 ? RoutePoint.X_COMPARATOR 
98                 : RoutePoint.Y_COMPARATOR);
99     }
100     
101     public boolean isNear(double x2, double y2, double tolerance) {
102         return isHorizontal 
103                 ? Math.abs(y2-position) <= tolerance 
104                     && points.get(0).x - tolerance <= x2
105                     && x2 <= points.get(points.size()-1).x + tolerance
106                 : Math.abs(x2-position) <= tolerance 
107                     && points.get(0).y - tolerance <= y2
108                     && y2 <= points.get(points.size()-1).y + tolerance;
109     }
110
111     public void print(PrintStream out) {
112         if(isHorizontal)
113             out.print("    HOR");
114         else
115             out.print("    VER");
116         for(RoutePoint point : points) {
117             out.print(" ("+point.x+","+point.y+")");
118         }
119         out.print(" (data=" + data + ")");
120         out.println();
121     }
122
123     void setLocation(double x, double y) {
124         if(isHorizontal)
125             position = y;
126         else
127             position = x;
128     }
129
130     public double getLength() {
131         if(isHorizontal)
132             return points.get(points.size()-1).x - points.get(0).x;
133         else
134             return points.get(points.size()-1).y - points.get(0).y;
135     }
136
137     boolean isConnectedToPeristentLine() {
138         for(RoutePoint point : points)
139             if(point instanceof RouteLink) {
140                 RouteLink link = (RouteLink)point;
141                 if(link.a == this) {
142                     if(!link.b.isTransient())
143                         return true;
144                 }
145                 else {
146                     if(!link.a.isTransient())
147                         return true;
148                 }
149             }
150         return false;
151     }
152     
153     public RoutePoint getBegin() {
154         return points.get(0);
155     }
156     
157     public RoutePoint getEnd() {
158         return points.get(points.size()-1);
159     }
160
161     public boolean isTransient() {
162         return terminal != null;
163     }
164
165     public RouteLine copy(THashMap<Object, Object> map) {       
166         RouteLine copy = (RouteLine)map.get(this);
167         if(copy == null) {
168                 copy = new RouteLine(isHorizontal, position);
169                 map.put(this, copy);
170                 copy.data = data;
171                 copy.nextTransient = nextTransient == null ? null : nextTransient.copy(map);
172                 copy.terminal = terminal == null ? null : terminal.copy(map);
173                 for(RoutePoint point : points)
174                         copy.points.add(point.copy(map));
175         }
176         return copy;
177     }
178     
179     public Collection<RouteLine> getPersistentNeighbors() {
180         ArrayList<RouteLine> lines = new ArrayList<RouteLine>();
181         for(RoutePoint point : points)
182                 if(point instanceof RouteLink) {
183                         RouteLink link = (RouteLink)point;
184                         RouteLine line = link.getOther(this);
185                         if(!line.isTransient())
186                                 lines.add(line);
187                 }
188         return lines;
189     }
190
191     public void removeRouteTerminals() {
192         points.removeIf(p -> p instanceof RouteTerminal);
193     }
194
195     public RouteTerminal getTerminal() {
196         return terminal;
197     }
198     
199     public void setTerminal(RouteTerminal terminal) {
200                 this.terminal = terminal;
201         }
202
203     public RouteLine getNextTransient() {
204         return nextTransient;
205     }
206
207     public boolean beginsWithTerminal() {
208         RoutePoint begin = points.get(0);
209         if(begin == terminal)
210             return true;
211         else if(begin instanceof RouteLink) {
212             RouteLink link = (RouteLink)begin;
213             if(link.a == this)
214                 return link.b.hasTerminal(link, terminal);
215             else
216                 return link.a.hasTerminal(link, terminal);
217         }
218         else
219             return false;
220     }
221
222     private boolean hasTerminal(RouteLink oldLink, RouteTerminal terminal) {
223         RoutePoint begin = points.get(0);
224         RoutePoint end = points.get(1);
225         if(begin == terminal || end == terminal)
226             return true;
227         if(begin instanceof RouteLink && begin != oldLink) {
228             RouteLink link = (RouteLink)begin;
229             if(link.a == this)
230                 return link.b.hasTerminal(link, terminal);
231             else
232                 return link.a.hasTerminal(link, terminal);
233         }
234         else if(end instanceof RouteLink && end != oldLink) {
235             RouteLink link = (RouteLink)end;
236             if(link.a == this)
237                 return link.b.hasTerminal(link, terminal);
238             else
239                 return link.a.hasTerminal(link, terminal);
240         }
241         else
242             return false;
243     }
244
245     public boolean isDegenerated() {
246         if(points.size() <= 1)
247             return true;
248         if(isHorizontal)
249             return points.get(0).x == points.get(points.size()-1).x;
250         else
251             return points.get(0).y == points.get(points.size()-1).y;
252     }
253
254     public void collectSegments(ArrayList<Segment> segments) {
255         RoutePoint p0 = points.get(0);
256         for(int i=1;i<points.size();++i) {
257             RoutePoint p1 = points.get(i);
258             segments.add(new Segment(p0, p1));            
259             p0 = p1;
260         }
261     }
262 }