Reputation: 89
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
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
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