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() ) )); } }