如何在 javafx 中调整旋转矩形的大小

How resize a rotated rectangle in javafx

借助这里的几篇文章,我创建了一个可拖动和可旋转的矩形。我希望用户可以拖动一个锚点以从中心旋转矩形并将其调整一个角的大小,同时对角保持在同一位置,如果矩形保持未旋转,则计算非常简单。不幸的是,在这种情况下,边界矩形可以旋转,三角学以及如何应用在这里对我来说不是很清楚。经过几天的谷歌搜索,到目前为止,我为使这项工作所做的任何尝试都惨遭失败。抱歉有任何错误,英语不是我的母语。提前致谢

import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.stage.Stage;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        final Delta dragDelta = new Delta();
        final Rotate rotate = new Rotate();
        Wrapper<Point2D> mouseLocation = new Wrapper<>();
            
        Pane root = new Pane();
        
        Rectangle rect = new Rectangle(100,100);
    
        //set pivot on rectangle center
        rotate.setPivotX((rect.getX() + rect.getWidth())/2);
        rotate.setPivotY((rect.getY() + rect.getHeight())/2);
    
        rect.setStyle(
                    "-fx-stroke: blue; " +
                    "-fx-stroke-width: 2px; " +
                    "-fx-stroke-dash-array: 12 2 4 2; " +
                    "-fx-stroke-dash-offset: 6; " +
                    "-fx-stroke-line-cap: butt; " +
                    "-fx-fill: rgba(255, 255, 255, .0);"
        );
        
        Group group = new Group();
        
        
        // make a rectangle movable by dragging it around with the mouse.
        rect.setOnMousePressed(mouseEvent -> {
            // record a delta distance for the drag and drop operation.
            mouseLocation.value = new Point2D(mouseEvent.getSceneX(), mouseEvent.getSceneY());
           
            group.getScene().setCursor(Cursor.MOVE);    
         });
            
         rect.setOnMouseReleased(mouseEvent -> {
             mouseLocation.value = null ;
             group.getScene().setCursor(Cursor.HAND);    
         });
            
         rect.setOnMouseDragged(mouseEvent -> {
             // Get the mouse deltas
             double deltaX = mouseEvent.getSceneX() - mouseLocation.value.getX();
             double deltaY = mouseEvent.getSceneY() - mouseLocation.value.getY();

             group.setTranslateX(group.getTranslateX() + deltaX); 
             group.setTranslateY(group.getTranslateY() + deltaY);

             mouseLocation.value = new Point2D(mouseEvent.getSceneX(), mouseEvent.getSceneY());   
         });
        
        Circle topLeft = new Circle(7);
        
        topLeft.centerXProperty().bind(rect.xProperty()); 
        topLeft.centerYProperty().bind(rect.yProperty());
        
        //Here is the tricky part
        topLeft.setOnMousePressed(e->{
            
        });
        
        topLeft.setOnMouseDragged(e->{
            
        });
        
        //Anchor for rotate the rectangle
        Circle rotateCircle = new Circle(7);
        rotateCircle.centerXProperty().bind(rect.xProperty().add(rect.widthProperty()).divide(2)); 
        rotateCircle.centerYProperty().bind(rect.yProperty().subtract(25d));
        
        rotateCircle.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
                dragDelta.x = event.getSceneX();
                dragDelta.x = event.getSceneY();
            });

        // When it's dragged rotate the box
        rotateCircle.addEventHandler(MouseEvent.MOUSE_DRAGGED, event -> {

            var localToScene = group.getLocalToSceneTransform();

            double x1 = dragDelta.x;
            double y1 = dragDelta.y;

            var x2 = event.getSceneX();
            var y2 = event.getSceneY();

            var px = rotate.getPivotX() + localToScene.getTx();
            var py = rotate.getPivotY() + localToScene.getTy();

            // Work out the angle rotated
            double th1 = deltaAngle(x1, y1, px, py);
            double th2 = deltaAngle(x2, y2, px, py);

            var angle = rotate.getAngle();

            angle += th2 - th1;

            // Rotate the rectangle
            rotate.setAngle(angle);

            dragDelta.x = event.getSceneX();
            dragDelta.y = event.getSceneY();
        });

        
        group.getChildren().addAll(rect, rotateCircle, topLeft);
        
        group.setLayoutX(100);
        group.setLayoutY(100);
        group.getTransforms().add(rotate);
        
        root.getChildren().add(group);
        
        
        Scene scene = new Scene(root,400,400);
        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();

    }
    
    // Return the angle from 0 to 360 
     public static double deltaAngle (double x, double y, double px, double py) {
        double dx = x - px;
        double dy = y - py;

        double angle = Math.abs(Math.toDegrees(Math.atan2(dy, dx)));

        if(dy < 0) {
             angle = 360 - angle;
         }

         return angle;
      }
     
    // records relative x and y co-ordinates.
    private static class Delta {
         double x, y;
    }
        
    static class Wrapper<T> {
       T value ; 
    } 

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

像这样...

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.NonInvertibleTransformException;
import javafx.scene.transform.Rotate;

public class FancyRectangle extends Application {

    @Override
    public void start(Stage primaryStage) {
        final MouseContext refPoint = new MouseContext();
        final Rotate rotate = new Rotate();
        Pane root = new Pane();
        Rectangle rect = new Rectangle(100, 100);

        //set pivot on rectangle center
        rotate.setPivotX((rect.getX() + rect.getWidth()) / 2);
        rotate.setPivotY((rect.getY() + rect.getHeight()) / 2);

        rect.setStyle(
                "-fx-stroke: blue; "
                + "-fx-stroke-width: 2px; "
                + "-fx-stroke-dash-array: 12 2 4 2; "
                + "-fx-stroke-dash-offset: 6; "
                + "-fx-stroke-line-cap: butt; "
                + "-fx-fill: rgba(255, 255, 255, .0);"
        );

        Group group = new Group();

        // make a rectangle movable by dragging it around with the mouse.
        rect.setOnMousePressed(mouseEvent -> {
            // record a delta distance for the drag and drop operation.
            refPoint.sceneX = mouseEvent.getSceneX();
            refPoint.sceneY = mouseEvent.getSceneY();
            group.getScene().setCursor(Cursor.MOVE);
        });

        rect.setOnMouseReleased(mouseEvent -> {
            group.getScene().setCursor(Cursor.HAND);
        });

        rect.setOnMouseDragged(mouseEvent -> {
            // Get the mouse deltas
            double deltaX = mouseEvent.getSceneX() - refPoint.sceneX;
            double deltaY = mouseEvent.getSceneY() - refPoint.sceneY;

            group.setTranslateX(group.getTranslateX() + deltaX);
            group.setTranslateY(group.getTranslateY() + deltaY);

            refPoint.sceneX = mouseEvent.getSceneX();
            refPoint.sceneY = mouseEvent.getSceneY();
        });

        Circle resizeCircle = new Circle(7);

        resizeCircle.centerXProperty().bind(rect.xProperty());
        resizeCircle.centerYProperty().bind(rect.yProperty());

        // Handle resize
        resizeCircle.setOnMousePressed(e -> {
            var sceneCenter = resizeCircle.localToScene(resizeCircle.getCenterX(), resizeCircle.getCenterY());
            refPoint.sceneX = e.getSceneX();
            refPoint.sceneY = e.getSceneY();
            refPoint.offX = rect.getWidth();
            refPoint.offY = rect.getHeight();
        });

        resizeCircle.setOnMouseDragged(e -> {
            try {
                var sceneToLocal = group.getLocalToSceneTransform().createInverse();
                var localRef = sceneToLocal.transform(refPoint.sceneX, refPoint.sceneY);
                var localMouse = sceneToLocal.transform(e.getSceneX(), e.getSceneY());

                var dx = localMouse.getX() - localRef.getX();
                var dy = localMouse.getY() - localRef.getY();

                var x = localMouse.getX();
                var y = localMouse.getY();
                var w = Math.abs(refPoint.offX-dx);
                var h = Math.abs(refPoint.offY-dy);
                rect.setX(x);
                rect.setY(y);
                rect.setWidth(w);
                rect.setHeight(h);

                rotate.setPivotX(x + w/2);
                rotate.setPivotY(y + h/2);
            } catch (NonInvertibleTransformException ex) {}
            e.consume();
        });

        // Anchor for rotate the rectangle
        Circle rotateCircle = new Circle(7);
        rotateCircle.centerXProperty().bind(rect.xProperty().add(rect.widthProperty().divide(2)));
        rotateCircle.centerYProperty().bind(rect.yProperty().subtract(25d));

        rotateCircle.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
            var sceneCenter = rotateCircle.localToScene(rotateCircle.getCenterX(), rotateCircle.getCenterY());
            refPoint.sceneX = e.getSceneX();
            refPoint.sceneY = e.getSceneY();
            refPoint.offX = sceneCenter.getX()-refPoint.sceneX;
            refPoint.offY = sceneCenter.getY()-refPoint.sceneY;
        });

        // When it's dragged rotate the box
        rotateCircle.addEventHandler(MouseEvent.MOUSE_DRAGGED, event -> {

            var localToScene = group.getLocalToSceneTransform();

            var x2 = event.getSceneX()+refPoint.offX;
            var y2 = event.getSceneY()+refPoint.offY;

            var pivotPoint = localToScene.transform(rotate.getPivotX(), rotate.getPivotY());
            double angle = Math.toDegrees(Math.atan2(x2-pivotPoint.getX(), pivotPoint.getY()-y2));
            // Rotate the rectangle
            rotate.setAngle(angle);
        });

        group.getChildren().addAll(rect, rotateCircle, resizeCircle);

        group.setLayoutX(100);
        group.setLayoutY(100);
        group.getTransforms().add(rotate);

        root.getChildren().add(group);

        Scene scene = new Scene(root, 400, 400);
        //scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    // records relative x and y co-ordinates.
    private static class MouseContext {
        double sceneX, sceneY;
        double offX, offY;
    }

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