Grant access to diagram APIs to enable web based diagram editing
[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     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 double getPosition() {
61         return position;
62     }
63     
64     public List<RoutePoint> getPoints() {
65         if(RouteGraph.RETURN_UNMODIFIABLE_COLLECTIONS)
66                 return Collections.unmodifiableList(points);
67         else
68                 return points;
69     }
70     
71     void addPoint(RoutePoint link) {
72         points.add(link);        
73     }
74
75     void remove() {
76         for(RoutePoint point : points)
77             point.removeFromOther(this);
78     }
79     
80     void setPointPositions() {        
81         if(isHorizontal) {
82             for(RoutePoint point : points)
83                 point.y = position;
84         }
85         else {
86             for(RoutePoint point : points)
87                 point.x = position;
88         }
89     }
90
91     void sortPoints() {
92         Collections.sort(points, isHorizontal 
93                 ? RoutePoint.X_COMPARATOR 
94                 : RoutePoint.Y_COMPARATOR);
95     }
96     
97     public boolean isNear(double x2, double y2, double tolerance) {
98         return isHorizontal 
99                 ? Math.abs(y2-position) <= tolerance 
100                     && points.get(0).x - tolerance <= x2
101                     && x2 <= points.get(points.size()-1).x + tolerance
102                 : Math.abs(x2-position) <= tolerance 
103                     && points.get(0).y - tolerance <= y2
104                     && y2 <= points.get(points.size()-1).y + tolerance;
105     }
106
107     public void print(PrintStream out) {
108         if(isHorizontal)
109             out.print("    HOR");
110         else
111             out.print("    VER");
112         for(RoutePoint point : points) {
113             out.print(" ("+point.x+","+point.y+")");
114         }
115         out.print(" (data=" + data + ")");
116         out.println();
117     }
118
119     void setLocation(double x, double y) {
120         if(isHorizontal)
121             position = y;
122         else
123             position = x;
124     }
125
126     public double getLength() {
127         if(isHorizontal)
128             return points.get(points.size()-1).x - points.get(0).x;
129         else
130             return points.get(points.size()-1).y - points.get(0).y;
131     }
132
133     boolean isConnectedToPeristentLine() {
134         for(RoutePoint point : points)
135             if(point instanceof RouteLink) {
136                 RouteLink link = (RouteLink)point;
137                 if(link.a == this) {
138                     if(!link.b.isTransient())
139                         return true;
140                 }
141                 else {
142                     if(!link.a.isTransient())
143                         return true;
144                 }
145             }
146         return false;
147     }
148     
149     public RoutePoint getBegin() {
150         return points.get(0);
151     }
152     
153     public RoutePoint getEnd() {
154         return points.get(points.size()-1);
155     }
156
157     public boolean isTransient() {
158         return terminal != null;
159     }
160
161     RouteLine copy(THashMap<Object, Object> map) {      
162         RouteLine copy = (RouteLine)map.get(this);
163         if(copy == null) {
164                 copy = new RouteLine(isHorizontal, position);
165                 map.put(this, copy);
166                 copy.data = data;
167                 copy.nextTransient = nextTransient == null ? null : nextTransient.copy(map);
168                 copy.terminal = terminal == null ? null : terminal.copy(map);
169                 for(RoutePoint point : points)
170                         copy.points.add(point.copy(map));
171         }
172         return copy;
173     }
174     
175     public Collection<RouteLine> getPersistentNeighbors() {
176         ArrayList<RouteLine> lines = new ArrayList<RouteLine>();
177         for(RoutePoint point : points)
178                 if(point instanceof RouteLink) {
179                         RouteLink link = (RouteLink)point;
180                         RouteLine line = link.getOther(this);
181                         if(!line.isTransient())
182                                 lines.add(line);
183                 }
184         return lines;
185     }
186
187     public RouteTerminal getTerminal() {
188         return terminal;
189     }
190
191     public RouteLine getNextTransient() {
192         return nextTransient;
193     }
194
195     public boolean beginsWithTerminal() {
196         RoutePoint begin = points.get(0);
197         if(begin == terminal)
198             return true;
199         else if(begin instanceof RouteLink) {
200             RouteLink link = (RouteLink)begin;
201             if(link.a == this)
202                 return link.b.hasTerminal(link, terminal);
203             else
204                 return link.a.hasTerminal(link, terminal);
205         }
206         else
207             return false;
208     }
209
210     private boolean hasTerminal(RouteLink oldLink, RouteTerminal terminal) {
211         RoutePoint begin = points.get(0);
212         RoutePoint end = points.get(1);
213         if(begin == terminal || end == terminal)
214             return true;
215         if(begin instanceof RouteLink && begin != oldLink) {
216             RouteLink link = (RouteLink)begin;
217             if(link.a == this)
218                 return link.b.hasTerminal(link, terminal);
219             else
220                 return link.a.hasTerminal(link, terminal);
221         }
222         else if(end instanceof RouteLink && end != oldLink) {
223             RouteLink link = (RouteLink)end;
224             if(link.a == this)
225                 return link.b.hasTerminal(link, terminal);
226             else
227                 return link.a.hasTerminal(link, terminal);
228         }
229         else
230             return false;
231     }
232
233     public boolean isDegenerated() {
234         if(points.size() <= 1)
235             return true;
236         if(isHorizontal)
237             return points.get(0).x == points.get(points.size()-1).x;
238         else
239             return points.get(0).y == points.get(points.size()-1).y;
240     }
241
242     public void collectSegments(ArrayList<Segment> segments) {
243         RoutePoint p0 = points.get(0);
244         for(int i=1;i<points.size();++i) {
245             RoutePoint p1 = points.get(i);
246             segments.add(new Segment(p0, p1));            
247             p0 = p1;
248         }
249     }
250 }