对于简单的线条,我写了这段代码:
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;
}
答案 0 :(得分:1)
请注意,此处不需要evalDt
和eval
方法。您不会在任何地方进行评估,只能在开始和结束时进行评估,在这种情况下,起点和终点是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();
}