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