X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.diagram.connection%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fconnection%2FRouteTerminal.java;fp=bundles%2Forg.simantics.diagram.connection%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fconnection%2FRouteTerminal.java;h=2f3fc9f86ec7ce7668c0dc12e87f741a4ae4c74e;hp=31064adf1f1275abe8f3082986bea3bfee1a923e;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hpb=24e2b34260f219f0d1644ca7a138894980e25b14 diff --git a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteTerminal.java b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteTerminal.java index 31064adf1..2f3fc9f86 100644 --- a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteTerminal.java +++ b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteTerminal.java @@ -1,452 +1,452 @@ -/******************************************************************************* - * 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.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; - - RouteLine line; - - RouteTerminal(double x, double y, double minX, double minY, - double maxX, double maxY, int allowedDirections, - boolean routeToBounds, - ILineEndStyle style) { - super(x, y); - this.minX = minX; - this.minY = minY; - this.maxX = maxX; - this.maxY = maxY; - this.allowedDirections = allowedDirections; - this.routeToBounds = routeToBounds; - this.style = style; - } - - @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 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 map) { - RouteTerminal copy = (RouteTerminal)map.get(this); - if(copy == null) { - copy = new RouteTerminal(x, y, minX, minY, maxX, maxY, - allowedDirections, routeToBounds, style); - 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; - } -} +/******************************************************************************* + * 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.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; + + RouteLine line; + + RouteTerminal(double x, double y, double minX, double minY, + double maxX, double maxY, int allowedDirections, + boolean routeToBounds, + ILineEndStyle style) { + super(x, y); + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + this.allowedDirections = allowedDirections; + this.routeToBounds = routeToBounds; + this.style = style; + } + + @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 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 map) { + RouteTerminal copy = (RouteTerminal)map.get(this); + if(copy == null) { + copy = new RouteTerminal(x, y, minX, minY, maxX, maxY, + allowedDirections, routeToBounds, style); + 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; + } +}