JavaFX 3D How to move node using relative position

2019-01-29 09:58发布

问题:

I am trying to automate some node's movements. I would like to move a node on top of another node but I am not able to achieve it using a generic method.

I.E. I wrote something like this:

    public Point3D getPosition(Node referenceNode, Node nodeToPlace) {
            Bounds refBounds = referenceNode.getBoundsInParent();
            double refX = refBounds.getMinX() + (refBounds.getWidth() / 2);
            double refY = refBounds.getMaxY() + nodeToPlace.getBoundsInParent().getHeight();
            double refZ = refBounds.getMinZ() + (refBounds.getDepth() / 2);

            double nodeToPlaceX = nodeToPlace.getBoundsInParent().getMinX() + 
                    (nodeToPlace.getBoundsInParent().getWidth()/2);
            double nodeToPlaceY = nodeToPlace.getBoundsInParent().getMinY() + 
                    (nodeToPlace.getBoundsInParent().getHeigth()/2);
            double nodeToPlaceZ = nodeToPlace.getBoundsInParent().getMinZ() + 
                    (nodeToPlace.getBoundsInParent().getDepth()/2);

            double translationX = refX - nodeToPlaceX;
            double translationY = refY - nodeToPlaceY;
            double translationZ = refZ - nodeToPlaceZ;

            nodeToPlace.getTransforms().add(new Translate(translationX,
            translationY, translationZ));
        }

What am I doing wrong? I suppose that I am not considering something of important but I can't figure it. I hope that someone can explain me the right way... Thanks in advance.

回答1:

Based on the first example seen here, the example below uses a Timeline to animate the motion of b1, shaded AQUA, toward b2, tinted CORAL.

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
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.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 @ @see https://stackoverflow.com/a/37516327/230513
 * @see https://stackoverflow.com/a/37370840/230513
 */
public class TimelineMove extends Application {

    private static final double SIZE = 300;
    private final Content content = Content.create(SIZE);

    public void play() {
        content.animation.play();
    }

    private static final class Content {

        private static final Duration DURATION = Duration.seconds(4);
        private static final int W = 64;
        private final Group group = new Group();
        private final Rotate rx = new Rotate(0, Rotate.X_AXIS);
        private final Rotate ry = new Rotate(0, Rotate.Y_AXIS);
        private final Rotate rz = new Rotate(0, Rotate.Z_AXIS);
        private final Box b1;
        private final Box b2;
        private final Animation animation;

        private static Content create(double size) {
            Content c = new Content(size);
            c.group.getChildren().addAll(c.b1, c.b2);
            c.group.getTransforms().addAll(c.rz, c.ry, c.rx);
            c.rx.setAngle(12);
            c.ry.setAngle(-12);
            return c;
        }

        private Content(double size) {
            Point3D p1 = new Point3D(-size / 4, -size / 4, size / 4);
            b1 = createBox(Color.AQUA, p1);
            Point3D p2 = new Point3D(size / 4, size / 4, -size / 4);
            b2 = createBox(Color.CORAL, p2);
            animation = createTimeline(p1, p2);
        }

        private Box createBox(Color color, Point3D p) {
            Box b = new Box(W, W, W);
            b.setMaterial(new PhongMaterial(color));
            b.setTranslateX(p.getX());
            b.setTranslateY(p.getY());
            b.setTranslateZ(p.getZ());
            return b;
        }

        private Timeline createTimeline(Point3D p1, Point3D p2) {
            Timeline t = new Timeline();
            t.setCycleCount(Timeline.INDEFINITE);
            t.setAutoReverse(true);
            KeyValue keyX = new KeyValue(b1.translateXProperty(), p2.getX() - p1.getX());
            KeyValue keyY = new KeyValue(b1.translateYProperty(), p2.getY() - p1.getY());
            KeyValue keyZ = new KeyValue(b1.translateZProperty(), p1.getZ() - p2.getZ());
            KeyFrame keyFrame = new KeyFrame(DURATION, keyX, keyY, keyZ);
            t.getKeyFrames().add(keyFrame);
            return 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.setOnScroll((final ScrollEvent e) -> {
            camera.setTranslateZ(camera.getTranslateZ() + e.getDeltaY());
        });
        primaryStage.show();
        play();
    }

    public static void main(String[] args) {
        launch(args);
    }
}


回答2:

Your code looks to be correct, except that you need to account for the transformations of the nodes' parents as well, in the general case that these two nodes don't have the same parent. (I assume getBoundsInParent returns the coordinates in the parent's frame of reference, not the world.)



标签: javafx 3d