From: Marko Luukkainen Date: Thu, 15 Dec 2022 11:36:08 +0000 (+0200) Subject: Improved line gaps X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F28%2F4928%2F1;p=simantics%2Fplatform.git Improved line gaps gitlab #888 Change-Id: I72fe0768500bc9830109e9a8e0501a967beff003 --- 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 index 3ccb492b6..2367805ca 100644 --- 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 @@ -29,10 +29,14 @@ public class ConnectionCrossings implements PathModifier { private List segments = new ArrayList<>(); private double width; + private double widthd2; private Type type; + private boolean keepLines = false; + public void setWidth(double gapWidth) { this.width = gapWidth; + this.widthd2 = width * 0.5; } public double getWidth() { @@ -46,6 +50,18 @@ public class ConnectionCrossings implements PathModifier { public Type getType() { return type; } + + /** + * When keep lines is enabled, we keep short lines in the start and end of a line segment, instead of removing them completely with gaps. + * @return + */ + public boolean isKeepLines() { + return keepLines; + } + + public void setKeepLines(boolean keepLines) { + this.keepLines = keepLines; + } static class Segment { public double x1, y1, x2, y2; @@ -80,83 +96,177 @@ public class ConnectionCrossings implements PathModifier { public Path2D modify(Path2D path) { Path2D.Double path2 = new Path2D.Double(); PathIterator iter = path.getPathIterator(null); + if (!isKeepLines()) { + 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]); - 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); + 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 (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); + double len1 = 1.0 / len; + + boolean finish = true; + Point2D prevGapEnd = null; + for (Double gapCenter : gaps) { + double pos2 = gapCenter - widthd2 * len1; + double pos3 = gapCenter + widthd2 * len1; + 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 (pos3 < 1.0) { - double x = l.x1 + pos3 * dx; - double y = l.y1 + pos3 * dy; - prevGapEnd = new Point2D.Double(x, y); + + if (finish) { + handleGap(path2, prevGapEnd); + path2.lineTo(l.x2, l.y2); } else { - finish = false; + prevGapEnd = new Point2D.Double(l.x2, l.y2); + handleGap(path2, prevGapEnd); } - pos = pos3; } - - if (finish) { - handleGap(path2, prevGapEnd); - path2.lineTo(l.x2, l.y2); + 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(); + } + } else { + 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 { - prevGapEnd = new Point2D.Double(l.x2, l.y2); - handleGap(path2, prevGapEnd); + 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); + double len1 = 1.0 / len; + + boolean finish = true; + Point2D prevGapEnd = null; + for (int j = 0; j < gaps.size(); j++) { + Double gapCenter = gaps.get(j); + double gc = gapCenter * len; + double pos2 = gc - widthd2; + double pos3 = gc + widthd2; + if (j == 0) { + if (pos2 < widthd2) + pos2 += (widthd2 - pos2) * 0.5; + } + if (j == gaps.size() - 1) { + double d = len - pos3; + if (d < widthd2) + pos3 -= (widthd2 - d) * 0.5; + } + if (pos2 > pos) { + handleGap(path2, prevGapEnd); + prevGapEnd = null; + pos2 *= len1; + path2.lineTo(l.x1 + pos2 * dx, l.y1 + pos2 * dy); + } + if (pos3 < len) { + pos3 *= len1; + 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); + 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); + 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(); } - iter.next(); } return path2; } diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionCrossingsParticipant.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionCrossingsParticipant.java index 5e97febda..4dd514475 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionCrossingsParticipant.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/ConnectionCrossingsParticipant.java @@ -44,6 +44,12 @@ public class ConnectionCrossingsParticipant extends AbstractDiagramParticipant { crossings.setWidth(width); crossings.setType(type); } + + public ConnectionCrossingsParticipant(double width, ConnectionCrossings.Type type, boolean keepLines) { + crossings.setWidth(width); + crossings.setType(type); + crossings.setKeepLines(keepLines); + } @SGInit(designation = SGDesignation.CONTROL) public void initSG(G2DParentNode parent) {