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%2FConnectionCrossings.java;fp=bundles%2Forg.simantics.diagram.connection%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fconnection%2Frendering%2FConnectionCrossings.java;h=3ccb492b6ae56bcfa4e7b28b3820b85dd3c05fb9;hp=0000000000000000000000000000000000000000;hb=8ded56d0a440f78cbf649b1e59b8a464e8650fdc;hpb=035118aa5f35c9e5acd1f34d22065055dfdee486 diff --git a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/ConnectionCrossings.java b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/ConnectionCrossings.java new file mode 100644 index 000000000..3ccb492b6 --- /dev/null +++ b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/ConnectionCrossings.java @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright (c) 2020 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: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.diagram.connection.rendering; + +import java.awt.geom.Arc2D; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ConnectionCrossings implements PathModifier { + public enum Type { + NONE, + GAP, + ARC, + SQUARE + } + + private List segments = new ArrayList<>(); + private double width; + private Type type; + + public void setWidth(double gapWidth) { + this.width = gapWidth; + } + + public double getWidth() { + return width; + } + + public void setType(Type type) { + this.type = type; + } + + public Type getType() { + return type; + } + + static class Segment { + public double x1, y1, x2, y2; + + public Segment(double x1, double y1, double x2, double y2) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + }; + + public void reset() { + segments.clear(); + } + + static Double lineLineIntersection(Segment l1, Segment l2) { + double epsilon = 0.001; + + double d = (l1.x1 - l1.x2) * (l2.y1 - l2.y2) - (l1.y1 - l1.y2) * (l2.x1 - l2.x2); + if (d == 0.0) return null; + double s = ((l1.x1 - l2.x1) * (l2.y1 - l2.y2) - (l1.y1 - l2.y1) * (l2.x1 - l2.x2)) / d; + if ((s > epsilon) && (s < 1 - epsilon)) { + double t = -((l1.x1 - l1.x2) * (l1.y1 - l2.y1) - (l1.y1 - l1.y2) * (l1.x1 - l2.x1)) / d; + if ((t > epsilon) && (t < 1 - epsilon)) { + return t; + } + } + return null; + } + + public Path2D modify(Path2D path) { + Path2D.Double path2 = new Path2D.Double(); + PathIterator iter = path.getPathIterator(null); + + while (!iter.isDone()) { + + double c[] = new double[6]; + int i = iter.currentSegment(c); + switch (i) { + case PathIterator.SEG_MOVETO: + path2.moveTo(c[0], c[1]); + break; + case PathIterator.SEG_LINETO: + Segment l = new Segment(path2.getCurrentPoint().getX(), path2.getCurrentPoint().getY(), c[0], c[1]); + + List gaps = new ArrayList<>(); + for (Segment old : segments) { + Double t = lineLineIntersection(old, l); + if (t != null) { + gaps.add(t); + } + } + + if (gaps.isEmpty()) { + path2.lineTo(c[0], c[1]); + } else { + Collections.sort(gaps); + double dx = l.x2 - l.x1; + double dy = l.y2 - l.y1; + + double pos = 0.0; + double len = Math.sqrt(dx*dx + dy*dy); + + boolean finish = true; + Point2D prevGapEnd = null; + for (Double gapCenter : gaps) { + double pos2 = gapCenter - width / 2 / len; + double pos3 = gapCenter + width / 2 / len; + if (pos2 > pos) { + handleGap(path2, prevGapEnd); + prevGapEnd = null; + path2.lineTo(l.x1 + pos2 * dx, l.y1 + pos2 * dy); + } + if (pos3 < 1.0) { + double x = l.x1 + pos3 * dx; + double y = l.y1 + pos3 * dy; + prevGapEnd = new Point2D.Double(x, y); + } else { + finish = false; + } + pos = pos3; + } + + if (finish) { + handleGap(path2, prevGapEnd); + path2.lineTo(l.x2, l.y2); + } else { + prevGapEnd = new Point2D.Double(l.x2, l.y2); + handleGap(path2, prevGapEnd); + } + } + segments.add(l); + + break; + case PathIterator.SEG_QUADTO: + // TODO: implement gaps + path2.quadTo(c[0], c[1], c[2], c[3]); + break; + case PathIterator.SEG_CUBICTO: + // TODO: implement gaps + path2.curveTo(c[0], c[1], c[2], c[3], c[4], c[5]); + break; + case PathIterator.SEG_CLOSE: + // TODO: implement gaps + path2.closePath(); + break; + default: + throw new RuntimeException("Unexpected segment type " + i); + } + iter.next(); + } + return path2; + } + + private void handleGap(Path2D path, Point2D prevGapEnd) { + if (prevGapEnd != null) { + switch (type) { + case ARC: + arcTo(path, prevGapEnd.getX(), prevGapEnd.getY()); + break; + case SQUARE: + squareTo(path, prevGapEnd.getX(), prevGapEnd.getY(), width); + break; + case GAP: + path.moveTo(prevGapEnd.getX(), prevGapEnd.getY()); + break; + case NONE: + break; + } + } + } + + private static void arcTo(Path2D path, double x2, double y2) { + Arc2D arc = new Arc2D.Double(); + double x1 = path.getCurrentPoint().getX(); + double y1 = path.getCurrentPoint().getY(); + double dx = x2 - x1; + double dy = y2 - y1; + double r = Math.sqrt(dx * dx + dy * dy) / 2; + double angle = Math.atan2(dx, dy) * 180 / Math.PI + 90; + double span = (angle > 225 || angle < 45) ? 180 : -180; + arc.setArcByCenter((x1 + x2) / 2, (y1 + y2) / 2, r, angle, span, Arc2D.OPEN); + path.append(arc, true); + } + + private static void squareTo(Path2D path, double x2, double y2, double width) { + double x1 = path.getCurrentPoint().getX(); + double y1 = path.getCurrentPoint().getY(); + double dx = x2 - x1; + double dy = y2 - y1; + double l = Math.sqrt(dx * dx + dy* dy); + if (l > 0) { + double nx = -dy / l; + double ny = dx / l; + if (nx - ny < 0) { + nx = -nx; + ny = -ny; + } + path.lineTo(x1 + nx * width / 2, y1 + ny * width / 2); + path.lineTo(x2 + nx * width / 2, y2 + ny * width / 2); + path.lineTo(x2, y2); + } + } + +}