-/*******************************************************************************\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.awt.geom.Rectangle2D;\r
-import java.io.PrintStream;\r
-import java.io.Serializable;\r
-import java.util.ArrayList;\r
-\r
-import org.simantics.diagram.connection.RouteGraph.Interval;\r
-import org.simantics.diagram.connection.RouteGraph.IntervalCache;\r
-import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;\r
-\r
-public class RouteTerminal extends RoutePoint implements RouteNode, Serializable {\r
-\r
- private static final long serialVersionUID = -8839093950347737029L;\r
-\r
- public static final int DIR_RIGHT = (1 << 0);\r
- public static final int DIR_DOWN = (1 << 1);\r
- public static final int DIR_LEFT = (1 << 2);\r
- public static final int DIR_UP = (1 << 3);\r
- public static final int DIR_DIRECT = (1 << 4);\r
-\r
- private Object data;\r
- private double minX, minY;\r
- private double maxX, maxY;\r
- private int allowedDirections;\r
- private ILineEndStyle style;\r
- private ILineEndStyle dynamicStyle;\r
- private boolean routeToBounds;\r
-\r
- RouteLine line;\r
-\r
- RouteTerminal(double x, double y, double minX, double minY,\r
- double maxX, double maxY, int allowedDirections,\r
- boolean routeToBounds,\r
- ILineEndStyle style) {\r
- super(x, y);\r
- this.minX = minX;\r
- this.minY = minY;\r
- this.maxX = maxX;\r
- this.maxY = maxY;\r
- this.allowedDirections = allowedDirections;\r
- this.routeToBounds = routeToBounds;\r
- this.style = style;\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 int getAllowedDirections() {\r
- return allowedDirections;\r
- }\r
- \r
- public double getMinX() {\r
- return minX;\r
- }\r
- \r
- public double getMinY() {\r
- return minY;\r
- }\r
- \r
- public double getMaxX() {\r
- return maxX;\r
- }\r
- \r
- public double getMaxY() {\r
- return maxY;\r
- }\r
- \r
- public Rectangle2D getBounds() {\r
- return new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY);\r
- }\r
-\r
- /**\r
- * Routes connection from the terminal to route line\r
- * adding necessary transient route lines.\r
- * @param cache \r
- */\r
- void route(ArrayList<RouteLine> lines, IntervalCache cache, boolean boundingBoxesIntersect) {\r
- if(routeToBounds) {\r
- int lineDir;\r
- boolean routeLineDoesNotIntersectTerminal;\r
- double linePosition = line.position;\r
- if(line.isHorizontal) { \r
- lineDir = linePosition < y ? 3 : 1;\r
- routeLineDoesNotIntersectTerminal = \r
- linePosition <= minY || linePosition >= maxY;\r
- }\r
- else {\r
- lineDir = linePosition < x ? 2 : 0;\r
- routeLineDoesNotIntersectTerminal = \r
- linePosition <= minX || linePosition >= maxX;\r
- }\r
- \r
- if(routeLineDoesNotIntersectTerminal) {\r
- RouteLine line0 = createLine0(lineDir);\r
- new RouteLink(line0, line);\r
- lines.add(line0);\r
- switch(lineDir) {\r
- case 0:\r
- x = maxX;\r
- y = 0.5*(minY+maxY);\r
- break;\r
- case 1:\r
- x = 0.5*(minX+maxX);\r
- y = maxY;\r
- break;\r
- case 2:\r
- x = minX;\r
- y = 0.5*(minY+maxY);\r
- break;\r
- case 3:\r
- x = 0.5*(minX+maxX);\r
- y = minY;\r
- break;\r
- }\r
- return;\r
- }\r
- else {\r
- line.addPoint(this);\r
- Interval interval = cache.get(line);\r
- if(line.isHorizontal) {\r
- if(interval.min < minX)\r
- x = minX;\r
- else\r
- x = maxX;\r
- y = linePosition;\r
- }\r
- else {\r
- x = linePosition;\r
- if(interval.min < minY)\r
- y = minY;\r
- else\r
- y = maxY;\r
- }\r
- }\r
- }\r
- else {\r
- // In which direction the route line is?\r
- int lineDir;\r
- boolean routeLineDoesNotIntersectTerminal;\r
- double linePosition = line.position;\r
- if(line.isHorizontal) { \r
- lineDir = linePosition < y ? 3 : 1;\r
- routeLineDoesNotIntersectTerminal = linePosition <= minY || linePosition >= maxY \r
- || boundingBoxesIntersect /* we ignore intersection in this case */;\r
- }\r
- else {\r
- lineDir = linePosition < x ? 2 : 0;\r
- routeLineDoesNotIntersectTerminal = linePosition <= minX || linePosition >= maxX\r
- || boundingBoxesIntersect /* we ignore intersection in this case */;\r
- }\r
- \r
- // We can route the connection directly to the right direction\r
- if(routeLineDoesNotIntersectTerminal && \r
- Directions.isAllowed(allowedDirections, lineDir)) { \r
- RouteLine line0 = createLine0(lineDir);\r
- new RouteLink(line0, line);\r
- lines.add(line0);\r
- return;\r
- }\r
- \r
- // We must make one bend\r
- oneBend: {\r
- int dir = 1-(lineDir&1);\r
- if(Directions.isAllowed(allowedDirections, dir)) {\r
- if(Directions.isAllowed(allowedDirections, dir+2)) {\r
- Interval interval = cache.get(line);\r
- if(dir == 0) {\r
- if(interval.max <= maxX)\r
- dir = 2;\r
- }\r
- else /* dir == 1 */ {\r
- if(interval.max <= maxY)\r
- dir = 3;\r
- }\r
- }\r
- else {\r
- // ok\r
- }\r
- }\r
- else {\r
- if(Directions.isAllowed(allowedDirections, dir+2)) {\r
- dir = dir + 2;\r
- }\r
- else {\r
- break oneBend;\r
- }\r
- }\r
- \r
- RouteLine line0 = createLine0(dir);\r
- RouteLine line1 = createLine1(dir);\r
- new RouteLink(line0, line1);\r
- new RouteLink(line1, line);\r
- lines.add(line0);\r
- lines.add(line1);\r
- line0.nextTransient = line1;\r
- return;\r
- }\r
- \r
- // We can begin to the right direction but do two bends\r
- if(!routeLineDoesNotIntersectTerminal && \r
- Directions.isAllowed(allowedDirections, lineDir)) { \r
- RouteLine line0 = createLine0(lineDir);\r
- RouteLine line1 = createLine1(lineDir);\r
- RouteLine line2 = createLine2(lineDir, cache);\r
- new RouteLink(line0, line1);\r
- new RouteLink(line1, line2);\r
- new RouteLink(line2, line);\r
- lines.add(line0);\r
- lines.add(line1);\r
- lines.add(line2);\r
- line0.nextTransient = line1;\r
- line1.nextTransient = line2;\r
- return;\r
- }\r
- \r
- // Only allowed direction is to completely wrong direction:\r
- // we must make two bends\r
- {\r
- int dir = lineDir^2;\r
- RouteLine line0 = createLine0(dir);\r
- RouteLine line1 = createLine1(dir);\r
- RouteLine line2 = createLine2(dir, cache);\r
- new RouteLink(line0, line1);\r
- new RouteLink(line1, line2);\r
- new RouteLink(line2, line);\r
- lines.add(line0);\r
- lines.add(line1);\r
- lines.add(line2);\r
- line0.nextTransient = line1;\r
- line1.nextTransient = line2;\r
- return;\r
- }\r
- }\r
- }\r
- \r
- private RouteLine createLine0(int dir) {\r
- RouteLine line0 = (dir&1) == 0 \r
- ? new RouteLine(true, y)\r
- : new RouteLine(false, x)\r
- ;\r
- line0.addPoint(this);\r
- line0.terminal = this;\r
- return line0;\r
- }\r
- \r
- private RouteLine createLine1(int dir) {\r
- RouteLine line1 = (dir&1) == 0 \r
- ? new RouteLine(false, (dir&2) == 0 ? maxX : minX)\r
- : new RouteLine(true, (dir&2) == 0 ? maxY : minY)\r
- ;\r
- line1.terminal = this;\r
- return line1;\r
- }\r
- \r
- private RouteLine createLine2(int dir, IntervalCache cache) {\r
- Interval interval = cache.get(line);\r
- RouteLine line2;\r
- if((dir&1) == 0) {\r
- double position;\r
- if(minY < interval.min) {\r
- if(maxY > interval.max) {\r
- position = 2*maxY-y-interval.max < interval.min+y-2*minY ? maxY : minY;\r
- }\r
- else {\r
- position = maxY;\r
- }\r
- }\r
- else {\r
- if(maxY > interval.max) {\r
- position = minY;\r
- }\r
- else {\r
- position = maxY-y < y-minY ? maxY : minY;\r
- }\r
- }\r
- line2 = new RouteLine(true, position);\r
- }\r
- else {\r
- double position;\r
- if(minX < interval.min) {\r
- if(maxX > interval.max) {\r
- position = 2*maxX-x-interval.max < interval.min+x-2*minX ? maxX : minX;\r
- }\r
- else {\r
- position = maxX;\r
- }\r
- }\r
- else {\r
- if(maxX > interval.max) {\r
- position = minX;\r
- }\r
- else {\r
- position = maxX-x < x-minX ? maxX : minX;\r
- }\r
- }\r
- line2 = new RouteLine(false, position);\r
- }\r
- line2.terminal = this; \r
- return line2;\r
- } \r
-\r
- public boolean isNear(double x2, double y2) {\r
- return minX <= x2 && x2 <= maxX && minY <= y2 && y2 <= maxY;\r
- }\r
-\r
- void setLocation(double x2, double y2) {\r
- double dx = x2 - x;\r
- double dy = y2 - y;\r
- x = x2;\r
- y = y2;\r
- minX += dx;\r
- minY += dy;\r
- maxX += dx;\r
- maxY += dy;\r
- }\r
-\r
- void rotate(int amount) {\r
- amount %= 4;\r
- if(amount < 0)\r
- amount += 4;\r
- \r
- int temp = (allowedDirections&15) << amount;\r
- allowedDirections = (temp&15) | (temp >> 4) | (allowedDirections&16); \r
- }\r
-\r
- public double approximatePositionToLine() {\r
- // In which direction the route line is?\r
- int lineDir = line.isHorizontal \r
- ? (line.position < y ? 3 : 1)\r
- : (line.position < x ? 2 : 0)\r
- ;\r
- \r
- // We can route the connection directly to the right direction\r
- if(Directions.isAllowed(allowedDirections, lineDir))\r
- return line.isHorizontal ? x : y;\r
- \r
- // We must make one bend \r
- for(int dir = 0;dir < 4;++dir) {\r
- if(Directions.isAllowed(allowedDirections, dir) && ((dir^lineDir)&1) == 1) {\r
- switch(dir) {\r
- case 0: return maxX;\r
- case 1: return maxY;\r
- case 2: return minX;\r
- case 3: return minY;\r
- }\r
- }\r
- }\r
- // Only allowed direction is to completely wrong direction:\r
- // we must make two bends\r
- {\r
- // Approximation\r
- return line.isHorizontal ? x : y;\r
- }\r
- }\r
-\r
- RouteTerminal copy(THashMap<Object, Object> map) {\r
- RouteTerminal copy = (RouteTerminal)map.get(this);\r
- if(copy == null) { \r
- copy = new RouteTerminal(x, y, minX, minY, maxX, maxY, \r
- allowedDirections, routeToBounds, style);\r
- copy.setDynamicStyle(dynamicStyle);\r
- map.put(this, copy);\r
- copy.data = data;\r
- copy.line = line == null ? null : line.copy(map);\r
- }\r
- return copy;\r
- }\r
-\r
- public void print(PrintStream out) {\r
- out.print(" (" + x + "," + y + ") " + allowedDirections + " -> ");\r
- if (line != null)\r
- line.print(out);\r
- else\r
- out.print("NO LINE");\r
- out.print(" (data=" + data + ")");\r
- out.println();\r
- }\r
-\r
- public ILineEndStyle getStyle() {\r
- return style;\r
- }\r
- \r
- public ILineEndStyle getRenderStyle() {\r
- if (dynamicStyle != null)\r
- return dynamicStyle;\r
- return style;\r
- }\r
-\r
- public boolean hasDirectConnection() {\r
- return (allowedDirections&16) == 16;\r
- }\r
- \r
- public RouteLine getLine() {\r
- return line;\r
- }\r
- \r
- public void setMinX(double minX) {\r
- this.minX = minX;\r
- }\r
- public void setMinY(double minY) {\r
- this.minY = minY;\r
- }\r
- \r
- public void setMaxX(double maxX) {\r
- this.maxX = maxX;\r
- }\r
- \r
- public void setMaxY(double maxY) {\r
- this.maxY = maxY;\r
- }\r
-\r
- public void toggleDirectLines() {\r
- this.allowedDirections ^= 16;\r
- }\r
- \r
- public boolean isRouteToBounds() {\r
- return routeToBounds;\r
- }\r
- \r
- public void setStyle(ILineEndStyle style) {\r
- this.style = style;\r
- }\r
- \r
- public ILineEndStyle getDynamicStyle() {\r
- return dynamicStyle;\r
- }\r
- \r
- public void setDynamicStyle(ILineEndStyle dynamicStyle) {\r
- this.dynamicStyle = dynamicStyle;\r
- }\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2011 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.diagram.connection;
+
+import gnu.trove.map.hash.THashMap;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+
+import org.simantics.diagram.connection.RouteGraph.Interval;
+import org.simantics.diagram.connection.RouteGraph.IntervalCache;
+import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;
+
+public class RouteTerminal extends RoutePoint implements RouteNode, Serializable {
+
+ private static final long serialVersionUID = -8839093950347737029L;
+
+ public static final int DIR_RIGHT = (1 << 0);
+ public static final int DIR_DOWN = (1 << 1);
+ public static final int DIR_LEFT = (1 << 2);
+ public static final int DIR_UP = (1 << 3);
+ public static final int DIR_DIRECT = (1 << 4);
+
+ private Object data;
+ private double minX, minY;
+ private double maxX, maxY;
+ private int allowedDirections;
+ private ILineEndStyle style;
+ private ILineEndStyle dynamicStyle;
+ private boolean routeToBounds;
+ private RouteTerminalPosition dynamicPosition;
+
+ RouteLine line;
+
+ RouteTerminal(double x, double y, double minX, double minY,
+ double maxX, double maxY, int allowedDirections,
+ boolean routeToBounds,
+ ILineEndStyle style, RouteTerminalPosition dynamicPosition) {
+ super(x, y);
+ this.minX = minX;
+ this.minY = minY;
+ this.maxX = maxX;
+ this.maxY = maxY;
+ this.allowedDirections = allowedDirections;
+ this.routeToBounds = routeToBounds;
+ this.style = style;
+ this.dynamicPosition = dynamicPosition;
+ }
+
+ @Override
+ public void setData(Object data) {
+ this.data = data;
+ }
+
+ @Override
+ public Object getData() {
+ return data;
+ }
+
+ public int getAllowedDirections() {
+ return allowedDirections;
+ }
+
+ public double getMinX() {
+ return minX;
+ }
+
+ public double getMinY() {
+ return minY;
+ }
+
+ public double getMaxX() {
+ return maxX;
+ }
+
+ public double getMaxY() {
+ return maxY;
+ }
+
+ public Rectangle2D getBounds() {
+ return new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY);
+ }
+
+ /**
+ * Routes connection from the terminal to route line
+ * adding necessary transient route lines.
+ * @param cache
+ */
+ void route(ArrayList<RouteLine> lines, IntervalCache cache, boolean boundingBoxesIntersect) {
+ if(routeToBounds) {
+ int lineDir;
+ boolean routeLineDoesNotIntersectTerminal;
+ double linePosition = line.position;
+ if(line.isHorizontal) {
+ lineDir = linePosition < y ? 3 : 1;
+ routeLineDoesNotIntersectTerminal =
+ linePosition <= minY || linePosition >= maxY;
+ }
+ else {
+ lineDir = linePosition < x ? 2 : 0;
+ routeLineDoesNotIntersectTerminal =
+ linePosition <= minX || linePosition >= maxX;
+ }
+
+ if(routeLineDoesNotIntersectTerminal) {
+ RouteLine line0 = createLine0(lineDir);
+ new RouteLink(line0, line);
+ lines.add(line0);
+ switch(lineDir) {
+ case 0:
+ x = maxX;
+ y = 0.5*(minY+maxY);
+ break;
+ case 1:
+ x = 0.5*(minX+maxX);
+ y = maxY;
+ break;
+ case 2:
+ x = minX;
+ y = 0.5*(minY+maxY);
+ break;
+ case 3:
+ x = 0.5*(minX+maxX);
+ y = minY;
+ break;
+ }
+ return;
+ }
+ else {
+ line.addPoint(this);
+ Interval interval = cache.get(line);
+ if(line.isHorizontal) {
+ if(interval.min < minX)
+ x = minX;
+ else
+ x = maxX;
+ y = linePosition;
+ }
+ else {
+ x = linePosition;
+ if(interval.min < minY)
+ y = minY;
+ else
+ y = maxY;
+ }
+ }
+ }
+ else {
+ // In which direction the route line is?
+ int lineDir;
+ boolean routeLineDoesNotIntersectTerminal;
+ double linePosition = line.position;
+ if(line.isHorizontal) {
+ lineDir = linePosition < y ? 3 : 1;
+ routeLineDoesNotIntersectTerminal = linePosition <= minY || linePosition >= maxY
+ || boundingBoxesIntersect /* we ignore intersection in this case */;
+ }
+ else {
+ lineDir = linePosition < x ? 2 : 0;
+ routeLineDoesNotIntersectTerminal = linePosition <= minX || linePosition >= maxX
+ || boundingBoxesIntersect /* we ignore intersection in this case */;
+ }
+
+ // We can route the connection directly to the right direction
+ if(routeLineDoesNotIntersectTerminal &&
+ Directions.isAllowed(allowedDirections, lineDir)) {
+ RouteLine line0 = createLine0(lineDir);
+ new RouteLink(line0, line);
+ lines.add(line0);
+ return;
+ }
+
+ // We must make one bend
+ oneBend: {
+ int dir = 1-(lineDir&1);
+ if(Directions.isAllowed(allowedDirections, dir)) {
+ if(Directions.isAllowed(allowedDirections, dir+2)) {
+ Interval interval = cache.get(line);
+ if(dir == 0) {
+ if(interval.max <= maxX)
+ dir = 2;
+ }
+ else /* dir == 1 */ {
+ if(interval.max <= maxY)
+ dir = 3;
+ }
+ }
+ else {
+ // ok
+ }
+ }
+ else {
+ if(Directions.isAllowed(allowedDirections, dir+2)) {
+ dir = dir + 2;
+ }
+ else {
+ break oneBend;
+ }
+ }
+
+ RouteLine line0 = createLine0(dir);
+ RouteLine line1 = createLine1(dir);
+ new RouteLink(line0, line1);
+ new RouteLink(line1, line);
+ lines.add(line0);
+ lines.add(line1);
+ line0.nextTransient = line1;
+ return;
+ }
+
+ // We can begin to the right direction but do two bends
+ if(!routeLineDoesNotIntersectTerminal &&
+ Directions.isAllowed(allowedDirections, lineDir)) {
+ RouteLine line0 = createLine0(lineDir);
+ RouteLine line1 = createLine1(lineDir);
+ RouteLine line2 = createLine2(lineDir, cache);
+ new RouteLink(line0, line1);
+ new RouteLink(line1, line2);
+ new RouteLink(line2, line);
+ lines.add(line0);
+ lines.add(line1);
+ lines.add(line2);
+ line0.nextTransient = line1;
+ line1.nextTransient = line2;
+ return;
+ }
+
+ // Only allowed direction is to completely wrong direction:
+ // we must make two bends
+ {
+ int dir = lineDir^2;
+ RouteLine line0 = createLine0(dir);
+ RouteLine line1 = createLine1(dir);
+ RouteLine line2 = createLine2(dir, cache);
+ new RouteLink(line0, line1);
+ new RouteLink(line1, line2);
+ new RouteLink(line2, line);
+ lines.add(line0);
+ lines.add(line1);
+ lines.add(line2);
+ line0.nextTransient = line1;
+ line1.nextTransient = line2;
+ return;
+ }
+ }
+ }
+
+ private RouteLine createLine0(int dir) {
+ RouteLine line0 = (dir&1) == 0
+ ? new RouteLine(true, y)
+ : new RouteLine(false, x)
+ ;
+ line0.addPoint(this);
+ line0.terminal = this;
+ return line0;
+ }
+
+ private RouteLine createLine1(int dir) {
+ RouteLine line1 = (dir&1) == 0
+ ? new RouteLine(false, (dir&2) == 0 ? maxX : minX)
+ : new RouteLine(true, (dir&2) == 0 ? maxY : minY)
+ ;
+ line1.terminal = this;
+ return line1;
+ }
+
+ private RouteLine createLine2(int dir, IntervalCache cache) {
+ Interval interval = cache.get(line);
+ RouteLine line2;
+ if((dir&1) == 0) {
+ double position;
+ if(minY < interval.min) {
+ if(maxY > interval.max) {
+ position = 2*maxY-y-interval.max < interval.min+y-2*minY ? maxY : minY;
+ }
+ else {
+ position = maxY;
+ }
+ }
+ else {
+ if(maxY > interval.max) {
+ position = minY;
+ }
+ else {
+ position = maxY-y < y-minY ? maxY : minY;
+ }
+ }
+ line2 = new RouteLine(true, position);
+ }
+ else {
+ double position;
+ if(minX < interval.min) {
+ if(maxX > interval.max) {
+ position = 2*maxX-x-interval.max < interval.min+x-2*minX ? maxX : minX;
+ }
+ else {
+ position = maxX;
+ }
+ }
+ else {
+ if(maxX > interval.max) {
+ position = minX;
+ }
+ else {
+ position = maxX-x < x-minX ? maxX : minX;
+ }
+ }
+ line2 = new RouteLine(false, position);
+ }
+ line2.terminal = this;
+ return line2;
+ }
+
+ public boolean isNear(double x2, double y2) {
+ return minX <= x2 && x2 <= maxX && minY <= y2 && y2 <= maxY;
+ }
+
+ void setLocation(double x2, double y2) {
+ double dx = x2 - x;
+ double dy = y2 - y;
+ x = x2;
+ y = y2;
+ minX += dx;
+ minY += dy;
+ maxX += dx;
+ maxY += dy;
+ }
+
+ void rotate(int amount) {
+ amount %= 4;
+ if(amount < 0)
+ amount += 4;
+
+ int temp = (allowedDirections&15) << amount;
+ allowedDirections = (temp&15) | (temp >> 4) | (allowedDirections&16);
+ }
+
+ public double approximatePositionToLine() {
+ // In which direction the route line is?
+ int lineDir = line.isHorizontal
+ ? (line.position < y ? 3 : 1)
+ : (line.position < x ? 2 : 0)
+ ;
+
+ // We can route the connection directly to the right direction
+ if(Directions.isAllowed(allowedDirections, lineDir))
+ return line.isHorizontal ? x : y;
+
+ // We must make one bend
+ for(int dir = 0;dir < 4;++dir) {
+ if(Directions.isAllowed(allowedDirections, dir) && ((dir^lineDir)&1) == 1) {
+ switch(dir) {
+ case 0: return maxX;
+ case 1: return maxY;
+ case 2: return minX;
+ case 3: return minY;
+ }
+ }
+ }
+ // Only allowed direction is to completely wrong direction:
+ // we must make two bends
+ {
+ // Approximation
+ return line.isHorizontal ? x : y;
+ }
+ }
+
+ RouteTerminal copy(THashMap<Object, Object> map) {
+ RouteTerminal copy = (RouteTerminal)map.get(this);
+ if(copy == null) {
+ copy = new RouteTerminal(x, y, minX, minY, maxX, maxY,
+ allowedDirections, routeToBounds, style, dynamicPosition);
+ copy.setDynamicStyle(dynamicStyle);
+ map.put(this, copy);
+ copy.data = data;
+ copy.line = line == null ? null : line.copy(map);
+ }
+ return copy;
+ }
+
+ public void print(PrintStream out) {
+ out.print(" (" + x + "," + y + ") " + allowedDirections + " -> ");
+ if (line != null)
+ line.print(out);
+ else
+ out.print("NO LINE");
+ out.print(" (data=" + data + ")");
+ out.println();
+ }
+
+ public ILineEndStyle getStyle() {
+ return style;
+ }
+
+ public ILineEndStyle getRenderStyle() {
+ if (dynamicStyle != null)
+ return dynamicStyle;
+ return style;
+ }
+
+ public boolean hasDirectConnection() {
+ return (allowedDirections&16) == 16;
+ }
+
+ public RouteLine getLine() {
+ return line;
+ }
+
+ public void setMinX(double minX) {
+ this.minX = minX;
+ }
+ public void setMinY(double minY) {
+ this.minY = minY;
+ }
+
+ public void setMaxX(double maxX) {
+ this.maxX = maxX;
+ }
+
+ public void setMaxY(double maxY) {
+ this.maxY = maxY;
+ }
+
+ public void toggleDirectLines() {
+ this.allowedDirections ^= 16;
+ }
+
+ public boolean isRouteToBounds() {
+ return routeToBounds;
+ }
+
+ public void setStyle(ILineEndStyle style) {
+ this.style = style;
+ }
+
+ public ILineEndStyle getDynamicStyle() {
+ return dynamicStyle;
+ }
+
+ public void setDynamicStyle(ILineEndStyle dynamicStyle) {
+ this.dynamicStyle = dynamicStyle;
+ }
+
+ public RouteTerminalPosition getDynamicPosition() {
+ return dynamicPosition;
+ }
+
+ public boolean updateDynamicPosition() {
+ boolean changed = false;
+ if (dynamicPosition != null) {
+ AffineTransform tr = dynamicPosition.getTransform();
+ if (tr != null) {
+ double nx = tr.getTranslateX();
+ changed |= x != nx;
+ x = nx;
+ double ny = tr.getTranslateY();
+ changed |= y != ny;
+ y = ny;
+ }
+ }
+ return changed;
+ }
+
+}