From: Tuukka Lehtonen Date: Fri, 24 Jan 2020 12:52:53 +0000 (+0200) Subject: Improve picking to prefer vertices and with a more useful pick area X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fdistrict.git;a=commitdiff_plain;h=7b29ec0924722d1388606d54fc398afb5b32b8d4 Improve picking to prefer vertices and with a more useful pick area gitlab #74 Change-Id: I6577a35f99523bcf9264bd3a12d48bbfde96beb2 --- diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java index e5ce207e..4ff23103 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java @@ -6,7 +6,6 @@ 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.db.Resource; @@ -15,6 +14,7 @@ import org.simantics.district.network.ui.adapters.DistrictNetworkEdgeElement; import org.simantics.district.network.ui.adapters.DistrictNetworkVertexElement; import org.simantics.district.network.ui.nodes.DistrictNetworkVertexNode; import org.simantics.district.network.ui.nodes.NetworkDrawingNode; +import org.simantics.district.network.ui.participants.DNPickSorter; import org.simantics.district.network.ui.participants.DynamicVisualisationContributionsParticipant; import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit; @@ -43,7 +43,7 @@ public class NetworkDrawingParticipant extends AbstractDiagramParticipant { /** * Holds the current element for which hover information is shown. - * This is just to optimize the + * This exists only to optimize the hover updating procedure. */ private IElement currentHoverElement; @@ -68,31 +68,8 @@ public class NetworkDrawingParticipant extends AbstractDiagramParticipant { PickRequest req = new PickRequest(getPickRect(canvasPos, viewTransform)).context(getContext()); List pickables = new ArrayList<>(); pick.pick(diagram, req, pickables); - - - Comparator nearestVerticesFirst = (IElement e1, IElement e2) -> { - // If there are any vertices in the elements, prefer those primarily. - DistrictNetworkVertexNode v1 = e1.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE); - DistrictNetworkVertexNode v2 = e2.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE); - - // Don't reorder edges - if ((v1 == null && v2 == null)) - return 0; - - // Sort vertices in nearest first order - if (v1 != null && v2 != null) { - Rectangle2D b1 = v1.getBounds(); - Rectangle2D b2 = v2.getBounds(); - double dist1 = canvasPos.distanceSq(b1.getCenterX(), b1.getCenterY()); - double dist2 = canvasPos.distanceSq(b2.getCenterX(), b2.getCenterY()); - return dist1 < dist2 ? -1 : dist1 > dist2 ? 1 : 0; - } - - // Always vertices before edges - return v1 != null && v2 == null ? -1 : 1; - }; - Collections.sort(pickables, nearestVerticesFirst); + Collections.sort(pickables, DNPickSorter.nearestVerticesFirst(false, DNPickSorter.centerDistSq(canvasPos.getX(), canvasPos.getY()))); updateHoveredElement(pickables, true, isConnectionTool, viewTransform); // Will repaint once the async hover info calculation is ready, no need to do it here diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPickSorter.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPickSorter.java new file mode 100644 index 00000000..82cd725a --- /dev/null +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPickSorter.java @@ -0,0 +1,105 @@ +package org.simantics.district.network.ui.participants; + +import java.awt.geom.Rectangle2D; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.function.ToDoubleFunction; + +import org.simantics.district.network.ui.adapters.DistrictNetworkEdgeElement; +import org.simantics.district.network.ui.adapters.DistrictNetworkVertexElement; +import org.simantics.district.network.ui.nodes.DistrictNetworkVertexNode; +import org.simantics.g2d.diagram.handler.PickRequest; +import org.simantics.g2d.diagram.handler.PickRequest.PickSorter; +import org.simantics.g2d.element.ElementHints; +import org.simantics.g2d.element.IElement; +import org.simantics.scenegraph.g2d.IG2DNode; +import org.simantics.scenegraph.g2d.nodes.SingleElementNode; + +/** + * @author Jani Simomaa + * @author Tuukka Lehtonen + */ +public class DNPickSorter implements PickSorter { + + public static ToDoubleFunction centerDistSq(double x, double y) { + return r -> { + double dx = r.getCenterX() - x; + double dy = r.getCenterY() - y; + return dx * dx + dy * dy; + }; + } + + public static ToDoubleFunction centerDistSq(Rectangle2D r1) { + return centerDistSq(r1.getCenterX(), r1.getCenterY()); + } + + /** + * @param nearestLast if true the nearest elements are sorted + * into the tail of the list, if false + * nearest elements are at the beginning of the list + * @param distanceFunction function used for calculating the distance of each + * element's bounding box + * @return comparator implementing the requested diagram element comparison + */ + public static Comparator nearestVerticesFirst(boolean nearestLast, ToDoubleFunction distanceFunction) { + int sign = nearestLast ? 1 : -1; + return (IElement e1, IElement e2) -> { + // If there are any vertices in the elements, prefer those primarily. + DistrictNetworkVertexNode v1 = e1.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE); + DistrictNetworkVertexNode v2 = e2.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE); + + // Don't reorder edges + if ((v1 == null && v2 == null)) + return 0; + + // Sort vertices in nearest first order + if (v1 != null && v2 != null) { + double dist1 = distanceFunction.applyAsDouble(v1.getBounds()); + double dist2 = distanceFunction.applyAsDouble(v2.getBounds()); + return dist1 < dist2 ? sign : dist1 > dist2 ? -sign : 0; + } + + // Always vertices before edges + return v1 != null && v2 == null ? sign : -sign; + }; + } + + private static IG2DNode getNode(IElement element) { + IG2DNode node = element.getHint(DistrictNetworkEdgeElement.KEY_DN_EDGE_NODE); + if (node == null) + node = element.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE); + if (node == null) { + node = element.getHint(ElementHints.KEY_SG_NODE); + if (node instanceof SingleElementNode) { + SingleElementNode snode = (SingleElementNode) node; + node = snode.getNodes().iterator().next(); + } + } + return node; + } + + private static Comparator zSorter() { + return (e1, e2) -> { + IG2DNode e1node = getNode(e1); + IG2DNode e2node = getNode(e2); + if (e1node.getZIndex() < e2node.getZIndex()) + return -1; + else if (e1node.getZIndex() > e2node.getZIndex()) + return 1; + return 0; + }; + }; + + @Override + public void sort(List elements) { + Collections.sort(elements, zSorter()); + } + + @Override + public void sort(PickRequest req, List elements) { + Collections.sort(elements, zSorter()); + Collections.sort(elements, nearestVerticesFirst( true, centerDistSq( req.pickArea.getBounds2D() ) )); + } + +} \ No newline at end of file diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPointerInteractor.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPointerInteractor.java index 9df6e5ef..770a3b4e 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPointerInteractor.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPointerInteractor.java @@ -1,59 +1,21 @@ package org.simantics.district.network.ui.participants; import java.awt.geom.Point2D; -import java.util.Collections; -import java.util.List; import java.util.Set; -import org.simantics.district.network.ui.adapters.DistrictNetworkEdgeElement; -import org.simantics.district.network.ui.adapters.DistrictNetworkVertexElement; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.ICanvasParticipant; -import org.simantics.g2d.diagram.handler.PickRequest.PickSorter; import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor; import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil.TerminalInfo; -import org.simantics.g2d.element.ElementHints; import org.simantics.g2d.element.IElement; -import org.simantics.scenegraph.g2d.IG2DNode; import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; -import org.simantics.scenegraph.g2d.events.KeyEvent.KeyReleasedEvent; import org.simantics.scenegraph.g2d.events.KeyEvent; -import org.simantics.scenegraph.g2d.nodes.SingleElementNode; +import org.simantics.scenegraph.g2d.events.KeyEvent.KeyReleasedEvent; public class DNPointerInteractor extends PointerInteractor { private RoutingMode routingMode; - private static class DNPickSorter implements PickSorter { - - @Override - public void sort(List elements) { - Collections.sort(elements, (e1, e2) -> { - IG2DNode e1node = getNode(e1); - IG2DNode e2node = getNode(e2); - if (e1node.getZIndex() < e2node.getZIndex()) - return -1; - else if (e1node.getZIndex() > e2node.getZIndex()) - return 1; - return 0; - }); - } - - private static IG2DNode getNode(IElement element) { - IG2DNode node = element.getHint(DistrictNetworkEdgeElement.KEY_DN_EDGE_NODE); - if (node == null) - node = element.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE); - if (node == null) { - node = element.getHint(ElementHints.KEY_SG_NODE); - if (node instanceof SingleElementNode) { - SingleElementNode snode = (SingleElementNode) node; - node = snode.getNodes().iterator().next(); - } - } - return node; - } - } - public DNPointerInteractor() { super(new DNPickSorter()); } @@ -83,6 +45,6 @@ public class DNPointerInteractor extends PointerInteractor { @Override public double getPickDistance() { - return 0.00001; + return 4; } }