JavaFX Roting 3D-объект с изменением точки поворота - PullRequest
1 голос
/ 24 марта 2020

Я пытаюсь повернуть группу фигур вокруг пользовательской (изменяющейся) точки поворота. Как, например, в CATIA, я хочу иметь возможность щелкнуть одну из этих фигур в группе, чтобы определить точку поворота. Затем я хочу иметь возможность вращать группу вокруг этой точки поворота, перетаскивая мышь по оси x или y. Как и в Catia, я хочу иметь возможность определять новую точку поворота после каждого поворота и вращать группу вокруг этой новой точки поворота в x и y. Однако группа не должна терять прежнюю ориентацию. Проблема в том, что первое вращение работает нормально, но каждое следующее вращение вращается вокруг чего-то, что не определено щелчком мыши.

Теперь, пытаясь это в течение нескольких недель, я думаю, что выяснил, почему это не работает. В документах говорится, что точка поворота установлена ​​относительно начала координат. Поэтому, когда я хочу определить новую опорную точку, координаты точки понимаются относительно начала формы (там, где она начиналась), а не там, где форма в настоящее время находится в результате вращения.

Я пытался сохраните все прошедшие Rotate-Transforms в списке и примените их к новой точке вращения ДО создания нового объекта Rotate и установки его точки вращения. Это тоже не похоже на работу. Я даже не уверен, является ли этот путь правильным.

Может ли кто-нибудь мне помочь? На mousePressedEvent я конвертирую координаты события в координаты сцены, а затем передаю эту информацию вместе со сценой и смарт-группой в свой метод newRotation (). Этот метод затем устанавливает mouseDraggedEvent-Listener. Это повторяется для каждого mousePressedEvent. Ниже мой код:

import application.MouseControl;
import application.SmartGroup;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Scene;  
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Sphere;
import javafx.stage.Stage;  

public class Test extends Application{  



    public void start(Stage primaryStage) throws Exception {
        // TODO Auto-generated method stub
        // TODO Auto-generated method stub  
        // creating the rectangles   
        Rectangle rect1 = new Rectangle(100,100,200,200);  
        Rectangle rect2 = new Rectangle(100,100,200,200);  
        Circle sphere1 = new Circle(100,100,10);
        Cylinder cli = new Cylinder(20,100);
        cli.setTranslateX(200);
        cli.setTranslateY(200);
        //spere1.setTranslateX(100);
        //spere1.setTranslateY(100);

        // setting the color and stroke for the Rectangles    
        rect1.setFill(Color.LIMEGREEN);  
        rect2.setFill(Color.DARKGREY);  
        rect1.setStroke(Color.BLACK);  
        rect2.setStroke(Color.BLACK);  

        // instantiating the Group

        SmartGroup root = new SmartGroup();
        SmartGroup rotationGroup = new SmartGroup();
        SmartGroup stationaryGroup = new SmartGroup();
        root.getChildren().add(rotationGroup);
        root.getChildren().add(stationaryGroup);
        stationaryGroup.getChildren().add(rect1);
        rotationGroup.getChildren().add(rect2);
        rotationGroup.getChildren().add(sphere1);
        rotationGroup.getChildren().add(cli);

        Scene scene = new Scene(root,500,420, true);  
        primaryStage.setScene(scene);  
        primaryStage.setTitle("Rotation");  
        MouseControl control = new MouseControl();

        rect2.setOnMousePressed(event -> {
            Point3D eventPoint = new Point3D(event.getX(),event.getY(),event.getZ());
            Sphere sphere2 = new Sphere(10);
            System.out.println("New sphere at location of pivot point created");
            Point3D scenePoint = new Point3D(rect2.localToScene(eventPoint).getX(), rect2.localToScene(eventPoint).getY(), rect2.localToScene(eventPoint).getZ());
            sphere2.setTranslateX(scenePoint.getX());
            sphere2.setTranslateY(scenePoint.getY());
            sphere2.setTranslateZ(scenePoint.getZ());
            root.getChildren().add(sphere2);
            control.newRotation(rotationGroup, scene, scenePoint);
        });
        scene.setOnMousePressed(event -> {
            Point3D scenePoint = new Point3D(event.getSceneX(), event.getSceneY(), control.getAnchorZ());
            control.newRotation(rotationGroup, scene, scenePoint);
        });
        primaryStage.show();  
    }
    public void startup(String[] args) {
        // TODO Auto-generated method stub
        launch(args);  
    }
}
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.EventHandler;
import javafx.geometry.Point3D;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.transform.Rotate;
/**
 * 
 * @author nim
 * @description 
 * This class is used to control the transformation/rotation/zoom of a SmartGroup based on mouse events
 */
public class MouseControl {
    private double anchorX, anchorY; 
    private double anchorZ; 
    private double anchorAngleX = 0;
    private double anchorAngleY = 0;
    private EventHandler<MouseEvent> draggHandler;
    private Rotate xRotate;
    private Rotate yRotate;
    private Point3D transformedPoint;
    /**
     * 
     * @param group The rotation is applied to this group
     * @param scene Mouse-Listeners are attached to this scene
     * @param pivotPoint PivotPoint in SceneCoordinates
     */
    public void newRotation(SmartGroup group, Scene scene, Point3D pivotPoint) { 
        setAnchorZ(pivotPoint.getZ());
        if (draggHandler != null) {
            scene.removeEventHandler(MouseEvent.MOUSE_DRAGGED, draggHandler); 
            xRotate.angleProperty().unbind();
            yRotate.angleProperty().unbind();
        }
        group.getTransforms().addAll(
                xRotate = new Rotate(0, Rotate.X_AXIS),
                yRotate = new Rotate(0, Rotate.Y_AXIS)
                );
        anchorX = pivotPoint.getX(); 
        anchorY = pivotPoint.getY();
        anchorAngleX = 0;
        anchorAngleY = 0;
        xRotate.setPivotX(pivotPoint.getX());
        xRotate.setPivotY(pivotPoint.getY());
        yRotate.setPivotX(pivotPoint.getX());
        yRotate.setPivotY(pivotPoint.getY());
        xRotate.setPivotZ(pivotPoint.getZ());
        yRotate.setPivotZ(pivotPoint.getZ());
        //create new MouseDraggedEvent
        DoubleProperty angleX = new SimpleDoubleProperty();
        DoubleProperty angleY = new SimpleDoubleProperty();
        EventHandler<MouseEvent> mDragged = (draggedEvent -> {
            angleX.set(anchorAngleX - (anchorY - draggedEvent.getSceneY()));
            angleY.set(anchorAngleY + (anchorX - draggedEvent.getSceneX())); 
        });
        xRotate.angleProperty().bind(angleX);
        yRotate.angleProperty().bind(angleY);
        scene.setOnMouseDragged(mDragged);
        draggHandler = mDragged;
    }
    public double getAnchorX() {
        return anchorX;
    }
    public void setAnchorX(double anchorX) {
        this.anchorX = anchorX;
    }
    public double getAnchorY() {
        return anchorY;
    }
    public void setAnchorY(double anchorY) {
        this.anchorY = anchorY;
    }
    public double getAnchorZ() {
        return anchorZ;
    }
    public void setAnchorZ(double anchorZ) {
        this.anchorZ = anchorZ;
    }
    public double getAnchorAngleX() {
        return anchorAngleX;
    }
    public void setAnchorAngleX(double anchorAngleX) {
        this.anchorAngleX = anchorAngleX;
    }
    public double getAnchorAngleY() {
        return anchorAngleY;
    }
    public void setAnchorAngleY(double anchorAngleY) {
        this.anchorAngleY = anchorAngleY;
    }
    public EventHandler<MouseEvent> getDraggHandler() {
        return draggHandler;
    }
    public void setDraggHandler(EventHandler<MouseEvent> draggHandler) {
        this.draggHandler = draggHandler;
    }
    public Rotate getxRotate() {
        return xRotate;
    }
    public void setxRotate(Rotate xRotate) {
        this.xRotate = xRotate;
    }
    public Rotate getyRotate() {
        return yRotate;
    }
    public void setyRotate(Rotate yRotate) {
        this.yRotate = yRotate;
    }

}
...