1 /*
   2  * Copyright (c) 2012, 2015, 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.65625, 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.65625, 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(event -> b1.startFullDrag());
2278 
2279         Box b2 = box().handleFullPDR(MouseDragEvent.MOUSE_DRAG_ENTERED, tmde)
2280                 .handleFullPDR(MouseDragEvent.MOUSE_DRAG_OVER, tmde2);
2281         b2.setTranslateX(100);
2282         b2.setTranslateZ(-1);
2283 
2284         Scene s = scene(group(b1, b2), perspective(), true);
2285 
2286         makeParallel(s, 70, 50);
2287         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_PRESSED,
2288                 PERSPECTIVE_CAMERA_X - 60, PERSPECTIVE_CAMERA_Y));
2289         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_DRAGGED,
2290                 PERSPECTIVE_CAMERA_X - 60, PERSPECTIVE_CAMERA_Y + 10));
2291         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_DRAGGED,
2292                 PERSPECTIVE_CAMERA_X - 59, PERSPECTIVE_CAMERA_Y + 10));
2293         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_DRAGGED,
2294                 PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y));
2295         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_RELEASED,
2296                 PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y));
2297 
2298         MouseEvent e = smde.event;
2299         assertNotNull(e);
2300         assertCoordinates(e, 15, 50, -201);
2301         assertPickResult(e.getPickResult(), b2, point(-30, 50, -200), 799,
2302                 NOFACE, point(0.2, 0.75));
2303 
2304         e = tmde.event;
2305         assertNotNull(e);
2306         assertCoordinates(e, -30, 50, -200);
2307         assertPickResult(e.getPickResult(), b2, point(-30, 50, -200), 799,
2308                 NOFACE, point(0.2, 0.75));
2309 
2310         e = tmde.event;
2311         assertNotNull(e);
2312         assertCoordinates(e, -30, 50, -200);
2313         assertPickResult(e.getPickResult(), b2, point(-30, 50, -200), 799,
2314                 NOFACE, point(0.2, 0.75));
2315     }
2316 
2317 
2318     /***************** moving camera ********************/
2319 
2320     @Test
2321     public void takesPerspectiveCameraMovesIntoAccount() {
2322         MouseEventGenerator g = new MouseEventGenerator();
2323         Box b = box().handleMove(me);
2324         Camera cam = perspective();
2325         Group camGroup = group(cam);
2326         cam.setTranslateX(-143);
2327         camGroup.setTranslateX(123);
2328         cam.impl_updatePeer();
2329         cam.setTranslateX(-43);
2330         camGroup.setTranslateX(23);
2331         cam.impl_updatePeer();
2332 
2333         Scene s = scene(group(b), cam, true);
2334         s.getRoot().getChildren().add(camGroup);
2335         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 30, 40));
2336 
2337         MouseEvent e = me.event;
2338         assertNotNull(e);
2339         assertCoordinates(e, 30, 40, 50, 70.638298, -85.106383);
2340         assertPickResult(e.getPickResult(),
2341                 b, point(50, 70.638298, -85.106383), 1063.207158, NOFACE, point(0.287234, 0.853192));
2342     }
2343 
2344     @Test
2345     public void takesParallelCameraMovesIntoAccount() {
2346         MouseEventGenerator g = new MouseEventGenerator();
2347         Box b = box().handleMove(me);
2348         Camera cam = parallel();
2349         Group camGroup = group(cam);
2350         cam.setTranslateX(-143);
2351         camGroup.setTranslateX(123);
2352         cam.impl_updatePeer();
2353         cam.setTranslateX(-43);
2354         camGroup.setTranslateX(23);
2355         cam.impl_updatePeer();
2356 
2357         Scene s = scene(group(b), cam, true);
2358         s.getRoot().getChildren().add(camGroup);
2359         s.impl_processMouseEvent(g.generateMouseEvent(MouseEvent.MOUSE_MOVED, 30, 40));
2360 
2361         MouseEvent e = me.event;
2362         assertNotNull(e);
2363         assertCoordinates(e, 30, 40, 10, 40, -200);
2364         assertPickResult(e.getPickResult(),
2365                 b, point(10, 40, -200), 1292.82032, NOFACE, point(0.6, 0.7));
2366     }
2367 
2368     /*****************   subscene   ********************/
2369 
2370     @Test
2371     public void BoxShouldBePickedInsideSubScene() {
2372         Group root = new Group();
2373         Scene scene = new Scene(root, 800, 800, false);
2374 
2375         Group subRoot = new Group();
2376         SubScene sub = new SubScene(subRoot, 700, 700, true, null);
2377         root.getChildren().add(sub);
2378 
2379         PerspectiveCamera cam = new PerspectiveCamera(true);
2380         sub.setCamera(cam);
2381 
2382         Box b = new Box();
2383         b.setTranslateZ(1.2);
2384         subRoot.getChildren().add(b);
2385 
2386         Stage stage = new Stage();
2387         stage.setScene(scene);
2388         stage.show();
2389 
2390         b.setOnMouseMoved(event -> {
2391             me.event = event;
2392         });
2393 
2394         me.event = null;
2395 
2396         scene.impl_processMouseEvent(
2397                 MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_MOVED,
2398                 350, 350));
2399 
2400         assertNotNull(me.event);
2401     }
2402 
2403     /***************** helper stuff ********************/
2404 
2405     private MouseEvent generateMouseEvent(EventType<MouseEvent> type) {
2406         MouseEventGenerator g = new MouseEventGenerator();
2407         return g.generateMouseEvent(type, PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y);
2408     }
2409 
2410     /**
2411      * Moves the camera so that picking on point
2412      * [PERSPECTIVE_CAMERA_X, PERSPECTIVE_CAMERA_Y] results in pick ray
2413      * with origin [x, y, -1000] and direction [0, 0, 1000].
2414      */
2415     private void makeParallel(Scene s, double x, double y) {
2416         if (!s.getRoot().getChildren().contains(s.getCamera())) {
2417             s.getRoot().getChildren().add(s.getCamera());
2418         }
2419         s.getCamera().setTranslateX(x - PERSPECTIVE_CAMERA_X);
2420         s.getCamera().setTranslateY(y - PERSPECTIVE_CAMERA_Y);
2421         s.getCamera().impl_updatePeer();
2422     }
2423 
2424     private Camera perspective() {
2425         return perspective(false);
2426     }
2427 
2428     private Camera perspective(boolean fixedEye) {
2429         PerspectiveCamera cam = new PerspectiveCamera(fixedEye);
2430         // this field of view makes camera Z position to be -1000
2431         cam.setFieldOfView(43.60281897);
2432         // this makes the near clip to be also at -1000
2433         cam.setNearClip(0.0);
2434         return cam;
2435     }
2436 
2437     private Camera parallel() {
2438         return new ParallelCamera();
2439     }
2440 
2441     private static TestRect rect() {
2442         return new TestRect();
2443     }
2444 
2445     private static TestBox box() {
2446         return new TestBox();
2447     }
2448 
2449     private static TestSphere sphere() {
2450         return new TestSphere();
2451     }
2452 
2453     private static TestSphere sphereWith4Divs() {
2454         return new TestSphere(4);
2455     }
2456 
2457     private static TestCylinder cylinder() {
2458         return new TestCylinder();
2459     }
2460 
2461     private static TestCylinder cylinderWith4Divs() {
2462         return new TestCylinder(4);
2463     }
2464 
2465     private static TestMesh meshXY() {
2466         return new TestMesh(
2467             new float[] {0f, 0f, 0f,   100f, 0f, 0f,   100f, 100f, 0f },
2468             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2469             new int[] {0, 0, 2, 2, 1, 1});
2470     }
2471 
2472     private static TestMesh meshXYParallel() {
2473         return new TestMesh(
2474             new float[] {0f, 0f, 7f,   100f, 0f, 7f,   100f, 100f, 7f },
2475             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2476             new int[] {0, 0, 2, 2, 1, 1});
2477     }
2478 
2479     private static TestMesh meshesXY() {
2480         return new TestMesh(
2481             new float[] {0f, 0f, 0f,   100f, 0f, 0f,   100f, 100f, 0f,
2482                          0f, 0f, -7f,   100f, 0f, -7f,   100f, 100f, -7f },
2483             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2484             new int[] {0, 0, 2, 2, 1, 1,
2485                        3, 0, 5, 2, 4, 1});
2486     }
2487 
2488     private static TestMesh meshesXY2() {
2489         return new TestMesh(
2490             new float[] {0f, 0f, 0f,   100f, 0f, 0f,   100f, 100f, 0f,
2491                          0f, 0f, -7f,   100f, 0f, -7f,   100f, 100f, -7f },
2492             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2493             new int[] {3, 0, 5, 2, 4, 1,
2494                        0, 0, 2, 2, 1, 1});
2495     }
2496 
2497     private static TestMesh meshesXYFacingEachOther() {
2498         return new TestMesh(
2499             new float[] {0f, 0f, 0f,   100f, 0f, 0f,   100f, 100f, 0f,
2500                          0f, 0f, -7f,   100f, 0f, -7f,   100f, 100f, -7f },
2501             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2502             new int[] {0, 0, 2, 2, 1, 1,
2503                        3, 0, 4, 1, 5, 2,});
2504     }
2505 
2506     private static TestMesh meshXYBack() {
2507         return new TestMesh(
2508             new float[] {0f, 0f, 7f,   100f, 0f, 7f,   100f, 100f, 7f },
2509             new float[] {0f, 0f,   1f, 0f,   1f, 1f},
2510             new int[] {0, 0, 1, 1, 2, 2});
2511     }
2512 
2513     private static TestMesh meshXYFlippedTexture() {
2514         return new TestMesh(
2515             new float[] {0f, 0f, 7f,   100f, 0f, 7f,   100f, 100f, 7f },
2516             new float[] {0f, 0f,   0f, 1f,   1f, 1f},
2517             new int[] {0, 0, 2, 1, 1, 2});
2518     }
2519 
2520     private static TestMesh meshYZ() {
2521         return new TestMesh(
2522             new float[] {7f, 0f, 0f,   7f, 0f, 100f,   7f, 100f, 100f },
2523             new float[] {0f, 0f,   0f, 1f,   1f, 1f},
2524             new int[] {0, 0, 2, 2, 1, 1});
2525     }
2526 
2527     private static TestMesh meshGeneral() {
2528         return new TestMesh(
2529             new float[] {0f, 100f, 0f,   100f, 0f, 100f,   0f, 0f, 0f },
2530             new float[] {0f, 1f,   1f, 0f,   0f, 0f},
2531             new int[] {0, 0, 1, 1, 2, 2});
2532     }
2533 
2534     private static TestMesh meshGeneralStretchedTexture() {
2535         return new TestMesh(
2536             new float[] {0f, 100f, 0f,   100f, 0f, 100f,   0f, 0f, 0f },
2537             new float[] {0f, 0.5f,   0.25f, 0f,   0f, 0f},
2538             new int[] {0, 0, 1, 1, 2, 2});
2539     }
2540 
2541     private static TestGroup group(Node... children) {
2542         return new TestGroup(children);
2543     }
2544 
2545     private Point3D point(double x, double y, double z) {
2546         return new Point3D(x, y, z);
2547     }
2548 
2549     private Point2D point(double x, double y) {
2550         return new Point2D(x, y);
2551     }
2552 
2553     private static TestScene scene(Parent root, Camera camera, boolean depthBuffer) {
2554         return new TestScene(root, camera, depthBuffer);
2555     }
2556 
2557     private static void doRotate(Node node, char ax, double angle) {
2558         Point3D axis = null;
2559         switch(ax) {
2560             case 'x': axis = Rotate.X_AXIS; break;
2561             case 'y': axis = Rotate.Y_AXIS; break;
2562             case 'z': axis = Rotate.Z_AXIS; break;
2563         }
2564         node.setRotationAxis(axis);
2565         node.setRotate(angle);
2566     }
2567 
2568     private static void doHandleMove(Node node, final EventHolder<MouseEvent> holder) {
2569         holder.event = null;
2570         node.setOnMouseMoved(event -> {
2571             holder.event = event;
2572         });
2573     }
2574 
2575     private static class TestScene extends Scene {
2576 
2577         public TestScene(Parent root, Camera camera, boolean depthBuffer) {
2578             super(root, 1000, 800, depthBuffer);
2579             setCamera(camera);
2580             Stage stage = new Stage();
2581             stage.setScene(this);
2582             stage.show();
2583         }
2584 
2585         public TestScene handleMove(final EventHolder<MouseEvent> holder) {
2586             holder.event = null;
2587             setOnMouseMoved(event -> {
2588                 holder.event = event;
2589             });
2590             return this;
2591         }
2592     }
2593 
2594     private static class TestGroup extends Group {
2595         public TestGroup(Node... nodes) {
2596             super(nodes);
2597         }
2598 
2599         public TestGroup rotate(char ax, double angle) {
2600             doRotate(this, ax, angle);
2601             return this;
2602         }
2603 
2604         public TestGroup handleMove(final EventHolder<MouseEvent> holder) {
2605             doHandleMove(this, holder);
2606             return this;
2607         }
2608     }
2609 
2610     private static class TestRect extends Rectangle {
2611         public TestRect() {
2612             super(100, 100);
2613         }
2614 
2615         public TestRect rotate(char ax, double angle) {
2616             doRotate(this, ax, angle);
2617             return this;
2618         }
2619 
2620         public TestRect handleMove(final EventHolder<MouseEvent> holder) {
2621             doHandleMove(this, holder);
2622             return this;
2623         }
2624     }
2625 
2626     private static class TestBox extends Box {
2627         public TestBox() {
2628             super(100, 200, 400);
2629         }
2630 
2631         public TestBox rotate(char ax, double angle) {
2632             doRotate(this, ax, angle);
2633             return this;
2634         }
2635 
2636         public TestBox handleMove(final EventHolder<MouseEvent> holder) {
2637             doHandleMove(this, holder);
2638             return this;
2639         }
2640 
2641         public TestBox handleDrag(final EventHolder<MouseEvent> holder) {
2642             holder.event = null;
2643             setOnMouseDragged(event -> {
2644                 holder.event = event;
2645             });
2646             return this;
2647         }
2648 
2649         public TestBox handle(final EventType<MouseEvent> type,
2650                 final EventHolder<MouseEvent> holder) {
2651             holder.event = null;
2652             addEventHandler(type, event -> {
2653                 holder.event = event;
2654             });
2655             return this;
2656         }
2657 
2658         public TestBox handleFullPDR(final EventType<MouseDragEvent> type,
2659                 final EventHolder<MouseDragEvent> holder) {
2660             holder.event = null;
2661             addEventHandler(type, event -> {
2662                 holder.event = event;
2663             });
2664             return this;
2665         }
2666     }
2667 
2668     private static class TestSphere extends Sphere {
2669         public TestSphere() {
2670             super(100);
2671         }
2672 
2673         public TestSphere(int divs) {
2674             super(100, divs);
2675         }
2676 
2677         public TestSphere rotate(char ax, double angle) {
2678             doRotate(this, ax, angle);
2679             return this;
2680         }
2681 
2682         public TestSphere handleMove(final EventHolder<MouseEvent> holder) {
2683             doHandleMove(this, holder);
2684             return this;
2685         }
2686     }
2687 
2688     private static class TestCylinder extends Cylinder {
2689         public TestCylinder() {
2690             super(50, 200);
2691         }
2692 
2693         public TestCylinder(int divs) {
2694             super(50, 200, divs);
2695         }
2696 
2697         public TestCylinder rotate(char ax, double angle) {
2698             doRotate(this, ax, angle);
2699             return this;
2700         }
2701 
2702         public TestCylinder handleMove(final EventHolder<MouseEvent> holder) {
2703             doHandleMove(this, holder);
2704             return this;
2705         }
2706     }
2707 
2708     private static class TestMesh extends MeshView {
2709         public TestMesh(float[] points, float[] tex, int[] faces) {
2710             super(new TriangleMesh());
2711             TriangleMesh mesh = (TriangleMesh)getMesh();
2712             mesh.getPoints().setAll(points);
2713             mesh.getTexCoords().setAll(tex);
2714             mesh.getFaces().setAll(faces);
2715         }
2716 
2717         public TestMesh rotate(char ax, double angle) {
2718             doRotate(this, ax, angle);
2719             return this;
2720         }
2721 
2722         public TestMesh handleMove(final EventHolder<MouseEvent> holder) {
2723             doHandleMove(this, holder);
2724             return this;
2725         }
2726     }
2727 
2728     private static class EventHolder<T extends Event> {
2729         public T event = null;
2730 
2731         public void clear() {
2732             event = null;
2733         }
2734     }
2735 
2736     private void assertCoordinates(MouseEvent e, double sceneX, double sceneY,
2737             double x, double y, double z) {
2738         assertEquals(sceneX, e.getSceneX(), 0.00001);
2739         assertEquals(sceneY, e.getSceneY(), 0.00001);
2740         assertEquals(x, e.getX(), 0.00001);
2741         assertEquals(y, e.getY(), 0.00001);
2742         assertEquals(z, e.getZ(), 0.00001);
2743     }
2744 
2745     private void assertCoordinates(MouseEvent e,
2746             double x, double y, double z) {
2747         assertEquals(PERSPECTIVE_CAMERA_X, e.getSceneX(), 0.00001);
2748         assertEquals(PERSPECTIVE_CAMERA_Y, e.getSceneY(), 0.00001);
2749         assertEquals(x, e.getX(), 0.00001);
2750         assertEquals(y, e.getY(), 0.00001);
2751         assertEquals(z, e.getZ(), 0.00001);
2752     }
2753 
2754     private void assertPickResult(PickResult res, Node n, Point3D p,
2755             double distance, int face, Point2D tex) {
2756         assertSame(n, res.getIntersectedNode());
2757         assertEquals(p.getX(), res.getIntersectedPoint().getX(), 0.00001);
2758         assertEquals(p.getY(), res.getIntersectedPoint().getY(), 0.00001);
2759         assertEquals(p.getZ(), res.getIntersectedPoint().getZ(), 0.00001);
2760         assertEquals(distance, res.getIntersectedDistance(), 0.00001);
2761         assertEquals(face, res.getIntersectedFace());
2762         if (tex == null) {
2763             assertNull(res.getIntersectedTexCoord());
2764         } else {
2765             assertEquals(tex.getX(), res.getIntersectedTexCoord().getX(), 0.00001);
2766             assertEquals(tex.getY(), res.getIntersectedTexCoord().getY(), 0.00001);
2767         }
2768     }
2769 
2770 }