1 /*
   2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene;
  27 
  28 import com.sun.javafx.geom.PickRay;
  29 import com.sun.javafx.test.MouseEventGenerator;
  30 import javafx.event.Event;
  31 import javafx.event.EventHandler;
  32 import javafx.event.EventType;
  33 import javafx.geometry.Point2D;
  34 import javafx.geometry.Point3D;
  35 import javafx.scene.input.MouseDragEvent;
  36 import javafx.scene.input.MouseEvent;
  37 import javafx.scene.input.PickResult;
  38 import javafx.scene.shape.Rectangle;
  39 import javafx.scene.shape.Box;
  40 import javafx.scene.shape.CullFace;
  41 import javafx.scene.shape.Cylinder;
  42 import javafx.scene.shape.MeshView;
  43 import javafx.scene.shape.Sphere;
  44 import javafx.scene.shape.TriangleMesh;
  45 import javafx.scene.transform.Rotate;
  46 import javafx.stage.Stage;
  47 import static org.junit.Assert.*;
  48 import org.junit.Test;
  49 
  50 public class Mouse3DTest {
  51 
  52     private static final int NOFACE = PickResult.FACE_UNDEFINED;
  53     private static final double PERSPECTIVE_CAMERA_X = 500;
  54     private static final double PERSPECTIVE_CAMERA_Y = 400;
  55     private static final double PERSPECTIVE_CAMERA_Z = -1492.820323027551;
  56 
  57     private EventHolder<MouseEvent> me = new EventHolder<MouseEvent>();
  58     private EventHolder<MouseEvent> pme = new EventHolder<MouseEvent>();
  59     private EventHolder<MouseEvent> sme = new EventHolder<MouseEvent>();
  60 
  61     /***************** pick ray ********************/
  62     // We use moving camera for the picking tests, so test pick ray sanity first
  63 
  64     @Test
  65     public void shouldComputeCorrectPerspectivePickRay() {
  66         Camera cam = new PerspectiveCamera();
  67         scene(group(), cam, true);
  68         cam.impl_updatePeer();
  69         PickRay pickRay = cam.computePickRay(10, 20, null);
  70         assertEquals(PERSPECTIVE_CAMERA_X, pickRay.getOriginNoClone().x, 0.00001);
  71         assertEquals(PERSPECTIVE_CAMERA_Y, pickRay.getOriginNoClone().y, 0.00001);
  72         assertEquals(PERSPECTIVE_CAMERA_Z, pickRay.getOriginNoClone().z, 0.00001);
  73         assertEquals(10 - PERSPECTIVE_CAMERA_X, pickRay.getDirectionNoClone().x, 0.00001);
  74         assertEquals(20 - PERSPECTIVE_CAMERA_Y, pickRay.getDirectionNoClone().y, 0.00001);
  75         assertEquals(-PERSPECTIVE_CAMERA_Z, pickRay.getDirectionNoClone().z, 0.00001);
  76     }
  77 
  78     @Test
  79     public void shouldComputeCorrectPerspectivePickRayWithFixedEye() {
  80         Camera cam = new PerspectiveCamera(true);
  81         scene(group(), cam, true);
  82         cam.impl_updatePeer();
  83         PickRay pickRay = cam.computePickRay(10, 20, null);
  84         assertEquals(0.0, pickRay.getOriginNoClone().x, 0.00001);
  85         assertEquals(0.0, pickRay.getOriginNoClone().y, 0.00001);
  86         assertEquals(0.0, pickRay.getOriginNoClone().z, 0.00001);
  87         assertEquals(10 - PERSPECTIVE_CAMERA_X, pickRay.getDirectionNoClone().x, 0.00001);
  88         assertEquals(20 - PERSPECTIVE_CAMERA_Y, pickRay.getDirectionNoClone().y, 0.00001);
  89         assertEquals(-PERSPECTIVE_CAMERA_Z, pickRay.getDirectionNoClone().z, 0.00001);
  90     }
  91 
  92     @Test
  93     public void shouldComputeCorrectParallelClipDistances() {
  94         Camera cam = new ParallelCamera();
  95         cam.setNearClip(100.0);
  96         cam.setFarClip(200.0);
  97         scene(group(), cam, true);
  98         cam.impl_updatePeer();
  99         PickRay pickRay = cam.computePickRay(100, 200, null);
 100 
 101         assertEquals(-PERSPECTIVE_CAMERA_Z * 100, pickRay.getNearClip(), 0.01);
 102         assertEquals(-PERSPECTIVE_CAMERA_Z * 200, pickRay.getFarClip(), 0.01);
 103     }
 104 
 105     @Test
 106     public void shouldComputeCorrectPerspectiveClipDistances() {
 107         Camera cam = new PerspectiveCamera();
 108         cam.setNearClip(100.0);
 109         cam.setFarClip(200.0);
 110         scene(group(), cam, true);
 111         cam.impl_updatePeer();
 112         PickRay pickRay = cam.computePickRay(100, 200, null);
 113 
 114         double xd = PERSPECTIVE_CAMERA_X - 100;
 115         double yd = PERSPECTIVE_CAMERA_Y - 200;
 116         double pd = Math.sqrt(xd * xd + yd * yd);
 117         double len = Math.sqrt(PERSPECTIVE_CAMERA_Z * PERSPECTIVE_CAMERA_Z + pd * pd);
 118 
 119         assertEquals(len * 100, pickRay.getNearClip(), 0.01);
 120         assertEquals(len * 200, pickRay.getFarClip(), 0.01);
 121     }
 122 
 123     @Test
 124     public void shouldComputeCorrectClipDistancesWithFixedEye() {
 125         Camera cam = new PerspectiveCamera(true);
 126         cam.setNearClip(100.0);
 127         cam.setFarClip(200.0);
 128         scene(group(), cam, true);
 129         cam.impl_updatePeer();
 130         PickRay pickRay = cam.computePickRay(100, 200, null);
 131         assertEquals(104.39, pickRay.getNearClip(), 0.01);
 132         assertEquals(208.78, pickRay.getFarClip(), 0.01);
 133     }
 134 
 135     @Test
 136     public void shouldComputeCorrectMovedPerspectivePickRay() {
 137         Camera cam = new PerspectiveCamera();
 138         scene(group(cam), cam, true);
 139         cam.setTranslateX(50);
 140         cam.getParent().setTranslateY(30);
 141         cam.impl_updatePeer();
 142         PickRay pickRay = cam.computePickRay(10, 20, null);
 143         assertEquals(50 + PERSPECTIVE_CAMERA_X, pickRay.getOriginNoClone().x, 0.00001);
 144         assertEquals(30 + PERSPECTIVE_CAMERA_Y, pickRay.getOriginNoClone().y, 0.00001);
 145         assertEquals(PERSPECTIVE_CAMERA_Z, pickRay.getOriginNoClone().z, 0.00001);
 146         assertEquals(10 - PERSPECTIVE_CAMERA_X, pickRay.getDirectionNoClone().x, 0.00001);
 147         assertEquals(20 - PERSPECTIVE_CAMERA_Y, pickRay.getDirectionNoClone().y, 0.00001);
 148         assertEquals(-PERSPECTIVE_CAMERA_Z, pickRay.getDirectionNoClone().z, 0.00001);
 149     }
 150 
 151     @Test
 152     public void shouldComputeCorrectParallelPickRay() {
 153         Camera cam = new ParallelCamera();
 154         scene(group(), cam, true);
 155         PickRay pickRay = cam.computePickRay(10, 20, null);
 156         assertEquals(10.0, pickRay.getOriginNoClone().x, 0.00001);
 157         assertEquals(20.0, pickRay.getOriginNoClone().y, 0.00001);
 158         assertEquals(PERSPECTIVE_CAMERA_Z, pickRay.getOriginNoClone().z, 0.1);
 159         assertEquals(0.0, pickRay.getDirectionNoClone().x, 0.00001);
 160         assertEquals(0.0, pickRay.getDirectionNoClone().y, 0.00001);
 161         assertEquals(-PERSPECTIVE_CAMERA_Z, pickRay.getDirectionNoClone().z, 0.1);
 162     }
 163 
 164     @Test
 165     public void shouldComputeCorrectMovedParallelPickRay() {
 166         Camera cam = new ParallelCamera();
 167         scene(group(cam), cam, true);
 168         cam.setTranslateX(50);
 169         cam.getParent().setTranslateY(30);
 170         cam.impl_updatePeer();
 171         PickRay pickRay = cam.computePickRay(10, 20, null);
 172         assertEquals(60.0, pickRay.getOriginNoClone().x, 0.00001);
 173         assertEquals(50.0, pickRay.getOriginNoClone().y, 0.00001);
 174         assertEquals(PERSPECTIVE_CAMERA_Z, pickRay.getOriginNoClone().z, 0.1);
 175         assertEquals(0.0, pickRay.getDirectionNoClone().x, 0.00001);
 176         assertEquals(0.0, pickRay.getDirectionNoClone().y, 0.00001);
 177         assertEquals(-PERSPECTIVE_CAMERA_Z, pickRay.getDirectionNoClone().z, 0.1);
 178     }
 179 
 180 
 181     /*****************  BOX picking ********************/
 182 
 183     @Test
 184     public void shouldPickBoxFromFront() {
 185         Box b = box().handleMove(me);
 186         b.setCullFace(CullFace.BACK);
 187         Scene s = scene(group(b), perspective(), true);
 188 
 189         makeParallel(s, 10, 40);
 190         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 191 
 192         MouseEvent e = me.event;
 193         assertNotNull(e);
 194         assertCoordinates(e, 10, 40, -200);
 195         assertPickResult(e.getPickResult(),
 196                 b, point(10, 40, -200), 800, NOFACE, point(0.6, 0.7));
 197     }
 198 
 199     @Test
 200     public void shouldPickBoxInteriorFromFront() {
 201         Box b = box().handleMove(me);
 202         b.setCullFace(CullFace.FRONT);
 203         Scene s = scene(group(b), perspective(), true);
 204 
 205         makeParallel(s, 10, 40);
 206         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 207 
 208         MouseEvent e = me.event;
 209         assertNotNull(e);
 210         assertCoordinates(e, 10, 40, 200);
 211         assertPickResult(e.getPickResult(),
 212                 b, point(10, 40, 200), 1200, NOFACE, point(0.4, 0.7));
 213     }
 214 
 215     @Test
 216     public void shouldPickNotCulledBoxFromFront() {
 217         Box b = box().handleMove(me);
 218         b.setCullFace(CullFace.NONE);
 219         Scene s = scene(group(b), perspective(), true);
 220 
 221         makeParallel(s, 10, 40);
 222         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 223 
 224         MouseEvent e = me.event;
 225         assertNotNull(e);
 226         assertCoordinates(e, 10, 40, -200);
 227         assertPickResult(e.getPickResult(),
 228                 b, point(10, 40, -200), 800, NOFACE, point(0.6, 0.7));
 229     }
 230 
 231     @Test
 232     public void shouldPickBoxFromTop() {
 233         Node b = box().rotate('x', 90).handleMove(me);
 234         Scene s = scene(group(b), perspective(), true);
 235 
 236         makeParallel(s, 10, 20);
 237         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 238 
 239         MouseEvent e = me.event;
 240         assertNotNull(e);
 241         assertCoordinates(e, 10, -100, -20);
 242         assertPickResult(e.getPickResult(),
 243                 b, point(10, -100, -20), 900, NOFACE, point(0.6, 0.55));
 244     }
 245 
 246     @Test
 247     public void shouldPickBoxFromBack() {
 248         Node b = box().rotate('x', 180).handleMove(me);
 249         Scene s = scene(group(b), perspective(), true);
 250 
 251         makeParallel(s, 10, 40);
 252         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 253 
 254         MouseEvent e = me.event;
 255         assertNotNull(e);
 256         assertCoordinates(e, 10, -40, 200);
 257         assertPickResult(e.getPickResult(),
 258                 b, point(10, -40, 200), 800, NOFACE, point(0.4, 0.3));
 259     }
 260 
 261     @Test
 262     public void shouldPickBoxFromBottom() {
 263         Node b = box().rotate('x', -90).handleMove(me);
 264         Scene s = scene(group(b), perspective(), true);
 265 
 266         makeParallel(s, 10, 20);
 267         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 268 
 269         MouseEvent e = me.event;
 270         assertNotNull(e);
 271         assertCoordinates(e, 10, 100, 20);
 272         assertPickResult(e.getPickResult(),
 273                 b, point(10, 100, 20), 900, NOFACE, point(0.6, 0.55));
 274     }
 275 
 276     @Test
 277     public void shouldPickBoxFromLeft() {
 278         Node b = box().rotate('y', -90).handleMove(me);
 279         Scene s = scene(group(b), perspective(), true);
 280 
 281         makeParallel(s, 10, 20);
 282         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 283 
 284         MouseEvent e = me.event;
 285         assertNotNull(e);
 286         assertCoordinates(e, -50, 20, -10);
 287         assertPickResult(e.getPickResult(),
 288                 b, point(-50, 20, -10), 950, NOFACE, point(0.525, 0.6));
 289     }
 290 
 291     @Test
 292     public void shouldPickBoxFromRight() {
 293         Node b = box().rotate('y', 90).handleMove(me);
 294         Scene s = scene(group(b), perspective(), true);
 295 
 296         makeParallel(s, 10, 20);
 297         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 298 
 299         MouseEvent e = me.event;
 300         assertNotNull(e);
 301         assertCoordinates(e, 50, 20, 10);
 302         assertPickResult(e.getPickResult(),
 303                 b, point(50, 20, 10), 950, NOFACE, point(0.525, 0.6));
 304     }
 305 
 306     @Test
 307     public void shouldPickBoxByParallelCameraFromFront() {
 308         MouseEventGenerator g = new MouseEventGenerator();
 309         Box b = box().handleMove(me);
 310         b.setCullFace(CullFace.BACK);
 311         Scene s = scene(group(b), parallel(), true);
 312         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 40));
 313 
 314         MouseEvent e = me.event;
 315         assertNotNull(e);
 316         assertCoordinates(e, 10, 40, 10, 40, -200);
 317         assertPickResult(e.getPickResult(),
 318                 b, point(10, 40, -200), 1292.82032, NOFACE, point(0.6, 0.7));
 319     }
 320 
 321     @Test
 322     public void shouldPickBoxByParallelCameraFromBack() {
 323         MouseEventGenerator g = new MouseEventGenerator();
 324         Node b = box().rotate('x', 180).handleMove(me);
 325         Scene s = scene(group(b), parallel(), true);
 326         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 40));
 327 
 328         MouseEvent e = me.event;
 329         assertNotNull(e);
 330         assertCoordinates(e, 10, 40, 10, -40, 200);
 331         assertPickResult(e.getPickResult(),
 332                 b, point(10, -40, 200), 1292.82032, NOFACE, point(0.4, 0.3));
 333     }
 334 
 335     @Test
 336     public void shouldNotPickBoxByParallelCameraFromFrontNextToIt() {
 337         MouseEventGenerator g = new MouseEventGenerator();
 338         Box b = box().handleMove(me);
 339         b.setCullFace(CullFace.BACK);
 340         Scene s = scene(group(b), parallel(), true);
 341         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 40));
 342         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, -500, 40));
 343         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 400));
 344         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, -400));
 345 
 346         MouseEvent e = me.event;
 347         assertNull(e);
 348     }
 349 
 350     @Test
 351     public void shouldPickBoxFromAngle() {
 352         Node b = box().rotate('y', 90).handleMove(me);
 353         Scene s = scene(group(group(b).rotate('x', 40)), perspective(), true);
 354 
 355         makeParallel(s, 0, 0);
 356         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 357 
 358         MouseEvent e = me.event;
 359         assertNotNull(e);
 360         assertCoordinates(e, 50, -41.95498, 0);
 361         assertPickResult(e.getPickResult(),
 362                 b, point(50, -41.95498, 0), 934.729635, NOFACE, point(0.5, 0.290226));
 363     }
 364 
 365     @Test
 366     public void shouldNotPickBoxOutside() {
 367         Node b = box().handleMove(me);
 368         b.setTranslateX(300);
 369         Scene s = scene(group(b), perspective(), true);
 370         makeParallel(s, 10, 20);
 371         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 372         makeParallel(s, 1000, 20);
 373         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 374         makeParallel(s, 10, -500);
 375         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 376         makeParallel(s, 10, 500);
 377         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 378 
 379         MouseEvent e = me.event;
 380         assertNull(e);
 381     }
 382 
 383     @Test
 384     public void shouldNotPickRotatedBoxOutside() {
 385         Node b = box().rotate('y', 30).handleMove(me);
 386         b.setTranslateX(300);
 387         Scene s = scene(group(b), perspective(), true);
 388         makeParallel(s, 10, 20);
 389         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 390         makeParallel(s, 1000, 20);
 391         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 392         makeParallel(s, 300, -500);
 393         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 394         makeParallel(s, 300, 500);
 395         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 396 
 397         MouseEvent e = me.event;
 398         assertNull(e);
 399     }
 400 
 401     @Test
 402     public void shouldPickBoxOnBounds() {
 403         Box b = box().handleMove(me);
 404         b.setPickOnBounds(true);
 405         Scene s = scene(group(b), perspective(), true);
 406 
 407         makeParallel(s, 10, 40);
 408         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 409 
 410         MouseEvent e = me.event;
 411         assertNotNull(e);
 412         assertCoordinates(e, 10, 40, -200);
 413         assertPickResult(e.getPickResult(),
 414                 b, point(10, 40, -200), 800, NOFACE, null);
 415     }
 416 
 417     @Test
 418     public void shouldNotPickBoxFromInsideIfCulled() {
 419         Box b = box().handleMove(me);
 420         b.setCullFace(CullFace.BACK);
 421         Scene s = scene(group(b), perspective(), true);
 422         b.setTranslateZ(-1000);
 423         makeParallel(s, 10, 40);
 424         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 425 
 426         MouseEvent e = me.event;
 427         assertNull(e);
 428     }
 429 
 430     @Test
 431     public void shouldPickBoxInteriorByPerspectiveCameraFromInside() {
 432         Box b = box().handleMove(me);
 433         b.setCullFace(CullFace.NONE);
 434         b.setTranslateZ(-1000);
 435         Scene s = scene(group(b), perspective(), true);
 436         makeParallel(s, 10, 40);
 437         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 438 
 439         MouseEvent e = me.event;
 440         assertNotNull(e);
 441         assertCoordinates(e, 10, 40, 200);
 442         assertPickResult(e.getPickResult(),
 443                 b, point(10, 40, 200), 200, NOFACE, point(0.4, 0.7));
 444     }
 445 
 446     @Test
 447     public void shouldPickBoxByParallelCameraFromInside() {
 448         MouseEventGenerator g = new MouseEventGenerator();
 449         Box b = box().handleMove(me);
 450         b.setCullFace(CullFace.NONE);
 451         Scene s = scene(group(b), parallel(), true);
 452         b.setTranslateZ(PERSPECTIVE_CAMERA_Z);
 453         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 40));
 454 
 455         MouseEvent e = me.event;
 456         assertNotNull(e);
 457         assertCoordinates(e, 10, 40, 10, 40, 200);
 458         assertPickResult(e.getPickResult(),
 459                 b, point(10, 40, 200), 200, NOFACE, point(0.4, 0.7));
 460     }
 461 
 462     @Test
 463     public void shouldNotPickBoxByPerspectiveCameraFromBehind() {
 464         Box b = box().handleMove(me);
 465         b.setCullFace(CullFace.NONE);
 466         b.setTranslateZ(-3000);
 467         Scene s = scene(group(b), perspective(), true);
 468         makeParallel(s, 10, 40);
 469         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 470 
 471         MouseEvent e = me.event;
 472         assertNull(e);
 473     }
 474 
 475     @Test
 476     public void shouldNotPickBoxByParallelCameraFromBehind() {
 477         MouseEventGenerator g = new MouseEventGenerator();
 478         Box b = box().handleMove(me);
 479         b.setCullFace(CullFace.NONE);
 480         Scene s = scene(group(b), parallel(), true);
 481         b.setTranslateZ(-3000);
 482         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 40));
 483 
 484         MouseEvent e = me.event;
 485         assertNull(e);
 486     }
 487 
 488     @Test
 489     public void shouldPickBoxByFixedEye() {
 490         Box b = box().handleMove(me);
 491         b.setTranslateZ(250);
 492         b.setCullFace(CullFace.NONE);
 493         Scene s = scene(group(b), perspective(true), true);
 494 
 495         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
 496 
 497         MouseEvent e = me.event;
 498         assertNotNull(e);
 499         assertEquals(-200, e.getPickResult().getIntersectedPoint().getZ(), 0.0001);
 500     }
 501 
 502     @Test
 503     public void shouldNotPickBoxCloserThanNearClip() {
 504         Box b = box().handleMove(me);
 505         b.setTranslateZ(250);
 506         b.setCullFace(CullFace.NONE);
 507         Camera cam = perspective(true);
 508         cam.setNearClip(800);
 509         cam.setFarClip(1800);
 510 
 511         Scene s = scene(group(b), cam, true);
 512 
 513         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
 514 
 515         MouseEvent e = me.event;
 516         assertNull(e);
 517     }
 518 
 519     @Test
 520     public void shouldNotPickBoxFartherThanFarClip() {
 521         Box b = box().handleMove(me);
 522         b.setTranslateZ(250);
 523         b.setCullFace(CullFace.NONE);
 524         Camera cam = perspective(true);
 525         cam.setNearClip(10);
 526         cam.setFarClip(40);
 527 
 528         Scene s = scene(group(b), cam, true);
 529 
 530         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
 531 
 532         MouseEvent e = me.event;
 533         assertNull(e);
 534     }
 535 
 536     @Test
 537     public void shouldPickBoxInteriorBetweenClips() {
 538         Box b = box().handleMove(me);
 539         b.setTranslateZ(250);
 540         b.setCullFace(CullFace.NONE);
 541         Camera cam = perspective(true);
 542         cam.setNearClip(250);
 543         cam.setFarClip(1800);
 544 
 545         Scene s = scene(group(b), cam, true);
 546 
 547         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
 548 
 549         MouseEvent e = me.event;
 550         assertNotNull(e);
 551         assertEquals(200, e.getPickResult().getIntersectedPoint().getZ(), 0.0001);
 552     }
 553 
 554     /*****************  SPHERE picking ********************/
 555 
 556 
 557     @Test
 558     public void shouldPickSphereFromFront() {
 559         Sphere sph = sphere().handleMove(me);
 560         sph.setCullFace(CullFace.BACK);
 561         Scene s = scene(group(sph), perspective(), true);
 562         makeParallel(s, 10, 20);
 563         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 564 
 565         MouseEvent e = me.event;
 566         assertNotNull(e);
 567         assertCoordinates(e, 10, 20, -97.46794);
 568         assertPickResult(e.getPickResult(),
 569                 sph, point(10, 20, -97.46794), 902.53205, NOFACE, point(0.516273, 0.6));
 570     }
 571 
 572     @Test
 573     public void shouldPickSphereInteriorFromFront() {
 574         Sphere sph = sphere().handleMove(me);
 575         sph.setCullFace(CullFace.FRONT);
 576         Scene s = scene(group(sph), perspective(), true);
 577         makeParallel(s, 10, 20);
 578         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 579 
 580         MouseEvent e = me.event;
 581         assertNotNull(e);
 582         assertCoordinates(e, 10, 20, 97.46794);
 583         assertPickResult(e.getPickResult(),
 584                 sph, point(10, 20, 97.46794), 1097.46794, NOFACE, point(0.98373, 0.6));
 585     }
 586 
 587     @Test
 588     public void shouldPickNotCulledSphereFromFront() {
 589         Sphere sph = sphere().handleMove(me);
 590         sph.setCullFace(CullFace.NONE);
 591         Scene s = scene(group(sph), perspective(), true);
 592         makeParallel(s, 10, 20);
 593         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 594 
 595         MouseEvent e = me.event;
 596         assertNotNull(e);
 597         assertCoordinates(e, 10, 20, -97.46794);
 598         assertPickResult(e.getPickResult(),
 599                 sph, point(10, 20, -97.46794), 902.53205, NOFACE, point(0.516273, 0.6));
 600     }
 601 
 602     @Test
 603     public void shouldPickSphereFromBack() {
 604         Sphere sph = sphere().rotate('y', 180).handleMove(me);
 605         sph.setCullFace(CullFace.BACK);
 606         Scene s = scene(group(sph), perspective(), true);
 607         makeParallel(s, 10, 20);
 608         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 609 
 610         MouseEvent e = me.event;
 611         assertNotNull(e);
 612         assertCoordinates(e, -10, 20, 97.46794);
 613         assertPickResult(e.getPickResult(),
 614                 sph, point(-10, 20, 97.46794), 902.53205, NOFACE, point(0.01628, 0.6));
 615     }
 616 
 617     @Test
 618     public void shouldNotPickSphereOutside() {
 619         Node sph = sphere().handleMove(me);
 620         sph.setTranslateX(100);
 621         sph.setTranslateY(110);
 622         Scene s = scene(group(sph), perspective(), true);
 623         makeParallel(s, 10, 20);
 624         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 625 
 626         MouseEvent e = me.event;
 627         assertNull(e);
 628     }
 629 
 630     @Test
 631     public void shouldPickRoughSphere() {
 632         Sphere sph = sphereWith4Divs().handleMove(me);
 633         Scene s = scene(group(sph), perspective(), true);
 634         sph.impl_updatePeer();
 635         makeParallel(s, 50, 25);
 636         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 637 
 638         MouseEvent e = me.event;
 639         assertNotNull(e);
 640         assertCoordinates(e, 50, 25, -25);
 641         assertPickResult(e.getPickResult(),
 642                 sph, point(50, 25, -25), 975, NOFACE, point(0.59375, 0.62402));
 643     }
 644 
 645     @Test
 646     public void shouldNotPickRoughSphereOutsideOfItsTriangles() {
 647         Sphere sph = sphereWith4Divs().handleMove(me);
 648         Scene s = scene(group(sph), perspective(), true);
 649         sph.impl_updatePeer();
 650         makeParallel(s, 50, 60);
 651         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 652 
 653         MouseEvent e = me.event;
 654         assertNull(e);
 655     }
 656 
 657     @Test
 658     public void shouldPickRoughSphereFrontFaceInsideOfShape() {
 659         Sphere sph = sphereWith4Divs().handleMove(me);
 660         sph.setTranslateZ(-974);
 661         sph.setCullFace(CullFace.BACK);
 662         Scene s = scene(group(sph), perspective(), true);
 663         sph.impl_updatePeer();
 664         makeParallel(s, 50, 25);
 665         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 666 
 667         MouseEvent e = me.event;
 668         assertNotNull(e);
 669         assertCoordinates(e, 50, 25, -25);
 670         assertPickResult(e.getPickResult(),
 671                 sph, point(50, 25, -25), 1, NOFACE, point(0.59375, 0.62402));
 672     }
 673 
 674     @Test
 675     public void shouldNotPickSphereFromInsideIfCulled() {
 676         Sphere sph = sphere().handleMove(me);
 677         sph.setTranslateZ(-980);
 678         sph.setCullFace(CullFace.BACK);
 679         Scene s = scene(group(sph), perspective(), true);
 680         sph.impl_updatePeer();
 681         makeParallel(s, 50, 25);
 682         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 683 
 684         MouseEvent e = me.event;
 685         assertNull(e);
 686     }
 687 
 688     @Test
 689     public void shouldPickSphereOnBounds() {
 690         Sphere sph = sphere().handleMove(me);
 691         sph.setPickOnBounds(true);
 692         Scene s = scene(group(sph), perspective(), true);
 693         makeParallel(s, 10, 20);
 694         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 695 
 696         MouseEvent e = me.event;
 697         assertNotNull(e);
 698         assertCoordinates(e, 10, 20, -100);
 699         assertPickResult(e.getPickResult(),
 700                 sph, point(10, 20, -100), 900, NOFACE, null);
 701     }
 702 
 703     @Test
 704     public void shouldPickRoughSphereOnBounds() {
 705         Sphere sph = sphereWith4Divs().handleMove(me);
 706         sph.setPickOnBounds(true);
 707         Scene s = scene(group(sph), perspective(), true);
 708         makeParallel(s, 10, 20);
 709         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 710 
 711         MouseEvent e = me.event;
 712         assertNotNull(e);
 713         assertCoordinates(e, 10, 20, -100);
 714         assertPickResult(e.getPickResult(),
 715                 sph, point(10, 20, -100), 900, NOFACE, null);
 716     }
 717 
 718     @Test
 719     public void shouldPickSphereOnBoundsOutsideOfShape() {
 720         Sphere sph = sphere().handleMove(me);
 721         Scene s = scene(group(sph), perspective(), true);
 722         makeParallel(s, 99, 1);
 723         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 724         MouseEvent e = me.event;
 725         assertNotNull(e);
 726 
 727         sph.setPickOnBounds(true);
 728         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 729         e = me.event;
 730         assertNotNull(e);
 731         assertCoordinates(e, 99, 1, -100);
 732         assertPickResult(e.getPickResult(),
 733                 sph, point(99, 1, -100), 900, NOFACE, null);
 734     }
 735 
 736     @Test
 737     public void shouldPickSphereInteriorByPerspectiveCameraFromInside() {
 738         Sphere sph = sphere().handleMove(me);
 739         sph.setTranslateZ(-1000);
 740         sph.setCullFace(CullFace.NONE);
 741         Scene s = scene(group(sph), perspective(), true);
 742         makeParallel(s, 10, 20);
 743         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 744 
 745         MouseEvent e = me.event;
 746         assertNotNull(e);
 747         assertCoordinates(e, 10, 20, 97.46794);
 748         assertPickResult(e.getPickResult(),
 749                 sph, point(10, 20, 97.46794), 97.46794, NOFACE, point(0.98373, 0.6));
 750     }
 751 
 752     @Test
 753     public void shouldPickSphereByParallelCameraFromInside() {
 754         MouseEventGenerator g = new MouseEventGenerator();
 755         Sphere sph = sphere().handleMove(me);
 756         sph.setTranslateZ(PERSPECTIVE_CAMERA_Z + 80);
 757         sph.setCullFace(CullFace.NONE);
 758         Scene s = scene(group(sph), parallel(), true);
 759         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 20));
 760 
 761         MouseEvent e = me.event;
 762         assertNotNull(e);
 763         assertCoordinates(e, 10, 20, 10, 20, 97.46794);
 764         assertPickResult(e.getPickResult(),
 765                 sph, point(10, 20, 97.46794), 177.46794, NOFACE, point(0.98372, 0.6));
 766     }
 767 
 768     @Test
 769     public void shouldNotPickSphereByPerspectiveCameraFromBehind() {
 770         Sphere sph = sphere().handleMove(me);
 771         sph.setTranslateZ(-1098);
 772         sph.setCullFace(CullFace.NONE);
 773         Scene s = scene(group(sph), perspective(), true);
 774         makeParallel(s, 10, 20);
 775         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 776 
 777         MouseEvent e = me.event;
 778         assertNull(e);
 779     }
 780 
 781     @Test
 782     public void shouldNotPickSphereByParallelCameraFromBehind() {
 783         MouseEventGenerator g = new MouseEventGenerator();
 784         Sphere sph = sphere().handleMove(me);
 785         sph.setTranslateZ(PERSPECTIVE_CAMERA_Z - 98);
 786         sph.setCullFace(CullFace.NONE);
 787         Scene s = scene(group(sph), parallel(), true);
 788         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 20));
 789 
 790         MouseEvent e = me.event;
 791         assertNull(e);
 792     }
 793 
 794     @Test
 795     public void shouldPickSphereByFixedEye() {
 796         Sphere sp = sphere().handleMove(me);
 797         sp.setTranslateZ(150);
 798         sp.setCullFace(CullFace.NONE);
 799         Scene s = scene(group(sp), perspective(true), true);
 800 
 801         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
 802 
 803         MouseEvent e = me.event;
 804         assertNotNull(e);
 805         assertEquals(-100, e.getPickResult().getIntersectedPoint().getZ(), 0.0001);
 806     }
 807 
 808     @Test
 809     public void shouldNotPickSphereCloserThanNearClip() {
 810         Sphere sp = sphere().handleMove(me);
 811         sp.setTranslateZ(150);
 812         sp.setCullFace(CullFace.NONE);
 813         Camera cam = perspective(true);
 814         cam.setNearClip(800);
 815         cam.setFarClip(1800);
 816 
 817         Scene s = scene(group(sp), cam, true);
 818 
 819         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
 820 
 821         MouseEvent e = me.event;
 822         assertNull(e);
 823     }
 824 
 825     @Test
 826     public void shouldNotPickSphereFartherThanFarClip() {
 827         Sphere sp = sphere().handleMove(me);
 828         sp.setTranslateZ(150);
 829         sp.setCullFace(CullFace.NONE);
 830         Camera cam = perspective(true);
 831         cam.setNearClip(10);
 832         cam.setFarClip(40);
 833 
 834         Scene s = scene(group(sp), cam, true);
 835 
 836         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
 837 
 838         MouseEvent e = me.event;
 839         assertNull(e);
 840     }
 841 
 842     @Test
 843     public void shouldPickSphereInteriorBetweenClips() {
 844         Sphere sp = sphere().handleMove(me);
 845         sp.setTranslateZ(150);
 846         sp.setCullFace(CullFace.NONE);
 847         Camera cam = perspective(true);
 848         cam.setNearClip(150);
 849         cam.setFarClip(1800);
 850 
 851         Scene s = scene(group(sp), cam, true);
 852 
 853         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
 854 
 855         MouseEvent e = me.event;
 856         assertNotNull(e);
 857         assertEquals(100, e.getPickResult().getIntersectedPoint().getZ(), 0.0001);
 858     }
 859 
 860     /*****************  CYLINDER picking ********************/
 861 
 862 
 863     @Test
 864     public void shouldPickCylinderFromFront() {
 865         Cylinder c = cylinder().handleMove(me);
 866         c.setCullFace(CullFace.BACK);
 867         Scene s = scene(group(c), perspective(), true);
 868         makeParallel(s, 10, 20);
 869         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 870 
 871         MouseEvent e = me.event;
 872         assertNotNull(e);
 873         assertCoordinates(e, 10, 20, -48.98979);
 874         assertPickResult(e.getPickResult(),
 875                 c, point(10, 20, -48.98979), 951.01020, NOFACE, point(0.532048, 0.6));
 876     }
 877 
 878     @Test
 879     public void shouldPickCylinderInteriorFromFront() {
 880         Cylinder c = cylinder().handleMove(me);
 881         c.setCullFace(CullFace.FRONT);
 882         Scene s = scene(group(c), perspective(), true);
 883         makeParallel(s, 10, 20);
 884         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 885 
 886         MouseEvent e = me.event;
 887         assertNotNull(e);
 888         assertCoordinates(e, 10, 20, 48.98979);
 889         assertPickResult(e.getPickResult(),
 890                 c, point(10, 20, 48.98979), 1048.98979, NOFACE, point(0.96796, 0.6));
 891     }
 892 
 893     @Test
 894     public void shouldPickCylinderFromBack() {
 895         Cylinder c = cylinder().rotate('y', 180).handleMove(me);
 896         c.setCullFace(CullFace.BACK);
 897         Scene s = scene(group(c), perspective(), true);
 898         makeParallel(s, 10, 20);
 899         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 900 
 901         MouseEvent e = me.event;
 902         assertNotNull(e);
 903         assertCoordinates(e, -10, 20, 48.98979);
 904         assertPickResult(e.getPickResult(),
 905                 c, point(-10, 20, 48.98979), 951.01020, NOFACE, point(0.032048, 0.6));
 906     }
 907 
 908     @Test
 909     public void shouldPickNotCulledCylinderFromFront() {
 910         Cylinder c = cylinder().handleMove(me);
 911         c.setCullFace(CullFace.NONE);
 912         Scene s = scene(group(c), perspective(), true);
 913         makeParallel(s, 10, 20);
 914         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 915 
 916         MouseEvent e = me.event;
 917         assertNotNull(e);
 918         assertCoordinates(e, 10, 20, -48.98979);
 919         assertPickResult(e.getPickResult(),
 920                 c, point(10, 20, -48.98979), 951.01020, NOFACE, point(0.532048, 0.6));
 921     }
 922 
 923     @Test
 924     public void shouldPickCylinderFromTop() {
 925         Node c = cylinder().rotate('x', 90).handleMove(me);
 926         Scene s = scene(group(c), perspective(), true);
 927         makeParallel(s, 10, 20);
 928         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 929 
 930         MouseEvent e = me.event;
 931         assertNotNull(e);
 932         assertCoordinates(e, 10, -100, -20);
 933         assertPickResult(e.getPickResult(),
 934                 c, point(10, -100, -20), 900, NOFACE, point(0.6, 0.7));
 935     }
 936 
 937     @Test
 938     public void shouldPickCylinderInteriorFromTop() {
 939         Cylinder c = cylinder().rotate('x', 90).handleMove(me);
 940         c.setCullFace(CullFace.FRONT);
 941         Scene s = scene(group(c), perspective(), true);
 942         makeParallel(s, 10, 20);
 943         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 944 
 945         MouseEvent e = me.event;
 946         assertNotNull(e);
 947         assertCoordinates(e, 10, 100, -20);
 948         assertPickResult(e.getPickResult(),
 949                 c, point(10, 100, -20), 1100, NOFACE, point(0.6, 0.3));
 950     }
 951 
 952     @Test
 953     public void shouldPickNotCulledCylinderFromTop() {
 954         Cylinder c = cylinder().rotate('x', 90).handleMove(me);
 955         c.setCullFace(CullFace.NONE);
 956         Scene s = scene(group(c), perspective(), true);
 957         makeParallel(s, 10, 20);
 958         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 959 
 960         MouseEvent e = me.event;
 961         assertNotNull(e);
 962         assertCoordinates(e, 10, -100, -20);
 963         assertPickResult(e.getPickResult(),
 964                 c, point(10, -100, -20), 900, NOFACE, point(0.6, 0.7));
 965     }
 966 
 967     @Test
 968     public void shouldPickCylinderFromBottom() {
 969         Node c = cylinder().rotate('x', -90).handleMove(me);
 970         Scene s = scene(group(c), perspective(), true);
 971         makeParallel(s, 10, 20);
 972         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 973 
 974         MouseEvent e = me.event;
 975         assertNotNull(e);
 976         assertCoordinates(e, 10, 100, 20);
 977         assertPickResult(e.getPickResult(),
 978                 c, point(10, 100, 20), 900, NOFACE, point(0.6, 0.7));
 979     }
 980 
 981     @Test
 982     public void shouldNotPickCylinderAboveIt() {
 983         Node c = cylinder().handleMove(me);
 984         c.setTranslateY(130);
 985         Scene s = scene(group(c), perspective(), true);
 986         makeParallel(s, 10, 20);
 987         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 988         makeParallel(s, 10, 520);
 989         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
 990 
 991         MouseEvent e = me.event;
 992         assertNull(e);
 993     }
 994 
 995     @Test
 996     public void shouldNotPickCylinderNextToIt() {
 997         Node c = cylinder().rotate('y', 45).handleMove(me);
 998         c.setTranslateX(-48);
 999         Scene s = scene(group(c), perspective(), true);
1000         makeParallel(s, 10, 20);
1001         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1002 
1003         MouseEvent e = me.event;
1004         assertNull(e);
1005     }
1006 
1007     @Test
1008     public void shouldNotPickCylinderParallelToIt() {
1009         Node c = cylinder().rotate('x', 90).handleMove(me);
1010         Scene s = scene(group(c), perspective(), true);
1011         makeParallel(s, 48, 48);
1012         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1013         makeParallel(s, -48, 48);
1014         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1015         makeParallel(s, 48, -48);
1016         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1017         makeParallel(s, -48, -48);
1018         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1019         makeParallel(s, 148, 148);
1020         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1021         makeParallel(s, -148, 148);
1022         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1023         makeParallel(s, 148, -148);
1024         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1025         makeParallel(s, -148, -148);
1026         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1027 
1028         MouseEvent e = me.event;
1029         assertNull(e);
1030     }
1031 
1032     @Test
1033     public void shouldPickRoughCylinder() {
1034         Cylinder c = cylinderWith4Divs().handleMove(me);
1035         Scene s = scene(group(c), perspective(), true);
1036         c.impl_updatePeer();
1037         makeParallel(s, 10, 20);
1038         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1039 
1040         MouseEvent e = me.event;
1041         assertNotNull(e);
1042         assertCoordinates(e, 10, 20, -40);
1043         assertPickResult(e.getPickResult(),
1044                 c, point(10, 20, -40), 960, NOFACE, point(0.55, 0.59922));
1045     }
1046 
1047     @Test
1048     public void shouldNotPickRoughCylinderOutsideOfItsTriangles() {
1049         Cylinder c = cylinderWith4Divs().rotate('y', 45).handleMove(me);
1050         Scene s = scene(group(c), perspective(), true);
1051         c.impl_updatePeer();
1052         makeParallel(s, 48, 20);
1053         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1054 
1055         MouseEvent e = me.event;
1056         assertNull(e);
1057     }
1058 
1059     @Test
1060     public void shouldPickRoughCylinderFrontFaceInsideOfShape() {
1061         Cylinder c = cylinderWith4Divs().handleMove(me);
1062         c.setTranslateZ(-959);
1063         c.setCullFace(CullFace.BACK);
1064         Scene s = scene(group(c), perspective(), true);
1065         c.impl_updatePeer();
1066         makeParallel(s, 10, 20);
1067         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1068 
1069         MouseEvent e = me.event;
1070         assertNotNull(e);
1071         assertCoordinates(e, 10, 20, -40);
1072         assertPickResult(e.getPickResult(),
1073                 c, point(10, 20, -40), 1, NOFACE, point(0.55, 0.59922));
1074     }
1075 
1076     @Test
1077     public void shouldNotPickCylinderFromInsideIfCulled() {
1078         Cylinder c = cylinder().handleMove(me);
1079         c.setTranslateZ(-959);
1080         c.setCullFace(CullFace.BACK);
1081         Scene s = scene(group(c), perspective(), true);
1082         c.impl_updatePeer();
1083         makeParallel(s, 10, 20);
1084         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1085 
1086         MouseEvent e = me.event;
1087         assertNull(e);
1088     }
1089 
1090     @Test
1091     public void shouldPickCylinderOnBounds() {
1092         Cylinder c = cylinder().handleMove(me);
1093         c.setPickOnBounds(true);
1094         Scene s = scene(group(c), perspective(), true);
1095         makeParallel(s, 10, 20);
1096         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1097 
1098         MouseEvent e = me.event;
1099         assertNotNull(e);
1100         assertCoordinates(e, 10, 20, -50);
1101         assertPickResult(e.getPickResult(),
1102                 c, point(10, 20, -50), 950, NOFACE, null);
1103     }
1104 
1105     @Test
1106     public void shouldPickRoughCylinderOnBounds() {
1107         Cylinder c = cylinderWith4Divs().handleMove(me);
1108         c.setPickOnBounds(true);
1109         Scene s = scene(group(c), perspective(), true);
1110         makeParallel(s, 10, 20);
1111         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1112 
1113         MouseEvent e = me.event;
1114         assertNotNull(e);
1115         assertCoordinates(e, 10, 20, -50);
1116         assertPickResult(e.getPickResult(),
1117                 c, point(10, 20, -50), 950, NOFACE, null);
1118     }
1119 
1120     @Test
1121     public void shouldPickCylinderOnBoundsOutsideOfShape() {
1122         Node c = cylinder().rotate('x', 90).handleMove(me);
1123         Scene s = scene(group(c), perspective(), true);
1124         makeParallel(s, 49, 48);
1125         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1126         MouseEvent e = me.event;
1127         assertNull(e);
1128 
1129         c.setPickOnBounds(true);
1130         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1131         e = me.event;
1132         assertNotNull(e);
1133         assertCoordinates(e, 49, -100, -48);
1134         assertPickResult(e.getPickResult(),
1135                 c, point(49, -100, -48), 900, NOFACE, null);
1136     }
1137 
1138     @Test
1139     public void shouldPickCylinderInteriorByPerspectiveCameraFromInside() {
1140         Cylinder c = cylinder().handleMove(me);
1141         c.setTranslateZ(-1000);
1142         c.setCullFace(CullFace.NONE);
1143         Scene s = scene(group(c), perspective(), true);
1144         makeParallel(s, 10, 20);
1145         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1146 
1147         MouseEvent e = me.event;
1148         assertNotNull(e);
1149         assertCoordinates(e, 10, 20, 48.98979);
1150         assertPickResult(e.getPickResult(),
1151                 c, point(10, 20, 48.98979), 48.98979, NOFACE, point(0.96796, 0.6));
1152     }
1153 
1154     @Test
1155     public void shouldPickCylinderByParallelCameraFromInside() {
1156         MouseEventGenerator g = new MouseEventGenerator();
1157         Cylinder c = cylinder().handleMove(me);
1158         c.setTranslateZ(PERSPECTIVE_CAMERA_Z + 150);
1159         c.setCullFace(CullFace.NONE);
1160         Scene s = scene(group(c), parallel(), true);
1161         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 20));
1162 
1163         MouseEvent e = me.event;
1164         assertNotNull(e);
1165         assertCoordinates(e, 10, 20, 10, 20, 48.98979);
1166         assertPickResult(e.getPickResult(),
1167                 c, point(10, 20, 48.98979), 198.9898, NOFACE, point(0.967952, 0.6));
1168     }
1169 
1170     @Test
1171     public void shouldNotPickCylinderByPerspectiveCameraFromBehind() {
1172         Cylinder c = cylinder().handleMove(me);
1173         c.setTranslateZ(-1049);
1174         c.setCullFace(CullFace.NONE);
1175         Scene s = scene(group(c), perspective(), true);
1176         makeParallel(s, 10, 20);
1177         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1178 
1179         MouseEvent e = me.event;
1180         assertNull(e);
1181     }
1182 
1183     @Test
1184     public void shouldNotPickCylinderByParallelCameraFromBehind() {
1185         MouseEventGenerator g = new MouseEventGenerator();
1186         Cylinder c = cylinder().handleMove(me);
1187         c.setTranslateZ(PERSPECTIVE_CAMERA_Z - 49);
1188         c.setCullFace(CullFace.NONE);
1189         Scene s = scene(group(c), parallel(), true);
1190         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 20));
1191 
1192         MouseEvent e = me.event;
1193         assertNull(e);
1194     }
1195 
1196     @Test
1197     public void shouldPickCylinderByFixedEye() {
1198         Cylinder c = cylinder().handleMove(me);
1199         c.setTranslateZ(100);
1200         c.setCullFace(CullFace.NONE);
1201         Scene s = scene(group(c), perspective(true), true);
1202 
1203         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1204 
1205         MouseEvent e = me.event;
1206         assertNotNull(e);
1207         assertEquals(-50, e.getPickResult().getIntersectedPoint().getZ(), 0.0001);
1208     }
1209 
1210     @Test
1211     public void shouldPickCylinderCapByFixedEye() {
1212         Cylinder c = cylinder().rotate('x', 90).handleMove(me);
1213         c.setTranslateZ(150);
1214         c.setCullFace(CullFace.NONE);
1215         Scene s = scene(group(c), perspective(true), true);
1216 
1217         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1218 
1219         MouseEvent e = me.event;
1220         assertNotNull(e);
1221         assertEquals(-100, e.getPickResult().getIntersectedPoint().getY(), 0.0001);
1222     }
1223 
1224     @Test
1225     public void shouldNotPickCylinderCloserThanNearClip() {
1226         Cylinder c = cylinder().handleMove(me);
1227         c.setTranslateZ(100);
1228         c.setCullFace(CullFace.NONE);
1229         Camera cam = perspective(true);
1230         cam.setNearClip(800);
1231         cam.setFarClip(1800);
1232 
1233         Scene s = scene(group(c), cam, true);
1234 
1235         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1236 
1237         MouseEvent e = me.event;
1238         assertNull(e);
1239     }
1240 
1241     @Test
1242     public void shouldNotPickCylinderCapCloserThanNearClip() {
1243         Cylinder c = cylinder().rotate('x', 90).handleMove(me);
1244         c.setTranslateZ(150);
1245         c.setCullFace(CullFace.NONE);
1246         Camera cam = perspective(true);
1247         cam.setNearClip(800);
1248         cam.setFarClip(1800);
1249 
1250         Scene s = scene(group(c), cam, true);
1251 
1252         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1253 
1254         MouseEvent e = me.event;
1255         assertNull(e);
1256     }
1257 
1258     @Test
1259     public void shouldNotPickCylinderFartherThanFarClip() {
1260         Cylinder c = cylinder().handleMove(me);
1261         c.setTranslateZ(100);
1262         c.setCullFace(CullFace.NONE);
1263         Camera cam = perspective(true);
1264         cam.setNearClip(10);
1265         cam.setFarClip(40);
1266 
1267         Scene s = scene(group(c), cam, true);
1268 
1269         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1270 
1271         MouseEvent e = me.event;
1272         assertNull(e);
1273     }
1274 
1275     @Test
1276     public void shouldNotPickCylinderCapFartherThanFarClip() {
1277         Cylinder c = cylinder().rotate('x', 90).handleMove(me);
1278         c.setTranslateZ(150);
1279         c.setCullFace(CullFace.NONE);
1280         Camera cam = perspective(true);
1281         cam.setNearClip(10);
1282         cam.setFarClip(40);
1283 
1284         Scene s = scene(group(c), cam, true);
1285 
1286         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1287 
1288         MouseEvent e = me.event;
1289         assertNull(e);
1290     }
1291 
1292     @Test
1293     public void shouldPickCylinderInteriorBetweenClips() {
1294         Cylinder c = cylinder().handleMove(me);
1295         c.setTranslateZ(100);
1296         c.setCullFace(CullFace.NONE);
1297         Camera cam = perspective(true);
1298         cam.setNearClip(100);
1299         cam.setFarClip(1800);
1300 
1301         Scene s = scene(group(c), cam, true);
1302 
1303         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1304 
1305         MouseEvent e = me.event;
1306         assertNotNull(e);
1307         assertEquals(50, e.getPickResult().getIntersectedPoint().getZ(), 0.0001);
1308     }
1309 
1310     @Test
1311     public void shouldPickCylinderCapInteriorBetweenClips() {
1312         Cylinder c = cylinder().rotate('x', 90).handleMove(me);
1313         c.setTranslateZ(150);
1314         c.setCullFace(CullFace.NONE);
1315         Camera cam = perspective(true);
1316         cam.setNearClip(150);
1317         cam.setFarClip(1800);
1318 
1319         Scene s = scene(group(c), cam, true);
1320 
1321         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1322 
1323         MouseEvent e = me.event;
1324         assertNotNull(e);
1325         assertEquals(100, e.getPickResult().getIntersectedPoint().getY(), 0.0001);
1326     }
1327 
1328 
1329     /*****************  MESH picking ********************/
1330 
1331 
1332     @Test
1333     public void shouldPickMeshXY() {
1334         Node m = meshXY().handleMove(me);
1335         Scene s = scene(group(m), perspective(), true);
1336         makeParallel(s, 60, 20);
1337         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1338 
1339         MouseEvent e = me.event;
1340         assertNotNull(e);
1341         assertCoordinates(e, 60, 20, 0);
1342         assertPickResult(e.getPickResult(),
1343                 m, point(60, 20, 0), 1000, 0, point(0.6, 0.2));
1344     }
1345 
1346     @Test
1347     public void shouldNotPickMeshXYOutsideOfIt() {
1348         Node m = meshXY().handleMove(me);
1349         Scene s = scene(group(m), perspective(), true);
1350         makeParallel(s, 60, 70);
1351         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1352 
1353         MouseEvent e = me.event;
1354         assertNull(e);
1355     }
1356 
1357     @Test
1358     public void shouldNotPickCulledMeshXY() {
1359         MeshView m = meshXY().handleMove(me);
1360         m.setCullFace(CullFace.FRONT);
1361         Scene s = scene(group(m), perspective(), true);
1362         makeParallel(s, 60, 20);
1363         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1364 
1365         MouseEvent e = me.event;
1366         assertNull(e);
1367     }
1368 
1369     @Test
1370     public void shouldPickNotCulledMeshXY() {
1371         MeshView m = meshXY().handleMove(me);
1372         m.setCullFace(CullFace.NONE);
1373         Scene s = scene(group(m), perspective(), true);
1374         makeParallel(s, 60, 20);
1375         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1376 
1377         MouseEvent e = me.event;
1378         assertNotNull(e);
1379         assertCoordinates(e, 60, 20, 0);
1380         assertPickResult(e.getPickResult(),
1381                 m, point(60, 20, 0), 1000, 0, point(0.6, 0.2));
1382     }
1383 
1384     @Test
1385     public void shouldPickMeshXYParallel() {
1386         MeshView m = meshXYParallel().handleMove(me);
1387         m.setCullFace(CullFace.BACK);
1388         Scene s = scene(group(m), perspective(), true);
1389         makeParallel(s, 60, 20);
1390         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1391 
1392         MouseEvent e = me.event;
1393         assertNotNull(e);
1394         assertCoordinates(e, 60, 20, 7);
1395         assertPickResult(e.getPickResult(),
1396                 m, point(60, 20, 7), 1007, 0, point(0.6, 0.2));
1397     }
1398 
1399     @Test
1400     public void shouldPickMeshXYFlippedTexture() {
1401         Node m = meshXYFlippedTexture().handleMove(me);
1402         Scene s = scene(group(m), perspective(), true);
1403         makeParallel(s, 60, 20);
1404         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1405 
1406         MouseEvent e = me.event;
1407         assertNotNull(e);
1408         assertCoordinates(e, 60, 20, 7);
1409         assertPickResult(e.getPickResult(),
1410                 m, point(60, 20, 7), 1007, 0, point(0.4, 0.6));
1411     }
1412 
1413     @Test
1414     public void shouldNotPickMeshXYBack() {
1415         Node m = meshXYBack().handleMove(me);
1416         Scene s = scene(group(m), perspective(), true);
1417         makeParallel(s, 60, 20);
1418         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1419 
1420         MouseEvent e = me.event;
1421         assertNull(e);
1422     }
1423 
1424     @Test
1425     public void shouldPickMeshYZ() {
1426         Node m = meshYZ().rotate('y', 90).handleMove(me);
1427         Scene s = scene(group(m), perspective(), true);
1428         makeParallel(s, 10, 20);
1429         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1430 
1431         MouseEvent e = me.event;
1432         assertNotNull(e);
1433         assertCoordinates(e, 7, 20, 53);
1434         assertPickResult(e.getPickResult(),
1435                 m, point(7, 20, 53), 1050, 0, point(0.2, 0.53));
1436     }
1437 
1438     @Test
1439     public void shouldPickMeshGeneral() {
1440         Node m = meshGeneral().handleMove(me);
1441         Scene s = scene(group(m), perspective(), true);
1442         makeParallel(s, 10, 20);
1443         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1444 
1445         MouseEvent e = me.event;
1446         assertNotNull(e);
1447         assertCoordinates(e, 10, 20, 10);
1448         assertPickResult(e.getPickResult(),
1449                 m, point(10, 20, 10), 1010, 0, point(0.1, 0.2));
1450     }
1451 
1452     @Test
1453     public void shouldPickMeshGeneralStretchedTexture() {
1454         Node m = meshGeneralStretchedTexture().handleMove(me);
1455         Scene s = scene(group(m), perspective(), true);
1456         makeParallel(s, 10, 20);
1457         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1458 
1459         MouseEvent e = me.event;
1460         assertNotNull(e);
1461         assertCoordinates(e, 10, 20, 10);
1462         assertPickResult(e.getPickResult(),
1463                 m, point(10, 20, 10), 1010, 0, point(0.025, 0.1));
1464     }
1465 
1466     @Test
1467     public void shouldPickMeshOnBounds() {
1468         Node m = meshGeneral().handleMove(me);
1469         m.setPickOnBounds(true);
1470         Scene s = scene(group(m), perspective(), true);
1471         makeParallel(s, 10, 20);
1472         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1473 
1474         MouseEvent e = me.event;
1475         assertNotNull(e);
1476         assertCoordinates(e, 10, 20, 0);
1477         assertPickResult(e.getPickResult(),
1478                 m, point(10, 20, 0), 1000, NOFACE, null);
1479     }
1480 
1481     @Test
1482     public void shouldPickMeshOnBoundsOutsideOfTriangles() {
1483         Node m = meshGeneral().handleMove(me);
1484         Scene s = scene(group(m), perspective(), true);
1485 
1486         makeParallel(s, 90, 90);
1487         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1488         MouseEvent e = me.event;
1489         assertNull(e);
1490 
1491         m.setPickOnBounds(true);
1492         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1493         e = me.event;
1494         assertNotNull(e);
1495         assertCoordinates(e, 90, 90, 0);
1496         assertPickResult(e.getPickResult(),
1497                 m, point(90, 90, 0), 1000, NOFACE, null);
1498     }
1499 
1500     @Test
1501     public void shouldNotPickMeshXYByPerspectiveCameraFromBehind() {
1502         Node m = meshXY().handleMove(me);
1503         m.setTranslateZ(-3000);
1504         Scene s = scene(group(m), perspective(), true);
1505         makeParallel(s, 60, 20);
1506         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1507 
1508         MouseEvent e = me.event;
1509         assertNull(e);
1510     }
1511 
1512     @Test
1513     public void shouldNotPickMeshXYByParallelCameraFromBehind() {
1514         MouseEventGenerator g = new MouseEventGenerator();
1515         Node m = meshXY().handleMove(me);
1516         m.setTranslateZ(-3000);
1517         Scene s = scene(group(m), parallel(), true);
1518         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 60, 20));
1519 
1520         MouseEvent e = me.event;
1521         assertNull(e);
1522     }
1523 
1524     @Test
1525     public void shouldNotPickMeshGeneralByPerspectiveCameraFromBehind() {
1526         Node m = meshGeneral().handleMove(me);
1527         m.setTranslateZ(-1011);
1528         Scene s = scene(group(m), perspective(), true);
1529         makeParallel(s, 10, 20);
1530         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1531 
1532         MouseEvent e = me.event;
1533         assertNull(e);
1534     }
1535 
1536     @Test
1537     public void shouldNotPickMeshGeneralByParallelCameraFromBehind() {
1538         MouseEventGenerator g = new MouseEventGenerator();
1539         Node m = meshGeneral().handleMove(me);
1540         m.setTranslateZ(PERSPECTIVE_CAMERA_Z - 11);
1541         Scene s = scene(group(m), parallel(), true);
1542         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 20));
1543 
1544         MouseEvent e = me.event;
1545         assertNull(e);
1546     }
1547 
1548     @Test
1549     public void shouldPickMeshByFixedEye() {
1550         Node m = meshesXY().handleMove(me);
1551         m.setTranslateZ(50);
1552         Scene s = scene(group(m), perspective(true), true);
1553 
1554         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1555 
1556         MouseEvent e = me.event;
1557         assertNotNull(e);
1558         assertEquals(-7, e.getPickResult().getIntersectedPoint().getZ(), 0.0001);
1559         assertEquals(1, e.getPickResult().getIntersectedFace());
1560     }
1561 
1562     @Test
1563     public void shouldNotPickMeshCloserThanNearClip() {
1564         Node m = meshesXY().handleMove(me);
1565         m.setTranslateZ(50);
1566         Camera cam = perspective(true);
1567         cam.setNearClip(800);
1568         cam.setFarClip(1800);
1569 
1570         Scene s = scene(group(m), cam, true);
1571 
1572         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1573 
1574         MouseEvent e = me.event;
1575         assertNull(e);
1576     }
1577 
1578     @Test
1579     public void shouldNotPickMeshFartherThanFarClip() {
1580         Node m = meshesXY().handleMove(me);
1581         m.setTranslateZ(50);
1582         Camera cam = perspective(true);
1583         cam.setNearClip(10);
1584         cam.setFarClip(40);
1585 
1586         Scene s = scene(group(m), cam, true);
1587 
1588         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1589 
1590         MouseEvent e = me.event;
1591         assertNull(e);
1592     }
1593 
1594     @Test
1595     public void shouldPickMeshInteriorBetweenClips() {
1596         Node m = meshesXY().handleMove(me);
1597         m.setTranslateZ(50);
1598         Camera cam = perspective(true);
1599         cam.setNearClip(47);
1600         cam.setFarClip(1800);
1601 
1602         Scene s = scene(group(m), cam, true);
1603 
1604         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED, 500, 400));
1605 
1606         MouseEvent e = me.event;
1607         assertNotNull(e);
1608         assertEquals(0, e.getPickResult().getIntersectedPoint().getZ(), 0.0001);
1609         assertEquals(0, e.getPickResult().getIntersectedFace());
1610     }
1611 
1612     /*****************  DEPTH BUFFER ********************/
1613 
1614 
1615     @Test
1616     public void shouldPickNearestFace() {
1617         Node m = meshesXY().handleMove(me);
1618         Scene s = scene(group(m), perspective(), true);
1619         makeParallel(s, 60, 20);
1620         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1621 
1622         MouseEvent e = me.event;
1623         assertNotNull(e);
1624         assertCoordinates(e, 60, 20, -7);
1625         assertPickResult(e.getPickResult(),
1626                 m, point(60, 20, -7), 993, 1, point(0.6, 0.2));
1627     }
1628 
1629     @Test
1630     public void shouldPickNearestFace2() {
1631         Node m = meshesXY2().handleMove(me);
1632         Scene s = scene(group(m), perspective(), true);
1633         makeParallel(s, 60, 20);
1634         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1635 
1636         MouseEvent e = me.event;
1637         assertNotNull(e);
1638         assertCoordinates(e, 60, 20, -7);
1639         assertPickResult(e.getPickResult(),
1640                 m, point(60, 20, -7), 993, 0, point(0.6, 0.2));
1641     }
1642 
1643     @Test
1644     public void shouldPickNearestThroughBackFace() {
1645         Node m = meshesXYFacingEachOther().handleMove(me);
1646         Scene s = scene(group(m), perspective(), true);
1647         makeParallel(s, 60, 20);
1648         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1649 
1650         MouseEvent e = me.event;
1651         assertNotNull(e);
1652         assertCoordinates(e, 60, 20, 0);
1653         assertPickResult(e.getPickResult(),
1654                 m, point(60, 20, 0), 1000, 0, point(0.6, 0.2));
1655     }
1656 
1657     @Test
1658     public void shouldPickNearestBackIfNotCulled() {
1659         MeshView m = meshesXYFacingEachOther().handleMove(me);
1660         m.setCullFace(CullFace.NONE);
1661         Scene s = scene(group(m), perspective(), true);
1662         makeParallel(s, 60, 20);
1663         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1664 
1665         MouseEvent e = me.event;
1666         assertNotNull(e);
1667         assertCoordinates(e, 60, 20, -7);
1668         assertPickResult(e.getPickResult(),
1669                 m, point(60, 20, -7), 993, 1, point(0.6, 0.2));
1670     }
1671 
1672     @Test
1673     public void shouldNotPickShapesIfNearerPickExists() {
1674         MeshView m = meshXY().handleMove(me);
1675         m.setTranslateZ(-500);
1676         Scene s = scene(group(meshXY(), cylinder(), sphere(), box(), m), perspective(), true);
1677         makeParallel(s, 40, 10);
1678         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1679 
1680         MouseEvent e = me.event;
1681         assertNotNull(e);
1682         assertCoordinates(e, 40, 10, 0);
1683         assertPickResult(e.getPickResult(),
1684                 m, point(40, 10, 0), 500, 0, point(0.4, 0.1));
1685     }
1686 
1687     @Test
1688     public void shouldPickNearestShapeOfMany() {
1689         MeshView m = meshXY().handleMove(me);
1690         m.setTranslateZ(-500);
1691         m.setTranslateX(-30);
1692         Scene s = scene(group(m, box(), sphere(), cylinder(), meshXY()), perspective(), true);
1693         makeParallel(s, 30, 20);
1694         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1695 
1696         MouseEvent e = me.event;
1697         assertNotNull(e);
1698         assertCoordinates(e, 60, 20, 0);
1699         assertPickResult(e.getPickResult(),
1700                 m, point(60, 20, 0), 500, 0, point(0.6, 0.2));
1701     }
1702 
1703     @Test
1704     public void shouldPickNodeWithDepthTestDisabledCoveredBySibling() {
1705         MeshView m = meshXY();
1706         m.setTranslateZ(-500);
1707         m.setTranslateX(-30);
1708 
1709         Box b = box().handleMove(me);
1710         b.setDepthTest(DepthTest.DISABLE);
1711 
1712         Scene s = scene(group(m, b), perspective(), true);
1713         makeParallel(s, 30, 20);
1714         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1715 
1716         MouseEvent e = me.event;
1717         assertNotNull(e);
1718         assertCoordinates(e, 30, 20, -200);
1719         assertPickResult(e.getPickResult(),
1720                 b, point(30, 20, -200), 800, NOFACE, point(0.8, 0.6));
1721     }
1722 
1723     @Test
1724     public void shouldPickNodeCoveringCloserSiblingWithDepthTestDisabled() {
1725         MeshView m = meshXY();
1726         m.setTranslateZ(-500);
1727         m.setTranslateX(-30);
1728         m.setDepthTest(DepthTest.DISABLE);
1729 
1730         Box b = box().handleMove(me);
1731         b.setDepthTest(DepthTest.ENABLE);
1732 
1733         Scene s = scene(group(m, b), perspective(), true);
1734         makeParallel(s, 30, 20);
1735         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1736 
1737         MouseEvent e = me.event;
1738         assertNotNull(e);
1739         assertCoordinates(e, 30, 20, -200);
1740         assertPickResult(e.getPickResult(),
1741                 b, point(30, 20, -200), 800, NOFACE, point(0.8, 0.6));
1742     }
1743 
1744     @Test
1745     public void shouldPickNodeWithDisabledDepthtestCoveredByOtherNode() {
1746 
1747         Box closer = box();
1748         closer.setTranslateZ(-10);
1749 
1750         Box b = box().handleMove(me);
1751         b.setDepthTest(DepthTest.DISABLE);
1752 
1753         Scene s = scene(group(group(closer), group(b)), perspective(), true);
1754         makeParallel(s, 30, 20);
1755         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1756 
1757         MouseEvent e = me.event;
1758         assertNotNull(e);
1759         assertCoordinates(e, 30, 20, -200);
1760         assertPickResult(e.getPickResult(),
1761                 b, point(30, 20, -200), 800, NOFACE, point(0.8, 0.6));
1762     }
1763 
1764     @Test
1765     public void shouldPickNodeCoveringNodeWithDisabledDepthtest() {
1766 
1767         Box b1 = box();
1768 
1769         Box b = box();
1770         b.setDepthTest(DepthTest.DISABLE);
1771 
1772         Box b2 = box().handleMove(me);
1773         b2.setTranslateZ(-10);
1774 
1775         Scene s = scene(group(group(b1), group(b), group(b2)), perspective(), true);
1776         makeParallel(s, 30, 20);
1777         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1778 
1779         MouseEvent e = me.event;
1780         assertNotNull(e);
1781         assertCoordinates(e, 30, 20, -200);
1782         assertPickResult(e.getPickResult(),
1783                 b2, point(30, 20, -200), 790, NOFACE, point(0.8, 0.6));
1784     }
1785 
1786     @Test
1787     public void shouldPickByOrderIfParentsDepthTestDisabled() {
1788         MeshView m = meshXY();
1789         m.setTranslateZ(-500);
1790         m.setTranslateX(-30);
1791 
1792         Box b = box().handleMove(me);
1793 
1794         Group parent = group(m, b);
1795         parent.setDepthTest(DepthTest.DISABLE);
1796 
1797         Scene s = scene(parent, perspective(), true);
1798         makeParallel(s, 30, 20);
1799         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1800 
1801         MouseEvent e = me.event;
1802         assertNotNull(e);
1803         assertCoordinates(e, 30, 20, -200);
1804         assertPickResult(e.getPickResult(),
1805                 b, point(30, 20, -200), 800, NOFACE, point(0.8, 0.6));
1806     }
1807 
1808     @Test
1809     public void depthTestShouldHaveNoEffectWithoutDepthBuffer() {
1810         MeshView m = meshXY();
1811         m.setTranslateZ(-500);
1812         m.setTranslateX(-30);
1813         m.setDepthTest(DepthTest.ENABLE);
1814 
1815         Box b = box().handleMove(me);
1816         b.setDepthTest(DepthTest.ENABLE);
1817 
1818         Scene s = scene(group(m, b), perspective(), false);
1819         makeParallel(s, 30, 20);
1820         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1821 
1822         MouseEvent e = me.event;
1823         assertNotNull(e);
1824         assertCoordinates(e, 30, 20, -200);
1825         assertPickResult(e.getPickResult(),
1826                 b, point(30, 20, -200), 800, NOFACE, point(0.8, 0.6));
1827     }
1828 
1829     @Test
1830     public void disabledDepthTestShouldNotInfluencePickingIfNotPicked() {
1831 
1832         Box b1 = box().handleMove(me);
1833         b1.setDepthTest(DepthTest.ENABLE);
1834 
1835         Box b2 = box();
1836         b2.setTranslateX(500);
1837         b2.setDepthTest(DepthTest.DISABLE);
1838 
1839         Scene s = scene(group(b1, b2), perspective(), false);
1840         makeParallel(s, 30, 20);
1841         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1842 
1843         MouseEvent e = me.event;
1844         assertNotNull(e);
1845         assertCoordinates(e, 30, 20, -200);
1846         assertPickResult(e.getPickResult(),
1847                 b1, point(30, 20, -200), 800, NOFACE, point(0.8, 0.6));
1848     }
1849 
1850     @Test
1851     public void disabledDepthTestShouldNotInfluencePickingIfNotPickedByNonEmptyResult() {
1852 
1853         Box odd = box();
1854         odd.setTranslateZ(10);
1855 
1856         Box b1 = box().handleMove(me);
1857         b1.setDepthTest(DepthTest.ENABLE);
1858 
1859         Box b2 = box();
1860         b2.setTranslateX(500);
1861         b2.setDepthTest(DepthTest.DISABLE);
1862 
1863         Scene s = scene(group(b1, b2, odd), perspective(), true);
1864         makeParallel(s, 30, 20);
1865         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1866 
1867         MouseEvent e = me.event;
1868         assertNotNull(e);
1869         assertCoordinates(e, 30, 20, -200);
1870         assertPickResult(e.getPickResult(),
1871                 b1, point(30, 20, -200), 800, NOFACE, point(0.8, 0.6));
1872     }
1873 
1874 
1875 
1876 
1877     /*****************  SCENE picking ********************/
1878 
1879 
1880     @Test
1881     public void shouldPickScene() {
1882         Rectangle r = rect().handleMove(me);
1883 
1884         Group parent = group(r).handleMove(pme);
1885 
1886         Scene s = scene(parent, perspective(), true).handleMove(sme);
1887         makeParallel(s, 150, 160);
1888         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1889 
1890         assertNull(me.event);
1891         assertNull(pme.event);
1892 
1893         MouseEvent e = sme.event;
1894         assertNotNull(e);
1895         assertCoordinates(e, 150, 160, 0);
1896         assertPickResult(e.getPickResult(), null, point(150, 160, 0), 1000,
1897                 NOFACE, null);
1898     }
1899 
1900 
1901     /*****************  SHAPE COMBINATION picking ********************/
1902 
1903 
1904     @Test
1905     public void shouldPickFirstShapeWithoutDepthBuffer() {
1906         Node trg;
1907         Group root = group(sphere(), trg = cylinder());
1908         Scene s = scene(root, perspective(), false).handleMove(me);
1909         makeParallel(s, 0, 0);
1910         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1911 
1912         MouseEvent e = me.event;
1913         assertNotNull(e);
1914         assertSame(trg, e.getPickResult().getIntersectedNode());
1915     }
1916 
1917     @Test
1918     public void shouldPickNearestShapeWithDepthBuffer() {
1919         Node trg;
1920         Group root = group(trg = sphere(), cylinder());
1921         Scene s = scene(root, perspective(), true).handleMove(me);
1922         makeParallel(s, 0, 0);
1923         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1924 
1925         MouseEvent e = me.event;
1926         assertNotNull(e);
1927         assertSame(trg, e.getPickResult().getIntersectedNode());
1928     }
1929 
1930 
1931     /*****************  RECTANGLE 3D picking ********************/
1932 
1933 
1934     @Test
1935     public void shouldPickRectWithPickRay() {
1936         Rectangle r = rect().handleMove(me);
1937 
1938         Scene s = scene(group(r), perspective(), true);
1939         makeParallel(s, 50, 60);
1940         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1941 
1942         MouseEvent e = me.event;
1943         assertNotNull(e);
1944         assertCoordinates(e, 50, 60, 0);
1945         assertPickResult(e.getPickResult(),
1946                 r, point(50, 60, 0), 1000, NOFACE, null);
1947     }
1948 
1949     @Test
1950     public void localCoordinatesShouldBeCorrectDuringBubbling() {
1951         Rectangle r = rect().handleMove(me);
1952         r.setTranslateX(100);
1953         r.setTranslateZ(50);
1954 
1955         Group parent = group(r).handleMove(pme);
1956         parent.setTranslateZ(-20);
1957 
1958         Scene s = scene(parent, perspective(), true).handleMove(sme);
1959         makeParallel(s, 150, 60);
1960         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1961 
1962         MouseEvent e = me.event;
1963         assertNotNull(e);
1964         assertCoordinates(e, 50, 60, 0);
1965 
1966         e = pme.event;
1967         assertNotNull(e);
1968         assertCoordinates(e, 150, 60, 50);
1969 
1970         e = sme.event;
1971         assertNotNull(e);
1972         assertCoordinates(e, 150, 60, 30);
1973     }
1974 
1975 
1976     @Test
1977     public void shouldPickRectRotatedIn3D() {
1978         Rectangle r = rect().rotate('y', 45).handleMove(me);
1979 
1980         Scene s = scene(group(r), perspective(), true).handleMove(sme);
1981 
1982         makeParallel(s, 10, 50);
1983         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1984 
1985         MouseEvent e = me.event;
1986         assertNull(e);
1987 
1988         e = sme.event;
1989         assertNotNull(e);
1990         assertCoordinates(e, 10, 50, 0);
1991         assertPickResult(e.getPickResult(), null, point(10, 50, 0), 1000,
1992                 NOFACE, null);
1993         sme.clear();
1994 
1995         makeParallel(s, 30, 50);
1996         s.impl_processMouseEvent(generateMouseEvent(MouseEvent.MOUSE_MOVED));
1997         e = me.event;
1998         assertNotNull(e);
1999         assertCoordinates(e, 21.71572, 50, 0);
2000         assertPickResult(e.getPickResult(), r, point(21.71572, 50, 0), 1020,
2001                 NOFACE, null);
2002 
2003         e = sme.event;
2004         assertNotNull(e);
2005         assertCoordinates(e, 30, 50, 20);
2006         assertPickResult(e.getPickResult(), r, point(21.71572, 50, 0), 1020,
2007                 NOFACE, null);
2008     }
2009 
2010     @Test
2011     public void shouldPickRectTranslatedAlongZByParallelCamera() {
2012         MouseEventGenerator g = new MouseEventGenerator();
2013         Rectangle r = rect().handleMove(me);
2014         r.setTranslateZ(70);
2015 
2016         Scene s = scene(group(r), parallel(), true).handleMove(sme);
2017 
2018         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 50));
2019 
2020         MouseEvent e = me.event;
2021         assertNotNull(e);
2022         assertCoordinates(e, 10, 50, 10, 50, 0);
2023         assertPickResult(e.getPickResult(), r, point(10, 50, 0), 
2024                 1562.82032, NOFACE, null);
2025 
2026         e = sme.event;
2027         assertNotNull(e);
2028         assertCoordinates(e, 10, 50, 10, 50, 70);
2029         assertPickResult(e.getPickResult(), r, point(10, 50, 0),
2030                 1562.82032, NOFACE, null);
2031     }
2032 
2033     @Test
2034     public void shouldPickRectRotatedIn3DByParallelCamera() {
2035         MouseEventGenerator g = new MouseEventGenerator();
2036         Rectangle r = rect().rotate('y', 45).handleMove(me);
2037 
2038         Scene s = scene(group(r), parallel(), true).handleMove(sme);
2039 
2040         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 10, 50));
2041 
2042         MouseEvent e = me.event;
2043         assertNull(e);
2044 
2045         e = sme.event;
2046         assertNotNull(e);
2047         assertCoordinates(e, 10, 50, 10, 50, 0);
2048         assertPickResult(e.getPickResult(), null, point(10, 50, 0),
2049                 1492.82032, NOFACE, null);
2050         sme.clear();
2051 
2052         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 30, 50));
2053         e = me.event;
2054         assertNotNull(e);
2055         assertCoordinates(e, 30, 50, 21.71572, 50, 0);
2056         assertPickResult(e.getPickResult(), r, point(21.71572, 50, 0),
2057                 1512.82032, NOFACE, null);
2058 
2059         e = sme.event;
2060         assertNotNull(e);
2061         assertCoordinates(e, 30, 50, 30, 50, 20);
2062         assertPickResult(e.getPickResult(), r, point(21.71572, 50, 0),
2063                 1512.82032, NOFACE, null);
2064     }
2065 
2066     @Test
2067     public void shouldIgnoreRectangleCloserThanNearClip() {
2068 
2069         Camera cam = new PerspectiveCamera();
2070         cam.setNearClip(0.2);
2071         double nearClip = PERSPECTIVE_CAMERA_Z * 0.8;
2072 
2073         Rectangle r1 = rect().handleMove(me);
2074         r1.setTranslateX(PERSPECTIVE_CAMERA_X - 50);
2075         r1.setTranslateY(PERSPECTIVE_CAMERA_Y - 50);
2076         r1.setTranslateZ(nearClip - 0.1);
2077         Rectangle r2 = rect().handleMove(sme);
2078         r2.setTranslateX(PERSPECTIVE_CAMERA_X - 50);
2079         r2.setTranslateY(PERSPECTIVE_CAMERA_Y - 50);
2080         r2.setTranslateZ(nearClip + 0.1);
2081 
2082         Scene s = scene(group(r1, r2), cam, true);
2083 
2084         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(
2085                 MouseEvent.MOUSE_MOVED, 540, 440));
2086 
2087         assertNull(me.event);
2088         assertNotNull(sme.event);
2089     }
2090 
2091     @Test
2092     public void shouldIgnoreRectangleFartherThanFarClip() {
2093 
2094         Camera cam = new PerspectiveCamera();
2095         cam.setNearClip(0.1);
2096         cam.setFarClip(0.3);
2097         double far = PERSPECTIVE_CAMERA_Z * 0.7;
2098 
2099         Rectangle r = rect().handleMove(me);
2100         r.setTranslateX(PERSPECTIVE_CAMERA_X - 50);
2101         r.setTranslateY(PERSPECTIVE_CAMERA_Y - 50);
2102         r.setTranslateZ(far - 0.1);
2103 
2104         Scene s = scene(group(r), cam, true);
2105 
2106         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(
2107                 MouseEvent.MOUSE_MOVED, 540, 440));
2108         assertNotNull(me.event);
2109 
2110         me.clear();
2111         r.setTranslateZ(far + 0.1);
2112         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(
2113                 MouseEvent.MOUSE_MOVED, 540, 440));
2114         assertNull(me.event);
2115     }
2116 
2117     @Test
2118     public void shouldIgnoreRectangleCloserThanNearClipWithParallelCamera() {
2119 
2120         Camera cam = new ParallelCamera();
2121         cam.setNearClip(0.2);
2122         double nearClip = PERSPECTIVE_CAMERA_Z * 0.8;
2123 
2124         Rectangle r1 = rect().handleMove(me);
2125         r1.setTranslateZ(nearClip - 0.1);
2126 
2127         Rectangle r2 = rect().handleMove(sme);
2128         r2.setTranslateZ(nearClip + 0.1);
2129 
2130         Scene s = scene(group(r1, r2), cam, false);
2131 
2132         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(
2133                 MouseEvent.MOUSE_MOVED, 20, 20));
2134 
2135         assertNull(me.event);
2136         assertNotNull(sme.event);
2137     }
2138 
2139     @Test
2140     public void shouldIgnoreRectangleFartherThanFarClipWithParallelCamera() {
2141 
2142         Camera cam = new ParallelCamera();
2143         cam.setNearClip(0.1);
2144         cam.setFarClip(0.3);
2145         double far = PERSPECTIVE_CAMERA_Z * 0.7;
2146 
2147         Rectangle r = rect().handleMove(me);
2148         r.setTranslateZ(far - 0.1);
2149 
2150         Scene s = scene(group(r), cam, true);
2151 
2152         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(
2153                 MouseEvent.MOUSE_MOVED, 20, 20));
2154         assertNotNull(me.event);
2155 
2156         me.clear();
2157         r.setTranslateZ(far + 0.1);
2158         s.impl_processMouseEvent(MouseEventGenerator.generateMouseEvent(
2159                 MouseEvent.MOUSE_MOVED, 20, 20));
2160         assertNull(me.event);
2161     }
2162 
2163     /*****************  Scenegraph-generated events ********************/
2164 
2165     @Test
2166     public void shouldReportCorrectPickResultForClick() {
2167         MouseEventGenerator g = new MouseEventGenerator();
2168         Box b = box().handle(MouseEvent.MOUSE_CLICKED, me);
2169 
2170         Scene s = scene(group(b), perspective(), true);
2171 
2172         makeParallel(s, 20, 50);
2173         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_PRESSED,
2174                 PERSPECTIVE_CAMERA_X - 10, PERSPECTIVE_CAMERA_Y));
2175         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_RELEASED,
2176                 PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y));
2177 
2178         MouseEvent e = me.event;
2179         assertNotNull(e);
2180         assertCoordinates(e, 20, 50, -200);
2181         assertPickResult(e.getPickResult(), b, point(20, 50, -200), 800,
2182                 NOFACE, point(0.7, 0.75));
2183     }
2184 
2185     @Test
2186     public void shouldReportCorrectPickResultForEnteredExited() {
2187         MouseEventGenerator g = new MouseEventGenerator();
2188         Box b1 = box().handle(MouseEvent.MOUSE_EXITED, me);
2189         b1.setTranslateX(55);
2190         Box b2 = box().handle(MouseEvent.MOUSE_ENTERED, pme);
2191         b2.setTranslateX(100);
2192         b2.setTranslateZ(-1);
2193 
2194         Scene s = scene(group(b1, b2), perspective(), true);
2195 
2196         makeParallel(s, 70, 50);
2197         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_PRESSED,
2198                 PERSPECTIVE_CAMERA_X - 60, PERSPECTIVE_CAMERA_Y));
2199         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_RELEASED,
2200                 PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y));
2201 
2202         MouseEvent e = me.event;
2203         assertNotNull(e);
2204         assertCoordinates(e, 15, 50, -201);
2205         assertPickResult(e.getPickResult(), b2, point(-30, 50, -200), 799,
2206                 NOFACE, point(0.2, 0.75));
2207 
2208         e = pme.event;
2209         assertNotNull(e);
2210         assertCoordinates(e, -30, 50, -200);
2211         assertPickResult(e.getPickResult(), b2, point(-30, 50, -200), 799,
2212                 NOFACE, point(0.2, 0.75));
2213     }
2214 
2215     @Test
2216     public void shouldReportCorrectPickResultForDragDetected() {
2217         MouseEventGenerator g = new MouseEventGenerator();
2218         Box b = box().handle(MouseEvent.DRAG_DETECTED, me);
2219 
2220         Scene s = scene(group(b), perspective(), true);
2221 
2222         makeParallel(s, 20, 50);
2223         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_PRESSED,
2224                 PERSPECTIVE_CAMERA_X - 10, PERSPECTIVE_CAMERA_Y));
2225         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_DRAGGED,
2226                 PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y));
2227         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_RELEASED,
2228                 PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y));
2229 
2230         MouseEvent e = me.event;
2231         assertNotNull(e);
2232         assertCoordinates(e, 20, 50, -200);
2233         assertPickResult(e.getPickResult(), b, point(20, 50, -200), 800,
2234                 NOFACE, point(0.7, 0.75));
2235     }
2236 
2237 
2238 
2239     /*****************  PDR ********************/
2240 
2241 
2242     @Test
2243     public void shouldReportCorrectPickResultDuringPDR() {
2244         MouseEventGenerator g = new MouseEventGenerator();
2245         Box b1 = box().handleDrag(me);
2246         b1.setTranslateX(55);
2247         Box b2 = box();
2248         b2.setTranslateX(100);
2249         b2.setTranslateZ(-1);
2250 
2251         Scene s = scene(group(b1, b2), perspective(), true);
2252 
2253         makeParallel(s, 70, 50);
2254         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_PRESSED,
2255                 PERSPECTIVE_CAMERA_X - 60, PERSPECTIVE_CAMERA_Y));
2256         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_DRAGGED,
2257                 PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y));
2258         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_RELEASED,
2259                 PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y));
2260 
2261         MouseEvent e = me.event;
2262         assertNotNull(e);
2263         assertCoordinates(e, 15, 50, -201);
2264         assertPickResult(e.getPickResult(), b2, point(-30, 50, -200), 799,
2265                 NOFACE, point(0.2, 0.75));
2266     }
2267 
2268     @Test
2269     public void shouldReportCorrectPickResultForFullPDR() {
2270         EventHolder<MouseDragEvent> smde = new EventHolder<MouseDragEvent>();
2271         EventHolder<MouseDragEvent> tmde = new EventHolder<MouseDragEvent>();
2272         EventHolder<MouseDragEvent> tmde2 = new EventHolder<MouseDragEvent>();
2273 
2274         MouseEventGenerator g = new MouseEventGenerator();
2275         final Box b1 = box().handleFullPDR(MouseDragEvent.MOUSE_DRAG_EXITED, smde);
2276         b1.setTranslateX(55);
2277         b1.setOnDragDetected(new EventHandler<MouseEvent>() {
2278             @Override public void handle(MouseEvent event) {
2279                 b1.startFullDrag();
2280             }
2281         });
2282 
2283         Box b2 = box().handleFullPDR(MouseDragEvent.MOUSE_DRAG_ENTERED, tmde)
2284                 .handleFullPDR(MouseDragEvent.MOUSE_DRAG_OVER, tmde2);
2285         b2.setTranslateX(100);
2286         b2.setTranslateZ(-1);
2287 
2288         Scene s = scene(group(b1, b2), perspective(), true);
2289 
2290         makeParallel(s, 70, 50);
2291         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_PRESSED,
2292                 PERSPECTIVE_CAMERA_X - 60, PERSPECTIVE_CAMERA_Y));
2293         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_DRAGGED,
2294                 PERSPECTIVE_CAMERA_X - 60, PERSPECTIVE_CAMERA_Y + 10));
2295         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_DRAGGED,
2296                 PERSPECTIVE_CAMERA_X - 59, PERSPECTIVE_CAMERA_Y + 10));
2297         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_DRAGGED,
2298                 PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y));
2299         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_RELEASED,
2300                 PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y));
2301 
2302         MouseEvent e = smde.event;
2303         assertNotNull(e);
2304         assertCoordinates(e, 15, 50, -201);
2305         assertPickResult(e.getPickResult(), b2, point(-30, 50, -200), 799,
2306                 NOFACE, point(0.2, 0.75));
2307 
2308         e = tmde.event;
2309         assertNotNull(e);
2310         assertCoordinates(e, -30, 50, -200);
2311         assertPickResult(e.getPickResult(), b2, point(-30, 50, -200), 799,
2312                 NOFACE, point(0.2, 0.75));
2313 
2314         e = tmde.event;
2315         assertNotNull(e);
2316         assertCoordinates(e, -30, 50, -200);
2317         assertPickResult(e.getPickResult(), b2, point(-30, 50, -200), 799,
2318                 NOFACE, point(0.2, 0.75));
2319     }
2320 
2321 
2322     /***************** moving camera ********************/
2323 
2324     @Test
2325     public void takesPerspectiveCameraMovesIntoAccount() {
2326         MouseEventGenerator g = new MouseEventGenerator();
2327         Box b = box().handleMove(me);
2328         Camera cam = perspective();
2329         Group camGroup = group(cam);
2330         cam.setTranslateX(-143);
2331         camGroup.setTranslateX(123);
2332         cam.impl_updatePeer();
2333         cam.setTranslateX(-43);
2334         camGroup.setTranslateX(23);
2335         cam.impl_updatePeer();
2336 
2337         Scene s = scene(group(b), cam, true);
2338         s.getRoot().getChildren().add(camGroup);
2339         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 30, 40));
2340 
2341         MouseEvent e = me.event;
2342         assertNotNull(e);
2343         assertCoordinates(e, 30, 40, 50, 70.638298, -85.106383);
2344         assertPickResult(e.getPickResult(),
2345                 b, point(50, 70.638298, -85.106383), 1063.207158, NOFACE, point(0.287234, 0.853192));
2346     }
2347 
2348     @Test
2349     public void takesParallelCameraMovesIntoAccount() {
2350         MouseEventGenerator g = new MouseEventGenerator();
2351         Box b = box().handleMove(me);
2352         Camera cam = parallel();
2353         Group camGroup = group(cam);
2354         cam.setTranslateX(-143);
2355         camGroup.setTranslateX(123);
2356         cam.impl_updatePeer();
2357         cam.setTranslateX(-43);
2358         camGroup.setTranslateX(23);
2359         cam.impl_updatePeer();
2360 
2361         Scene s = scene(group(b), cam, true);
2362         s.getRoot().getChildren().add(camGroup);
2363         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 30, 40));
2364 
2365         MouseEvent e = me.event;
2366         assertNotNull(e);
2367         assertCoordinates(e, 30, 40, 10, 40, -200);
2368         assertPickResult(e.getPickResult(),
2369                 b, point(10, 40, -200), 1292.82032, NOFACE, point(0.6, 0.7));
2370     }
2371 
2372     /*****************   subscene   ********************/
2373 
2374     @Test
2375     public void BoxShouldBePickedInsideSubScene() {
2376         Group root = new Group();
2377         Scene scene = new Scene(root, 800, 800, false);
2378 
2379         Group subRoot = new Group();
2380         SubScene sub = new SubScene(subRoot, 700, 700, true, null);
2381         root.getChildren().add(sub);
2382 
2383         PerspectiveCamera cam = new PerspectiveCamera(true);
2384         sub.setCamera(cam);
2385 
2386         Box b = new Box();
2387         b.setTranslateZ(1.2);
2388         subRoot.getChildren().add(b);
2389 
2390         Stage stage = new Stage();
2391         stage.setScene(scene);
2392         stage.show();
2393 
2394         b.setOnMouseMoved(new EventHandler<MouseEvent>() {
2395             @Override public void handle(MouseEvent event) {
2396                 me.event = event;
2397             }
2398         });
2399 
2400         me.event = null;
2401 
2402         scene.impl_processMouseEvent(
2403                 MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED,
2404                 350, 350));
2405 
2406         assertNotNull(me.event);
2407     }
2408 
2409     /***************** helper stuff ********************/
2410 
2411     private MouseEvent generateMouseEvent(EventType<MouseEvent> type) {
2412         MouseEventGenerator g = new MouseEventGenerator();
2413         return g.generateMouseEvent(type, PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y);
2414     }
2415 
2416     /**
2417      * Moves the camera so that picking on point
2418      * [PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y] results in pick ray
2419      * with origin [x, y, -1000] and direction [0, 0, 1000].
2420      */
2421     private void makeParallel(Scene s, double x, double y) {
2422         if (!s.getRoot().getChildren().contains(s.getCamera())) {
2423             s.getRoot().getChildren().add(s.getCamera());
2424         }
2425         s.getCamera().setTranslateX(x - PERSPECTIVE_CAMERA_X);
2426         s.getCamera().setTranslateY(y - PERSPECTIVE_CAMERA_Y);
2427         s.getCamera().impl_updatePeer();
2428     }
2429 
2430     private Camera perspective() {
2431         return perspective(false);
2432     }
2433 
2434     private Camera perspective(boolean fixedEye) {
2435         PerspectiveCamera cam = new PerspectiveCamera(fixedEye);
2436         // this field of view makes camera Z position to be -1000
2437         cam.setFieldOfView(43.60281897);
2438         // this makes the near clip to be also at -1000
2439         cam.setNearClip(0.0);
2440         return cam;
2441     }
2442 
2443     private Camera parallel() {
2444         return new ParallelCamera();
2445     }
2446 
2447     private static TestRect rect() {
2448         return new TestRect();
2449     }
2450 
2451     private static TestBox box() {
2452         return new TestBox();
2453     }
2454 
2455     private static TestSphere sphere() {
2456         return new TestSphere();
2457     }
2458 
2459     private static TestSphere sphereWith4Divs() {
2460         return new TestSphere(4);
2461     }
2462 
2463     private static TestCylinder cylinder() {
2464         return new TestCylinder();
2465     }
2466 
2467     private static TestCylinder cylinderWith4Divs() {
2468         return new TestCylinder(4);
2469     }
2470 
2471     private static TestMesh meshXY() {
2472         return new TestMesh(
2473             new float[] {0f, 0f, 0f,   100f, 0f, 0f,   100f, 100f, 0f },
2474             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2475             new int[] {0, 0, 2, 2, 1, 1});
2476     }
2477 
2478     private static TestMesh meshXYParallel() {
2479         return new TestMesh(
2480             new float[] {0f, 0f, 7f,   100f, 0f, 7f,   100f, 100f, 7f },
2481             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2482             new int[] {0, 0, 2, 2, 1, 1});
2483     }
2484 
2485     private static TestMesh meshesXY() {
2486         return new TestMesh(
2487             new float[] {0f, 0f, 0f,   100f, 0f, 0f,   100f, 100f, 0f,
2488                          0f, 0f, -7f,   100f, 0f, -7f,   100f, 100f, -7f },
2489             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2490             new int[] {0, 0, 2, 2, 1, 1,
2491                        3, 0, 5, 2, 4, 1});
2492     }
2493 
2494     private static TestMesh meshesXY2() {
2495         return new TestMesh(
2496             new float[] {0f, 0f, 0f,   100f, 0f, 0f,   100f, 100f, 0f,
2497                          0f, 0f, -7f,   100f, 0f, -7f,   100f, 100f, -7f },
2498             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2499             new int[] {3, 0, 5, 2, 4, 1,
2500                        0, 0, 2, 2, 1, 1});
2501     }
2502 
2503     private static TestMesh meshesXYFacingEachOther() {
2504         return new TestMesh(
2505             new float[] {0f, 0f, 0f,   100f, 0f, 0f,   100f, 100f, 0f,
2506                          0f, 0f, -7f,   100f, 0f, -7f,   100f, 100f, -7f },
2507             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2508             new int[] {0, 0, 2, 2, 1, 1,
2509                        3, 0, 4, 1, 5, 2,});
2510     }
2511 
2512     private static TestMesh meshXYBack() {
2513         return new TestMesh(
2514             new float[] {0f, 0f, 7f,   100f, 0f, 7f,   100f, 100f, 7f },
2515             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2516             new int[] {0, 0, 1, 1, 2, 2});
2517     }
2518 
2519     private static TestMesh meshXYFlippedTexture() {
2520         return new TestMesh(
2521             new float[] {0f, 0f, 7f,   100f, 0f, 7f,   100f, 100f, 7f },
2522             new float[] {0f, 0f,   0f, 1f,   1f, 1f},
2523             new int[] {0, 0, 2, 1, 1, 2});
2524     }
2525 
2526     private static TestMesh meshYZ() {
2527         return new TestMesh(
2528             new float[] {7f, 0f, 0f,   7f, 0f, 100f,   7f, 100f, 100f },
2529             new float[] {0f, 0f,   0f, 1f,   1f, 1f},
2530             new int[] {0, 0, 2, 2, 1, 1});
2531     }
2532 
2533     private static TestMesh meshGeneral() {
2534         return new TestMesh(
2535             new float[] {0f, 100f, 0f,   100f, 0f, 100f,   0f, 0f, 0f },
2536             new float[] {0f, 1f,   1f, 0f,   0f, 0f},
2537             new int[] {0, 0, 1, 1, 2, 2});
2538     }
2539 
2540     private static TestMesh meshGeneralStretchedTexture() {
2541         return new TestMesh(
2542             new float[] {0f, 100f, 0f,   100f, 0f, 100f,   0f, 0f, 0f },
2543             new float[] {0f, 0.5f,   0.25f, 0f,   0f, 0f},
2544             new int[] {0, 0, 1, 1, 2, 2});
2545     }
2546 
2547     private static TestGroup group(Node... children) {
2548         return new TestGroup(children);
2549     }
2550 
2551     private Point3D point(double x, double y, double z) {
2552         return new Point3D(x, y, z);
2553     }
2554 
2555     private Point2D point(double x, double y) {
2556         return new Point2D(x, y);
2557     }
2558 
2559     private static TestScene scene(Parent root, Camera camera, boolean depthBuffer) {
2560         return new TestScene(root, camera, depthBuffer);
2561     }
2562 
2563     private static void doRotate(Node node, char ax, double angle) {
2564         Point3D axis = null;
2565         switch(ax) {
2566             case 'x': axis = Rotate.X_AXIS; break;
2567             case 'y': axis = Rotate.Y_AXIS; break;
2568             case 'z': axis = Rotate.Z_AXIS; break;
2569         }
2570         node.setRotationAxis(axis);
2571         node.setRotate(angle);
2572     }
2573 
2574     private static void doHandleMove(Node node, final EventHolder<MouseEvent> holder) {
2575         holder.event = null;
2576         node.setOnMouseMoved(new EventHandler<MouseEvent>() {
2577             @Override public void handle(MouseEvent event) {
2578                 holder.event = event;
2579             }
2580         });
2581     }
2582 
2583     private static class TestScene extends Scene {
2584 
2585         public TestScene(Parent root, Camera camera, boolean depthBuffer) {
2586             super(root, 1000, 800, depthBuffer);
2587             setCamera(camera);
2588             Stage stage = new Stage();
2589             stage.setScene(this);
2590             stage.show();
2591         }
2592 
2593         public TestScene handleMove(final EventHolder<MouseEvent> holder) {
2594             holder.event = null;
2595             setOnMouseMoved(new EventHandler<MouseEvent>() {
2596                 @Override public void handle(MouseEvent event) {
2597                     holder.event = event;
2598                 }
2599             });
2600             return this;
2601         }
2602     }
2603 
2604     private static class TestGroup extends Group {
2605         public TestGroup(Node... nodes) {
2606             super(nodes);
2607         }
2608 
2609         public TestGroup rotate(char ax, double angle) {
2610             doRotate(this, ax, angle);
2611             return this;
2612         }
2613 
2614         public TestGroup handleMove(final EventHolder<MouseEvent> holder) {
2615             doHandleMove(this, holder);
2616             return this;
2617         }
2618     }
2619 
2620     private static class TestRect extends Rectangle {
2621         public TestRect() {
2622             super(100, 100);
2623         }
2624 
2625         public TestRect rotate(char ax, double angle) {
2626             doRotate(this, ax, angle);
2627             return this;
2628         }
2629 
2630         public TestRect handleMove(final EventHolder<MouseEvent> holder) {
2631             doHandleMove(this, holder);
2632             return this;
2633         }
2634     }
2635 
2636     private static class TestBox extends Box {
2637         public TestBox() {
2638             super(100, 200, 400);
2639         }
2640 
2641         public TestBox rotate(char ax, double angle) {
2642             doRotate(this, ax, angle);
2643             return this;
2644         }
2645 
2646         public TestBox handleMove(final EventHolder<MouseEvent> holder) {
2647             doHandleMove(this, holder);
2648             return this;
2649         }
2650 
2651         public TestBox handleDrag(final EventHolder<MouseEvent> holder) {
2652             holder.event = null;
2653             setOnMouseDragged(new EventHandler<MouseEvent>() {
2654                 @Override public void handle(MouseEvent event) {
2655                     holder.event = event;
2656                 }
2657             });
2658             return this;
2659         }
2660 
2661         public TestBox handle(final EventType<MouseEvent> type,
2662                 final EventHolder<MouseEvent> holder) {
2663             holder.event = null;
2664             addEventHandler(type, new EventHandler<MouseEvent>() {
2665                 @Override public void handle(MouseEvent event) {
2666                     holder.event = event;
2667                 }
2668             });
2669             return this;
2670         }
2671 
2672         public TestBox handleFullPDR(final EventType<MouseDragEvent> type,
2673                 final EventHolder<MouseDragEvent> holder) {
2674             holder.event = null;
2675             addEventHandler(type, new EventHandler<MouseDragEvent>() {
2676                 @Override public void handle(MouseDragEvent event) {
2677                     holder.event = event;
2678                 }
2679             });
2680             return this;
2681         }
2682     }
2683 
2684     private static class TestSphere extends Sphere {
2685         public TestSphere() {
2686             super(100);
2687         }
2688 
2689         public TestSphere(int divs) {
2690             super(100, divs);
2691         }
2692 
2693         public TestSphere rotate(char ax, double angle) {
2694             doRotate(this, ax, angle);
2695             return this;
2696         }
2697 
2698         public TestSphere handleMove(final EventHolder<MouseEvent> holder) {
2699             doHandleMove(this, holder);
2700             return this;
2701         }
2702     }
2703 
2704     private static class TestCylinder extends Cylinder {
2705         public TestCylinder() {
2706             super(50, 200);
2707         }
2708 
2709         public TestCylinder(int divs) {
2710             super(50, 200, divs);
2711         }
2712 
2713         public TestCylinder rotate(char ax, double angle) {
2714             doRotate(this, ax, angle);
2715             return this;
2716         }
2717 
2718         public TestCylinder handleMove(final EventHolder<MouseEvent> holder) {
2719             doHandleMove(this, holder);
2720             return this;
2721         }
2722     }
2723 
2724     private static class TestMesh extends MeshView {
2725         public TestMesh(float[] points, float[] tex, int[] faces) {
2726             super(new TriangleMesh());
2727             TriangleMesh mesh = (TriangleMesh)getMesh();
2728             mesh.getPoints().setAll(points);
2729             mesh.getTexCoords().setAll(tex);
2730             mesh.getFaces().setAll(faces);
2731         }
2732 
2733         public TestMesh rotate(char ax, double angle) {
2734             doRotate(this, ax, angle);
2735             return this;
2736         }
2737 
2738         public TestMesh handleMove(final EventHolder<MouseEvent> holder) {
2739             doHandleMove(this, holder);
2740             return this;
2741         }
2742     }
2743 
2744     private static class EventHolder<T extends Event> {
2745         public T event = null;
2746 
2747         public void clear() {
2748             event = null;
2749         }
2750     }
2751 
2752     private void assertCoordinates(MouseEvent e, double sceneX, double sceneY,
2753             double x, double y, double z) {
2754         assertEquals(sceneX, e.getSceneX(), 0.00001);
2755         assertEquals(sceneY, e.getSceneY(), 0.00001);
2756         assertEquals(x, e.getX(), 0.00001);
2757         assertEquals(y, e.getY(), 0.00001);
2758         assertEquals(z, e.getZ(), 0.00001);
2759     }
2760 
2761     private void assertCoordinates(MouseEvent e,
2762             double x, double y, double z) {
2763         assertEquals(PERSPECTIVE_CAMERA_X, e.getSceneX(), 0.00001);
2764         assertEquals(PERSPECTIVE_CAMERA_Y, e.getSceneY(), 0.00001);
2765         assertEquals(x, e.getX(), 0.00001);
2766         assertEquals(y, e.getY(), 0.00001);
2767         assertEquals(z, e.getZ(), 0.00001);
2768     }
2769 
2770     private void assertPickResult(PickResult res, Node n, Point3D p,
2771             double distance, int face, Point2D tex) {
2772         assertSame(n, res.getIntersectedNode());
2773         assertEquals(p.getX(), res.getIntersectedPoint().getX(), 0.00001);
2774         assertEquals(p.getY(), res.getIntersectedPoint().getY(), 0.00001);
2775         assertEquals(p.getZ(), res.getIntersectedPoint().getZ(), 0.00001);
2776         assertEquals(distance, res.getIntersectedDistance(), 0.00001);
2777         assertEquals(face, res.getIntersectedFace());
2778         if (tex == null) {
2779             assertNull(res.getIntersectedTexCoord());
2780         } else {
2781             assertEquals(tex.getX(), res.getIntersectedTexCoord().getX(), 0.00001);
2782             assertEquals(tex.getY(), res.getIntersectedTexCoord().getY(), 0.00001);
2783         }
2784     }
2785 
2786 }