Reputation: 175
I want to track my points in a Polygon class after transformations. My problem with using the Rotate
class from JavaFX, is to get the points position after the rotation, by doing something like this in the Piece
class:
double x = this.getPoints().get(0) + this.getLocalToParentTransform().getTx()
double y = this.getPoints().get(1) + this.getLocalToParentTransform().getTy()
It works using the Translate
class, but when I rotate, the coordinates will rotate itself with the rotation with a weird pivot point, and not follow the polygon at all, unless it is rotated 360 degrees. Piece
is a subclass of Polygon
.
private double originalX;
private double originalY;
private double centerX;
private double centerY;
private void initializePiece(Piece piece, Pane pane, int i) {
piece.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
originalX = event.getSceneX();
originalY = event.getSceneY();
centerX = piece.getCenterX();
centerY = piece.getCenterY();
}
});
piece.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.getButton() == MouseButton.PRIMARY) {
// Position of piece wrt. picked up position
double deltaX = event.getSceneX() - originalX;
double deltaY = event.getSceneY() - originalY;
Translate translate = new Translate();
translate.setX(deltaX);
translate.setY(deltaY);
piece.getTransforms().addAll(translate);
originalX = event.getSceneX();
originalY = event.getSceneY();
}
if (event.getButton() == MouseButton.SECONDARY) {
double deltaY = event.getSceneY() - originalY;
Rotate rotation = new Rotate(deltaY, centerX, centerY);
piece.getTransforms().add(rotation);
originalY = event.getSceneY();
}
}
});
}
And this is a snippet from the Piece
class.
public double getCenterX() {
double avg = 0;
for (int i = 0; i < this.getPoints().size(); i += 2) {
avg += this.getPoints().get(i) + this.getLocalToParentTransform().getTx();
}
avg = avg / (this.getPoints().size() / 2);
return avg;
}
public double getCenterY() {
double avg = 0;
for (int i = 1; i < this.getPoints().size(); i += 2) {
avg += this.getPoints().get(i) + this.getLocalToParentTransform().getTy();
}
avg = avg / (this.getPoints().size() / 2);
return avg;
}
Upvotes: 0
Views: 468
Reputation: 209245
All transformations are applied in local coordinates, so the pivot point should be given in the local coordinate system of the polygon, which is "unaware" of the transformations applied to it. I.e. you should just compute the center of the polygon in its own coordinate system, not its parent's coordinate system.
The mouse event's getX()
and getY()
methods will give the coordinates in the coordinate system of the event's source node, so using these makes the computations relatively easy. Here's a simple example (I calculated the current angle between the mouse press and the center of the polygon, and then the change in angle on dragging, instead of just using the y-coordinate; this feels more natural.)
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class DraggingTransforms extends Application {
public static void main(String[] args) {
Application.launch(args);
}
private double pressX ;
private double pressY ;
private double angle ;
@Override
public void start(Stage stage) throws Exception {
Polygon poly = new Polygon(10, 10, 50, 10, 50, 0, 70, 20, 50, 40, 50, 30, 10, 30, 10, 10);
poly.setFill(Color.web("#00b140"));
Pane root = new Pane(poly);
poly.setOnMousePressed(e -> {
pressX = e.getX();
pressY = e.getY();
angle = computeAngle(poly, e);
});
poly.setOnMouseDragged(e -> {
if (e.getButton() == MouseButton.PRIMARY) {
poly.getTransforms().add(new Translate(e.getX() - pressX, e.getY()-pressY));
} else {
double delta = computeAngle(poly, e) - angle;
Rotate rotation = new Rotate(delta, computeCenterX(poly), computeCenterY(poly));
poly.getTransforms().add(rotation);
}
});
Scene scene = new Scene(root, 800, 800);
stage.setScene(scene);
stage.show();
}
private double computeAngle(Polygon poly, MouseEvent e) {
return new Point2D(computeCenterX(poly), computeCenterY(poly))
.angle(new Point2D(e.getX(), e.getY()));
}
private double computeCenter(int offset, Polygon poly) {
double total = 0 ;
for (int i = offset ; i < poly.getPoints().size(); i+=2) {
total += poly.getPoints().get(i);
}
return total / (poly.getPoints().size() / 2);
}
private double computeCenterX(Polygon poly) {
return computeCenter(0, poly);
}
private double computeCenterY(Polygon poly) {
return computeCenter(1, poly);
}
}
Note that if you do need the coordinates of a point in the shape transformed to the parent's coordinate system, all you need to do is, for example,
poly.getLocalToParentTransform()
.transform(
poly.getPoints().get(0),
poly.getPoints().get(1)
)
Upvotes: 3