]> gerrit.simantics Code Review - simantics/district.git/blob - 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
1 package org.simantics.district.network.ui.participants;
2
3 import java.awt.geom.Rectangle2D;
4 import java.util.Collections;
5 import java.util.Comparator;
6 import java.util.List;
7 import java.util.function.ToDoubleFunction;
8
9 import org.simantics.district.network.ui.adapters.DistrictNetworkEdgeElement;
10 import org.simantics.district.network.ui.adapters.DistrictNetworkVertexElement;
11 import org.simantics.district.network.ui.nodes.DistrictNetworkVertexNode;
12 import org.simantics.g2d.diagram.handler.PickRequest;
13 import org.simantics.g2d.diagram.handler.PickRequest.PickSorter;
14 import org.simantics.g2d.element.ElementHints;
15 import org.simantics.g2d.element.IElement;
16 import org.simantics.scenegraph.g2d.IG2DNode;
17 import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
18
19 /**
20  * @author Jani Simomaa
21  * @author Tuukka Lehtonen
22  */
23 public class DNPickSorter implements PickSorter {
24
25     public static ToDoubleFunction<Rectangle2D> centerDistSq(double x, double y) {
26         return r -> {
27             double dx = r.getCenterX() - x;
28             double dy = r.getCenterY() - y;
29             return dx * dx + dy * dy;
30         };
31     }
32
33     public static ToDoubleFunction<Rectangle2D> centerDistSq(Rectangle2D r1) {
34         return centerDistSq(r1.getCenterX(), r1.getCenterY());
35     }
36
37     /**
38      * @param nearestLast      if <code>true</code> the nearest elements are sorted
39      *                         into the tail of the list, if <code>false</code>
40      *                         nearest elements are at the beginning of the list
41      * @param distanceFunction function used for calculating the distance of each
42      *                         element's bounding box
43      * @return comparator implementing the requested diagram element comparison
44      */
45     public static Comparator<IElement> nearestVerticesFirst(boolean nearestLast, ToDoubleFunction<Rectangle2D> distanceFunction) {
46         int sign = nearestLast ? 1 : -1;
47         return (IElement e1, IElement e2) -> {
48             // If there are any vertices in the elements, prefer those primarily.
49             DistrictNetworkVertexNode v1 = e1.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
50             DistrictNetworkVertexNode v2 = e2.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
51
52             // Don't reorder edges
53             if ((v1 == null && v2 == null))
54                 return 0;
55
56             // Sort vertices in nearest first order
57             if (v1 != null && v2 != null) {
58                 double dist1 = distanceFunction.applyAsDouble(v1.getBounds());
59                 double dist2 = distanceFunction.applyAsDouble(v2.getBounds());
60                 return dist1 < dist2 ? sign : dist1 > dist2 ? -sign : 0;
61             }
62
63             // Always vertices before edges
64             return v1 != null && v2 == null ? sign : -sign;
65         };
66     }
67
68     private static IG2DNode getNode(IElement element) {
69         IG2DNode node = element.getHint(DistrictNetworkEdgeElement.KEY_DN_EDGE_NODE);
70         if (node == null)
71             node = element.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
72         if (node == null) {
73             node = element.getHint(ElementHints.KEY_SG_NODE);
74             if (node instanceof SingleElementNode) {
75                 SingleElementNode snode = (SingleElementNode) node;
76                 node = snode.getNodes().iterator().next();
77             }
78         }
79         return node;
80     }
81
82     private static Comparator<IElement> zSorter() {
83         return (e1, e2) -> {
84             IG2DNode e1node = getNode(e1);
85             IG2DNode e2node = getNode(e2);
86             if (e1node.getZIndex() < e2node.getZIndex())
87                 return -1;
88             else if (e1node.getZIndex() > e2node.getZIndex())
89                 return 1;
90             return 0;
91         };
92     };
93
94     @Override
95     public void sort(List<IElement> elements) {
96         Collections.sort(elements, zSorter());
97     }
98
99     @Override
100     public void sort(PickRequest req, List<IElement> elements) {
101         Collections.sort(elements, zSorter());
102         Collections.sort(elements, nearestVerticesFirst( true, centerDistSq( req.pickArea.getBounds2D() ) ));
103     }
104
105 }