同时旋转和平移在 javafx 中无法按预期工作
Simultaneous Rotate and Translate not working as expected in javafx
我从 Circles 和 Line 构建了以下 "system" .
我正在尝试在系统中执行两个转换。
- 拖动绿色圆时,绿色和蓝色圆都应围绕红色中心旋转,并沿拖动方向旋转。
- 当拖动 Red 中心时,整个系统应该相应地被拖动(像一个整体)。
我尝试实现它但遇到了问题。
两个转换单独完成时都工作正常。
即
当应用程序启动时,当您尝试拖动绿色圆圈时,整个系统完美地围绕红色圆圈旋转。
同样,在启动时,当拖动红色圆圈时,一切都被拖动得很好。
但是
当一个接一个地尝试这些拖动时,形状会相互远离!!
请提出可能导致此行为的原因。
也欢迎任何其他实现转换的方法,因为我还是新手到 JavaFx 中的动画,这显然不是解决问题的最佳代码。
以下是我的代码:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class SpindleAndWheel extends Application
{
Circle circle;
Circle oppositeCircle;
Circle pivot;
Line spindle;
Rotate rotateCircle, rotateOppositeCircle;
Translate translateCircle, translateOppositeCircle;
Translate translateCircleBack, translateOppositeCircleBack;
Translate dragTranslateCircle, dragTranslatePivot, dragTranslateOppositeCircle, dragTranslateSpindle;
double dragInitX, dragInitY;
double dragInitTheta;
double theta1,theta2;
double angleOfRotation;
double dragPivotInitX,dragPivotInitY,systemDragOffsetX,systemDragOffsetY;
double dragTranslateCircleBackupX,dragTranslatePivotBackupX, dragTranslateOppositeCircleBackupX, dragTranslateSpindleBackupX;
double dragTranslateCircleBackupY,dragTranslatePivotBackupY, dragTranslateOppositeCircleBackupY, dragTranslateSpindleBackupY;
@Override
public void start(Stage primaryStage) throws Exception
{
Stage stage = new Stage();
stage.setMinHeight(500);
stage.setMinWidth(500);
Pane root = new Pane();
circle = new Circle(150, 150, 30);
oppositeCircle = new Circle(350, 350, 30);
pivot = new Circle(250, 250, 5);
spindle = new Line(150, 150, 350, 350);
/**************** Initializing Shapes **********/
circle.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.35));
circle.setStroke(Color.GREEN);
oppositeCircle.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.35));
oppositeCircle.setStroke(Color.BLUE);
pivot.setFill(Color.RED.deriveColor(1, 1, 1, 0.35));
pivot.setStroke(Color.RED);
spindle.setStrokeWidth(3);
spindle.setStroke(Color.BLACK.deriveColor(1, 1, 1, 0.35));
/****************************************************/
/**************** Initializing Animations **********/
rotateCircle = new Rotate(0, 0, 0);
translateCircle = new Translate(0, 0);
translateCircleBack = new Translate(0, 0);
dragTranslateCircle = new Translate(0, 0);
rotateOppositeCircle = new Rotate(0, 0, 0);
translateOppositeCircle = new Translate(0, 0);
translateOppositeCircleBack = new Translate(0, 0);
dragTranslateOppositeCircle = new Translate(0, 0);
dragTranslatePivot = new Translate(0, 0);
dragTranslateSpindle = new Translate(0, 0);
/****************************************************/
/**************** Adding Animations **************/
circle.getTransforms().addAll(translateCircle, rotateCircle, translateCircleBack, dragTranslateCircle);
oppositeCircle.getTransforms().addAll(translateOppositeCircle, rotateOppositeCircle, translateOppositeCircleBack, dragTranslateOppositeCircle);
pivot.getTransforms().addAll(dragTranslatePivot);
spindle.getTransforms().addAll(dragTranslateSpindle);
/****************************************************/
Scene scene = new Scene(root);
stage.setScene(scene);
root.getChildren().addAll(circle,oppositeCircle,pivot,spindle);
stage.show();
/** Get angle of point of click with
* point of rotation, before drag begins **/
circle.setOnMousePressed(event -> {
dragInitX = event.getSceneX();
dragInitY = event.getSceneY();
dragInitTheta = angleOfRotation + dragInitTheta;
double initialSlope;
double pointOfRotationX,pointOfRotationY;
pointOfRotationY = pivot.getCenterY() + dragTranslatePivot.getY();
pointOfRotationX = pivot.getCenterX() + dragTranslatePivot.getX();
initialSlope = Math.atan((dragInitY - (pointOfRotationX)) / (dragInitX - (pointOfRotationY)));
theta1 = Math.toDegrees(initialSlope);
if (dragInitX < pointOfRotationX)
theta1 = (360 + theta1) % 360;
else
theta1 = 180 + theta1;
});
/********************************************/
/** Get angle of point of drags with
* point of rotation, when the drag is on **/
circle.setOnMouseDragged(event -> {
double finalSlope;
double pointOfRotationX,pointOfRotationY;
pointOfRotationY = pivot.getCenterY() + dragTranslatePivot.getY();
pointOfRotationX = pivot.getCenterX() + dragTranslatePivot.getX();
finalSlope = Math.atan((event.getSceneY() - (pointOfRotationX)) / (event.getSceneX() - (pointOfRotationY)));
theta2 = Math.toDegrees(finalSlope);
if (event.getSceneX() < pointOfRotationX)
theta2 = (360 + theta2) % 360;
else
theta2 = 180 + theta2;
angleOfRotation = theta2 - theta1;
translateCircle.setX(pointOfRotationX);
translateCircle.setY(pointOfRotationY);
rotateCircle.setAngle(angleOfRotation + dragInitTheta);
translateCircleBack.setX(-pointOfRotationX);
translateCircleBack.setY(-pointOfRotationY);
translateOppositeCircle.setX(pointOfRotationX);
translateOppositeCircle.setY(pointOfRotationY);
rotateOppositeCircle.setAngle(angleOfRotation + dragInitTheta);
translateOppositeCircleBack.setX(-pointOfRotationX);
translateOppositeCircleBack.setY(-pointOfRotationY);
spindle.setRotate(angleOfRotation + dragInitTheta);
});
/********************************************/
/** Relocate the whole system when the point of
* rotation is dragged **/
pivot.setOnMousePressed(event -> {
dragPivotInitX = event.getSceneX();
dragPivotInitY = event.getSceneY();
dragTranslateCircleBackupX = dragTranslateCircle.getX();
dragTranslateCircleBackupY = dragTranslateCircle.getY();
dragTranslatePivotBackupX = dragTranslatePivot.getX();
dragTranslatePivotBackupY = dragTranslatePivot.getY();
dragTranslateOppositeCircleBackupX = dragTranslateOppositeCircle.getX();
dragTranslateOppositeCircleBackupY = dragTranslateOppositeCircle.getY();
dragTranslateSpindleBackupX = dragTranslateSpindle.getX();
dragTranslateSpindleBackupY = dragTranslateSpindle.getY();
});
pivot.setOnMouseDragged(event -> {
systemDragOffsetX = event.getSceneX() - dragPivotInitX;
systemDragOffsetY = event.getSceneY() - dragPivotInitY;
dragTranslateCircle.setX(dragTranslateCircleBackupX + systemDragOffsetX);
dragTranslateCircle.setY(dragTranslateCircleBackupY + systemDragOffsetY);
dragTranslatePivot.setX(dragTranslatePivotBackupX+ systemDragOffsetX);
dragTranslatePivot.setY(dragTranslatePivotBackupY+ systemDragOffsetY);
dragTranslateOppositeCircle.setX(dragTranslateOppositeCircleBackupX+ systemDragOffsetX);
dragTranslateOppositeCircle.setY(dragTranslateOppositeCircleBackupY+ systemDragOffsetY);
dragTranslateSpindle.setX(dragTranslateSpindleBackupX+ systemDragOffsetX);
dragTranslateSpindle.setY(dragTranslateSpindleBackupY + systemDragOffsetY);
});
/********************************************/
}
public static void main(String[] args)
{
launch(args);
}
}
不错的方法,但正如您已经发现的那样,它有一个主要缺点:应用一个转换后,另一个转换效果不佳。原因在于您定义转换的方式。此外,分配如此多的转换导致系统复杂,难以维护。
我的建议要简单得多:将所有形状包裹在一个 Group
中,并且只变换这组,在拖动轴时平移它,或者在轴上旋转它,当你拖动圆圈。注意这里可以用setPivotX()
和setPivotY()
来表示实际的旋转点
如您所见,您只需要两个转换,更重要的是,以任何顺序应用其中任何一个都不会产生任何副作用。
编辑
正如 OP 正确指出的那样,旋转计算存在错误。为了完整起见,我编辑了我的答案以显示正确的代码。
private Circle circle;
private Circle oppositeCircle;
private Circle pivot;
private Line spindle;
private Group group;
private Rotate rotateGroup;
double dragInitTheta;
double theta1,theta2;
double angleOfRotation;
private Translate translateGroup;
private double dragTranslateGroupBackupX, dragTranslateGroupBackupY;
private double dragPivotInitX,dragPivotInitY,systemDragOffsetX,systemDragOffsetY;
@Override
public void start(Stage stage){
circle = new Circle(150, 150, 30);
oppositeCircle = new Circle(350, 350, 30);
pivot = new Circle(250, 250, 5);
spindle = new Line(150, 150, 350, 350);
group = new Group(circle,oppositeCircle,pivot,spindle);
/**************** Initializing Shapes **********/
circle.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.35));
circle.setStroke(Color.GREEN);
oppositeCircle.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.35));
oppositeCircle.setStroke(Color.BLUE);
pivot.setFill(Color.RED.deriveColor(1, 1, 1, 0.35));
pivot.setStroke(Color.RED);
spindle.setStrokeWidth(3);
spindle.setStroke(Color.BLACK.deriveColor(1, 1, 1, 0.35));
/****************************************************/
/**************** Initializing Transforms **********/
rotateGroup = new Rotate(0, 0, 0);
translateGroup = new Translate(0, 0);
/****************************************************/
/**************** Adding Transforms **************/
group.getTransforms().addAll(translateGroup,rotateGroup);
/****************************************************/
Pane root = new Pane(group);
Scene scene = new Scene(root,500,500);
stage.setScene(scene);
stage.show();
/** Get angle of point of click with
* point of rotation, before drag begins **/
circle.setOnMousePressed(event -> {
dragInitTheta = angleOfRotation + dragInitTheta;
double pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
double initialSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta1 = Math.toDegrees(initialSlope);
if (event.getSceneX() < pointOfRotationX)
theta1 = (360 + theta1) % 360;
else
theta1 = 180 + theta1;
});
/********************************************/
/** Get angle of point of drags with
* point of rotation, when the drag is on **/
circle.setOnMouseDragged(event -> {
double pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
double finalSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta2 = Math.toDegrees(finalSlope);
if (event.getSceneX() < pointOfRotationX)
theta2 = (360 + theta2) % 360;
else
theta2 = 180 + theta2;
angleOfRotation = theta2 - theta1;
rotateGroup.setPivotX(pivot.getCenterX());
rotateGroup.setPivotY(pivot.getCenterY());
rotateGroup.setAngle(angleOfRotation + dragInitTheta);
});
/********************************************/
/** Relocate the whole system when the point of
* rotation is dragged **/
pivot.setOnMousePressed(event -> {
dragPivotInitX = event.getSceneX();
dragPivotInitY = event.getSceneY();
dragTranslateGroupBackupX = translateGroup.getX();
dragTranslateGroupBackupY = translateGroup.getY();
});
pivot.setOnMouseDragged(event -> {
systemDragOffsetX = event.getSceneX() - dragPivotInitX;
systemDragOffsetY = event.getSceneY() - dragPivotInitY;
translateGroup.setX(dragTranslateGroupBackupX + systemDragOffsetX);
translateGroup.setY(dragTranslateGroupBackupY + systemDragOffsetY);
});
/********************************************/
}
José Pereda、很好的答案!! 更好的方法。
学习了 许多 个新事物。
只需要做一个简单的修正。
在计算阻力点的斜率时,还需要考虑由于(translateGroup.getY(),translateGroup.getX())[=25=引起的偏移量] 在 (pivot.getCenterY(),pivot.getCenterX()).
以下是经过上述更正的 José 代码。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import javafx.scene.Group;
public class SpindleAndWheelGroup extends Application
{
private Circle circle;
private Circle oppositeCircle;
private Circle pivot;
private Line spindle;
private Group group;
private Rotate rotateGroup;
double dragInitTheta;
double theta1, theta2;
double angleOfRotation;
private Translate translateGroup;
private double dragTranslateGroupBackupX, dragTranslateGroupBackupY;
private double dragPivotInitX, dragPivotInitY, systemDragOffsetX, systemDragOffsetY;
double pointOfRotationX,pointOfRotationY;
@Override
public void start(Stage stage)
{
circle = new Circle(150, 150, 30);
oppositeCircle = new Circle(350, 350, 30);
pivot = new Circle(250, 250, 5);
spindle = new Line(150, 150, 350, 350);
group = new Group(circle, oppositeCircle, pivot, spindle);
/**************** Initializing Shapes **********/
circle.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.35));
circle.setStroke(Color.GREEN);
oppositeCircle.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.35));
oppositeCircle.setStroke(Color.BLUE);
pivot.setFill(Color.RED.deriveColor(1, 1, 1, 0.35));
pivot.setStroke(Color.RED);
spindle.setStrokeWidth(3);
spindle.setStroke(Color.BLACK.deriveColor(1, 1, 1, 0.35));
/****************************************************/
/**************** Initializing Transforms **********/
rotateGroup = new Rotate(0, 0, 0);
translateGroup = new Translate(0, 0);
/****************************************************/
/**************** Adding Transforms **************/
group.getTransforms().addAll(translateGroup, rotateGroup);
/****************************************************/
Pane root = new Pane(group);
Scene scene = new Scene(root, 800, 700);
stage.setScene(scene);
stage.show();
/** Get angle of point of click with
* point of rotation, before drag begins **/
circle.setOnMousePressed(event -> {
dragInitTheta = angleOfRotation + dragInitTheta;
pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double initialSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta1 = Math.toDegrees(initialSlope);
if (event.getSceneX() < pointOfRotationX)
theta1 = (360 + theta1) % 360;
else
theta1 = 180 + theta1;
});
/********************************************/
/** Get angle of point of drags with
* point of rotation, when the drag is on **/
circle.setOnMouseDragged(event -> {
pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double finalSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta2 = Math.toDegrees(finalSlope);
if (event.getSceneX() < pointOfRotationX)
theta2 = (360 + theta2) % 360;
else
theta2 = 180 + theta2;
angleOfRotation = theta2 - theta1;
rotateGroup.setPivotX(pivot.getCenterX());
rotateGroup.setPivotY(pivot.getCenterY());
rotateGroup.setAngle(angleOfRotation + dragInitTheta);
});
/********************************************/
/** Relocate the whole system when the point of
* rotation is dragged **/
pivot.setOnMousePressed(event -> {
dragPivotInitX = event.getSceneX();
dragPivotInitY = event.getSceneY();
dragTranslateGroupBackupX = translateGroup.getX();
dragTranslateGroupBackupY = translateGroup.getY();
});
pivot.setOnMouseDragged(event -> {
systemDragOffsetX = event.getSceneX() - dragPivotInitX;
systemDragOffsetY = event.getSceneY() - dragPivotInitY;
translateGroup.setX(dragTranslateGroupBackupX + systemDragOffsetX);
translateGroup.setY(dragTranslateGroupBackupY + systemDragOffsetY);
});
/********************************************/
}
}
我从 Circles 和 Line 构建了以下 "system" .
我正在尝试在系统中执行两个转换。
- 拖动绿色圆时,绿色和蓝色圆都应围绕红色中心旋转,并沿拖动方向旋转。
- 当拖动 Red 中心时,整个系统应该相应地被拖动(像一个整体)。
我尝试实现它但遇到了问题。
两个转换单独完成时都工作正常。
即
当应用程序启动时,当您尝试拖动绿色圆圈时,整个系统完美地围绕红色圆圈旋转。
同样,在启动时,当拖动红色圆圈时,一切都被拖动得很好。
但是
当一个接一个地尝试这些拖动时,形状会相互远离!!
请提出可能导致此行为的原因。
也欢迎任何其他实现转换的方法,因为我还是新手到 JavaFx 中的动画,这显然不是解决问题的最佳代码。
以下是我的代码:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class SpindleAndWheel extends Application
{
Circle circle;
Circle oppositeCircle;
Circle pivot;
Line spindle;
Rotate rotateCircle, rotateOppositeCircle;
Translate translateCircle, translateOppositeCircle;
Translate translateCircleBack, translateOppositeCircleBack;
Translate dragTranslateCircle, dragTranslatePivot, dragTranslateOppositeCircle, dragTranslateSpindle;
double dragInitX, dragInitY;
double dragInitTheta;
double theta1,theta2;
double angleOfRotation;
double dragPivotInitX,dragPivotInitY,systemDragOffsetX,systemDragOffsetY;
double dragTranslateCircleBackupX,dragTranslatePivotBackupX, dragTranslateOppositeCircleBackupX, dragTranslateSpindleBackupX;
double dragTranslateCircleBackupY,dragTranslatePivotBackupY, dragTranslateOppositeCircleBackupY, dragTranslateSpindleBackupY;
@Override
public void start(Stage primaryStage) throws Exception
{
Stage stage = new Stage();
stage.setMinHeight(500);
stage.setMinWidth(500);
Pane root = new Pane();
circle = new Circle(150, 150, 30);
oppositeCircle = new Circle(350, 350, 30);
pivot = new Circle(250, 250, 5);
spindle = new Line(150, 150, 350, 350);
/**************** Initializing Shapes **********/
circle.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.35));
circle.setStroke(Color.GREEN);
oppositeCircle.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.35));
oppositeCircle.setStroke(Color.BLUE);
pivot.setFill(Color.RED.deriveColor(1, 1, 1, 0.35));
pivot.setStroke(Color.RED);
spindle.setStrokeWidth(3);
spindle.setStroke(Color.BLACK.deriveColor(1, 1, 1, 0.35));
/****************************************************/
/**************** Initializing Animations **********/
rotateCircle = new Rotate(0, 0, 0);
translateCircle = new Translate(0, 0);
translateCircleBack = new Translate(0, 0);
dragTranslateCircle = new Translate(0, 0);
rotateOppositeCircle = new Rotate(0, 0, 0);
translateOppositeCircle = new Translate(0, 0);
translateOppositeCircleBack = new Translate(0, 0);
dragTranslateOppositeCircle = new Translate(0, 0);
dragTranslatePivot = new Translate(0, 0);
dragTranslateSpindle = new Translate(0, 0);
/****************************************************/
/**************** Adding Animations **************/
circle.getTransforms().addAll(translateCircle, rotateCircle, translateCircleBack, dragTranslateCircle);
oppositeCircle.getTransforms().addAll(translateOppositeCircle, rotateOppositeCircle, translateOppositeCircleBack, dragTranslateOppositeCircle);
pivot.getTransforms().addAll(dragTranslatePivot);
spindle.getTransforms().addAll(dragTranslateSpindle);
/****************************************************/
Scene scene = new Scene(root);
stage.setScene(scene);
root.getChildren().addAll(circle,oppositeCircle,pivot,spindle);
stage.show();
/** Get angle of point of click with
* point of rotation, before drag begins **/
circle.setOnMousePressed(event -> {
dragInitX = event.getSceneX();
dragInitY = event.getSceneY();
dragInitTheta = angleOfRotation + dragInitTheta;
double initialSlope;
double pointOfRotationX,pointOfRotationY;
pointOfRotationY = pivot.getCenterY() + dragTranslatePivot.getY();
pointOfRotationX = pivot.getCenterX() + dragTranslatePivot.getX();
initialSlope = Math.atan((dragInitY - (pointOfRotationX)) / (dragInitX - (pointOfRotationY)));
theta1 = Math.toDegrees(initialSlope);
if (dragInitX < pointOfRotationX)
theta1 = (360 + theta1) % 360;
else
theta1 = 180 + theta1;
});
/********************************************/
/** Get angle of point of drags with
* point of rotation, when the drag is on **/
circle.setOnMouseDragged(event -> {
double finalSlope;
double pointOfRotationX,pointOfRotationY;
pointOfRotationY = pivot.getCenterY() + dragTranslatePivot.getY();
pointOfRotationX = pivot.getCenterX() + dragTranslatePivot.getX();
finalSlope = Math.atan((event.getSceneY() - (pointOfRotationX)) / (event.getSceneX() - (pointOfRotationY)));
theta2 = Math.toDegrees(finalSlope);
if (event.getSceneX() < pointOfRotationX)
theta2 = (360 + theta2) % 360;
else
theta2 = 180 + theta2;
angleOfRotation = theta2 - theta1;
translateCircle.setX(pointOfRotationX);
translateCircle.setY(pointOfRotationY);
rotateCircle.setAngle(angleOfRotation + dragInitTheta);
translateCircleBack.setX(-pointOfRotationX);
translateCircleBack.setY(-pointOfRotationY);
translateOppositeCircle.setX(pointOfRotationX);
translateOppositeCircle.setY(pointOfRotationY);
rotateOppositeCircle.setAngle(angleOfRotation + dragInitTheta);
translateOppositeCircleBack.setX(-pointOfRotationX);
translateOppositeCircleBack.setY(-pointOfRotationY);
spindle.setRotate(angleOfRotation + dragInitTheta);
});
/********************************************/
/** Relocate the whole system when the point of
* rotation is dragged **/
pivot.setOnMousePressed(event -> {
dragPivotInitX = event.getSceneX();
dragPivotInitY = event.getSceneY();
dragTranslateCircleBackupX = dragTranslateCircle.getX();
dragTranslateCircleBackupY = dragTranslateCircle.getY();
dragTranslatePivotBackupX = dragTranslatePivot.getX();
dragTranslatePivotBackupY = dragTranslatePivot.getY();
dragTranslateOppositeCircleBackupX = dragTranslateOppositeCircle.getX();
dragTranslateOppositeCircleBackupY = dragTranslateOppositeCircle.getY();
dragTranslateSpindleBackupX = dragTranslateSpindle.getX();
dragTranslateSpindleBackupY = dragTranslateSpindle.getY();
});
pivot.setOnMouseDragged(event -> {
systemDragOffsetX = event.getSceneX() - dragPivotInitX;
systemDragOffsetY = event.getSceneY() - dragPivotInitY;
dragTranslateCircle.setX(dragTranslateCircleBackupX + systemDragOffsetX);
dragTranslateCircle.setY(dragTranslateCircleBackupY + systemDragOffsetY);
dragTranslatePivot.setX(dragTranslatePivotBackupX+ systemDragOffsetX);
dragTranslatePivot.setY(dragTranslatePivotBackupY+ systemDragOffsetY);
dragTranslateOppositeCircle.setX(dragTranslateOppositeCircleBackupX+ systemDragOffsetX);
dragTranslateOppositeCircle.setY(dragTranslateOppositeCircleBackupY+ systemDragOffsetY);
dragTranslateSpindle.setX(dragTranslateSpindleBackupX+ systemDragOffsetX);
dragTranslateSpindle.setY(dragTranslateSpindleBackupY + systemDragOffsetY);
});
/********************************************/
}
public static void main(String[] args)
{
launch(args);
}
}
不错的方法,但正如您已经发现的那样,它有一个主要缺点:应用一个转换后,另一个转换效果不佳。原因在于您定义转换的方式。此外,分配如此多的转换导致系统复杂,难以维护。
我的建议要简单得多:将所有形状包裹在一个 Group
中,并且只变换这组,在拖动轴时平移它,或者在轴上旋转它,当你拖动圆圈。注意这里可以用setPivotX()
和setPivotY()
来表示实际的旋转点
如您所见,您只需要两个转换,更重要的是,以任何顺序应用其中任何一个都不会产生任何副作用。
编辑
正如 OP 正确指出的那样,旋转计算存在错误。为了完整起见,我编辑了我的答案以显示正确的代码。
private Circle circle;
private Circle oppositeCircle;
private Circle pivot;
private Line spindle;
private Group group;
private Rotate rotateGroup;
double dragInitTheta;
double theta1,theta2;
double angleOfRotation;
private Translate translateGroup;
private double dragTranslateGroupBackupX, dragTranslateGroupBackupY;
private double dragPivotInitX,dragPivotInitY,systemDragOffsetX,systemDragOffsetY;
@Override
public void start(Stage stage){
circle = new Circle(150, 150, 30);
oppositeCircle = new Circle(350, 350, 30);
pivot = new Circle(250, 250, 5);
spindle = new Line(150, 150, 350, 350);
group = new Group(circle,oppositeCircle,pivot,spindle);
/**************** Initializing Shapes **********/
circle.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.35));
circle.setStroke(Color.GREEN);
oppositeCircle.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.35));
oppositeCircle.setStroke(Color.BLUE);
pivot.setFill(Color.RED.deriveColor(1, 1, 1, 0.35));
pivot.setStroke(Color.RED);
spindle.setStrokeWidth(3);
spindle.setStroke(Color.BLACK.deriveColor(1, 1, 1, 0.35));
/****************************************************/
/**************** Initializing Transforms **********/
rotateGroup = new Rotate(0, 0, 0);
translateGroup = new Translate(0, 0);
/****************************************************/
/**************** Adding Transforms **************/
group.getTransforms().addAll(translateGroup,rotateGroup);
/****************************************************/
Pane root = new Pane(group);
Scene scene = new Scene(root,500,500);
stage.setScene(scene);
stage.show();
/** Get angle of point of click with
* point of rotation, before drag begins **/
circle.setOnMousePressed(event -> {
dragInitTheta = angleOfRotation + dragInitTheta;
double pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
double initialSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta1 = Math.toDegrees(initialSlope);
if (event.getSceneX() < pointOfRotationX)
theta1 = (360 + theta1) % 360;
else
theta1 = 180 + theta1;
});
/********************************************/
/** Get angle of point of drags with
* point of rotation, when the drag is on **/
circle.setOnMouseDragged(event -> {
double pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
double finalSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta2 = Math.toDegrees(finalSlope);
if (event.getSceneX() < pointOfRotationX)
theta2 = (360 + theta2) % 360;
else
theta2 = 180 + theta2;
angleOfRotation = theta2 - theta1;
rotateGroup.setPivotX(pivot.getCenterX());
rotateGroup.setPivotY(pivot.getCenterY());
rotateGroup.setAngle(angleOfRotation + dragInitTheta);
});
/********************************************/
/** Relocate the whole system when the point of
* rotation is dragged **/
pivot.setOnMousePressed(event -> {
dragPivotInitX = event.getSceneX();
dragPivotInitY = event.getSceneY();
dragTranslateGroupBackupX = translateGroup.getX();
dragTranslateGroupBackupY = translateGroup.getY();
});
pivot.setOnMouseDragged(event -> {
systemDragOffsetX = event.getSceneX() - dragPivotInitX;
systemDragOffsetY = event.getSceneY() - dragPivotInitY;
translateGroup.setX(dragTranslateGroupBackupX + systemDragOffsetX);
translateGroup.setY(dragTranslateGroupBackupY + systemDragOffsetY);
});
/********************************************/
}
José Pereda、很好的答案!! 更好的方法。
学习了 许多 个新事物。
只需要做一个简单的修正。
在计算阻力点的斜率时,还需要考虑由于(translateGroup.getY(),translateGroup.getX())[=25=引起的偏移量] 在 (pivot.getCenterY(),pivot.getCenterX()).
以下是经过上述更正的 José 代码。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import javafx.scene.Group;
public class SpindleAndWheelGroup extends Application
{
private Circle circle;
private Circle oppositeCircle;
private Circle pivot;
private Line spindle;
private Group group;
private Rotate rotateGroup;
double dragInitTheta;
double theta1, theta2;
double angleOfRotation;
private Translate translateGroup;
private double dragTranslateGroupBackupX, dragTranslateGroupBackupY;
private double dragPivotInitX, dragPivotInitY, systemDragOffsetX, systemDragOffsetY;
double pointOfRotationX,pointOfRotationY;
@Override
public void start(Stage stage)
{
circle = new Circle(150, 150, 30);
oppositeCircle = new Circle(350, 350, 30);
pivot = new Circle(250, 250, 5);
spindle = new Line(150, 150, 350, 350);
group = new Group(circle, oppositeCircle, pivot, spindle);
/**************** Initializing Shapes **********/
circle.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.35));
circle.setStroke(Color.GREEN);
oppositeCircle.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.35));
oppositeCircle.setStroke(Color.BLUE);
pivot.setFill(Color.RED.deriveColor(1, 1, 1, 0.35));
pivot.setStroke(Color.RED);
spindle.setStrokeWidth(3);
spindle.setStroke(Color.BLACK.deriveColor(1, 1, 1, 0.35));
/****************************************************/
/**************** Initializing Transforms **********/
rotateGroup = new Rotate(0, 0, 0);
translateGroup = new Translate(0, 0);
/****************************************************/
/**************** Adding Transforms **************/
group.getTransforms().addAll(translateGroup, rotateGroup);
/****************************************************/
Pane root = new Pane(group);
Scene scene = new Scene(root, 800, 700);
stage.setScene(scene);
stage.show();
/** Get angle of point of click with
* point of rotation, before drag begins **/
circle.setOnMousePressed(event -> {
dragInitTheta = angleOfRotation + dragInitTheta;
pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double initialSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta1 = Math.toDegrees(initialSlope);
if (event.getSceneX() < pointOfRotationX)
theta1 = (360 + theta1) % 360;
else
theta1 = 180 + theta1;
});
/********************************************/
/** Get angle of point of drags with
* point of rotation, when the drag is on **/
circle.setOnMouseDragged(event -> {
pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double finalSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta2 = Math.toDegrees(finalSlope);
if (event.getSceneX() < pointOfRotationX)
theta2 = (360 + theta2) % 360;
else
theta2 = 180 + theta2;
angleOfRotation = theta2 - theta1;
rotateGroup.setPivotX(pivot.getCenterX());
rotateGroup.setPivotY(pivot.getCenterY());
rotateGroup.setAngle(angleOfRotation + dragInitTheta);
});
/********************************************/
/** Relocate the whole system when the point of
* rotation is dragged **/
pivot.setOnMousePressed(event -> {
dragPivotInitX = event.getSceneX();
dragPivotInitY = event.getSceneY();
dragTranslateGroupBackupX = translateGroup.getX();
dragTranslateGroupBackupY = translateGroup.getY();
});
pivot.setOnMouseDragged(event -> {
systemDragOffsetX = event.getSceneX() - dragPivotInitX;
systemDragOffsetY = event.getSceneY() - dragPivotInitY;
translateGroup.setX(dragTranslateGroupBackupX + systemDragOffsetX);
translateGroup.setY(dragTranslateGroupBackupY + systemDragOffsetY);
});
/********************************************/
}
}