1 package org.simantics.diagram.connection.splitting;
3 import java.awt.geom.Line2D;
4 import java.awt.geom.Point2D;
5 import java.util.ArrayList;
7 import org.simantics.diagram.connection.RouteGraph;
8 import org.simantics.diagram.connection.RouteLine;
9 import org.simantics.diagram.connection.RouteNode;
10 import org.simantics.diagram.connection.RoutePoint;
11 import org.simantics.diagram.connection.RouteTerminal;
12 import org.simantics.diagram.connection.segments.Segment;
14 import gnu.trove.set.hash.THashSet;
16 public class SplittedRouteGraph {
17 public final RouteLine splitLine;
18 public final THashSet<RouteNode> interfaceNodes1;
19 public final THashSet<RouteLine> lines1; // does not contain splitLine
20 public final THashSet<RouteTerminal> terminals1;
21 public final THashSet<RouteNode> interfaceNodes2;
22 public final THashSet<RouteLine> lines2; // does not contain splitLine
23 public final THashSet<RouteTerminal> terminals2;
25 public SplittedRouteGraph(RouteLine splitLine,
26 THashSet<RouteNode> interfaceNodes1, THashSet<RouteLine> lines1,
27 THashSet<RouteTerminal> terminals1,
28 THashSet<RouteNode> interfaceNodes2, THashSet<RouteLine> lines2,
29 THashSet<RouteTerminal> terminals2) {
31 this.splitLine = splitLine;
32 this.interfaceNodes1 = interfaceNodes1;
34 this.terminals1 = terminals1;
35 this.interfaceNodes2 = interfaceNodes2;
37 this.terminals2 = terminals2;
41 public String toString() {
42 StringBuilder b = new StringBuilder();
44 b.append("splitLine = " + splitLine.getData() + "\n");
46 b.append("interfaceNodes1 =");
47 for(RouteNode node : interfaceNodes1)
48 b.append(" " + node.getData() + "(" + node.getClass().getSimpleName() + ")");
52 for(RouteLine node : lines1)
53 b.append(" " + node.getData());
56 b.append("terminals1 =");
57 for(RouteTerminal node : terminals1)
58 b.append(" " + node.getData());
61 b.append("interfaceNodes2 =");
62 for(RouteNode node : interfaceNodes2)
63 b.append(" " + node.getData() + "(" + node.getClass().getSimpleName() + ")");
67 for(RouteLine node : lines2)
68 b.append(" " + node.getData());
71 b.append("terminals2 =");
72 for(RouteTerminal node : terminals2)
73 b.append(" " + node.getData());
79 public static RouteLine findNearestLine(RouteGraph rg, Point2D splitCanvasPos) {
80 double hi = 1000, lo = 1;
81 RouteLine nearestLine = null;
82 final double LIMIT = 0.5;
84 double tolerance = (hi + lo) * 0.5;
85 RouteLine line = rg.pickLine(splitCanvasPos.getX(), splitCanvasPos.getY(), tolerance);
86 double delta = (hi - lo) * 0.5;
98 public static final class PickResult {
100 * The connection route line nearest to {@link #pickPoint}.
102 public final RouteLine nearestLine;
104 * Original pick point in canvas coordinates.
106 public final Point2D pickPoint;
108 * Intersection point in canvas coordinates of {@link #nearestLine} and
109 * perpendicular line from {@link #pickPoint} to {@link #nearestLine}.
111 public final Point2D intersectionPoint;
113 public PickResult(RouteLine nearestLine, Point2D pickPoint, Point2D intersectionPoint) {
114 this.nearestLine = nearestLine;
115 this.pickPoint = pickPoint;
116 this.intersectionPoint = intersectionPoint;
120 public static PickResult pickNearestLine(RouteGraph rg, double x, double y) {
121 Segment nearestSegment = null;
122 RouteLine nearestLine = null;
124 ArrayList<Segment> segments = new ArrayList<>();
125 double minDistanceSq = Double.MAX_VALUE;
126 for (RouteLine line : rg.getAllLines()) {
128 line.collectSegments(segments);
129 for (Segment segment : segments) {
130 RoutePoint p1 = segment.p1;
131 RoutePoint p2 = segment.p2;
132 double distanceSq = Line2D.ptSegDistSq(p1.getX(), p1.getY(), p2.getX(), p2.getY(), x, y);
133 if (distanceSq < minDistanceSq) {
134 minDistanceSq = distanceSq;
135 nearestSegment = segment;
141 if (nearestSegment == null)
144 RoutePoint p1 = nearestSegment.p1;
145 RoutePoint p2 = nearestSegment.p2;
146 Point2D p = pointToLineIntersection(p1.getX(), p1.getY(), p2.getX(), p2.getY(), x, y);
147 return new PickResult(nearestLine, new Point2D.Double(x, y), p);
150 private static Point2D pointToLineIntersection(double x1, double y1, double x2, double y2, double px, double py) {
151 double d = Math.pow(x2 - x1, 2.0) + Math.pow(y2 - y1, 2.0);
153 return new Point2D.Double(x1, y1);
155 double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / d;
157 return new Point2D.Double(x2, y2);
158 } else if (u <= 0.0) {
159 return new Point2D.Double(x1, y1);
161 return new Point2D.Double(x2 * u + x1 * (1.0-u), (y2 * u + y1 * (1.0- u)));
169 * @return the specified point instance snapped to the specified line
171 public static Point2D snapToLine(Point2D point, RouteLine line) {
172 // line.print(System.out);
173 // for (RoutePoint rp : line.getPoints())
174 // System.out.println("RP: " + rp.getX() + ", " + rp.getY());
175 // Get exact intersection point on the line
176 if (line.isHorizontal()) {
177 point.setLocation( point.getX(), line.getPosition() );
179 point.setLocation( line.getPosition(), point.getY() );
187 * @return new {@link Point2D} instance with specified point snapped to specified line
189 public static Point2D snappedToLine(Point2D point, RouteLine line) {
190 Point2D result = (Point2D) point.clone();
191 return snapToLine(result, line);