javafx CubicCurve箭头角度和长度

时间:2016-08-08 00:12:33

标签: java javafx

对于简单的线条,我写了这段代码:

double lineAngle = Math.atan2(startPosition.getY() - endPosition.getY(), startPosition.getX() - endPosition.getX());

    double arrowX1 = Math.cos(lineAngle + Math.toRadians(ARROW_ANGLE)) * ARROW_LENGTH + endPosition.getX();
    double arrowY1 = Math.sin(lineAngle + Math.toRadians(ARROW_ANGLE)) * ARROW_LENGTH + endPosition.getY();

    double arrowX2 = Math.cos(lineAngle - Math.toRadians(ARROW_ANGLE)) * ARROW_LENGTH + endPosition.getX();
    double arrowY2 = Math.sin(lineAngle - Math.toRadians(ARROW_ANGLE)) * ARROW_LENGTH + endPosition.getY();

    MoveTo leftArrowMove = new MoveTo(endPosition.getX(), endPosition.getY());
    LineTo leftArrowLine = new LineTo(arrowX1, arrowY1);
    MoveTo rightArrowMove = new MoveTo(endPosition.getX(), endPosition.getY());
    LineTo rightArrowLine = new LineTo(arrowX2, arrowY2);

    path.getElements().addAll(leftArrowMove, leftArrowLine, rightArrowMove, rightArrowLine);

其中ARROW_ANGLE和ARROW_LENGTH是常量。

我如何为立方曲线做同样的事情? 我在这里找到了一些立方曲线箭头的样本,但我无法改变角度和长度。

public void start(Stage primaryStage) {

    Group root = new Group();

    // bending curve
    Rectangle srcRect1 = new Rectangle(100,100,50,50);
    Rectangle dstRect1 = new Rectangle(300,300,50,50);

    CubicCurve curve1 = new CubicCurve( 125, 150, 125, 225, 325, 225, 325, 300);
    curve1.setStroke(Color.BLACK);
    curve1.setStrokeWidth(1);
    curve1.setFill( null);

    double size=Math.max(curve1.getBoundsInLocal().getWidth(),
                         curve1.getBoundsInLocal().getHeight());
    double scale=size/4d;

    Point2D ori=eval(curve1,0);
    Point2D tan=evalDt(curve1,0).normalize().multiply(scale);
    Path arrowIni=new Path();
    arrowIni.getElements().add(new MoveTo(ori.getX()+0.2*tan.getX()-0.2*tan.getY(),
                                        ori.getY()+0.2*tan.getY()+0.2*tan.getX()));
    arrowIni.getElements().add(new LineTo(ori.getX(), ori.getY()));
    arrowIni.getElements().add(new LineTo(ori.getX()+0.2*tan.getX()+0.2*tan.getY(),
                                        ori.getY()+0.2*tan.getY()-0.2*tan.getX()));

    ori=eval(curve1,1);
    tan=evalDt(curve1,1).normalize().multiply(scale);
    Path arrowEnd=new Path();
    arrowEnd.getElements().add(new MoveTo(ori.getX()-0.2*tan.getX()-0.2*tan.getY(),
                                        ori.getY()-0.2*tan.getY()+0.2*tan.getX()));
    arrowEnd.getElements().add(new LineTo(ori.getX(), ori.getY()));
    arrowEnd.getElements().add(new LineTo(ori.getX()-0.2*tan.getX()+0.2*tan.getY(),
                                        ori.getY()-0.2*tan.getY()-0.2*tan.getX()));

    root.getChildren().addAll(srcRect1, dstRect1, curve1, arrowIni, arrowEnd);

    primaryStage.setScene(new Scene(root, 800, 600));
    primaryStage.show();
}

/**
 * Evaluate the cubic curve at a parameter 0<=t<=1, returns a Point2D
 * @param c the CubicCurve 
 * @param t param between 0 and 1
 * @return a Point2D 
 */
private Point2D eval(CubicCurve c, float t){
    Point2D p=new Point2D(Math.pow(1-t,3)*c.getStartX()+
            3*t*Math.pow(1-t,2)*c.getControlX1()+
            3*(1-t)*t*t*c.getControlX2()+
            Math.pow(t, 3)*c.getEndX(),
            Math.pow(1-t,3)*c.getStartY()+
            3*t*Math.pow(1-t, 2)*c.getControlY1()+
            3*(1-t)*t*t*c.getControlY2()+
            Math.pow(t, 3)*c.getEndY());
    return p;
}

/**
 * Evaluate the tangent of the cubic curve at a parameter 0<=t<=1, returns a Point2D
 * @param c the CubicCurve 
 * @param t param between 0 and 1
 * @return a Point2D 
 */
private Point2D evalDt(CubicCurve c, float t){
    Point2D p=new Point2D(-3*Math.pow(1-t,2)*c.getStartX()+
            3*(Math.pow(1-t, 2)-2*t*(1-t))*c.getControlX1()+
            3*((1-t)*2*t-t*t)*c.getControlX2()+
            3*Math.pow(t, 2)*c.getEndX(),
            -3*Math.pow(1-t,2)*c.getStartY()+
            3*(Math.pow(1-t, 2)-2*t*(1-t))*c.getControlY1()+
            3*((1-t)*2*t-t*t)*c.getControlY2()+
            3*Math.pow(t, 2)*c.getEndY());
    return p;
}

1 个答案:

答案 0 :(得分:1)

请注意,此处不需要evalDteval方法。您不会在任何地方进行评估,只能在开始和结束时进行评估,在这种情况下,起点和终点是evalDt方法的结果,control1 - start方法的结果是{{1分别和control2 - end

也可以使用tan.angle(1, 0)计算线角度(即通过确定切向量和x轴之间的角度)。

此外,可以使用相对 PathElement s,即使用相对于最后PathElement的结束点的位置。这简化了箭头。

在以下示例中,除了相对Rotate之外,还使用LineTo转换来旋转切线:

@Override
public void start(Stage primaryStage) {
    Group root = new Group();

    // bending curve
    Rectangle srcRect1 = new Rectangle(100, 100, 50, 50);
    Rectangle dstRect1 = new Rectangle(300, 300, 50, 50);

    CubicCurve curve1 = new CubicCurve(125, 150, 125, 225, 100, 325, 300, 325);
    curve1.setStroke(Color.BLACK);
    curve1.setStrokeWidth(1);
    curve1.setFill(null);

    final double ARROW_LENGTH = 15;
    final double ARROW_ANGLE = 45;

    // the transform for the rotation arrow rotation
    Rotate rotation = new Rotate(ARROW_ANGLE);

    // direction = inwards from the start point
    Point2D tan = new Point2D(
            curve1.getControlX1() - curve1.getStartX(),
            curve1.getControlY1() - curve1.getStartY()
    ).normalize().multiply(ARROW_LENGTH);

    Path arrowIni = new Path();

    // move to start point of curve
    MoveTo move = new MoveTo(curve1.getStartX(), curve1.getStartY());

    // transform tangent by rotating with +angle
    Point2D p = rotation.transform(tan);

    LineTo a1 = new LineTo(p.getX(), p.getY());
    // position relative to end point
    a1.setAbsolute(false);

    // same as above, but in oposite direction
    rotation.setAngle(-ARROW_ANGLE);
    p = rotation.transform(tan);
    LineTo a2 = new LineTo(p.getX(), p.getY());
    a2.setAbsolute(false);

    arrowIni.getElements().addAll(move, a1, move, a2);

    // direction = inwards from the end point
    tan = new Point2D(
            curve1.getControlX2() - curve1.getEndX(),
            curve1.getControlY2() - curve1.getEndY()
    ).normalize().multiply(ARROW_LENGTH);
    move = new MoveTo(curve1.getEndX(), curve1.getEndY());
    p = rotation.transform(tan);
    a1 = new LineTo(p.getX(), p.getY());
    a1.setAbsolute(false);
    rotation.setAngle(ARROW_ANGLE);
    p = rotation.transform(tan);
    a2 = new LineTo(p.getX(), p.getY());
    a2.setAbsolute(false);

    Path arrowEnd = new Path();
    arrowEnd.getElements().addAll(move, a1, move, a2);

    root.getChildren().addAll(srcRect1, dstRect1, curve1, arrowIni, arrowEnd);

    primaryStage.setScene(new Scene(root, 800, 600));
    primaryStage.show();
}