我在JavaFX中绘制Path
,我想绘制此类型的路径(lineTo
和arcTo
):
有没有简单的方法如何将弧与线(和其他弧)连接起来,以获得这样的平滑路径?
我不知道弧的周长,我只知道起点和终点。在图片中只有半圈,我还需要绘制其他类型的arcTo
。
我到目前为止唯一的想法是获得路径结束的方向,然后计算并加入另一个arcTo
/ lineTo
朝这个方向。但是,我没有找到任何方法来做到这一点。
答案 0 :(得分:3)
Cubic Bezier Curve由四个点定义,start
,end
和两个"控制点" control1
和control2
。它具有
start
和end
start
)它与start
和control1
end
,它与control2
和end
曲线的形状也取决于从start
到control1
和control2
到end
的线段的大小:粗略地说这些控制了&# 34;速度"在转向终点之前,线接近控制点。
因此,要使用平滑曲线连接两个线段,可以使用三次曲线,其起点是第一个线段的末尾,其末端是第二个线段的起点。仅通过将每条线延伸到其末端(第一行)或开始(第二行)之后来计算控制点。使用相同长度的扩展将提供平衡的外观。
这是一个例子。运行此代码:在窗格上拖动鼠标以绘制一条线,然后再次绘制第二条线,这两条线将通过三次曲线连接。
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class JoinLineSegmentsWithCubic extends Application {
private Line unconnectedLine = null ;
private Line currentDraggingLine = null ;
@Override
public void start(Stage primaryStage) {
Pane pane = new Pane();
pane.setOnDragDetected(e -> {
currentDraggingLine = new Line(e.getX(), e.getY(), e.getX(), e.getY());
pane.getChildren().add(currentDraggingLine);
});
pane.setOnMouseDragged(e -> {
if (currentDraggingLine != null) {
currentDraggingLine.setEndX(e.getX());
currentDraggingLine.setEndY(e.getY());
}
});
pane.setOnMouseReleased(e -> {
if (currentDraggingLine != null) {
currentDraggingLine.setEndX(e.getX());
currentDraggingLine.setEndY(e.getY());
if (unconnectedLine != null) {
connect(unconnectedLine, currentDraggingLine, pane);
}
unconnectedLine = currentDraggingLine ;
currentDraggingLine = null ;
}
});
Scene scene = new Scene(pane, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private void connect(Line line1, Line line2, Pane parent) {
Point2D line1Start = new Point2D(line1.getStartX(), line1.getStartY());
Point2D line1End = new Point2D(line1.getEndX(), line1.getEndY());
Point2D line2Start = new Point2D(line2.getStartX(), line2.getStartY());
Point2D line2End = new Point2D(line2.getEndX(), line2.getEndY());
double line1Length = line1End.subtract(line1Start).magnitude();
double line2Length = line2End.subtract(line2Start).magnitude();
// average length:
double aveLength = (line1Length + line2Length) / 2 ;
// extend line1 in direction of line1 for aveLength:
Point2D control1 = line1End.add(line1End.subtract(line1Start).normalize().multiply(aveLength));
// extend line2 in (reverse) direction of line2 for aveLength:
Point2D control2 = line2Start.add(line2Start.subtract(line2End).normalize().multiply(aveLength));
CubicCurve cc = new CubicCurve(
line1End.getX(), line1End.getY(),
control1.getX(), control1.getY(),
control2.getX(), control2.getY(),
line2Start.getX(), line2Start.getY());
cc.setStroke(Color.BLACK);
cc.setFill(null);
parent.getChildren().add(cc);
}
public static void main(String[] args) {
launch(args);
}
}
您还可以使用路径元素CubicCurveTo
将三次贝塞尔曲线合并到路径中。下面是一个使用Path的示例,其中垂直线段由三次贝塞尔曲线连接(生成路径的方法适用于任意线段):
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
public class SmoothPathWithCubicBezier extends Application {
@Override
public void start(Stage primaryStage) {
double[] points = new double[24];
for (int i = 0; i < 24 ; i+=8) {
double x = (1 + i/8) * 200 ;
points[i] = x ;
points[i+1] = 200 ;
points[i+2] = x ;
points[i+3] = 400 ;
points[i+4] = x + 100 ;
points[i+5] = 400 ;
points[i+6] = x+ 100 ;
points[i+7] = 200 ;
}
Pane pane = new Pane();
pane.getChildren().add(createPath(points));
Scene scene = new Scene(pane, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
// points should be an array of length a multiple of four,
// defining a set of lines {startX1, startY1, endX1, endY1, startX2, ...}
// The path will consist of the straight line segments, joined by
// cubic beziers
private Path createPath(double[] points) {
Path path = new Path();
for (int i = 0 ; i < points.length; i+=4) {
double startX = points[i];
double startY = points[i+1];
double endX = points[i+2];
double endY = points[i+3];
if (i==0) {
MoveTo moveTo = new MoveTo(startX, startY);
moveTo.setAbsolute(true);
path.getElements().add(moveTo);
} else {
double lastStartX = points[i-4];
double lastStartY = points[i-3];
double lastEndX = points[i-2];
double lastEndY = points[i-1];
double lastLength = Math.sqrt((lastEndX-lastStartX)*(lastEndX-lastStartX)
+ (lastEndY-lastStartY)*(lastEndY-lastStartY));
double length = Math.sqrt((endX-startX)*(endX-startX)
+ (endY-startY)*(endY-startY));
double aveLength = (lastLength+length)/2;
double control1X = lastEndX + (lastEndX-lastStartX)*aveLength/lastLength ;
double control1Y = lastEndY + (lastEndY-lastStartY)*aveLength/lastLength ;
double control2X = startX - (endX-startX)*aveLength/length ;
double control2Y = startY - (endY-startY)*aveLength/length ;
CubicCurveTo cct = new CubicCurveTo(control1X, control1Y, control2X, control2Y, startX, startY);
cct.setAbsolute(true);
path.getElements().add(cct);
}
LineTo lineTo = new LineTo(endX, endY);
lineTo.setAbsolute(true);
path.getElements().add(lineTo);
}
return path ;
}
public static void main(String[] args) {
launch(args);
}
}
这给出了