X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Fdiagram%2Fhandler%2FPickRequest.java;h=8d9d814d8eeb3c5599a08a4113e380752a1863b6;hp=a43e8350a15b2aeff8c2f155558d4cd93b5aa72b;hb=9f479d68d86a8b5116be5a884c220f816e3cbb18;hpb=0ae2b770234dfc3cbb18bd38f324125cf0faca07 diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/handler/PickRequest.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/handler/PickRequest.java index a43e8350a..8d9d814d8 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/handler/PickRequest.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/handler/PickRequest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * Copyright (c) 2007, 2020 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,18 +8,25 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - gitlab #454 *******************************************************************************/ package org.simantics.g2d.diagram.handler; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Area; +import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import org.simantics.diagram.connection.RouteLine; +import org.simantics.diagram.connection.RoutePoint; +import org.simantics.diagram.connection.segments.Segment; +import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.connection.handler.ConnectionHandler; import org.simantics.g2d.element.IElement; import org.simantics.g2d.element.handler.BendsHandler; @@ -27,8 +34,11 @@ import org.simantics.g2d.element.handler.TerminalTopology; import org.simantics.g2d.element.handler.impl.ConnectionSelectionOutline; import org.simantics.g2d.elementclass.BranchPoint; import org.simantics.g2d.elementclass.MonitorHandler; +import org.simantics.g2d.elementclass.RouteGraphConnectionClass; import org.simantics.g2d.utils.GeometryUtils; +import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphNode; import org.simantics.scenegraph.utils.TransformedRectangle; +import org.simantics.utils.datastructures.Pair; /** * @@ -50,6 +60,12 @@ public class PickRequest { public PickFilter pickFilter = null; public PickSorter pickSorter = null; + /** + * Used to optimize picking if provided via R-tree traversal to find + * intersecting elements, not everything. + */ + public ICanvasContext pickContext; + public PickRequest(double x, double y) { pickArea = new Rectangle2D.Double(x, y, 1, 1); @@ -67,6 +83,11 @@ public class PickRequest { pickArea = GeometryUtils.transformShape(shape, transform); } + public PickRequest context(ICanvasContext ctx) { + this.pickContext = ctx; + return this; + } + public static interface PickFilter { boolean accept(IElement e); @@ -123,8 +144,33 @@ public class PickRequest { } public static interface PickSorter { + /** + * Sorts the specified element list. + * + * @param elements the element list to sort + */ void sort(List elements); + /** + * Extended interface-method that receives the pick request in addition to the + * picked elements to be sorted. Allows e.g. looking at the pick area in the + * sorter. + * + *

+ * The default implementation just invokes {@link #sort(List)} ignoring the pick + * request. The default implementation also keeps PickSorter API/ABI-compatible. + * + * @param request the original pick request that produced the hits listed in + * elements + * @param elements the element list to sort + * + * @author Tuukka Lehtonen + * @since 1.43.0, 1.35.3 + */ + default void sort(PickRequest request, List elements) { + sort(elements); + } + // public static final PickSorter CONNECTIONS_LAST = new PickSorter() { @Override @@ -160,6 +206,74 @@ public class PickRequest { }); } }; + + /* + * First use the default sorting if available, then sort successive connections by their distance to cursor. + */ + public static PickSorter connectionSorter(PickSorter sorter, double x, double y) { + return new PickSorter() { + + private double getDistanceSqToRouteGraphConnection(RouteGraphNode rgn, double x, double y) { + double minDistanceSq = Double.MAX_VALUE; + for (RouteLine line : rgn.getRouteGraph().getAllLines()) { + ArrayList segments = new ArrayList(); + 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; + } + } + } + return minDistanceSq; + } + + private void sortConnections(List elements) { + List> connections = new ArrayList<>(elements.size()); + int tail = 0; + for (int i = 0; i < elements.size(); i++) { + IElement element = elements.get(i); + RouteGraphNode rgn = element.getHint(RouteGraphConnectionClass.KEY_RG_NODE); + if (rgn != null) { + double distanceSq = getDistanceSqToRouteGraphConnection(rgn, x, y); + connections.add(Pair.make(distanceSq, element)); + } + + if (rgn == null || i == elements.size() - 1) { + Collections.sort(connections, new Comparator>() { + @Override + public int compare(Pair connection1, Pair connection2) { + return Double.compare(connection2.first, connection1.first); + } + }); + for (Pair connection : connections) { + elements.set(tail, connection.second); + tail++; + } + connections.clear(); + tail = i + 1; + } + } + } + + @Override + public void sort(PickRequest request, List elements) { + if (sorter != null) + sorter.sort(request, elements); + sortConnections(elements); + } + + @Override + public void sort(List elements) { + if (sorter != null) + sorter.sort(elements); + sortConnections(elements); + } + }; + } } }