我制作了一个小演示来说明我遇到的问题。使用步骤如下:
1 - 点击屏幕四次以创建网格。
2 - 点击底部的按钮,给创建的网格添加透视效果。
3 - 再次点击屏幕,绘制一个圆。
我的问题是:我不知道应该对 Circle 节点施加哪种变换才能在用户单击的确切位置上具有与网格相同的视觉效果。
此演示目前仅绘制了一个没有变换的圆形。
期望的输出如下(这里我用椭圆代替圆形,这不能成为我的解决方案,因为用户输入网格的四个坐标):
以下是该演示的代码。
Main.java
package application;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("View.fxml"));
Scene scene = new Scene(loader.load(), 600, 600);
primaryStage.setScene(scene);
primaryStage.setTitle("Perspective Transformation");
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
View.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="vBox" maxHeight="600.0" maxWidth="600.0" minHeight="600.0" minWidth="600.0" prefHeight="600.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
<children>
<AnchorPane fx:id="anchorPane" maxHeight="575.0" minHeight="575.0" prefHeight="575.0" prefWidth="600.0" />
<Button fx:id="button" alignment="CENTER" mnemonicParsing="false" prefHeight="25.0" prefWidth="600.0" text="Perspective Transformation" />
</children>
</VBox>
控制器.java
package application;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
public class Controller {
@FXML
VBox vBox;
@FXML
AnchorPane anchorPane;
@FXML
Button button;
Line line_1, line_2, line_3, line_4, middle_1, middle_2;
private int numberOfClicks = 0;
private int W = 10;
//Store coordinates of the corresponding clicks
private double cx1, cy1,
cx2, cy2,
cx3, cy3,
cx4, cy4,
cx5, cy5;
@FXML
private void initialize() {
button.setDisable(true);
button.setOnAction((event) -> {
//Create a standard grid
Line standard_1 = new Line(0, 0, 0, 600);
Line standard_2 = new Line(0, 600, 600, 600);
Line standard_3 = new Line(600, 600, 600, 0);
Line standard_4 = new Line(600, 0, 0, 0);
//Middle ones
Line standard_5 = new Line(300, 0, 300, 600);
Line standard_6 = new Line(0, 300, 600, 300);
standard_1.setStrokeWidth(W);
standard_2.setStrokeWidth(W);
standard_3.setStrokeWidth(W);
standard_4.setStrokeWidth(W);
standard_5.setStrokeWidth(W);
standard_6.setStrokeWidth(W);
anchorPane.getChildren().clear();
Pane perspectivePane = new Pane();
perspectivePane.getChildren().addAll(standard_1, standard_2, standard_3,
standard_4, standard_5, standard_6);
PerspectiveTransform pt = new PerspectiveTransform();
pt.setUlx(cx1);
pt.setUly(cy1);
pt.setUrx(cx2);
pt.setUry(cy2);
pt.setLrx(cx3);
pt.setLry(cy3);
pt.setLlx(cx4);
pt.setLly(cy4);
perspectivePane.setEffect(pt);
anchorPane.getChildren().add(perspectivePane);
});
anchorPane.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
numberOfClicks++;
if(numberOfClicks == 1){
cx1 = event.getX();
cy1 = event.getY();
}
else if(numberOfClicks == 2){
cx2 = event.getX();
cy2 = event.getY();
line_1 = new Line(cx1, cy1, cx2, cy2);
line_1.setStrokeWidth(W);
anchorPane.getChildren().add(line_1);
}
else if(numberOfClicks == 3){
cx3 = event.getX();
cy3 = event.getY();
line_2 = new Line(cx2, cy2, cx3, cy3);
line_2.setStrokeWidth(W);
anchorPane.getChildren().add(line_2);
}
else if(numberOfClicks == 4){
cx4 = event.getX();
cy4 = event.getY();
line_3 = new Line(cx3, cy3, cx4, cy4);
line_4 = new Line(cx4, cy4, cx1, cy1);
line_3.setStrokeWidth(W);
line_4.setStrokeWidth(W);
middle_1 = new Line((cx1+cx2)/2, (cy1+cy2)/2, (cx3+cx4)/2, (cy3+cy4)/2);
middle_2 = new Line((cx2+cx3)/2, (cy2+cy3)/2, (cx4+cx1)/2, (cy4+cy1)/2);
middle_1.setStrokeWidth(W);
middle_2.setStrokeWidth(W);
anchorPane.getChildren().addAll(line_3, line_4, middle_1, middle_2);
button.setDisable(false);
}
else if(numberOfClicks == 5){
cx5 = event.getX();
cy5 = event.getY();
Circle circle = new Circle();
circle.setCenterX(cx5);
circle.setCenterY(cy5);
circle.setRadius(30);
circle.setFill(Color.TRANSPARENT);
circle.setStroke(Color.BLACK);
circle.setStrokeWidth(W);
//PerspectiveTransform pt = new PerspectiveTransform();
//What transformation should I apply to the circle?
//circle.setEffect(pt);
anchorPane.getChildren().add(circle);
}
else {
anchorPane.getChildren().clear();
numberOfClicks = 0;
}
}
});
}
}
perspectivePane
相同的透视变换吗?还是尝试将圆形添加到perspectivePane
中?另外,下次提问时的一个小提示:尽量减少代码示例。同时,最好将UI作为代码提供,而不是作为“.fxml”文件,这样我就可以整体复制和粘贴您的代码,而无需创建多个文件并确保每个文件都在正确的文件夹中。 - Markus Köbele