0

I have a few 3D geometrical objects like sphere, Tube, Cube etc. I am generating using usual way of using classes like Sphere, Cylinder,Box etc inside FXML based-menu in a FXMLcontroller. This means object box1 is local to @FXMLmakeCube sort of method.

Now I wish to perform few operations like boolean operation, copy, mirroring etc. in another method inside this controller. I want to keep all created geometries in JavaFXCollection sort of List so that I may call the handle to those geometries from inside any other method.

My question is how can I do this? How can I refer this handles in other method inside the same FXMLController?

I did not find exact question in the net.

gouessej
  • 3,640
  • 3
  • 33
  • 67
vegaonline
  • 43
  • 10
  • I am sorry, I can't follow you. Can you kindly illustrate, please? Are you saying that I need to store full command in a `TextField` and then restore? I thought differently. If I use `Box box1 = new Box(...)` then if I may store `box1` as handle in some List and if I may call from that List, it would be good. The point is I may generate many boxes by clicking Box menu which means I can't define them globally. – vegaonline May 20 '16 at 13:06

1 Answers1

1

You can place all those 3D objects in one collection, since all of them extend from Shape3D.

You can create an ObservableList<Shape3D> collection, and add each object to it when you create them. Then you can listen to changes in the collection, and add to the scene/subscene all the new objects.

This would be a sample of a controller with four buttons, where you can create random Box or Sphere 3D objects, add them to the collection, and place them in a subscene.

Also you can perform operations with the full collection (translate or rotate them in this case).

public class FXMLDocumentController {

    @FXML
    private Pane pane;

    private Group pane3D;
    private PerspectiveCamera camera;
    private ObservableList<Shape3D> items;

    @FXML
    void createBox(ActionEvent event) {
        Box box = new Box(new Random().nextInt(200), new Random().nextInt(200), new Random().nextInt(200));
        box.setMaterial(new PhongMaterial(new Color(new Random().nextDouble(), 
                new Random().nextDouble(), new Random().nextDouble(), new Random().nextDouble())));
        box.setTranslateX(-100 + new Random().nextInt(200));
        box.setTranslateY(-100 + new Random().nextInt(200));
        box.setTranslateZ(new Random().nextInt(200));
        items.add(box);
    }

    @FXML
    void createSphere(ActionEvent event) {
        Sphere sphere = new Sphere(new Random().nextInt(100));
        sphere.setMaterial(new PhongMaterial(new Color(new Random().nextDouble(), 
                new Random().nextDouble(), new Random().nextDouble(), new Random().nextDouble())));
        sphere.setTranslateX(-100 + new Random().nextInt(200));
        sphere.setTranslateY(-100 + new Random().nextInt(200));
        sphere.setTranslateZ(new Random().nextInt(200));
        items.add(sphere);
    }

    public void initialize() {
        camera = new PerspectiveCamera(true);
        camera.setNearClip(0.1);
        camera.setFarClip(10000);
        camera.setTranslateZ(-1000);
        pane3D = new Group(camera);
        SubScene subScene = new SubScene(pane3D, 400, 400, true, SceneAntialiasing.BALANCED);
        subScene.setFill(Color.ROSYBROWN);
        subScene.setCamera(camera);
        pane.getChildren().add(subScene);

        items = FXCollections.observableArrayList();

        items.addListener((ListChangeListener.Change<? extends Shape3D> c) -> {
            while (c.next()) {
                if (c.wasAdded()) {
                    c.getAddedSubList().forEach(i -> pane3D.getChildren().add(i));
                }
            }
        });

    }    

    @FXML
    void rotateAll(ActionEvent event) {
        items.forEach(s -> {
            s.setRotate(new Random().nextInt(360));
            s.setRotationAxis(new Point3D(-100 + new Random().nextInt(200), 
                    -100 + new Random().nextInt(200), new Random().nextInt(200)));
        });
    }

    @FXML
    void translateAll(ActionEvent event) {
        items.forEach(s -> {
            s.setTranslateX(-100 + new Random().nextInt(200));
            s.setTranslateY(-100 + new Random().nextInt(200));
            s.setTranslateZ(new Random().nextInt(200));
        });

    }
}

subscene

José Pereda
  • 44,311
  • 7
  • 104
  • 132
  • Dear Jose, Thanks a lot. Great. I war trying a lot. I did not think to use `Shape3D` for the `ObservableList`. – vegaonline May 21 '16 at 15:19
  • I like to know one important issue related to this problem. I have defined another class as `myTube` or `mySphere` etc. which uses `TriangleMesh`. If I need to make a list for this case, I cannot use Shape3D. What should I do for these cases? – vegaonline May 21 '16 at 16:45
  • 1
    You need to add the `TriangleMesh` object to a `MeshView` node, which also extends from `Shape3D. – José Pereda May 21 '16 at 16:55
  • Thanks a lot for your kind advice. – vegaonline May 21 '16 at 18:15
  • sorry to disturb again. However, if I want to put that TriangleMesh object, should I use `private ObservableList items`? Or I may safely put `Shape3D` in place of `MeshView` as finally it extends to Shape3D? – vegaonline May 21 '16 at 18:35
  • 1
    If you have other objects, you can safely use `Shape3D`, and if needed, downcast to `MeshView`: `if (items.get(0) instanceof MeshView) { ((MeshView) items.get(0)).... }` – José Pereda May 21 '16 at 18:37