]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/handler/PickRequest.java
Merge "Automatically import also SCLMain modules of dependent index roots"
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / diagram / handler / PickRequest.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.g2d.diagram.handler;
13
14 import java.awt.Shape;
15 import java.awt.geom.AffineTransform;
16 import java.awt.geom.Area;
17 import java.awt.geom.Line2D;
18 import java.awt.geom.Point2D;
19 import java.awt.geom.Rectangle2D;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.List;
24
25 import org.simantics.diagram.connection.RouteLine;
26 import org.simantics.diagram.connection.RoutePoint;
27 import org.simantics.diagram.connection.segments.Segment;
28 import org.simantics.g2d.canvas.ICanvasContext;
29 import org.simantics.g2d.connection.handler.ConnectionHandler;
30 import org.simantics.g2d.element.IElement;
31 import org.simantics.g2d.element.handler.BendsHandler;
32 import org.simantics.g2d.element.handler.TerminalTopology;
33 import org.simantics.g2d.element.handler.impl.ConnectionSelectionOutline;
34 import org.simantics.g2d.elementclass.BranchPoint;
35 import org.simantics.g2d.elementclass.MonitorHandler;
36 import org.simantics.g2d.elementclass.RouteGraphConnectionClass;
37 import org.simantics.g2d.utils.GeometryUtils;
38 import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphNode;
39 import org.simantics.scenegraph.utils.TransformedRectangle;
40 import org.simantics.utils.datastructures.Pair;
41
42 /**
43  *
44  * @See {@link GeometryUtils} for intersect and contains tests
45  * @See {@link TransformedRectangle}
46  * @See {@link Area} intersects operations for complex shapes
47  * @author Toni Kalajainen
48  */
49 public class PickRequest {
50
51     public static enum PickPolicy {
52         PICK_INTERSECTING_OBJECTS,
53         PICK_CONTAINED_OBJECTS
54     }
55
56     public Shape      pickArea;
57     public PickPolicy pickPolicy = PickPolicy.PICK_INTERSECTING_OBJECTS;
58     /** Pick filter (null == everything is accepted) */
59     public PickFilter pickFilter = null;
60     public PickSorter pickSorter = null;
61
62     /**
63      * Used to optimize picking if provided via R-tree traversal to find
64      * intersecting elements, not everything.
65      */
66     public ICanvasContext pickContext;
67
68     public PickRequest(double x, double y)
69     {
70         pickArea = new Rectangle2D.Double(x, y, 1, 1);
71     }
72     public PickRequest(Point2D p)
73     {
74         pickArea = new Rectangle2D.Double(p.getX(), p.getY(), 0.0001, 0.0001);
75     }
76     public PickRequest(Shape shape)
77     {
78         pickArea = shape;
79     }
80     public PickRequest(Shape shape, AffineTransform transform)
81     {
82         pickArea = GeometryUtils.transformShape(shape, transform);
83     }
84
85     public PickRequest context(ICanvasContext ctx) {
86         this.pickContext = ctx;
87         return this;
88     }
89
90     public static interface PickFilter {
91         boolean accept(IElement e);
92
93         public static final PickFilter FILTER_ALL = new PickFilter() {
94             @Override
95             public boolean accept(IElement e) {
96                 return true;
97             }
98         };
99         // Connections
100         public static final PickFilter FILTER_CONNECTIONS = new PickFilter() {
101             @Override
102             public boolean accept(IElement e) {
103                 return e.getElementClass().containsClass(ConnectionHandler.class);
104             }
105             @Override
106             public String toString() { return "FILTER_CONNECTIONS"; }
107         };
108         // Connection edges
109         public static final PickFilter FILTER_CONNECTION_EDGES = new PickFilter() {
110             @Override
111             public boolean accept(IElement e) {
112                 return e.getElementClass().containsClass(BendsHandler.class) || e.getElementClass().containsClass(ConnectionSelectionOutline.class);
113             }
114             @Override
115             public String toString() { return "FILTER_CONNECTION_EDGES"; }
116         };
117         // Connections
118         public static final PickFilter FILTER_BRANCH_POINT = new PickFilter() {
119             @Override
120             public boolean accept(IElement e) {
121                 return e.getElementClass().containsClass(BranchPoint.class);
122             }
123             @Override
124             public String toString() { return "FILTER_BRANCH_POINTS"; }
125         };
126         // Anything that has terminals
127         public static final PickFilter FILTER_NODES = new PickFilter() {
128             @Override
129             public boolean accept(IElement e) {
130                 return e.getElementClass().containsClass(TerminalTopology.class);
131             }
132             @Override
133             public String toString() { return "FILTER_NODES"; }
134         };
135         public static final PickFilter FILTER_MONITORS = new PickFilter() {
136             @Override
137             public boolean accept(IElement e) {
138                 return e.getElementClass().containsClass(MonitorHandler.class);
139             }
140             @Override
141             public String toString() { return "FILTER_MONITORS"; }
142         };
143     }
144
145     public static interface PickSorter {
146         void sort(List<IElement> elements);
147
148         //
149         public static final PickSorter CONNECTIONS_LAST = new PickSorter() {
150             @Override
151             public void sort(List<IElement> elements) {
152                 Collections.sort(elements, new Comparator<IElement>() {
153                     @Override
154                     public int compare(IElement e1, IElement e2) {
155                         boolean isConn1 = PickFilter.FILTER_CONNECTION_EDGES.accept(e1);
156                         boolean isConn2 = PickFilter.FILTER_CONNECTION_EDGES.accept(e2);
157                         if (!isConn1 && isConn2)
158                             return -1;
159                         if (isConn1 && !isConn2)
160                             return 1;
161                         return 0;
162                     }
163                 });
164             }
165         };
166         public static final PickSorter CONNECTIONS_FIRST = new PickSorter() {
167             @Override
168             public void sort(List<IElement> elements) {
169                 Collections.sort(elements, new Comparator<IElement>() {
170                     @Override
171                     public int compare(IElement e1, IElement e2) {
172                         boolean isConn1 = PickFilter.FILTER_CONNECTION_EDGES.accept(e1);
173                         boolean isConn2 = PickFilter.FILTER_CONNECTION_EDGES.accept(e2);
174                         if (!isConn1 && isConn2)
175                             return 1;
176                         if (isConn1 && !isConn2)
177                             return -1;
178                         return 0;
179                     }
180                 });
181             }
182         };
183
184         /*
185          * First use the default sorting if available, then sort successive connections by their distance to cursor.
186          */
187         public static PickSorter connectionSorter(PickSorter sorter, double x, double y) {
188             return new PickSorter() {
189
190                 private double getDistanceSqToRouteGraphConnection(RouteGraphNode rgn, double x, double y) {
191                     double minDistanceSq = Double.MAX_VALUE;
192                     for (RouteLine line : rgn.getRouteGraph().getAllLines()) {
193                         ArrayList<Segment> segments = new ArrayList<Segment>();
194                         line.collectSegments(segments);
195                         for (Segment segment : segments) {
196                             RoutePoint p1 = segment.p1;
197                             RoutePoint p2 = segment.p2;
198
199                             double distanceSq = Line2D.ptSegDistSq(p1.getX(), p1.getY(), p2.getX(), p2.getY(), x, y);
200                             if (distanceSq < minDistanceSq) {
201                                 minDistanceSq = distanceSq;
202                             }
203                         }
204                     }
205                     return minDistanceSq;
206                 }
207                 
208                 @Override
209                 public void sort(List<IElement> elements) {
210                     if (sorter != null)
211                         sorter.sort(elements);
212
213                     List<Pair<Double, IElement>> connections = new ArrayList<>(elements.size());
214                     int tail = 0;
215                     for (int i = 0; i < elements.size(); i++) {
216                         IElement element = elements.get(i);
217                         RouteGraphNode rgn = element.getHint(RouteGraphConnectionClass.KEY_RG_NODE);
218                         if (rgn != null) {
219                             double distanceSq = getDistanceSqToRouteGraphConnection(rgn, x, y);
220                             connections.add(new Pair<Double, IElement>(distanceSq, element));
221                         }
222                         
223                         if (rgn == null || i == elements.size() - 1) {
224                             Collections.sort(connections, new Comparator<Pair<Double, IElement>>() {
225                                 @Override
226                                 public int compare(Pair<Double, IElement> connection1, Pair<Double, IElement> connection2) {
227                                     return Double.compare(connection2.first, connection1.first);
228                                 }
229                             });
230                             for (Pair<Double, IElement> connection : connections) {
231                                 elements.set(tail, connection.second);
232                                 tail++;
233                             }
234                             connections.clear();
235                             tail = i + 1;
236                         }
237                     }
238                 }
239             }; 
240         }
241     }
242
243 }