import java.awt.Composite;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import org.simantics.Simantics;
import org.simantics.db.common.request.WriteRequest;
import org.simantics.db.exception.DatabaseException;
import org.simantics.diagram.connection.RouteGraph;
-import org.simantics.diagram.connection.RouteGraphConnectionClass;
import org.simantics.diagram.connection.RouteLine;
import org.simantics.diagram.connection.RoutePoint;
import org.simantics.diagram.connection.RouteTerminal;
import org.simantics.diagram.connection.rendering.arrows.ArrowLineEndStyle;
import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;
import org.simantics.diagram.connection.rendering.arrows.PlainLineEndStyle;
+import org.simantics.diagram.connection.segments.Segment;
import org.simantics.diagram.synchronization.ISynchronizationContext;
import org.simantics.diagram.synchronization.SynchronizationHints;
import org.simantics.diagram.synchronization.graph.RouteGraphConnection;
import org.simantics.g2d.element.impl.Element;
import org.simantics.g2d.elementclass.FlagClass;
import org.simantics.g2d.elementclass.FlagHandler;
+import org.simantics.g2d.elementclass.RouteGraphConnectionClass;
import org.simantics.g2d.participant.TransformUtil;
import org.simantics.g2d.utils.geom.DirectionSet;
import org.simantics.scenegraph.g2d.G2DParentNode;
endFlagNode.setTransform(AffineTransform.getTranslateInstance(mouseCanvasPos.getX(), mouseCanvasPos.getY()));
}
- TerminalInfo ti = pi.pickTerminal(me.controlPosition);
- if (ti != null) {
- Object canConnect = canConnect(ti.e, ti.t);
- if (canConnect != null) {
- connectionJudgment = (ConnectionJudgement) canConnect;
+ List<TerminalInfo> tis = pi.pickTerminals(me.controlPosition);
+ tis = TerminalUtil.findNearestOverlappingTerminals(tis);
+ if (!tis.isEmpty()) {
+ for (TerminalInfo ti : tis) {
+ Object canConnect = canConnect(ti.e, ti.t);
- if (!isEndingInFlag() || !TerminalUtil.isSameTerminal(ti, endTerminal)) {
- controlPoints.getLast()
- .setPosition(ti.posDia)
- .setAttachedToTerminal(ti);
+ if (canConnect != null) {
+ connectionJudgment = (ConnectionJudgement) canConnect;
- endTerminal = ti;
+ if (!isEndingInFlag() || !TerminalUtil.isSameTerminal(ti, endTerminal)) {
+ controlPoints.getLast().setPosition(ti.posDia).setAttachedToTerminal(ti);
- connect(ti);
-
- }
+ endTerminal = ti;
+
+ connect(ti);
+
+ }
- // Make sure that we are ending with a flag if ALT is pressed
- // and no end terminal is defined.
- endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));
+ // Make sure that we are ending with a flag if ALT is pressed
+ // and no end terminal is defined.
+ endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me));
- updateSG(new Point2D.Double(ti.posDia.getTranslateX(), ti.posDia.getTranslateY()));
- return false;
+ updateSG(new Point2D.Double(ti.posDia.getTranslateX(), ti.posDia.getTranslateY()));
+ return false;
+ }
}
}
}
private static RouteGraphTarget pickNearestRouteGraphConnection(ArrayList<IElement> elements, double x, double y, double pd) {
- // Find the nearest distance at which we get hits.
- double hi = pd + 1;
- double lo = hi * .01;
- double limit = 0.5;
- while (true) {
- double delta = (hi - lo);
- if (delta <= limit)
- break;
+ Segment nearestSegment = null;
+ RouteLine nearestLine = null;
+ IElement nearestConnection = null;
- pd = (lo + hi) * .5;
-
- boolean hit = false;
- for (IElement connection : elements) {
- RouteGraphNode rgn = connection.getHint(RouteGraphConnectionClass.KEY_RG_NODE);
- RouteLine line = rgn.getRouteGraph().pickLine(x, y, pd);
- if (line != null) {
- hit = true;
- break;
+ double minDistanceSq = Double.MAX_VALUE;
+
+ for (IElement connection : elements) {
+ RouteGraphNode rgn = connection.getHint(RouteGraphConnectionClass.KEY_RG_NODE);
+ for (RouteLine line : rgn.getRouteGraph().getAllLines()) {
+ ArrayList<Segment> segments = new ArrayList<Segment>();
+ 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 && distanceSq < Math.pow(pd + rgn.getSelectionStrokeWidth() / 2, 2)) {
+ minDistanceSq = distanceSq;
+ nearestSegment = segment;
+ nearestLine = line;
+ nearestConnection = connection;
+ }
}
}
-
- if (hit)
- hi = pd;
- else
- lo = pd;
}
- // Now that the nearest hitting distance is found, find the nearest intersection.
- RouteGraphTarget nearestTarget = null;
- double nearest = Double.MAX_VALUE;
- for (IElement connection : elements) {
- RouteGraphNode rgn = connection.getHint(RouteGraphConnectionClass.KEY_RG_NODE);
- RouteLine line = rgn.getRouteGraph().pickLine(x, y, pd);
- if (line == null)
- continue;
-
- Point2D intersection = intersectionPoint(x, y, line);
- if (intersection == null)
- continue;
-
- double dx = intersection.getX() - x;
- double dy = intersection.getY() - y;
- double dist = Math.sqrt(dx*dx + dy*dy);
- if (dist < nearest) {
- nearest = dist;
- nearestTarget = new RouteGraphTarget(connection, rgn, line, new Point2D.Double(x, y), intersection);
+ if (nearestSegment != null) {
+ RoutePoint p1 = nearestSegment.p1;
+ RoutePoint p2 = nearestSegment.p2;
+ double d = Math.pow(p2.getX() - p1.getX(), 2.0) + Math.pow(p2.getY() - p1.getY(), 2.0);
+ Point2D p;
+ if (d == 0) {
+ p = new Point2D.Double(p1.getX(), p1.getY());
+ } else {
+ double u = ((x - p1.getX()) * (p2.getX() - p1.getX()) + (y - p1.getY()) * (p2.getY() - p1.getY())) / d;
+ if (u > 1.0) {
+ p = new Point2D.Double(p2.getX(), p2.getY());
+ } else if (u <= 0.0) {
+ p = new Point2D.Double(p1.getX(), p1.getY());
+ } else {
+ p = new Point2D.Double(p2.getX() * u + p1.getX() * (1.0-u), (p2.getY() * u + p1.getY() * (1.0- u)));
+ }
}
+ return new RouteGraphTarget(nearestConnection, nearestConnection.getHint(RouteGraphConnectionClass.KEY_RG_NODE), nearestLine, new Point2D.Double(x, y), p);
+ } else {
+ return null;
}
-
- return nearestTarget;
}
static Point2D intersectionPoint(double x, double y, RouteLine line) {