user1878143
user1878143

Reputation: 89

How is set the Pivot for Shapes in JavaFX after Rotate Transformation?

I'm trying to move the upper left corner on a rotated rectangle and keep the lower right corner fixed. But after the update of the pivots of the rectangle there is a jump of the rectangle. How do I have the corners set correctly so that the jump does not occur after update the pivots? The example illustrates the problem. The green and blue rectangle are different after clicking the button! Has everone an idea? May help the 'deltaTransform' procedure?

import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.NonInvertibleTransformException;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

public class RotateTest extends Application {

    Rectangle rect0,rect1, rect2;

    @Override
    public void start(Stage primaryStage) {

        rect0 = new Rectangle(100, 100, 200, 100); //start rect to compare
        rect0.setFill(Color.TRANSPARENT);
        rect0.setStroke(Color.GREEN);
        rect0.setStrokeWidth(1.5); 
        rect0.setRotate(20);

        rect1 = new Rectangle(100, 100, 200, 100); // moved rect
        rect1.setFill(Color.TRANSPARENT);
        rect1.setStroke(Color.RED);
        rect1.setStrokeWidth(1.5);
        rect2 = new Rectangle(100, 100, 200, 100);// unmoved rect
        rect2.setFill(Color.TRANSPARENT);
        rect2.setStrokeWidth(1.5);
        rect2.setStroke(Color.BLUE);

        Rotate rotate = new Rotate(20, rect1.getX() + rect1.getWidth() / 2., rect1.getY() + rect1.getHeight() / 2.);
        rect1.getTransforms().add(rotate);
        rect2.getTransforms().add(rotate);

        Button btn = new Button();
        btn.setText("Move to target");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                try {
                    Point2D p1ns = new Point2D(150, 50); //target for upper left corner in transformed system
                    Point2D p1n = rotate.inverseTransform(p1ns);//target for upper left corner in nontransformed system
                    Point2D p2 = new Point2D(rect1.getX()+rect1.getWidth(), rect1.getY()+rect1.getHeight());
                                                    //bottom right corner in nontransformed system
                    Point2D p2s = rotate.transform(p2);//bottom right corner in transformed system

                    rect1.setX(p1n.getX());
                    rect1.setY(p1n.getY());
                    rect1.setWidth(p2.getX()-p1n.getX());
                    rect1.setHeight(p2.getY()-p1n.getY());

                    //this make the problem:
                    rotate.setPivotX(rect1.getX() + rect1.getWidth() / 2.);
                    rotate.setPivotY(rect1.getY() + rect1.getHeight() / 2.);                    

                } catch (NonInvertibleTransformException ex) {
                    Logger.getLogger(RotateTest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });

        Group root = new Group();
        for (int i = 0; i < 10; i++) {
            Line l1 = new Line(i * 100, 0, i * 100, 400);
            Line l2 = new Line(0, i * 100, 1000, i * 100);
            root.getChildren().addAll(l1, l2);
        }

        root.getChildren().addAll(btn, rect0, rect1, rect2);

        Scene scene = new Scene(root, 400, 300);

        primaryStage.setTitle("Rotation");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

Upvotes: 0

Views: 1642

Answers (2)

user1878143
user1878143

Reputation: 89

Now I have found a solution. A secondary temporary Rotate-object helps! See the code now! The green and red rectangle have the same right bottom corner!

 @Override
            public void handle(ActionEvent event) {
                try {
                    Point2D p1s = new Point2D(150, 50); //target for upper left corner in transformed system
                    Point2D p2s = rotate.transform(rect1.getX()+rect1.getWidth(), rect1.getY()+rect1.getHeight());//bottom right corner in transformed system

                    Rotate rotTemp=new Rotate(rotate.getAngle(), (p1s.getX() + p2s.getX() )/ 2., (p1s.getY() + p2s.getY() )/ 2.);

                Point2D q1 = rotTemp.inverseTransform(p1s);
                Point2D q2 = rotTemp.inverseTransform(p2s);

                rect1.setX(q1.getX());
                rect1.setY(q1.getY());
                rect1.setWidth(q2.getX()-q1.getX());
                rect1.setHeight(q2.getY()-q1.getY());
                rotate.setPivotX(rotTemp.getPivotX());
                rotate.setPivotY(rotTemp.getPivotY());
            } catch (NonInvertibleTransformException ex) {
                Logger.getLogger(RotateTest.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

Upvotes: 1

James_D
James_D

Reputation: 209330

You can always fix the bottom right of a rectangle with a change of properties of the form:

x      -> x + deltaX ;
y      -> y + deltaY ;
width  -> width - deltaX ;
height -> height - deltaY ;

So you can do

btn.setOnAction(new EventHandler<ActionEvent>() {

    @Override
    public void handle(ActionEvent event) {
        try {

            Point2D targetAbsolute = new Point2D(150, 50);
            Point2D targetLocal = rotate.inverseTransform(targetAbsolute);
            double newX = targetLocal.getX() ;
            double newY = targetLocal.getY() ;

            double deltaX = newX - rect1.getX();
            double deltaY = newY - rect1.getY();

            rect1.setX(newX);
            rect1.setY(newY);
            rect1.setWidth(rect1.getWidth() - deltaX);
            rect1.setHeight(rect1.getHeight() - deltaY);

        } catch (NonInvertibleTransformException ex) {
            Logger.getLogger(RotateTest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
});

Upvotes: 0

Related Questions