1 /*******************************************************************************
2 * Copyright (c) 2007, 2020 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 * Semantum Oy - gitlab #454
12 *******************************************************************************/
13 package org.simantics.g2d.diagram.handler;
15 import java.awt.Shape;
16 import java.awt.geom.AffineTransform;
17 import java.awt.geom.Area;
18 import java.awt.geom.Point2D;
19 import java.awt.geom.Rectangle2D;
20 import java.util.Collections;
21 import java.util.Comparator;
22 import java.util.List;
24 import org.simantics.g2d.canvas.ICanvasContext;
25 import org.simantics.g2d.connection.handler.ConnectionHandler;
26 import org.simantics.g2d.element.IElement;
27 import org.simantics.g2d.element.handler.BendsHandler;
28 import org.simantics.g2d.element.handler.TerminalTopology;
29 import org.simantics.g2d.element.handler.impl.ConnectionSelectionOutline;
30 import org.simantics.g2d.elementclass.BranchPoint;
31 import org.simantics.g2d.elementclass.MonitorHandler;
32 import org.simantics.g2d.utils.GeometryUtils;
33 import org.simantics.scenegraph.utils.TransformedRectangle;
37 * @See {@link GeometryUtils} for intersect and contains tests
38 * @See {@link TransformedRectangle}
39 * @See {@link Area} intersects operations for complex shapes
40 * @author Toni Kalajainen
42 public class PickRequest {
44 public static enum PickPolicy {
45 PICK_INTERSECTING_OBJECTS,
46 PICK_CONTAINED_OBJECTS
49 public Shape pickArea;
50 public PickPolicy pickPolicy = PickPolicy.PICK_INTERSECTING_OBJECTS;
51 /** Pick filter (null == everything is accepted) */
52 public PickFilter pickFilter = null;
53 public PickSorter pickSorter = null;
56 * Used to optimize picking if provided via R-tree traversal to find
57 * intersecting elements, not everything.
59 public ICanvasContext pickContext;
61 public PickRequest(double x, double y)
63 pickArea = new Rectangle2D.Double(x, y, 1, 1);
65 public PickRequest(Point2D p)
67 pickArea = new Rectangle2D.Double(p.getX(), p.getY(), 0.0001, 0.0001);
69 public PickRequest(Shape shape)
73 public PickRequest(Shape shape, AffineTransform transform)
75 pickArea = GeometryUtils.transformShape(shape, transform);
78 public PickRequest context(ICanvasContext ctx) {
79 this.pickContext = ctx;
83 public static interface PickFilter {
84 boolean accept(IElement e);
86 public static final PickFilter FILTER_ALL = new PickFilter() {
88 public boolean accept(IElement e) {
93 public static final PickFilter FILTER_CONNECTIONS = new PickFilter() {
95 public boolean accept(IElement e) {
96 return e.getElementClass().containsClass(ConnectionHandler.class);
99 public String toString() { return "FILTER_CONNECTIONS"; }
102 public static final PickFilter FILTER_CONNECTION_EDGES = new PickFilter() {
104 public boolean accept(IElement e) {
105 return e.getElementClass().containsClass(BendsHandler.class) || e.getElementClass().containsClass(ConnectionSelectionOutline.class);
108 public String toString() { return "FILTER_CONNECTION_EDGES"; }
111 public static final PickFilter FILTER_BRANCH_POINT = new PickFilter() {
113 public boolean accept(IElement e) {
114 return e.getElementClass().containsClass(BranchPoint.class);
117 public String toString() { return "FILTER_BRANCH_POINTS"; }
119 // Anything that has terminals
120 public static final PickFilter FILTER_NODES = new PickFilter() {
122 public boolean accept(IElement e) {
123 return e.getElementClass().containsClass(TerminalTopology.class);
126 public String toString() { return "FILTER_NODES"; }
128 public static final PickFilter FILTER_MONITORS = new PickFilter() {
130 public boolean accept(IElement e) {
131 return e.getElementClass().containsClass(MonitorHandler.class);
134 public String toString() { return "FILTER_MONITORS"; }
138 public static interface PickSorter {
140 * Sorts the specified element list.
142 * @param elements the element list to sort
144 void sort(List<IElement> elements);
147 * Extended interface-method that receives the pick request in addition to the
148 * picked elements to be sorted. Allows e.g. looking at the pick area in the
152 * The default implementation just invokes {@link #sort(List)} ignoring the pick
153 * request. The default implementation also keeps PickSorter API/ABI-compatible.
155 * @param request the original pick request that produced the hits listed in
156 * <code>elements</code>
157 * @param elements the element list to sort
159 * @author Tuukka Lehtonen
160 * @since 1.43.0, 1.35.3
162 default void sort(PickRequest request, List<IElement> elements) {
167 public static final PickSorter CONNECTIONS_LAST = new PickSorter() {
169 public void sort(List<IElement> elements) {
170 Collections.sort(elements, new Comparator<IElement>() {
172 public int compare(IElement e1, IElement e2) {
173 boolean isConn1 = PickFilter.FILTER_CONNECTION_EDGES.accept(e1);
174 boolean isConn2 = PickFilter.FILTER_CONNECTION_EDGES.accept(e2);
175 if (!isConn1 && isConn2)
177 if (isConn1 && !isConn2)
184 public static final PickSorter CONNECTIONS_FIRST = new PickSorter() {
186 public void sort(List<IElement> elements) {
187 Collections.sort(elements, new Comparator<IElement>() {
189 public int compare(IElement e1, IElement e2) {
190 boolean isConn1 = PickFilter.FILTER_CONNECTION_EDGES.accept(e1);
191 boolean isConn2 = PickFilter.FILTER_CONNECTION_EDGES.accept(e2);
192 if (!isConn1 && isConn2)
194 if (isConn1 && !isConn2)