+/*******************************************************************************\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;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import java.io.PrintStream;\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.simantics.diagram.connection.segments.Segment;\r
+\r
+public class RouteLine implements RouteNode, Serializable {\r
+ private static final long serialVersionUID = -7256429294500809465L;\r
+\r
+ Object data;\r
+ boolean isHorizontal;\r
+ double position;\r
+ boolean hidden;\r
+ \r
+ ArrayList<RoutePoint> points = new ArrayList<RoutePoint>(4);\r
+ RouteLine nextTransient;\r
+ RouteTerminal terminal;\r
+ \r
+ RouteLine(boolean isHorizontal, double position) {\r
+ this.isHorizontal = isHorizontal;\r
+ this.position = position;\r
+ }\r
+ \r
+ @Override\r
+ public void setData(Object data) {\r
+ this.data = data;\r
+ }\r
+ \r
+ @Override\r
+ public Object getData() {\r
+ return data;\r
+ }\r
+\r
+ public boolean isHorizontal() {\r
+ return isHorizontal;\r
+ }\r
+ \r
+ public boolean isHidden() {\r
+ return hidden;\r
+ }\r
+ \r
+ public double getPosition() {\r
+ return position;\r
+ }\r
+ \r
+ public List<RoutePoint> getPoints() {\r
+ if(RouteGraph.RETURN_UNMODIFIABLE_COLLECTIONS)\r
+ return Collections.unmodifiableList(points);\r
+ else\r
+ return points;\r
+ }\r
+ \r
+ void addPoint(RoutePoint link) {\r
+ points.add(link); \r
+ }\r
+\r
+ void remove() {\r
+ for(RoutePoint point : points)\r
+ point.removeFromOther(this);\r
+ }\r
+ \r
+ void setPointPositions() { \r
+ if(isHorizontal) {\r
+ for(RoutePoint point : points)\r
+ point.y = position;\r
+ }\r
+ else {\r
+ for(RoutePoint point : points)\r
+ point.x = position;\r
+ }\r
+ }\r
+\r
+ void sortPoints() {\r
+ Collections.sort(points, isHorizontal \r
+ ? RoutePoint.X_COMPARATOR \r
+ : RoutePoint.Y_COMPARATOR);\r
+ }\r
+ \r
+ public boolean isNear(double x2, double y2, double tolerance) {\r
+ return isHorizontal \r
+ ? Math.abs(y2-position) <= tolerance \r
+ && points.get(0).x <= x2 \r
+ && x2 <= points.get(points.size()-1).x\r
+ : Math.abs(x2-position) <= tolerance \r
+ && points.get(0).y <= y2 \r
+ && y2 <= points.get(points.size()-1).y;\r
+ }\r
+\r
+ public void print(PrintStream out) {\r
+ if(isHorizontal)\r
+ out.print(" HOR");\r
+ else\r
+ out.print(" VER");\r
+ for(RoutePoint point : points) {\r
+ out.print(" ("+point.x+","+point.y+")");\r
+ }\r
+ out.print(" (data=" + data + ")");\r
+ out.println();\r
+ }\r
+\r
+ void setLocation(double x, double y) {\r
+ if(isHorizontal)\r
+ position = y;\r
+ else\r
+ position = x;\r
+ }\r
+\r
+ public double getLength() {\r
+ if(isHorizontal)\r
+ return points.get(points.size()-1).x - points.get(0).x;\r
+ else\r
+ return points.get(points.size()-1).y - points.get(0).y;\r
+ }\r
+\r
+ boolean isConnectedToPeristentLine() {\r
+ for(RoutePoint point : points)\r
+ if(point instanceof RouteLink) {\r
+ RouteLink link = (RouteLink)point;\r
+ if(link.a == this) {\r
+ if(!link.b.isTransient())\r
+ return true;\r
+ }\r
+ else {\r
+ if(!link.a.isTransient())\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+ \r
+ public RoutePoint getBegin() {\r
+ return points.get(0);\r
+ }\r
+ \r
+ public RoutePoint getEnd() {\r
+ return points.get(points.size()-1);\r
+ }\r
+\r
+ public boolean isTransient() {\r
+ return terminal != null;\r
+ }\r
+\r
+ RouteLine copy(THashMap<Object, Object> map) { \r
+ RouteLine copy = (RouteLine)map.get(this);\r
+ if(copy == null) {\r
+ copy = new RouteLine(isHorizontal, position);\r
+ map.put(this, copy);\r
+ copy.data = data;\r
+ copy.nextTransient = nextTransient == null ? null : nextTransient.copy(map);\r
+ copy.terminal = terminal == null ? null : terminal.copy(map);\r
+ for(RoutePoint point : points)\r
+ copy.points.add(point.copy(map));\r
+ }\r
+ return copy;\r
+ }\r
+ \r
+ public Collection<RouteLine> getPersistentNeighbors() {\r
+ ArrayList<RouteLine> lines = new ArrayList<RouteLine>();\r
+ for(RoutePoint point : points)\r
+ if(point instanceof RouteLink) {\r
+ RouteLink link = (RouteLink)point;\r
+ RouteLine line = link.getOther(this);\r
+ if(!line.isTransient())\r
+ lines.add(line);\r
+ }\r
+ return lines;\r
+ }\r
+\r
+ public RouteTerminal getTerminal() {\r
+ return terminal;\r
+ }\r
+\r
+ public boolean beginsWithTerminal() {\r
+ RoutePoint begin = points.get(0);\r
+ if(begin == terminal)\r
+ return true;\r
+ else if(begin instanceof RouteLink) {\r
+ RouteLink link = (RouteLink)begin;\r
+ if(link.a == this)\r
+ return link.b.hasTerminal(link, terminal);\r
+ else\r
+ return link.a.hasTerminal(link, terminal);\r
+ }\r
+ else\r
+ return false;\r
+ }\r
+\r
+ private boolean hasTerminal(RouteLink oldLink, RouteTerminal terminal) {\r
+ RoutePoint begin = points.get(0);\r
+ RoutePoint end = points.get(1);\r
+ if(begin == terminal || end == terminal)\r
+ return true;\r
+ if(begin instanceof RouteLink && begin != oldLink) {\r
+ RouteLink link = (RouteLink)begin;\r
+ if(link.a == this)\r
+ return link.b.hasTerminal(link, terminal);\r
+ else\r
+ return link.a.hasTerminal(link, terminal);\r
+ }\r
+ else if(end instanceof RouteLink && end != oldLink) {\r
+ RouteLink link = (RouteLink)end;\r
+ if(link.a == this)\r
+ return link.b.hasTerminal(link, terminal);\r
+ else\r
+ return link.a.hasTerminal(link, terminal);\r
+ }\r
+ else\r
+ return false;\r
+ }\r
+\r
+ public boolean isDegenerated() {\r
+ if(points.size() <= 1)\r
+ return true;\r
+ if(isHorizontal)\r
+ return points.get(0).x == points.get(points.size()-1).x;\r
+ else\r
+ return points.get(0).y == points.get(points.size()-1).y;\r
+ }\r
+\r
+ public void collectSegments(ArrayList<Segment> segments) {\r
+ RoutePoint p0 = points.get(0);\r
+ for(int i=1;i<points.size();++i) {\r
+ RoutePoint p1 = points.get(i);\r
+ segments.add(new Segment(p0, p1)); \r
+ p0 = p1;\r
+ }\r
+ }\r
+}\r