1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.g2d.diagram.handler.impl;
\r
14 import java.awt.Shape;
\r
15 import java.awt.geom.AffineTransform;
\r
16 import java.awt.geom.NoninvertibleTransformException;
\r
17 import java.awt.geom.Rectangle2D;
\r
18 import java.util.ArrayList;
\r
19 import java.util.Collection;
\r
20 import java.util.List;
\r
22 import org.simantics.g2d.diagram.DiagramHints;
\r
23 import org.simantics.g2d.diagram.IDiagram;
\r
24 import org.simantics.g2d.diagram.handler.PickContext;
\r
25 import org.simantics.g2d.diagram.handler.PickRequest;
\r
26 import org.simantics.g2d.diagram.handler.PickRequest.PickPolicy;
\r
27 import org.simantics.g2d.element.ElementClass;
\r
28 import org.simantics.g2d.element.ElementUtils;
\r
29 import org.simantics.g2d.element.IElement;
\r
30 import org.simantics.g2d.element.handler.ElementLayers;
\r
31 import org.simantics.g2d.element.handler.InternalSize;
\r
32 import org.simantics.g2d.element.handler.Outline;
\r
33 import org.simantics.g2d.element.handler.Pick;
\r
34 import org.simantics.g2d.element.handler.Pick2;
\r
35 import org.simantics.g2d.element.handler.Transform;
\r
36 import org.simantics.g2d.layers.ILayers;
\r
37 import org.simantics.g2d.utils.GeometryUtils;
\r
40 * @author Toni Kalajainen
\r
42 public class PickContextImpl implements PickContext {
\r
44 public static final PickContextImpl INSTANCE = new PickContextImpl();
\r
49 PickRequest request,
\r
50 Collection<IElement> finalResult)
\r
52 assert(diagram!=null);
\r
53 assert(request!=null);
\r
54 assert(finalResult!=null);
\r
56 ILayers layers = diagram.getHint(DiagramHints.KEY_LAYERS);
\r
58 Collection<IElement> result = finalResult;
\r
59 if (request.pickSorter != null) {
\r
60 // Need a temporary List<IElement> for PickSorter
\r
61 result = new ArrayList<IElement>();
\r
63 Rectangle2D elementBounds = new Rectangle2D.Double();
\r
65 for (IElement e : diagram.getSnapshot())
\r
67 // Ignore hidden elements.
\r
68 if (ElementUtils.isHidden(e))
\r
71 ElementClass ec = e.getElementClass();
\r
73 if(layers != null && !layers.getIgnoreFocusSettings()) {
\r
74 ElementLayers el = ec.getAtMostOneItemOfClass(ElementLayers.class);
\r
76 if(!el.isFocusable(e, layers)) continue;
\r
80 if (request.pickFilter!=null && !request.pickFilter.accept(e)) continue;
\r
82 Transform t = e.getElementClass().getSingleItem(Transform.class);
\r
83 AffineTransform canvasToElement = t.getTransform(e);
\r
84 if (canvasToElement==null) continue;
\r
85 double det = canvasToElement.getDeterminant();
\r
87 // Singular transform, just reset the rotation/scaling part to
\r
88 // allow picking to proceed.
\r
89 // TODO: this may modify the internal transform value of an element which is not intended
\r
90 canvasToElement.setToTranslation(
\r
91 canvasToElement.getTranslateX(),
\r
92 canvasToElement.getTranslateY());
\r
95 // Get bounds, ignore elements that have no bounds
\r
96 InternalSize b = e.getElementClass().getAtMostOneItemOfClass(InternalSize.class);
\r
97 if (b==null) continue;
\r
98 elementBounds.setFrame(Double.NaN, Double.NaN, Double.NaN, Double.NaN);
\r
99 b.getBounds(e, elementBounds);
\r
100 if (Double.isNaN(elementBounds.getWidth()) || Double.isNaN(elementBounds.getHeight()))
\r
103 Shape elementBoundsOnCanvas = GeometryUtils.transformShape(elementBounds, canvasToElement);
\r
104 if (elementBoundsOnCanvas instanceof Rectangle2D)
\r
105 elementBoundsOnCanvas = elementBoundsOnCanvas.getBounds2D();
\r
106 elementBoundsOnCanvas = elementBoundsOnCanvas.getBounds2D();
\r
107 org.simantics.scenegraph.utils.GeometryUtils.expandRectangle((Rectangle2D)elementBoundsOnCanvas, 1e-3, 1e-3, 1e-3, 1e-3);
\r
109 // Pick with pick handler(s)
\r
110 List<Pick> pickHandlers = e.getElementClass().getItemsByClass(Pick.class);
\r
111 if (!pickHandlers.isEmpty())
\r
113 // Rough filtering with bounds
\r
114 if (!GeometryUtils.intersects(request.pickArea, elementBoundsOnCanvas)) {
\r
115 // System.out.println("Element bounds discards " + e.getElementClass());
\r
119 // Convert pick shape to element coordinates
\r
120 // AffineTransform elementToCanvas;
\r
122 // elementToCanvas = canvasToElement.createInverse();
\r
123 // } catch (NoninvertibleTransformException e1) {
\r
124 // throw new RuntimeException(e1);
\r
126 // Shape pickShapeInElementCoords = GeometryUtils.transformShape(request.pickArea, elementToCanvas);
\r
127 for (Pick p : pickHandlers)
\r
129 if (p instanceof Pick2) {
\r
130 Pick2 p2 = (Pick2) p;
\r
131 //if (p2.pick(e, pickShapeInElementCoords, request.pickPolicy, result) > 0)
\r
132 if (p2.pick(e, request.pickArea, request.pickPolicy, result) > 0)
\r
133 continue nextElement;
\r
135 //if (p.pickTest(e, pickShapeInElementCoords, request.pickPolicy)) {
\r
136 if (p.pickTest(e, request.pickArea, request.pickPolicy)) {
\r
138 continue nextElement;
\r
142 continue nextElement;
\r
145 // Pick with shape handler(s)
\r
146 List<Outline> shapeHandlers = e.getElementClass().getItemsByClass(Outline.class);
\r
147 if (!shapeHandlers.isEmpty())
\r
149 // Rough filtering with bounds
\r
150 if (!GeometryUtils.intersects(request.pickArea, elementBoundsOnCanvas)) continue;
\r
152 // Convert pick shape to element coordinates
\r
153 AffineTransform elementToCanvas;
\r
155 elementToCanvas = canvasToElement.createInverse();
\r
156 } catch (NoninvertibleTransformException e1) {
\r
157 throw new RuntimeException(e1);
\r
159 Shape pickShapeInElementCoords = GeometryUtils.transformShape(request.pickArea, elementToCanvas);
\r
161 // Intersection with one shape is enough
\r
162 if (request.pickPolicy == PickPolicy.PICK_INTERSECTING_OBJECTS)
\r
164 for (Outline es : shapeHandlers)
\r
166 Shape elementShape = es.getElementShape(e);
\r
167 if (elementShape==null) continue nextElement;
\r
168 if (GeometryUtils.intersects(pickShapeInElementCoords, elementShape))
\r
171 continue nextElement;
\r
174 continue nextElement;
\r
177 // Contains of all shapes is required
\r
178 if (request.pickPolicy == PickPolicy.PICK_CONTAINED_OBJECTS)
\r
180 for (Outline es : shapeHandlers)
\r
182 Shape elementShape = es.getElementShape(e);
\r
183 if (!GeometryUtils.contains(pickShapeInElementCoords, elementShape))
\r
184 continue nextElement;
\r
187 continue nextElement;
\r
189 continue nextElement;
\r
192 // Pick by rectangle
\r
193 if (request.pickPolicy == PickPolicy.PICK_INTERSECTING_OBJECTS)
\r
195 if (GeometryUtils.intersects(request.pickArea, elementBoundsOnCanvas))
\r
201 if (request.pickPolicy == PickPolicy.PICK_CONTAINED_OBJECTS)
\r
203 if (GeometryUtils.contains(request.pickArea, elementBoundsOnCanvas))
\r
209 if (request.pickSorter != null) {
\r
210 request.pickSorter.sort((List<IElement>) result);
\r
211 finalResult.addAll(result);
\r