【问题标题】:How resize a rotated rectangle in javafx如何在javafx中调整旋转矩形的大小
【发布时间】:2021-12-29 19:03:28
【问题描述】:

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

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);
    }
}

【问题讨论】:

    标签: javafx rotation resize trigonometry


    【解决方案1】:

    这样的……

    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);
        }
    }
    
    

    【讨论】:

    • 感谢您的回答。如果 rect 被旋转并拖动调整大小手柄 rect 位置变化。如问题所述,我希望调整大小时 rect 在视觉上保持在同一位置。
    • @Michael 如果您在计算 w 和 h 时仅从 2*dx、2*dy 中删除 2*,则它很接近。但它并不完美。
    • @Michael 我已经修好了。
    • 你是对的。我在问自己为什么是 2*。我想我必须努力实现我的要求。如果找到任何方法,我会发布它。非常感谢您的努力。
    • 为了在从 topLeft 手柄拖动时保持矩形视觉到位,只需添加 group.setTranslateX(group.getTranslateX + (e.getSceneX - refPoint.sceneX)); group.setTranslateY(group.getTranslateY + (e.getSceneY - refPoint.sceneY));目前正在尝试在其他三个角落找到如何做,欢迎任何想法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    • 2017-03-25
    相关资源
    最近更新 更多