package org.simantics.diagram.connection.splitting;
-import gnu.trove.set.hash.THashSet;
-
+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 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<Segment> 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