]> gerrit.simantics Code Review - simantics/district.git/blobdiff - org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DNPickSorter.java
Improve picking to prefer vertices and with a more useful pick area
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / participants / DNPickSorter.java
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 (file)
index 0000000..82cd725
--- /dev/null
@@ -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<Rectangle2D> 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<Rectangle2D> centerDistSq(Rectangle2D r1) {
+        return centerDistSq(r1.getCenterX(), r1.getCenterY());
+    }
+
+    /**
+     * @param nearestLast      if <code>true</code> the nearest elements are sorted
+     *                         into the tail of the list, if <code>false</code>
+     *                         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<IElement> nearestVerticesFirst(boolean nearestLast, ToDoubleFunction<Rectangle2D> 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<IElement> 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<IElement> elements) {
+        Collections.sort(elements, zSorter());
+    }
+
+    @Override
+    public void sort(PickRequest req, List<IElement> elements) {
+        Collections.sort(elements, zSorter());
+        Collections.sort(elements, nearestVerticesFirst( true, centerDistSq( req.pickArea.getBounds2D() ) ));
+    }
+
+}
\ No newline at end of file