@Override protected Group buildGroup() { mb = new MeshBuilder(); triangleMesh = mb.getTriangleMesh(); meshView = new MeshView(triangleMesh); material = new PhongMaterial(); material.setDiffuseColor(Color.LIGHTGRAY); material.setSpecularColor(Color.rgb(30, 30, 30)); meshView.setMaterial(material); //Set Wireframe mode meshView.setDrawMode(DrawMode.FILL); meshView.setCullFace(CullFace.BACK); meshView.setScaleX(SCALE); meshView.setScaleY(SCALE); meshView.setScaleZ(SCALE); grp = new Group(meshView); return grp; }
@Override protected void initScene() { DefaultMeshBuilder dmb = new DefaultMeshBuilder() { @Override protected double function(double fx, double fy) { return 1; } }; MeshView meshView = new MeshView(dmb.getTriangleMesh()); meshView.setScaleX(100); meshView.setScaleY(100); meshView.setScaleZ(100); Sphere s = new Sphere(50); s.setTranslateX(WIDTH / 2); s.setTranslateY(HEIGHT / 2); Group root = new Group(s, meshView); scene = createScene(root, WIDTH, HEIGHT); scene.setCamera(new PerspectiveCamera()); }
public void updateArrow(String face, boolean hover){ boolean bFaceArrow = !(face.startsWith("X") || face.startsWith("Y") || face.startsWith("Z")); MeshView arrow = bFaceArrow ? faceArrow : axisArrow; if (hover && onRotation.get()) { return; } arrow.getTransforms().clear(); if (hover) { double d0 = arrow.getBoundsInParent().getHeight() / 2d; Affine aff = Utils.getAffine(dimCube, d0, bFaceArrow, face); arrow.getTransforms().setAll(aff); arrow.setMaterial(Utils.getMaterial(face)); if (previewFace.get().isEmpty()) { previewFace.set(face); onPreview.set(true); rotateFace(face, true, false); } } else if (previewFace.get().equals(face)) { rotateFace(Utils.reverseRotation(face), true, true); } else if (previewFace.get().equals("V")) { previewFace.set(""); onPreview.set(false); } }
/** * Check that the decorator will set the object's material correctly. */ @Test @Ignore public void checkMesh() { // Create a render object Shape shape = GeometryFactory.eINSTANCE.createShape(); FXRenderObject object = new FXRenderObject( GeometryFactory.eINSTANCE.createCube(), new FXMeshCache()); // Create a color decorator for it FXColorOption decorator = new FXColorOption(object); // Set the color object.setProperty(ColorOptionImpl.PROPERTY_NAME_RED, 200); object.setProperty(ColorOptionImpl.PROPERTY_NAME_GREEN, 100); object.setProperty(ColorOptionImpl.PROPERTY_NAME_BLUE, 0); // We cannot test PhongMaterials for equality as JavaFX does not // overload equals() or provide methods for getting a PhongMaterial's // attributes, so instead just check that the decorator returned a // meshview. assertTrue(object.getMesh().getChildren().get(0) instanceof MeshView); }
/** * Set all the MeshViews in the group to the given material, as well as the * children of any child groups. * * @param group * The group whose children will have their material set. * @param material * The material to be set to the group's children. */ private void setMaterial(Group group, Material material) { // Handle each of the group's children for (Node node : group.getChildren()) { // If the node is a mesh view, set its material if (node.getClass() == MeshView.class) { ((MeshView) node).setMaterial(material); } // Otherwise, recursively handle the child group else if (node.getClass() == Group.class) { setMaterial((Group) node, material); } } }
/** * Set all the MeshViews in the group to the given draw mode, as well as the * children of any child groups. * * @param group * The group whose children will have their draw modes set. * @param mode * The mode to be set to the group's children. */ private void setMode(Group group, DrawMode mode) { // Handle each of the group's children for (Node node : group.getChildren()) { // If the node is a mesh view, set its material if (node.getClass() == MeshView.class) { ((MeshView) node).setDrawMode(mode); } // Otherwise, recursively handle the child group else if (node.getClass() == Group.class) { setMode((Group) node, mode); } } }
public List<MeshView> getAsMeshViews() { List<MeshView> result = new ArrayList<>(meshes.size()); for (int i = 0; i < meshes.size(); i++) { Mesh mesh = meshes.get(i); Material mat = materials.get(i); MeshView view = new MeshView(mesh); view.setMaterial(mat); view.setCullFace(CullFace.NONE); result.add(view); } return result; }
public void updateArrow(String face, boolean hover){ boolean bFaceArrow=!(face.startsWith("X")||face.startsWith("Y")||face.startsWith("Z")); MeshView arrow=bFaceArrow?faceArrow:axisArrow; if(hover && onRotation.get()){ return; } arrow.getTransforms().clear(); if(hover){ double d0=arrow.getBoundsInParent().getHeight()/2d; Affine aff=Utils.getAffine(dimCube, d0, bFaceArrow, face); arrow.getTransforms().setAll(aff); arrow.setMaterial(Utils.getMaterial(face)); if(previewFace.get().isEmpty()) { previewFace.set(face); onPreview.set(true); rotateFace(face,true,false); } } else if(previewFace.get().equals(face)){ rotateFace(Utils.reverseRotation(face),true,true); } else if(previewFace.get().equals("V")){ previewFace.set(""); onPreview.set(false); } }
/** * @param view the view to set */ public final void setView(MeshView view) { this.view = view; // remove all previously added mesh views List<Node> nodesToRemove = getGroup().getChildren().stream().filter( e -> e instanceof MeshView). collect(Collectors.toList()); getGroup().getChildren().removeAll(nodesToRemove); // finally add the new view getGroup().getChildren().add(view); }
/**Adds the high resolution volume interaction to a group, that consists of meshView objects. * Do not use this on the low resolution model. * @param volumeMeshView the group of meshViews (volumes) that should be selectable **/ private void addVolumeInteraction(MeshView volumeMeshView) { volumeMeshView.addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClick -> { if (mouseClick.getButton().toString().matches("SECONDARY")) { Node pickedNode = mouseClick.getPickResult().getIntersectedNode(); PickResult res = mouseClick.getPickResult(); if (debugMode) { System.out.println("Selected node is a volume!"); System.out.println(newFaceMap.get(pickedNode)); } handleSelection(faceNodeSelection, faceNodeSelectionMaterial, pickedNode, new MeshView()); } }); }
/** * Load a 3D file, always loaded as TriangleMesh. * * @param fileUrl the url of the 3D file to load * @return the loaded Node which could be a MeshView or a Group * @throws IOException if there is a problem loading the file */ public static Group load(final String fileUrl) throws IOException { final int dot = fileUrl.lastIndexOf('.'); if (dot <= 0) { throw new IOException("Unknown 3D file format, url missing extension [" + fileUrl + "]"); } final String extension = fileUrl.substring(dot + 1, fileUrl.length()).toLowerCase(); switch (extension) { case "3ds": ModelImporter tdsImporter = new TdsModelImporter(); tdsImporter.read(fileUrl); final Node[] tdsMesh = (Node[]) tdsImporter.getImport(); tdsImporter.close(); return new Group(tdsMesh); case "stl": StlMeshImporter stlImporter = new StlMeshImporter(); stlImporter.read(fileUrl); // STL includes only geometry data TriangleMesh cylinderHeadMesh = stlImporter.getImport(); stlImporter.close(); // Create Shape3D MeshView cylinderHeadMeshView = new MeshView(); cylinderHeadMeshView.setMaterial(new PhongMaterial(Color.GRAY)); cylinderHeadMeshView.setMesh(cylinderHeadMesh); stlImporter.close(); return new Group(cylinderHeadMeshView); default: throw new IOException("Unsupported 3D file format [" + extension + "]"); } }
public Cone(double rad, double height) { this.rad = rad; this.height = height; mv = new MeshView(); mv.setMesh(dmb.getTriangleMesh()); grp = new Group(mv); }
public SemiSphere(double rad,int divX,int divY) { this.rad = rad; dmb = new SemiSphereBuilder(divX,divY); mv = new MeshView(); mv.setMesh(dmb.getTriangleMesh()); grp = new Group(mv); }
public void doSequence(String list){ onScrambling.set(true); sequence = Utils.unifyNotation(list); /* This is the way to perform several rotations from a list, waiting till each of them ends properly. A listener is added to onRotation, so only when the last rotation finishes a new rotation is performed. The end of the list is used to stop the listener, by adding a new listener to the index property. Note the size+1, to allow for the last rotation to end. */ IntegerProperty index = new SimpleIntegerProperty(1); ChangeListener<Boolean> lis = (ov, b, b1) -> { if (!b1) { if (index.get()<sequence.size()) { rotateFace(sequence.get(index.get())); } else { // save transforms for (Map.Entry<String, MeshView> entry : mapMeshes.entrySet()) { mapTransformsScramble.put(entry.getKey(), entry.getValue().getTransforms().get(0)); } orderScramble = new ArrayList<>(); for (Integer i : reorder) { orderScramble.add(i); } } index.set(index.get()+1); } }; index.addListener((ov, v, v1) -> { if (v1.intValue() == sequence.size()+1) { onScrambling.set(false); onRotation.removeListener(lis); count.set(-1); } }); onRotation.addListener(lis); rotateFace(sequence.get(0)); }
public void doReset(){ // System.out.println("Reset!"); content.resetCam(); for (Map.Entry<String, MeshView> entry : mapMeshes.entrySet()) { entry.getValue().getTransforms().setAll(mapTransformsOriginal.get(entry.getKey())); } order = new ArrayList<>(); for (Integer i : orderOriginal) { order.add(i); } rot.setCube(order); count.set(-1); }
private static Point3D getMeshNormal(MeshView mesh){ TriangleMesh tm = (TriangleMesh) mesh.getMesh(); float[] fPoints = new float[tm.getPoints().size()]; tm.getPoints().toArray(fPoints); Point3D BA = new Point3D(fPoints[3] - fPoints[0], fPoints[4] - fPoints[1], fPoints[5] - fPoints[2]); Point3D CA = new Point3D(fPoints[6] - fPoints[0], fPoints[7] - fPoints[1], fPoints[8] - fPoints[2]); Point3D normal = BA.crossProduct(CA); Affine a = new Affine(mesh.getTransforms().get(0)); return a.transform(normal.normalize()); }
public MeshView buildMeshView(String key) { MeshView meshView = new MeshView(); meshView.setId(key); meshView.setMaterial(materials.get(key)); meshView.setMesh(meshes.get(key)); meshView.setCullFace(CullFace.NONE); return meshView; }
/** * Check that the decorator will set the object's material correctly. */ @Test @Ignore public void checkMesh() { // Create a render object Shape shape = GeometryFactory.eINSTANCE.createShape(); FXRenderObject object = new FXRenderObject(shape, new FXMeshCache()); // Create an opacity decorator for it FXWireframeOption decorator = new FXWireframeOption(object); // Set the shape as a wireframe object.setProperty(WireframeOptionImpl.PROPERTY_NAME_WIREFRAME, true); // The child's draw mode should have been changed assertTrue(((MeshView) object.getMesh().getChildren().get(0)) .getDrawMode() == DrawMode.LINE); // Make the shape solid again and check that it was reset object.setProperty(WireframeOptionImpl.PROPERTY_NAME_WIREFRAME, false); assertTrue(((MeshView) object.getMesh().getChildren().get(0)) .getDrawMode() == DrawMode.FILL); // Sending an update from the shape should also set the wireframe mode shape.changeDecoratorProperty( WireframeOptionImpl.PROPERTY_NAME_WIREFRAME, true); assertTrue(((MeshView) object.getMesh().getChildren().get(0)) .getDrawMode() == DrawMode.LINE); // Deactivating the option should leave the object filled in decorator.setActive(false); assertTrue(((MeshView) object.getMesh().getChildren().get(0)) .getDrawMode() == DrawMode.FILL); }
@Test public void testGetMeshViewAdjuster() { Adjuster adjuster = Adjuster.getAdjuster(MeshView.class); assertThat(adjuster, is(instanceOf(NodeAdjuster.class))); assertThat(adjuster.getNodeClass(), is(sameInstance(Node.class))); }
public void validate(Node node) { if (node instanceof MeshView) { MeshView meshView = (MeshView) node; validate(meshView.getMesh()); } else if (node instanceof Parent) { for (Node child : ((Parent) node).getChildrenUnmodifiable()) { validate(child); } } }
private void setMeshScale( MeshContainer meshContainer, Bounds t1, final MeshView meshView) { double maxDim = Math.max(meshContainer.getWidth(), Math.max(meshContainer.getHeight(), meshContainer.getDepth())); double minContDim = Math.min(t1.getWidth(), t1.getHeight()); double scale = minContDim / (maxDim * 2); meshView.setScaleX(scale); meshView.setScaleY(scale); meshView.setScaleZ(scale); }
private static Point3D getMeshNormal(MeshView mesh){ TriangleMesh tm=(TriangleMesh)mesh.getMesh(); float[] fPoints=new float[tm.getPoints().size()]; tm.getPoints().toArray(fPoints); Point3D BA=new Point3D(fPoints[3]-fPoints[0],fPoints[4]-fPoints[1],fPoints[5]-fPoints[2]); Point3D CA=new Point3D(fPoints[6]-fPoints[0],fPoints[7]-fPoints[1],fPoints[8]-fPoints[2]); Point3D normal=BA.crossProduct(CA); Affine a=new Affine(mesh.getTransforms().get(0)); return a.transform(normal.normalize()); }
/**Adds the high resolution edge interaction to a group, that consists of meshView objects. * Do not use this on the low resolution model. * @param eGroup the group of meshViews (edges/hexahedrons) that should be selectable **/ private void addEdgeInteraction(Group eGroup) { eGroup.addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClick -> { if (mouseClick.getButton().toString().matches("SECONDARY")) { Node pickRes = mouseClick.getPickResult().getIntersectedNode(); handleSelection(edgeNodeSelection, edgeNodeSelectionMaterial, pickRes, new MeshView()); } } ); }
public static MeshView createMesh() { float[] points = { -0.866f, 0f, 0.5f, 0f, 0f, 1f, 0.866f, 0f, 0.5f, 0.866f, 0f, -0.5f, 0f, 0f, -1f, -0.866f, 0f, -0.5f, 0f, 0f, 0f }; float[] texCoords = { 0f, 0.25f, 0.5f, 0f, 1f, 0.25f, 1f, 0.75f, 0.5f, 1f, 0f, 0.75f, 0.5f, 0.5f }; int[] faces = { 6, 6, 1, 1, 0, 0, 6, 6, 2, 2, 1, 1, 6, 6, 3, 3, 2, 2, 6, 6, 4, 4, 3, 3, 6, 6, 5, 5, 4, 4, 6, 6, 0, 0, 5, 5, }; TriangleMesh mesh = new TriangleMesh(); mesh.getPoints().setAll(points); mesh.getTexCoords().setAll(texCoords); mesh.getFaces().setAll(faces); return new MeshView(mesh); }
public void addTiles() { for (Tile tile : Board.getTiles()) { MeshView mesh = tile.getMesh(); PhongMaterial material = new PhongMaterial(Color.WHITE); material.setDiffuseMap(new Image(GameGroup.class.getResourceAsStream(tile.getResourceString()))); mesh.setMaterial(material); mesh.getTransforms().add(new Translate(tile.getCenter().getX(), tile.getCenter().getY(), tile.getCenter().getZ())); getChildren().add(mesh); } }
@Override protected Shape3D getShape() { triMesh = buildTriMesh(); meshView = new MeshView(triMesh); return meshView; }
public MeshView getMesh() { return mv; }
public Map<String, MeshView> getMapMeshes() { return mapMeshes; }
public MeshView getFaceArrow() { return faceArrow; }
public MeshView getAxisArrow() { return axisArrow; }
public void doReplay(List<Move> moves){ if (moves.isEmpty()) { return; } content.resetCam(); //restore scramble if (mapTransformsScramble.size() > 0) { // System.out.println("Restoring scramble"); for (Map.Entry<String, MeshView> entry : mapMeshes.entrySet()) { entry.getValue().getTransforms().setAll(mapTransformsScramble.get(entry.getKey())); } order = new ArrayList<>(); for (Integer i : orderScramble) { order.add(i); } rot.setCube(order); count.set(-1); } else { // restore original doReset(); } onReplaying.set(true); IntegerProperty index = new SimpleIntegerProperty(1); ChangeListener<Boolean> lis = (ov, v, v1) -> { if (!v1 && moves.size() > 1) { if (index.get() < moves.size()) { timestamp.set(moves.get(index.get()).getTimestamp()); rotateFace(moves.get(index.get()).getFace()); } index.set(index.get() + 1); } }; index.addListener((ov, v, v1) -> { if (v1.intValue() == moves.size() + 1) { onReplaying.set(false); onRotation.removeListener(lis); } }); onRotation.addListener(lis); timestamp.set(moves.get(0).getTimestamp()); rotateFace(moves.get(0).getFace()); }
public static String getPickedRotation(int cubie, MeshView mesh){ Point3D normal = getMeshNormal(mesh); String rots = ""; // Rx-Ry switch(cubie){ case 0: rots = (normal.getZ() > 0.99) ? "Ui-Li" : ((normal.getX() < -0.99) ? "Ui-F" : ((normal.getY() > 0.99) ? "Ui-Li" : "")); break; case 1: rots = (normal.getZ() > 0.99) ? "F-Mi" : ((normal.getY() > 0.99) ? "Ui-Mi" : ""); // between L and R, as L break; case 2: rots = (normal.getZ() > 0.99) ? "Ui-R" : ((normal.getX() > 0.99) ? "Ui-Fi" : ((normal.getY() > 0.99) ? "Ui-R" : "")); break; case 3: rots = (normal.getZ() > 0.99) ? "E-F" : ((normal.getX() < -0.99) ? "E-Li" : ""); // between U and D, as D break; case 4: rots = (normal.getZ() > 0.99) ? "Yi-X" : ""; break; case 5: rots = (normal.getZ() > 0.99) ? "E-Fi" : ((normal.getX() > 0.99) ? "E-R" : ""); // between U and D, as D break; case 6: rots = (normal.getZ() > 0.99) ? "D-Li" : ((normal.getX() < -0.99) ? "D-F" : ((normal.getY() < -0.99) ? "D-Li" : "")); break; case 7: rots = (normal.getZ() > 0.99) ? "Fi-Mi" : ((normal.getY() < -0.99) ? "Fi-Mi" : ""); // between L and R, as L break; case 8: rots = (normal.getZ() > 0.99) ? "D-R" : ((normal.getX() > 0.99) ? "D-Fi" : ((normal.getY() < -0.99) ? "D-R" : "")); break; case 9: rots = (normal.getY() > 0.99) ? "S-U" : ((normal.getX() < -0.99) ? "L-S" : ""); // between U and D, as D break; case 10: rots = (normal.getY() > 0.99) ? "Z-X" : ""; break; case 11: rots = (normal.getY() > 0.99) ? "S-Ui" : ((normal.getX() > 0.99) ? "R-Si" : ""); // between U and D, as D break; case 12: rots = (normal.getX() < -0.99) ? "Yi-Z" : ""; break; case 14: rots = (normal.getX() > 0.99) ? "Yi-Zi" : ""; break; case 15: rots = (normal.getY() < -0.99) ? "D-S" : ((normal.getX() < -0.99) ? "Li-S" : ""); // between U and D, as D break; case 16: rots = (normal.getY() < -0.99) ? "Zi-X" : ""; break; case 17: rots = (normal.getY() < -0.99) ? "D-S" : ((normal.getX() > 0.99) ? "Ri-Si" : ""); // between U and D, as D break; case 18: rots = (normal.getZ() < -0.99) ? "Ui-L" : ((normal.getX() < -0.99) ? "Ui-Bi" : ((normal.getY() > 0.99) ? "Ui-L" : "")); break; case 19: rots = (normal.getZ() < -0.99) ? "B-M" : ((normal.getY() > 0.99) ? "U-M" : ""); // between L and R, as L break; case 20: rots = (normal.getZ() < -0.99) ? "Ui-Ri" : ((normal.getX() > 0.99) ? "Ui-B" : ((normal.getY() > 0.99) ? "Ui-Ri" : "")); break; case 21: rots = (normal.getZ() < -0.99) ? "E-Bi" : ((normal.getX() < -0.99) ? "E-L" : ""); // between U and D, as D break; case 22: rots = (normal.getZ() < -0.99) ? "Yi-Xi" : ""; break; case 23: rots = (normal.getZ() < -0.99) ? "E-B" : ((normal.getX() > 0.99) ? "E-Ri" : ""); // between U and D, as D break; case 24: rots = (normal.getZ() < -0.99) ? "D-L" : ((normal.getX() < -0.99) ? "D-Bi" : ((normal.getY() < -0.99) ? "D-L" : "")); break; case 25: rots = (normal.getZ() < -0.99) ? "Bi-M" : ((normal.getY() < -0.99) ? "Bi-M" : ""); // between L and R, as L break; case 26: rots = (normal.getZ() < -0.99) ? "D-Ri" : ((normal.getX() > 0.99) ? "D-B" : ((normal.getY() < -0.99) ? "D-B" : "")); break; } return rots; }
/** * Check that the object is properly initialized. */ @Test public void checkConstruction() { // The cache that will provide the render objects with their meshes TestCache cache = new TestCache(); // Create a node with type "test". ShapeImpl testShape = new ShapeImpl() { @Override public String getType() { return "test"; } }; // Create a render object which will render based on type. FXRenderObject renderType = new FXRenderObject(testShape, cache); // The result should contain a MeshView based on mesh1 from the cache assertTrue(renderType.getRender().getChildren() .get(0) instanceof MeshView); assertTrue(cache.getMesh1() == cache.getLast()); // Create a shape with the first set of triangles. Shape shape1 = GeometryFactory.eINSTANCE.createShape(); shape1.getTriangles().addAll(cache.getSet1()); // Create a render object based on the shape FXRenderObject renderTri1 = new FXRenderObject(shape1, cache); // The result should contain a MeshView based on mesh1 from the cache assertTrue(renderTri1.getRender().getChildren() .get(0) instanceof MeshView); // Create a shape with the second set of triangles. Shape shape2 = GeometryFactory.eINSTANCE.createShape(); shape2.getTriangles().addAll(cache.getSet2()); // Create a render object based on the shape FXRenderObject renderTri2 = new FXRenderObject(shape2, cache); // The result should contain a MeshView based on mesh2 from the cache assertTrue( renderTri2.getMesh().getChildren().get(0) instanceof MeshView); // Move the shape to another location Vertex vertex = GeometryFactory.eINSTANCE.createVertex(); vertex.setX(3); vertex.setY(4); vertex.setZ(5); shape2.setCenter(vertex); // The mesh should have moved to the new point assertEquals(3d, renderTri2.getMesh().getTranslateX(), 0.01d); assertEquals(4d, renderTri2.getMesh().getTranslateY(), 0.01d); assertEquals(5d, renderTri2.getMesh().getTranslateZ(), 0.01d); }
/** * The default constructor. * * @param manager * The manager which will oversee this attachment */ public FXGeometryAttachment(FXGeometryAttachmentManager manager) { super(manager); selectMultiple = false; // Add block to run when the mouse is clicked on the geometry // canvas. This will allow for selection in the Editor. super.fxAttachmentNode.setOnMouseClicked((event) -> { selectMultiple = event.isControlDown(); // Get the pick result, see if we are selecting a node PickResult pick = event.getPickResult(); // Get the node Node selected = pick.getIntersectedNode(); // The render to select IRenderElement selectedRender = null; // All geometry editor objects in the root are now TriangleMeshViews if (selected instanceof MeshView) { MeshView view = (MeshView) selected; // Go through the rendered nodes and find the node that // corresponds // to the selected MeshView for (IRenderElement element : renderedNodes) { Object mesh = element.getMesh(); // Test each mesh with the selected one if (element.getMesh().equals(view)) { selectedRender = element; // If the mesh is a group node, check each child node } else if (mesh instanceof Group) { Group group = (Group) mesh; for (Node node : group.getChildren()) { if (node.equals(view)) { // Finally set the render element selectedRender = element; break; } } } // If we found the selected render, break out of the loop if (selectedRender != null) { break; } } } // Set the selection in the tree view, which also sets the // transformation view IViewPart treeView = PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getActivePage() .findView(ShapeTreeView.ID); if (selectMultiple) { ((ShapeTreeView) treeView).toggleSelected(selectedRender); } else { ((ShapeTreeView) treeView).setSelected(selectedRender); } }); }
/** * The default constructor. * * @param source * The object to be rendered. * @param meshCache * The cache of TriangleMeshes from which this object will draw * the mesh to render. */ public FXRenderObject(INode source, MeshCache<TriangleMesh> meshCache) { super(); // Save the data members this.source = source; this.meshCache = meshCache; // Create a new, empty group for the render render = new Group(); // Try to get a mesh based on the source's type. TriangleMesh mesh = meshCache.getMesh(source.getType()); // If there was no mesh for the source's type, instead specify one by a // mesh of triangles if (mesh == null) { mesh = meshCache.getMesh(source.getTriangles()); } // If a mesh was returned, create a view from it and add it to the // render group. Otherwise, we will use an empty group to render the // object. if (mesh != null) { render.getChildren().add(new MeshView(mesh)); } // Register as a listener to the source object source.eAdapters().add(new AdapterImpl() { @Override public void notifyChanged(Notification notification) { handleUpdate(notification); } }); // Get the center of the data object from the source Vertex center = source.getCenter(); // Move the render to the correct location if (center != null) { render.setTranslateX(center.getX()); render.setTranslateY(center.getY()); render.setTranslateZ(center.getZ()); } }
/** * Handle a notification from the source object. * * @param notification * The message of from the source object, specifying what has * changed. */ protected void handleUpdate(Notification notification) { // If a changeDecoratorProperty() function was called, then update own // properties according to the special message format of the old value // being the property name and the new value being the property value if (notification.getFeatureID( GeometryPackage.class) == GeometryPackage.INODE___CHANGE_DECORATOR_PROPERTY__STRING_OBJECT || notification.getEventType() == Notification.NO_FEATURE_ID) { String propertyName = notification.getOldStringValue(); Object propertyValue = notification.getNewValue(); // If the property already had this value, ignore it if (propertyValue == null || !propertyValue.equals(properties.get(propertyName))) { properties.put(notification.getOldStringValue(), notification.getNewValue()); } else { // If nothing changed, there are no need for further updates return; } } // Cast the cache as a cache of TriangleMeshes MeshCacheImpl<TriangleMesh> castCache = (MeshCacheImpl<TriangleMesh>) meshCache; // For the base implementation, we simply clear the render group of all // nodes and add the new mesh to it. render = new Group(); // Try to get the mesh based on type TriangleMesh mesh = castCache.getMesh(source.getType()); // If no mesh was found, specify one with triangles if (mesh == null) { mesh = castCache.getMesh(source.getTriangles()); } // If a mesh was found, create a view for it and add it to the render // group. if (mesh != null) { render.getChildren().add(new MeshView(mesh)); } // Get the center of the data object from the source Vertex center = source.getCenter(); // Move the render to the correct location if (center != null) { render.setTranslateX(center.getX()); render.setTranslateY(center.getY()); render.setTranslateZ(center.getZ()); } // Pass the update on to own observer eNotify(notification); }
public void setHeightData(float[][] arrayY, int spacing, Color color, boolean ambient, boolean fill) { material = new PhongMaterial(); material.setSpecularColor(color); material.setDiffuseColor(color); mesh = new TriangleMesh(); // Fill Points for (int x = 0; x < arrayY.length; x++) { for (int z = 0; z < arrayY[0].length; z++) { mesh.getPoints().addAll(x * spacing, arrayY[x][z], z * spacing); } } //for now we'll just make an empty texCoordinate group mesh.getTexCoords().addAll(0, 0); int total = arrayY.length * arrayY.length; int nextRow = arrayY.length; //Add the faces "winding" the points generally counter clock wise for (int i = 0; i < total - nextRow -1; i++) { //Top upper left triangle mesh.getFaces().addAll(i,0,i+nextRow,0,i+1,0); //Top lower right triangle mesh.getFaces().addAll(i+nextRow,0,i+nextRow + 1,0,i+1,0); //Bottom } //Create a viewable MeshView to be added to the scene //To add a TriangleMesh to a 3D scene you need a MeshView container object meshView = new MeshView(mesh); //The MeshView allows you to control how the TriangleMesh is rendered if(fill) { meshView.setDrawMode(DrawMode.FILL); } else { meshView.setDrawMode(DrawMode.LINE); //show lines only by default } meshView.setCullFace(CullFace.BACK); //Removing culling to show back lines getChildren().add(meshView); meshView.setMaterial(material); if (ambient) { selfLight.getScope().add(meshView); if(!getChildren().contains(selfLight)) getChildren().add(selfLight); } else if(getChildren().contains(selfLight)) getChildren().remove(selfLight); setDepthTest(DepthTest.ENABLE); }
public PolyLine3D(List<Point3D> points, int width, Color color) { this.points = points; this.width = width; this.color = color; setDepthTest(DepthTest.ENABLE); mesh = new TriangleMesh(); //add each point. For each point add another point shifted on Z axis by width //This extra point allows us to build triangles later for(Point3D point: points) { mesh.getPoints().addAll(point.x,point.y,point.z); mesh.getPoints().addAll(point.x,point.y,point.z+width); } //add dummy Texture Coordinate mesh.getTexCoords().addAll(0,0); //Now generate trianglestrips for each line segment for(int i=2;i<points.size()*2;i+=2) { //add each segment //Vertices wound counter-clockwise which is the default front face of any Triange //These triangles live on the frontside of the line facing the camera mesh.getFaces().addAll(i,0,i-2,0,i+1,0); //add primary face mesh.getFaces().addAll(i+1,0,i-2,0,i-1,0); //add secondary Width face //Add the same faces but wind them clockwise so that the color looks correct when camera is rotated //These triangles live on the backside of the line facing away from initial the camera mesh.getFaces().addAll(i+1,0,i-2,0,i,0); //add primary face mesh.getFaces().addAll(i-1,0,i-2,0,i+1,0); //add secondary Width face } //Need to add the mesh to a MeshView before adding to our 3D scene meshView = new MeshView(mesh); meshView.setDrawMode(DrawMode.FILL); //Fill so that the line shows width material = new PhongMaterial(color); material.setDiffuseColor(color); material.setSpecularColor(color); meshView.setMaterial(material); //Make sure you Cull the Back so that no black shows through meshView.setCullFace(CullFace.BACK); //Add some ambient light so folks can see it AmbientLight light = new AmbientLight(Color.WHITE); light.getScope().add(meshView); getChildren().add(light); getChildren().add(meshView); }