KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > nightlabs > editor2d > viewer > HitTestManager


1 /* *****************************************************************************
2  * NightLabs Editor2D - Graphical editor framework *
3  * Copyright (C) 2004-2005 NightLabs - http://NightLabs.org *
4  * *
5  * This library is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU Lesser General Public *
7  * License as published by the Free Software Foundation; either *
8  * version 2.1 of the License, or (at your option) any later version. *
9  * *
10  * This library is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13  * Lesser General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU Lesser General Public *
16  * License along with this library; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 51 Franklin St, Fifth Floor, *
19  * Boston, MA 02110-1301 USA *
20  * *
21  * Or get it online : *
22  * http://www.gnu.org/copyleft/lesser.html *
23  * *
24  * *
25  ******************************************************************************/

26
27 package org.nightlabs.editor2d.viewer;
28
29 import java.awt.Rectangle JavaDoc;
30 import java.awt.geom.Area JavaDoc;
31 import java.awt.geom.Rectangle2D JavaDoc;
32 import java.util.Collection JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.LinkedList JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.Map JavaDoc;
38
39 import org.apache.log4j.Logger;
40 import org.nightlabs.editor2d.DrawComponent;
41 import org.nightlabs.editor2d.DrawComponentContainer;
42 import org.nightlabs.editor2d.Layer;
43 import org.nightlabs.editor2d.ShapeDrawComponent;
44 import org.nightlabs.editor2d.j2d.GeneralShape;
45 import org.nightlabs.editor2d.viewer.util.TransformUtil;
46
47 public class HitTestManager
48 {
49     public static final Logger LOGGER = Logger.getLogger(HitTestManager.class);
50     
51     public HitTestManager(DrawComponent dc)
52     {
53         this.dc = dc;
54         init(dc);
55     }
56     
57     protected void init(DrawComponent dc)
58     {
59         long startTime = System.currentTimeMillis();
60         initBounds(dc);
61         initShapes(dc);
62         long endTime = System.currentTimeMillis() - startTime;
63         LOGGER.debug("Initialzation took "+endTime+" ms");
64     }
65     
66     protected DrawComponent dc = null;
67     public DrawComponent getDrawComponent() {
68         return dc;
69     }
70     public void setDrawComponent(DrawComponent dc) {
71         this.dc = dc;
72         init(dc);
73     }
74     
75     protected double hitTolerance = 3;
76     public void setHitTolerance(double hitTolerance) {
77         this.hitTolerance = hitTolerance;
78         initShapes(dc);
79     }
80     public double getHitTolerance() {
81         return hitTolerance;
82     }
83     
84 // protected IDrawComponentConditional conditional = null;
85
// public IDrawComponentConditional getConditional() {
86
// return conditional;
87
// }
88
// public void setConitional(IDrawComponentConditional conditional) {
89
// this.conditional = conditional;
90
// }
91
//
92
// protected Collection<DrawComponent> excludeList = null;
93
// public void setExcludeList(Collection<DrawComponent> excludeList) {
94
// this.excludeList = excludeList;
95
// }
96
// public Collection<DrawComponent> getExcludeList() {
97
// return excludeList;
98
// }
99

100     protected void initBounds(DrawComponent dc)
101     {
102         if (dc instanceof DrawComponentContainer) {
103             DrawComponentContainer container = (DrawComponentContainer) dc;
104             for (Iterator JavaDoc it = container.getDrawComponents().iterator(); it.hasNext(); ) {
105                 DrawComponent drawComponent = (DrawComponent) it.next();
106                 initBounds(drawComponent);
107             }
108         }
109         else
110             dc.getBounds();
111     }
112     
113     protected Map JavaDoc<ShapeDrawComponent, Area JavaDoc> unfilledShape2Area = new HashMap JavaDoc<ShapeDrawComponent, Area JavaDoc>();
114     protected void initShapes(DrawComponent dc)
115     {
116 // unfilledShape2Area.clear();
117
if (dc instanceof DrawComponentContainer) {
118             DrawComponentContainer container = (DrawComponentContainer) dc;
119             for (Iterator JavaDoc it = container.getDrawComponents().iterator(); it.hasNext(); ) {
120                 DrawComponent drawComponent = (DrawComponent) it.next();
121                 initShapes(drawComponent);
122             }
123         }
124         else if (dc instanceof ShapeDrawComponent) {
125             ShapeDrawComponent sdc = (ShapeDrawComponent) dc;
126             if (!sdc.isFill()) {
127                 Area JavaDoc outlineArea = calculateOutlineArea(sdc, hitTolerance);
128                 unfilledShape2Area.put(sdc, outlineArea);
129             }
130         }
131     }
132     
133     protected Area JavaDoc calculateOutlineArea(ShapeDrawComponent sdc, double hitTolerance)
134     {
135     Rectangle JavaDoc outerBounds = TransformUtil.expand(sdc.getBounds(), (int)hitTolerance, (int)hitTolerance, true);
136     Rectangle JavaDoc innerBounds = TransformUtil.shrink(sdc.getBounds(), (int)hitTolerance, (int)hitTolerance, true);
137     GeneralShape outerGS = (GeneralShape) sdc.getGeneralShape().clone();
138     GeneralShape innerGS = (GeneralShape) sdc.getGeneralShape().clone();
139     TransformUtil.transformGeneralShape(outerGS, sdc.getBounds(), outerBounds);
140     TransformUtil.transformGeneralShape(innerGS, sdc.getBounds(), innerBounds);
141     Area JavaDoc outlineArea = new Area JavaDoc(outerGS);
142     Area JavaDoc innerArea = new Area JavaDoc(innerGS);
143     outlineArea.exclusiveOr(innerArea);
144     return outlineArea;
145     }
146     
147     /**
148      *
149      * @param sdc the ShapeDrawComponent to check for containment
150      * @param x the x-Coordinate
151      * @param y the y-Coordinate
152      * @return true if the ShapeDrawComponent contains x,y or false if not
153      */

154     public boolean contains(ShapeDrawComponent sdc, double x, double y)
155     {
156         if (sdc.isFill())
157             return sdc.getGeneralShape().contains(x, y);
158         else {
159             Area JavaDoc outlineArea = unfilledShape2Area.get(sdc);
160             if (outlineArea == null) {
161                 LOGGER.debug("outlineArea for "+sdc.getName()+" not preCalculated");
162                 outlineArea = calculateOutlineArea(sdc, hitTolerance);
163             }
164             return outlineArea.contains(x, y);
165         }
166     }
167     
168     /**
169      *
170      * @param dc the DrawComponent to iterate through
171      * @param x the x-Coordinate
172      * @param y the y-Coordinate
173      * @return the topmost DrawComponent in the Z-Order which contains x and y or null if
174      * no drawComponent is found
175      */

176     public DrawComponent findObjectAt(DrawComponent dc, int x, int y)
177     {
178         if (dc instanceof DrawComponentContainer)
179         {
180             if (dc instanceof Layer)
181             {
182                 Layer layer = (Layer) dc;
183                 if (!layer.isVisible())
184                     return null;
185             }
186             DrawComponentContainer container = (DrawComponentContainer) dc;
187             int size = container.getDrawComponents().size();
188             if (container.getBounds().contains(x, y) && size != 0)
189             {
190                 for (int i = size - 1; i >= 0; i--) {
191                     DrawComponent child = (DrawComponent) container.getDrawComponents().get(i);
192                     if (findObjectAt(child, x, y) != null) {
193                         return findObjectAt(child, x, y);
194                     }
195                 }
196             }
197             return null;
198         }
199         if (dc instanceof ShapeDrawComponent) {
200             ShapeDrawComponent sdc = (ShapeDrawComponent) dc;
201             return contains(sdc, x, y) ? sdc : null;
202         }
203         else {
204             return dc.getBounds().contains(x, y) ? dc : null;
205         }
206     }
207      
208     /**
209      *
210      * @param dc the DrawComponent to iterate through (if it is a DrawComponentContainer)
211      * @param x the x-Coordinate
212      * @param y the y-Coordinate
213      * @param conditional an optional (maybe null) IDrawComponentConditional to filter the returned Objects
214      * @param excludeList an optional (mybe null) Collection of excluded DrawComponents
215      * @return a List which contains all DrawComponents which contain x and y and fullfill
216      * the condition as well as are not included in the excludeList
217      * if no drawComponents are found an empty List is returned
218      */

219     public List JavaDoc findObjectsAt(DrawComponent dc, int x, int y,
220             IDrawComponentConditional conditional, Collection JavaDoc excludeList)
221     {
222         List JavaDoc objects = findObjectsAt(dc, x, y);
223         for (Iterator JavaDoc it = objects.iterator(); it.hasNext(); )
224         {
225             DrawComponent drawComponent = (DrawComponent) it.next();
226             if (conditional != null) {
227                 if (!conditional.evalute(drawComponent))
228                     it.remove();
229             }
230             if (excludeList != null) {
231                 if (excludeList.contains(drawComponent))
232                     it.remove();
233             }
234         }
235         return objects;
236     }
237
238     /**
239      *
240      * @param dc the DrawComponent to iterate through
241      * @param x the x-Coordinate
242      * @param y the y-Coordinate
243      * @param conditional an optional (maybe null) IDrawComponentConditional to filter the returned Objects
244      * @param excludeList an optional (mybe null) Collection of excluded DrawComponents
245      * @return the topmost DrawComponent in the Z-Order which contains x and y and
246      * fullfills the condition and is not included in the excludeList
247      */

248     public DrawComponent findObjectAt(DrawComponent dc, int x, int y,
249             IDrawComponentConditional conditional, Collection JavaDoc excludeList)
250     {
251         List JavaDoc objects = findObjectsAt(dc, x, y, conditional, excludeList);
252         return !objects.isEmpty() ? (DrawComponent) objects.get(0) : null;
253     }
254     
255     /**
256      * the order of the returned List represents the Z-Order of the hit-testing
257      * (first entry = topmost, last entry = bottommost)
258      *
259      *
260      * @param dc the DrawComponent to iterate through
261      * @param x the x-Coordinate
262      * @param y the y-Coordinate
263      * @return a List which contains all DrawComponents which contain x and y,
264      * if no drawComponents are found an empty List is returned
265      *
266      */

267     public List JavaDoc findObjectsAt(DrawComponent dc, int x, int y)
268     {
269         List JavaDoc l = new LinkedList JavaDoc();
270         if (dc instanceof DrawComponentContainer)
271         {
272             if (dc instanceof Layer)
273             {
274                 Layer layer = (Layer) dc;
275                 if (!layer.isVisible())
276                     return l;
277             }
278             DrawComponentContainer container = (DrawComponentContainer) dc;
279             int size = container.getDrawComponents().size();
280             if (container.getBounds().contains(x, y) && size != 0)
281             {
282                 for (int i = size - 1; i >= 0; i--)
283                 {
284                     DrawComponent child = (DrawComponent) container.getDrawComponents().get(i);
285                     List JavaDoc childrenObjects = findObjectsAt(child, x, y);
286                     if (!childrenObjects.isEmpty()) {
287                         l.addAll(childrenObjects);
288                     }
289                 }
290             }
291         }
292         else {
293             if (dc instanceof ShapeDrawComponent) {
294                 ShapeDrawComponent sdc = (ShapeDrawComponent) dc;
295                 // TODO: calculate outlineArea for all not filled shapes once at initalization
296
if (contains(sdc, x, y))
297                     l.add(sdc);
298             }
299             else if (dc.getBounds().contains(x, y))
300              l.add(dc);
301         }
302         return l;
303     }
304         
305     /**
306      *
307      * @param sdc the ShapeDrawComponent to check for intersection
308      * @param r the Rectangle2D to check for
309      * @return true if the ShapeDrawComponent intersects r
310      */

311     public boolean intersects(ShapeDrawComponent sdc, Rectangle2D JavaDoc r)
312     {
313         return sdc.getGeneralShape().intersects(r);
314     }
315     
316     /**
317      *
318      * @param dc the DrawComponent to iterate through (if it is a DrawComponentContainer)
319      * @param r the Rectangle to check for intersection
320      * @return a List of DrawCompoennts which intersects the Rectangle
321      */

322     public List JavaDoc findObjectsAt(DrawComponent dc, Rectangle2D JavaDoc r)
323     {
324         List JavaDoc l = new LinkedList JavaDoc();
325         if (dc instanceof DrawComponentContainer)
326         {
327             if (dc instanceof Layer)
328             {
329                 Layer layer = (Layer) dc;
330                 if (!layer.isVisible())
331                     return l;
332             }
333             DrawComponentContainer container = (DrawComponentContainer) dc;
334             int size = container.getDrawComponents().size();
335             if (container.getBounds().intersects(r) && size != 0)
336             {
337                 for (int i = size - 1; i >= 0; i--)
338                 {
339                     DrawComponent child = (DrawComponent) container.getDrawComponents().get(i);
340                     List JavaDoc childrenObjects = findObjectsAt(child, r);
341                     if (!childrenObjects.isEmpty()) {
342                         l.addAll(childrenObjects);
343                     }
344                 }
345             }
346         }
347         else {
348             if (dc instanceof ShapeDrawComponent) {
349                 ShapeDrawComponent sdc = (ShapeDrawComponent) dc;
350                 if (intersects(sdc, r))
351                     l.add(sdc);
352             }
353             else if (dc.getBounds().intersects(r))
354              l.add(dc);
355         }
356         return l;
357     }
358     
359     /**
360      * @param dc the DrawComponent to iterate through (if it is a DrawComponentContainer)
361      * @param r the Rectangel to check for intersection
362      * @param conditional an optional (maybe null) IDrawComponentConditional to filter the returned Objects
363      * @param excludeList an optional (maybe null) Collection of excluded DrawComponents
364      * @return a List which contains all DrawComponents which intersect r and fullfill
365      * the condition as well as are not included in the excludeList
366      * if no drawComponents are found an empty List is returned
367      */

368     public List JavaDoc findObjectsAt(DrawComponent dc, Rectangle2D JavaDoc r,
369             IDrawComponentConditional conditional, Collection JavaDoc excludeList)
370     {
371         List JavaDoc objects = findObjectsAt(dc, r);
372         for (Iterator JavaDoc it = objects.iterator(); it.hasNext(); )
373         {
374             DrawComponent drawComponent = (DrawComponent) it.next();
375             if (conditional != null) {
376                 if (!conditional.evalute(drawComponent))
377                     it.remove();
378             }
379             if (excludeList != null) {
380                 if (excludeList.contains(drawComponent))
381                     it.remove();
382             }
383         }
384         return objects;
385     }
386 }
387
Popular Tags