1 26 27 package org.nightlabs.editor2d.viewer; 28 29 import java.awt.Rectangle ; 30 import java.awt.geom.Area ; 31 import java.awt.geom.Rectangle2D ; 32 import java.util.Collection ; 33 import java.util.HashMap ; 34 import java.util.Iterator ; 35 import java.util.LinkedList ; 36 import java.util.List ; 37 import java.util.Map ; 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 100 protected void initBounds(DrawComponent dc) 101 { 102 if (dc instanceof DrawComponentContainer) { 103 DrawComponentContainer container = (DrawComponentContainer) dc; 104 for (Iterator 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 <ShapeDrawComponent, Area > unfilledShape2Area = new HashMap <ShapeDrawComponent, Area >(); 114 protected void initShapes(DrawComponent dc) 115 { 116 if (dc instanceof DrawComponentContainer) { 118 DrawComponentContainer container = (DrawComponentContainer) dc; 119 for (Iterator 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 outlineArea = calculateOutlineArea(sdc, hitTolerance); 128 unfilledShape2Area.put(sdc, outlineArea); 129 } 130 } 131 } 132 133 protected Area calculateOutlineArea(ShapeDrawComponent sdc, double hitTolerance) 134 { 135 Rectangle outerBounds = TransformUtil.expand(sdc.getBounds(), (int)hitTolerance, (int)hitTolerance, true); 136 Rectangle 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 outlineArea = new Area (outerGS); 142 Area innerArea = new Area (innerGS); 143 outlineArea.exclusiveOr(innerArea); 144 return outlineArea; 145 } 146 147 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 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 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 219 public List findObjectsAt(DrawComponent dc, int x, int y, 220 IDrawComponentConditional conditional, Collection excludeList) 221 { 222 List objects = findObjectsAt(dc, x, y); 223 for (Iterator 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 248 public DrawComponent findObjectAt(DrawComponent dc, int x, int y, 249 IDrawComponentConditional conditional, Collection excludeList) 250 { 251 List objects = findObjectsAt(dc, x, y, conditional, excludeList); 252 return !objects.isEmpty() ? (DrawComponent) objects.get(0) : null; 253 } 254 255 267 public List findObjectsAt(DrawComponent dc, int x, int y) 268 { 269 List l = new LinkedList (); 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 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 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 311 public boolean intersects(ShapeDrawComponent sdc, Rectangle2D r) 312 { 313 return sdc.getGeneralShape().intersects(r); 314 } 315 316 322 public List findObjectsAt(DrawComponent dc, Rectangle2D r) 323 { 324 List l = new LinkedList (); 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 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 368 public List findObjectsAt(DrawComponent dc, Rectangle2D r, 369 IDrawComponentConditional conditional, Collection excludeList) 370 { 371 List objects = findObjectsAt(dc, r); 372 for (Iterator 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 |