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%2Frendering%2FBasicConnectionStyle.java;h=94de76bb447af1a435a8323ea7d24c4187ab7b4a;hp=b2895fb342d60fc1571b7f9b1fe4424c07144203;hb=e3f46ffc9d4a6930adc83ebb8e6730f19708cc94;hpb=32a6aa7b656804c95b8a2a2df06900955c6df44b diff --git a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/BasicConnectionStyle.java b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/BasicConnectionStyle.java index b2895fb34..94de76bb4 100644 --- a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/BasicConnectionStyle.java +++ b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/BasicConnectionStyle.java @@ -17,9 +17,11 @@ import java.awt.RenderingHints; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; +import java.awt.geom.FlatteningPathIterator; import java.awt.geom.Line2D; import java.awt.geom.Path2D; import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; import java.io.Serializable; /** @@ -37,12 +39,13 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable { final Stroke routeLineStroke; final double degenerateLineLength; final double rounding; + final double offset; transient Line2D line = new Line2D.Double(); transient Ellipse2D ellipse = new Ellipse2D.Double(); public BasicConnectionStyle(Color lineColor, Color branchPointColor, double branchPointRadius, Stroke lineStroke, Stroke routeLineStroke, double degenerateLineLength, - double rounding) { + double rounding, double offset) { this.lineColor = lineColor; this.branchPointColor = branchPointColor; this.branchPointRadius = branchPointRadius; @@ -50,10 +53,16 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable { this.routeLineStroke = routeLineStroke; this.degenerateLineLength = degenerateLineLength; this.rounding = rounding; + this.offset = offset; + } + + public BasicConnectionStyle(Color lineColor, Color branchPointColor, double branchPointRadius, Stroke lineStroke, Stroke routeLineStroke, double degenerateLineLength, + double rounding) { + this(lineColor, branchPointColor, branchPointRadius, lineStroke, routeLineStroke, degenerateLineLength, rounding, 0.0); } public BasicConnectionStyle(Color lineColor, Color branchPointColor, double branchPointRadius, Stroke lineStroke, Stroke routeLineStroke, double degenerateLineLength) { - this(lineColor, branchPointColor, branchPointRadius, lineStroke, routeLineStroke, degenerateLineLength, 0.0); + this(lineColor, branchPointColor, branchPointRadius, lineStroke, routeLineStroke, degenerateLineLength, 0.0, 0.0); } public Color getLineColor() { @@ -101,11 +110,101 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable { if(rounding > 0.0) { Object oldRenderingHint = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g.draw(round(path)); + path = round(path); + if (offset != 0) { + path = offsetPath(path, offset); + } + g.draw(path); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldRenderingHint); } - else + else { + if (offset != 0) { + path = offsetPath(path, offset); + } g.draw(path); + } + } + + private static Point2D getNormal(Point2D dir) { + return new Point2D.Double(-dir.getY(), dir.getX()); + } + + private static Point2D normalize(Point2D v) { + double d = Math.sqrt(v.getX() * v.getX() + v.getY() * v.getY()); + v.setLocation(v.getX() / d, v.getY() / d); + return v; + } + + private static Path2D offsetPath(Path2D path, double offset) { + Path2D result = new Path2D.Double(); + PathIterator iter = new FlatteningPathIterator(path.getPathIterator(null), 0.05, 10); + + double c[] = new double[6]; + double initialX = 0; + double initialY = 0; + boolean first = true; + Point2D prevDir = null; + Point2D prevPos = null; + + while (!iter.isDone()) { + int i = iter.currentSegment(c); + switch (i) { + case PathIterator.SEG_MOVETO: + if (first) { + initialX = c[0]; + initialY = c[1]; + first = false; + } + if (prevDir != null) { + Point2D N = normalize(getNormal(prevDir)); + result.lineTo(prevPos.getX() + N.getX() * offset , prevPos.getY() + N.getY() * offset); + } + prevPos = new Point2D.Double(c[0], c[1]); + prevDir = null; + break; + case PathIterator.SEG_LINETO: + case PathIterator.SEG_CLOSE: + if (i == PathIterator.SEG_CLOSE) { + c[0] = initialX; + c[1] = initialY; + } + Point2D currentDir = new Point2D.Double(c[0] - prevPos.getX(), c[1] - prevPos.getY()); + if (currentDir.getX() == 0.0 && currentDir.getY() == 0) break; + + if (prevDir == null) { + Point2D N = normalize(getNormal(currentDir)); + result.moveTo(prevPos.getX() + N.getX() * offset, prevPos.getY() + N.getY() * offset); + prevPos = new Point2D.Double(c[0], c[i]); + prevDir = currentDir; + } else { + Point2D N1 = normalize(getNormal(prevDir)); + Point2D N2 = normalize(getNormal(currentDir)); + Point2D N = normalize(new Point2D.Double(N1.getX() + N2.getX(), N1.getY() + N2.getY())); + double dot = N1.getX() * N.getX() + N1.getY() * N.getY(); + + if (!Double.isFinite(dot) || Math.abs(dot) < 0.1) { + result.lineTo(prevPos.getX() + (N1.getX() + N1.getY()) * offset, prevPos.getY() + (N1.getY() - N1.getX()) * offset); + result.lineTo(prevPos.getX() + (N2.getX() + N1.getY()) * offset, prevPos.getY() + (N2.getY() - N1.getX()) * offset); + prevPos = new Point2D.Double(c[0], c[i]); + prevDir = currentDir; + } else { + double Nx = N.getX() * offset / dot; + double Ny = N.getY() * offset / dot; + result.lineTo(prevPos.getX() + Nx, prevPos.getY() + Ny); + prevPos = new Point2D.Double(c[0], c[i]); + prevDir = currentDir; + } + } + + break; + } + iter.next(); + } + if (prevDir != null) { + Point2D N = normalize(getNormal(prevDir)); + result.lineTo(prevPos.getX() + N.getX() * offset , prevPos.getY() + N.getY() * offset); + } + return result; } private Path2D round(Path2D path) { @@ -126,16 +225,18 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable { double dy1 = curY-oldY; double dx2 = curX-newX; double dy2 = curY-newY; - double maxRadius = 0.5 * Math.min(Math.sqrt(dx1*dx1 + dy1*dy1), Math.sqrt(dx2*dx2 + dy2*dy2)); + double r1 = Math.sqrt(dx1*dx1 + dy1*dy1); + double r2 = Math.sqrt(dx2*dx2 + dy2*dy2); + double maxRadius = 0.5 * Math.min(r1, r2); double radius = Math.min(rounding, maxRadius); - newPath.lineTo(curX + radius*Math.signum(oldX-curX), curY + radius*Math.signum(oldY-curY)); + double dx1Normalized = r1 > 0 ? dx1 / r1 : 0; + double dy1Normalized = r1 > 0 ? dy1 / r1 : 0; + double dx2Normalized = r2 > 0 ? dx2 / r2 : 0; + double dy2Normalized = r2 > 0 ? dy2 / r2 : 0; + newPath.lineTo(curX - radius*dx1Normalized, curY - radius*dy1Normalized); newPath.curveTo(curX, curY, curX, curY, - curX + radius*Math.signum(newX-curX), curY + radius*Math.signum(newY-curY)); - - //newPath.lineTo(curX + round*Math.signum(oldX-curX), curY + round*Math.signum(oldY-curY)); - //newPath.lineTo(curX + round*Math.signum(newX-curX), curY + round*Math.signum(newY-curY)); - //newPath.lineTo(curX, curY); + curX - radius*dx2Normalized, curY - radius*dy2Normalized); } else ++state; @@ -216,6 +317,8 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable { result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + ((lineColor == null) ? 0 : lineColor.hashCode()); result = prime * result + ((lineStroke == null) ? 0 : lineStroke.hashCode()); + temp = Double.doubleToLongBits(rounding); + result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + ((routeLineStroke == null) ? 0 : routeLineStroke.hashCode()); return result; } @@ -248,6 +351,8 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable { return false; } else if (!lineStroke.equals(other.lineStroke)) return false; + if (Double.doubleToLongBits(rounding) != Double.doubleToLongBits(other.rounding)) + return false; if (routeLineStroke == null) { if (other.routeLineStroke != null) return false; @@ -260,4 +365,7 @@ public class BasicConnectionStyle implements ConnectionStyle, Serializable { return rounding; } + public double getOffset() { + return offset; + } }