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%2Fsplitting%2FSplittedRouteGraph.java;h=8f7f71a299f08f5b08a51cf1adc29db72b623c03;hp=fe7dc25250edb5a4ac154cd2cb4a2e8ffa1b099c;hb=b643293df21959d6416d0ba42637419c33a1dbad;hpb=969bd23cab98a79ca9101af33334000879fb60c5 diff --git a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/splitting/SplittedRouteGraph.java b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/splitting/SplittedRouteGraph.java index fe7dc2525..8f7f71a29 100644 --- a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/splitting/SplittedRouteGraph.java +++ b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/splitting/SplittedRouteGraph.java @@ -1,122 +1,194 @@ -package org.simantics.diagram.connection.splitting; - -import gnu.trove.set.hash.THashSet; - -import java.awt.geom.Point2D; - -import org.simantics.diagram.connection.RouteGraph; -import org.simantics.diagram.connection.RouteLine; -import org.simantics.diagram.connection.RouteNode; -import org.simantics.diagram.connection.RouteTerminal; - -public class SplittedRouteGraph { - public final RouteLine splitLine; - public final THashSet interfaceNodes1; - public final THashSet lines1; // does not contain splitLine - public final THashSet terminals1; - public final THashSet interfaceNodes2; - public final THashSet lines2; // does not contain splitLine - public final THashSet terminals2; - - public SplittedRouteGraph(RouteLine splitLine, - THashSet interfaceNodes1, THashSet lines1, - THashSet terminals1, - THashSet interfaceNodes2, THashSet lines2, - THashSet terminals2) { - super(); - this.splitLine = splitLine; - this.interfaceNodes1 = interfaceNodes1; - this.lines1 = lines1; - this.terminals1 = terminals1; - this.interfaceNodes2 = interfaceNodes2; - this.lines2 = lines2; - this.terminals2 = terminals2; - } - - @Override - public String toString() { - StringBuilder b = new StringBuilder(); - - b.append("splitLine = " + splitLine.getData() + "\n"); - - b.append("interfaceNodes1 ="); - for(RouteNode node : interfaceNodes1) - b.append(" " + node.getData() + "(" + node.getClass().getSimpleName() + ")"); - b.append("\n"); - - b.append("lines1 ="); - for(RouteLine node : lines1) - b.append(" " + node.getData()); - b.append("\n"); - - b.append("terminals1 ="); - for(RouteTerminal node : terminals1) - b.append(" " + node.getData()); - b.append("\n"); - - b.append("interfaceNodes2 ="); - for(RouteNode node : interfaceNodes2) - b.append(" " + node.getData() + "(" + node.getClass().getSimpleName() + ")"); - b.append("\n"); - - b.append("lines2 ="); - for(RouteLine node : lines2) - b.append(" " + node.getData()); - b.append("\n"); - - b.append("terminals2 ="); - for(RouteTerminal node : terminals2) - b.append(" " + node.getData()); - b.append("\n"); - - return b.toString(); - } - - public static RouteLine findNearestLine(RouteGraph rg, Point2D splitCanvasPos) { - double hi = 1000, lo = 1; - RouteLine nearestLine = null; - final double LIMIT = 0.5; - while (true) { - double tolerance = (hi + lo) * 0.5; - RouteLine line = rg.pickLine(splitCanvasPos.getX(), splitCanvasPos.getY(), tolerance); - double delta = (hi - lo) * 0.5; - if (delta < LIMIT) - return nearestLine; - if (line == null) { - lo = tolerance; - } else { - nearestLine = line; - hi = tolerance; - } - } - } - - /** - * @param point - * @param line - * @return the specified point instance snapped to the specified line - */ - public static Point2D snapToLine(Point2D point, RouteLine line) { -// line.print(System.out); -// for (RoutePoint rp : line.getPoints()) -// System.out.println("RP: " + rp.getX() + ", " + rp.getY()); - // Get exact intersection point on the line - if (line.isHorizontal()) { - point.setLocation( point.getX(), line.getPosition() ); - } else { - point.setLocation( line.getPosition(), point.getY() ); - } - return point; - } - - /** - * @param point - * @param line - * @return new {@link Point2D} instance with specified point snapped to specified line - */ - public static Point2D snappedToLine(Point2D point, RouteLine line) { - Point2D result = (Point2D) point.clone(); - return snapToLine(result, line); - } - -} +package org.simantics.diagram.connection.splitting; + +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; +import java.util.ArrayList; + +import org.simantics.diagram.connection.RouteGraph; +import org.simantics.diagram.connection.RouteLine; +import org.simantics.diagram.connection.RouteNode; +import org.simantics.diagram.connection.RoutePoint; +import org.simantics.diagram.connection.RouteTerminal; +import org.simantics.diagram.connection.segments.Segment; + +import gnu.trove.set.hash.THashSet; + +public class SplittedRouteGraph { + public final RouteLine splitLine; + public final THashSet interfaceNodes1; + public final THashSet lines1; // does not contain splitLine + public final THashSet terminals1; + public final THashSet interfaceNodes2; + public final THashSet lines2; // does not contain splitLine + public final THashSet terminals2; + + public SplittedRouteGraph(RouteLine splitLine, + THashSet interfaceNodes1, THashSet lines1, + THashSet terminals1, + THashSet interfaceNodes2, THashSet lines2, + THashSet terminals2) { + super(); + this.splitLine = splitLine; + this.interfaceNodes1 = interfaceNodes1; + this.lines1 = lines1; + this.terminals1 = terminals1; + this.interfaceNodes2 = interfaceNodes2; + this.lines2 = lines2; + this.terminals2 = terminals2; + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + + b.append("splitLine = " + splitLine.getData() + "\n"); + + b.append("interfaceNodes1 ="); + for(RouteNode node : interfaceNodes1) + b.append(" " + node.getData() + "(" + node.getClass().getSimpleName() + ")"); + b.append("\n"); + + b.append("lines1 ="); + for(RouteLine node : lines1) + b.append(" " + node.getData()); + b.append("\n"); + + b.append("terminals1 ="); + for(RouteTerminal node : terminals1) + b.append(" " + node.getData()); + b.append("\n"); + + b.append("interfaceNodes2 ="); + for(RouteNode node : interfaceNodes2) + b.append(" " + node.getData() + "(" + node.getClass().getSimpleName() + ")"); + b.append("\n"); + + b.append("lines2 ="); + for(RouteLine node : lines2) + b.append(" " + node.getData()); + b.append("\n"); + + b.append("terminals2 ="); + for(RouteTerminal node : terminals2) + b.append(" " + node.getData()); + b.append("\n"); + + return b.toString(); + } + + public static RouteLine findNearestLine(RouteGraph rg, Point2D splitCanvasPos) { + double hi = 1000, lo = 1; + RouteLine nearestLine = null; + final double LIMIT = 0.5; + while (true) { + double tolerance = (hi + lo) * 0.5; + RouteLine line = rg.pickLine(splitCanvasPos.getX(), splitCanvasPos.getY(), tolerance); + double delta = (hi - lo) * 0.5; + if (delta < LIMIT) + return nearestLine; + if (line == null) { + lo = tolerance; + } else { + nearestLine = line; + hi = tolerance; + } + } + } + + public static final class PickResult { + /** + * The connection route line nearest to {@link #pickPoint}. + */ + public final RouteLine nearestLine; + /** + * Original pick point in canvas coordinates. + */ + public final Point2D pickPoint; + /** + * Intersection point in canvas coordinates of {@link #nearestLine} and + * perpendicular line from {@link #pickPoint} to {@link #nearestLine}. + */ + public final Point2D intersectionPoint; + + public PickResult(RouteLine nearestLine, Point2D pickPoint, Point2D intersectionPoint) { + this.nearestLine = nearestLine; + this.pickPoint = pickPoint; + this.intersectionPoint = intersectionPoint; + } + } + + public static PickResult pickNearestLine(RouteGraph rg, double x, double y) { + Segment nearestSegment = null; + RouteLine nearestLine = null; + + ArrayList segments = new ArrayList<>(); + double minDistanceSq = Double.MAX_VALUE; + for (RouteLine line : rg.getAllLines()) { + segments.clear(); + line.collectSegments(segments); + for (Segment segment : segments) { + RoutePoint p1 = segment.p1; + RoutePoint p2 = segment.p2; + double distanceSq = Line2D.ptSegDistSq(p1.getX(), p1.getY(), p2.getX(), p2.getY(), x, y); + if (distanceSq < minDistanceSq) { + minDistanceSq = distanceSq; + nearestSegment = segment; + nearestLine = line; + } + } + } + + if (nearestSegment == null) + return null; + + RoutePoint p1 = nearestSegment.p1; + RoutePoint p2 = nearestSegment.p2; + Point2D p = pointToLineIntersection(p1.getX(), p1.getY(), p2.getX(), p2.getY(), x, y); + return new PickResult(nearestLine, new Point2D.Double(x, y), p); + } + + private static Point2D pointToLineIntersection(double x1, double y1, double x2, double y2, double px, double py) { + double d = Math.pow(x2 - x1, 2.0) + Math.pow(y2 - y1, 2.0); + if (d == 0) { + return new Point2D.Double(x1, y1); + } else { + double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / d; + if (u > 1.0) { + return new Point2D.Double(x2, y2); + } else if (u <= 0.0) { + return new Point2D.Double(x1, y1); + } else { + return new Point2D.Double(x2 * u + x1 * (1.0-u), (y2 * u + y1 * (1.0- u))); + } + } + } + + /** + * @param point + * @param line + * @return the specified point instance snapped to the specified line + */ + public static Point2D snapToLine(Point2D point, RouteLine line) { +// line.print(System.out); +// for (RoutePoint rp : line.getPoints()) +// System.out.println("RP: " + rp.getX() + ", " + rp.getY()); + // Get exact intersection point on the line + if (line.isHorizontal()) { + point.setLocation( point.getX(), line.getPosition() ); + } else { + point.setLocation( line.getPosition(), point.getY() ); + } + return point; + } + + /** + * @param point + * @param line + * @return new {@link Point2D} instance with specified point snapped to specified line + */ + public static Point2D snappedToLine(Point2D point, RouteLine line) { + Point2D result = (Point2D) point.clone(); + return snapToLine(result, line); + } + +}