]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/handler/impl/PickContextImpl.java
1f6a76903e9247e1c7d8aa3b21da14cc3d833616
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / diagram / handler / impl / PickContextImpl.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.impl;
13
14 import java.awt.Shape;
15 import java.awt.geom.AffineTransform;
16 import java.awt.geom.NoninvertibleTransformException;
17 import java.awt.geom.Rectangle2D;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.List;
21
22 import org.simantics.g2d.diagram.DiagramHints;
23 import org.simantics.g2d.diagram.IDiagram;
24 import org.simantics.g2d.diagram.handler.PickContext;
25 import org.simantics.g2d.diagram.handler.PickRequest;
26 import org.simantics.g2d.diagram.handler.PickRequest.PickPolicy;
27 import org.simantics.g2d.element.ElementClass;
28 import org.simantics.g2d.element.ElementUtils;
29 import org.simantics.g2d.element.IElement;
30 import org.simantics.g2d.element.handler.ElementLayers;
31 import org.simantics.g2d.element.handler.InternalSize;
32 import org.simantics.g2d.element.handler.Outline;
33 import org.simantics.g2d.element.handler.Pick;
34 import org.simantics.g2d.element.handler.Pick2;
35 import org.simantics.g2d.element.handler.Transform;
36 import org.simantics.g2d.layers.ILayers;
37 import org.simantics.g2d.utils.GeometryUtils;
38
39 /**
40  * @author Toni Kalajainen
41  */
42 public class PickContextImpl implements PickContext {
43
44         public static final PickContextImpl INSTANCE = new PickContextImpl(); 
45
46         @Override
47         public void pick(
48                         IDiagram diagram, 
49                         PickRequest request, 
50                         Collection<IElement> finalResult) 
51         {
52                 assert(diagram!=null);
53                 assert(request!=null);
54                 assert(finalResult!=null);
55
56                 ILayers layers = diagram.getHint(DiagramHints.KEY_LAYERS);
57
58                 Collection<IElement> result = finalResult;
59                 if (request.pickSorter != null) {
60                         // Need a temporary List<IElement> for PickSorter
61                         result = new ArrayList<IElement>();
62                 }
63                 Rectangle2D elementBounds = new Rectangle2D.Double();
64                 nextElement:
65                 for (IElement e : diagram.getSnapshot())
66                 {
67                         // Ignore hidden elements.
68                         if (ElementUtils.isHidden(e))
69                                 continue;
70
71                         ElementClass ec = e.getElementClass();
72                         
73                         if(layers != null && !layers.getIgnoreFocusSettings()) {
74                                 ElementLayers el = ec.getAtMostOneItemOfClass(ElementLayers.class);
75                                 if(el != null) {
76                                         if(!el.isFocusable(e, layers)) continue;
77                                 }
78                         }
79                         
80                         if (request.pickFilter!=null && !request.pickFilter.accept(e)) continue;
81                         
82                         Transform t = e.getElementClass().getSingleItem(Transform.class);
83                         AffineTransform canvasToElement = t.getTransform(e);
84                         if (canvasToElement==null) continue;
85                         double det = canvasToElement.getDeterminant();
86                         if (det == 0) {
87                                 // Singular transform, just reset the rotation/scaling part to
88                                 // allow picking to proceed.
89                                 // TODO: this may modify the internal transform value of an element which is not intended
90                                 canvasToElement.setToTranslation(
91                                                 canvasToElement.getTranslateX(),
92                                                 canvasToElement.getTranslateY());
93                         }
94
95                         // Get bounds, ignore elements that have no bounds
96                         InternalSize b = e.getElementClass().getAtMostOneItemOfClass(InternalSize.class);
97                         if (b==null) continue;
98                         elementBounds.setFrame(Double.NaN, Double.NaN, Double.NaN, Double.NaN);
99                         b.getBounds(e, elementBounds);
100                         if (Double.isNaN(elementBounds.getWidth()) || Double.isNaN(elementBounds.getHeight()))
101                                 continue;
102
103                         Shape elementBoundsOnCanvas = GeometryUtils.transformShape(elementBounds, canvasToElement);
104                         if (elementBoundsOnCanvas instanceof Rectangle2D)
105                                 elementBoundsOnCanvas = elementBoundsOnCanvas.getBounds2D();
106                         elementBoundsOnCanvas = elementBoundsOnCanvas.getBounds2D();
107                         org.simantics.scenegraph.utils.GeometryUtils.expandRectangle((Rectangle2D)elementBoundsOnCanvas, 1e-3, 1e-3, 1e-3, 1e-3);
108                         
109                         // Pick with pick handler(s)
110                         List<Pick> pickHandlers = e.getElementClass().getItemsByClass(Pick.class);
111                         if (!pickHandlers.isEmpty())
112                         {
113                             // Rough filtering with bounds
114                                 if (!GeometryUtils.intersects(request.pickArea, elementBoundsOnCanvas)) {
115 //                                      System.out.println("Element bounds discards " + e.getElementClass());
116                                         continue;
117                                 }
118                                 
119                                 // Convert pick shape to element coordinates
120 //                              AffineTransform elementToCanvas;
121 //                              try {
122 //                                      elementToCanvas = canvasToElement.createInverse();
123 //                              } catch (NoninvertibleTransformException e1) {
124 //                                      throw new RuntimeException(e1);
125 //                              }
126 //                              Shape pickShapeInElementCoords = GeometryUtils.transformShape(request.pickArea, elementToCanvas);
127                                 for (Pick p : pickHandlers)
128                                 {
129                                         if (p instanceof Pick2) {
130                                                 Pick2 p2 = (Pick2) p;
131                                                 //if (p2.pick(e, pickShapeInElementCoords, request.pickPolicy, result) > 0)
132                                                 if (p2.pick(e, request.pickArea, request.pickPolicy, result) > 0)
133                                                         continue nextElement;
134                                         } else {
135                                                 //if (p.pickTest(e, pickShapeInElementCoords, request.pickPolicy)) {
136                                                 if (p.pickTest(e, request.pickArea, request.pickPolicy)) {
137                                                         result.add(e);
138                                                         continue nextElement;
139                                                 }
140                                         }
141                                 }
142                                 continue nextElement;
143                         }
144                         
145                         // Pick with shape handler(s) 
146                         List<Outline> shapeHandlers = e.getElementClass().getItemsByClass(Outline.class);
147                         if (!shapeHandlers.isEmpty())
148                         {
149                                 // Rough filtering with bounds
150                                 if (!GeometryUtils.intersects(request.pickArea, elementBoundsOnCanvas)) continue;
151                                 
152                                 // Convert pick shape to element coordinates
153                                 AffineTransform elementToCanvas;
154                                 try {
155                                         elementToCanvas = canvasToElement.createInverse();
156                                 } catch (NoninvertibleTransformException e1) {
157                                         throw new RuntimeException(e1);
158                                 }
159                                 Shape pickShapeInElementCoords = GeometryUtils.transformShape(request.pickArea, elementToCanvas);
160                                 
161                                 // Intersection with one shape is enough
162                                 if (request.pickPolicy == PickPolicy.PICK_INTERSECTING_OBJECTS)
163                                 {
164                                         for (Outline es : shapeHandlers)
165                                         {
166                                                 Shape elementShape = es.getElementShape(e);             
167                                                 if (elementShape==null) continue nextElement;
168                                                 if (GeometryUtils.intersects(pickShapeInElementCoords, elementShape))
169                                                 {
170                                                         result.add(e);
171                                                         continue nextElement;
172                                                 }
173                                         }
174                                         continue nextElement;
175                                 }
176                                 
177                                 // Contains of all shapes is required 
178                                 if (request.pickPolicy == PickPolicy.PICK_CONTAINED_OBJECTS)
179                                 {
180                                         for (Outline es : shapeHandlers)
181                                         {
182                                                 Shape elementShape = es.getElementShape(e);
183                                                 if (!GeometryUtils.contains(pickShapeInElementCoords, elementShape))
184                                                         continue nextElement;
185                                         }
186                                         result.add(e);          
187                                         continue nextElement;
188                                 }
189                                 continue nextElement;
190                         } 
191                         
192                         // Pick by rectangle
193                         if (request.pickPolicy == PickPolicy.PICK_INTERSECTING_OBJECTS)
194                         {
195                                 if (GeometryUtils.intersects(request.pickArea, elementBoundsOnCanvas)) 
196                                         result.add(e);
197                         }
198                         
199                         else
200                                 
201                         if (request.pickPolicy == PickPolicy.PICK_CONTAINED_OBJECTS)
202                         {
203                                 if (GeometryUtils.contains(request.pickArea, elementBoundsOnCanvas)) 
204                                         result.add(e);
205                         }
206                         
207                 }
208
209                 if (request.pickSorter != null) {
210                         request.pickSorter.sort((List<IElement>) result);
211                         finalResult.addAll(result);
212                 }
213         }
214
215 }