JavaFX - 旋转后绘制箭头中的额外水平空间

时间:2016-11-15 20:58:40

标签: java javafx rotation shape

我有这部分代码:

Group g = new Group();

double xMid = (end.getCenterX() - start.getCenterX())/2;
double yMid = (end.getCenterY() - start.getCenterY())/2;
Line a = new Line(xMid, yMid-4, xMid, yMid+4);
Line b = new Line(xMid, yMid-4, xMid-10, yMid);
Line c = new Line(xMid, yMid+4, xMid-10, yMid);

g.getChildren().add(a);
g.getChildren().add(b);
g.getChildren().add(c);

g.setRotate(getAngle(start, end));
g.setTranslateX(start.getCenterX());
g.setTranslateY(start.getCenterY());

以上代码负责在一行中间绘制一个箭头,该箭头从startend(这些Circle作为起点和终点) 。箭头必须以正确的方向旋转。这是带有这样箭头的多行的输出:

output

如您所见,如果角度接近±90°,则向左移动。

read

  

[...]如果转换和效果直接设置在这个孩子身上   分组,这些将包含在本集团的布局范围内。

但它并没有真正帮助我解决这个问题。您有任何想法如何解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

首先,形成三角形的3条线最容易使用Polygon

要修复基于布局边界选择的轴心点,您可以使用Rotate转换和Translate转换为transform,或者只是计算2个矩阵的连接你自己的并使用Affine

private static final double[] POLYGON_POINTS = {
    -5, -4,
    -5, 4,
    5, 0
};

private static void makeArrow(Pane parent, Circle start, Circle end, double t) {
    Polygon arrow = new Polygon(POLYGON_POINTS);
    arrow.setFill(null);
    arrow.setStroke(Color.BLACK);
    double dx = end.getCenterX() - start.getCenterX();
    double dy = end.getCenterY() - start.getCenterY();

    double d = Math.hypot(dx, dy);

    double sin = dy / d;
    double cos = dx / d;

    // matrix:
    //  [  cos     -sin     0    t * dx + start.getCenterX() ]        
    //  [  sin      cos     0    t * dy + start.getCenterY() ]        
    //  [   0        0      1                   0            ]        
    //  [   0        0      0                   1            ]
    Affine affine = new Affine(cos, -sin, t * dx + start.getCenterX(), sin, cos, t * dy + start.getCenterY());

    arrow.getTransforms().add(affine);
    parent.getChildren().add(arrow);
}

@Override
public void start(Stage primaryStage) {
    Circle end = new Circle(200, 20, 5);
    Circle start = new Circle(20, 200, 5);
    Line line = new Line(start.getCenterX(), start.getCenterY(), end.getCenterX(), end.getCenterY());

    Pane root = new Pane(line, start, end);

    makeArrow(root, start, end, 0.5);

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

    primaryStage.setScene(scene);
    primaryStage.show();
}

答案 1 :(得分:0)

我认为创建一个包含向上线和箭头的组更容易,然后只围绕中心旋转这个组。

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            Pane root = createPane();
            root.setTranslateX(200);
            root.setTranslateY(200);
            Scene scene = new Scene(root,400,400);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    private Pane createPane() {
        BorderPane root = new BorderPane();
        ArrowFactory arrowfactory = new ArrowFactory();
        double lineLength = 100;
        double centerX = 0;
        double centerY = 0;
        root.getChildren().addAll(
            arrowfactory.createLineAndArrow(centerX, centerY, lineLength, 0),
            arrowfactory.createLineAndArrow(centerX, centerY, lineLength, 30),
            arrowfactory.createLineAndArrow(centerX, centerY, lineLength, 45),
            arrowfactory.createLineAndArrow(centerX, centerY, lineLength, 60),
            arrowfactory.createLineAndArrow(centerX, centerY, lineLength, 90),
            arrowfactory.createLineAndArrow(centerX, centerY, lineLength, 135),
            arrowfactory.createLineAndArrow(centerX, centerY, lineLength, 180),
            arrowfactory.createLineAndArrow(centerX, centerY, lineLength, 225),
            arrowfactory.createLineAndArrow(centerX, centerY, lineLength, 270),
            arrowfactory.createLineAndArrow(centerX, centerY, lineLength, 315)
            );
        return root;
    }

    public static void main(String[] args) {
        launch(args);
    }

}

ArrayFactory.java

public class ArrowFactory {
    private final int arrowWidth = 10;
    private final int arrowHeight = 10;

    public Group createLineAndArrow(double centerX, double centerY, double lineLength, double rotation) {
        Group group = new Group();

        Line line = new Line(centerX, centerY, centerX, centerY - lineLength);
        Polygon upwardArrow = createUpwardArrow(centerX, centerY - lineLength / 2);

        group.getChildren().addAll(line, upwardArrow);
        group.getTransforms().add(new Rotate(rotation, centerX, centerY));
        return group;
    }

    private Polygon createUpwardArrow(double centerX, double centerY) {
        Polygon arrow = new Polygon(
                createUpwardArrowPoints(centerX, centerY + arrowHeight/2));
        arrow.setFill(Color.TRANSPARENT);
        arrow.setStroke(Color.BLACK);
        return arrow;
    }

    private double[] createUpwardArrowPoints(double centerX, double centerY) {
        return new double[] {
            centerX - arrowWidth / 2, centerY,  // left
            centerX + arrowWidth / 2, centerY,  // right
            centerX, centerY - arrowHeight,     // top
                };
    }
}

enter image description here

使用圆心作为输入可以使用:

private Group createLineAndArrow(double x1, double y1, double x2, double y2) {
        double distance = Math.hypot(x1-x2, y1-y2);
        double angle = Math.toDegrees(Math.atan2(x2 - x1, y2 - y1));
        return arrowfactory.createLineAndArrow(x1, y1, distance, angle);
}