1

I currently have a project I am working on in JavaFX that simulates our solar system. The way it is made, a planet (which extends the Sphere class) orbits on a 2D plane, meaning the Z never gets changed according to the planet object. This was done to simplify the calculations of the orbit. The path the planet goes on is then drawn on this same plane. It looks a little bit like this:

Planet and its' orbit

I then rotate the group that contains the planet and the orbit to get a result that looks like this:

Planet and orbit group rotated

It is done by adding a transform to the group:

Group planeteSeule = new Group(PLANETES[i]);
planeteSeule.getTransforms().addAll(
    new Rotate(infoPlanetes[i].inclination, Rotate.X_AXIS),
    new Rotate(infoPlanetes[i].inclination, Rotate.Y_AXIS));

The problem with the way this is done is that there is no real way to bind the Z value the planet is at according to the scene (the Z value on the planet object itself is always 0), which is something that I need to get working to be able to interact with the planet on the Z-Axis. Is there any way to bind the Z to another property according to where it is in the scene and not according to the X it has in the group?

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • IIUC, the `Sphere` in this [example](https://stackoverflow.com/a/44447913/230513) is translated to its position in a `Group`, and then the `Group` as a whole is rotated and translated with respect to the _z_-axis in the mouse handlers. See also this [example](https://stackoverflow.com/a/69339586/230513) that explores orientation. – trashgod May 18 '22 at 17:50
  • @trashgod I am unsure if you understood what I meant or if I am misunderstanding what you mean. If I print the TranslateZ positon of my sphere, regardless of where it is in the Z of the scene, it will always be 0. This is because the position of the planet is in fact always 0 according to its position relative to the group. The group is rotated though, which means relatively to the scene, my planet goes up and down on the Z-Axis. I am trying to get access to this Z as a property that I can bind. – Nicolas Cinq-Mars May 18 '22 at 21:53
  • Thank you for clarifying; you are correct. I don't know a general solution. Can you amplify on the goal: annotation, picking, other? – trashgod May 19 '22 at 00:47
  • Yes, the goal is basicly to bind the z position of the planet (the one in the seen) to a property in the planet class to access it and bind it on the camera for example or to get the distance of a spaceship in the Z-Axis aswell (currently, only affected by the distance of the Y-Axis and X-Axis). – Nicolas Cinq-Mars May 19 '22 at 22:31
  • You should be able to leverage the `PickResult`, discussed [here](https://stackoverflow.com/search?tab=newest&q=%5bjavafx%5d%20%5b3d%5d%20PickResult); more [here](https://docs.oracle.com/javase/8/javafx/graphics-tutorial/picking.htm). – trashgod May 19 '22 at 23:30
  • I still don't believe I am clearly expressing what I am trying to do. Check the second picture in original post. You can see that the orbit of a certain planet makes changes in the x, y and z position. According to the planet though, only the x and y positions change, not the z. According to the scene, the z does change, as the planet and it's orbit (the line) is rotated in a group after creation. I am trying to access this z, the one not of the planet in the group, but the one of the planet in the world. – Nicolas Cinq-Mars May 20 '22 at 16:20
  • Alright and sorry if what you are telling me is actually what I want, it's just that reading makes it seem like it isn't what I am looking for. – Nicolas Cinq-Mars May 20 '22 at 16:33

1 Answers1

2

I am trying to access this z, the one not of the planet in the group, but the one of the planet in the world.

As outlined here, "the JavaFX node picking implementation will do that for you." Starting from this example, I enlarged the Sphere, added Text, and implemented a pair of mouse listeners. Move the mouse to the red planet, and the handler shows its name; this works no matter how the group is rotated. Print the parameter t, a MouseEvent, to see the coordinates; use the PickResult explicitly, as seen here; or simply update related model elements as desired.

text = new Text(edge / 5, -edge / 3 , "");
text.setFill(Color.BLUE);
text.setFont(new Font(20));
//sphere.setOnMouseEntered(t -> System.out.println(t));
sphere.setOnMouseEntered(t -> text.setText("Mars"));
sphere.setOnMouseExited(t -> text.setText(""));

See also JavaFX: Working with JavaFX Graphics: 7 Picking.

mars


import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.Sphere;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;
import javafx.stage.Stage;

/**
 * @see https://stackoverflow.com/q/72282224/230513
 * @see https://stackoverflow.com/a/37755149/230513
 * @see https://stackoverflow.com/a/37743539/230513
 * @see https://stackoverflow.com/a/37370840/230513
 */
public class TriadBox extends Application {

    private static final double SIZE = 300;
    private final Content content = Content.create(SIZE);
    private double mousePosX, mousePosY, mouseOldX, mouseOldY, mouseDeltaX, mouseDeltaY;

    private static final class Content {

        private static final double WIDTH = 3;
        private final Xform group = new Xform();
        private final Group cube = new Group();
        private final Group axes = new Group();
        private final Box xAxis;
        private final Box yAxis;
        private final Box zAxis;
        private final Box box;
        private final Sphere sphere;
        private final Text text;

        private static Content create(double size) {
            Content c = new Content(size);
            c.cube.getChildren().addAll(c.box, c.sphere, c.text);
            c.axes.getChildren().addAll(c.xAxis, c.yAxis, c.zAxis);
            c.group.getChildren().addAll(c.cube, c.axes);
            return c;
        }

        private Content(double size) {
            double edge = 3 * size / 4;
            xAxis = createBox(edge, WIDTH, WIDTH, edge);
            yAxis = createBox(WIDTH, edge / 2, WIDTH, edge);
            zAxis = createBox(WIDTH, WIDTH, edge / 4, edge);
            box = new Box(edge, edge / 2, edge / 4);
            box.setDrawMode(DrawMode.LINE);
            sphere = new Sphere(24);
            PhongMaterial redMaterial = new PhongMaterial();
            redMaterial.setDiffuseColor(Color.CORAL.darker());
            redMaterial.setSpecularColor(Color.CORAL);
            sphere.setMaterial(redMaterial);
            sphere.setTranslateX(edge / 2);
            sphere.setTranslateY(-edge / 4);
            sphere.setTranslateZ(-edge / 8);
            text = new Text(edge / 5, -edge / 3 , "");
            text.setFill(Color.BLUE);
            text.setFont(new Font(20));
            sphere.setOnMouseEntered(t -> text.setText("Mars"));
            sphere.setOnMouseExited(t -> text.setText(""));
        }

        private Box createBox(double w, double h, double d, double edge) {
            Box b = new Box(w, h, d);
            b.setMaterial(new PhongMaterial(Color.AQUA));
            b.setTranslateX(-edge / 2 + w / 2);
            b.setTranslateY(edge / 4 - h / 2);
            b.setTranslateZ(edge / 8 - d / 2);
            return b;
        }
    }

    private static class Xform extends Group {

        private final Point3D px = new Point3D(1.0, 0.0, 0.0);
        private final Point3D py = new Point3D(0.0, 1.0, 0.0);
        private Rotate r;
        private Transform t = new Rotate();

        public void rx(double angle) {
            r = new Rotate(angle, px);
            this.t = t.createConcatenation(r);
            this.getTransforms().clear();
            this.getTransforms().addAll(t);
        }

        public void ry(double angle) {
            r = new Rotate(angle, py);
            this.t = t.createConcatenation(r);
            this.getTransforms().clear();
            this.getTransforms().addAll(t);
        }

        public void rz(double angle) {
            r = new Rotate(angle);
            this.t = t.createConcatenation(r);
            this.getTransforms().clear();
            this.getTransforms().addAll(t);
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("JavaFX 3D");
        Scene scene = new Scene(content.group, SIZE * 2, SIZE * 2, true);
        primaryStage.setScene(scene);
        scene.setFill(Color.BLACK);
        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.setFarClip(SIZE * 6);
        camera.setTranslateZ(-2 * SIZE);
        scene.setCamera(camera);
        scene.setOnMousePressed((MouseEvent e) -> {
            mousePosX = e.getSceneX();
            mousePosY = e.getSceneY();
            mouseOldX = e.getSceneX();
            mouseOldY = e.getSceneY();
        });
        scene.setOnMouseDragged((MouseEvent e) -> {
            mouseOldX = mousePosX;
            mouseOldY = mousePosY;
            mousePosX = e.getSceneX();
            mousePosY = e.getSceneY();
            mouseDeltaX = (mousePosX - mouseOldX);
            mouseDeltaY = (mousePosY - mouseOldY);
            if (e.isShiftDown()) {
                content.group.rz(-mouseDeltaX * 180.0 / scene.getWidth());
            } else if (e.isPrimaryButtonDown()) {
                content.group.rx(+mouseDeltaY * 180.0 / scene.getHeight());
                content.group.ry(-mouseDeltaX * 180.0 / scene.getWidth());
            } else if (e.isSecondaryButtonDown()) {
                camera.setTranslateX(camera.getTranslateX() - mouseDeltaX * 0.1);
                camera.setTranslateY(camera.getTranslateY() - mouseDeltaY * 0.1);
                camera.setTranslateZ(camera.getTranslateZ() + mouseDeltaY);
            }
        });
        scene.setOnScroll((final ScrollEvent e) -> {
            camera.setTranslateZ(camera.getTranslateZ() + e.getDeltaY());
        });
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045