javaFX中的平滑路径

E.B*_*own 0 javafx

我正在PathJavaFX 中绘制 a并且我想绘制这种类型的路径(lineToarcTo): 图片仅供说明

有没有什么简单的方法可以将弧与线(和其他弧)连接起来以获得这样的平滑路径?

我不知道圆弧的周长,我只知道起点和终点。图片中只有半个圆圈,我还需要绘制其他类型的arcTo

到目前为止,我唯一的想法是获得路径终点的方向,然后在这个方向上计数并加入另一个arcTo/ lineTo。但是,我也没有找到任何方法来做到这一点。

Jam*_*s_D 5

A Cubic Bezier Curve is defined by four points, start, end, and two "control points" control1 and control2. It has the property that

  • it starts and ends at start and end
  • initially (i.e. at start) it is tangential to the line segment between start and control1
  • at end it is tangential to the line segment between control2 and end

The shape of the curve is also determined by the sizes of the line segments from start to control1 and control2 to end: roughly speaking these control the "speed" with which the line approaches the control points before turning towards the end points.

So to join two line segments with a smooth curve, you can use a cubic curve whose start is the end of the first line segment and whose end is the start of the second line segment. Compute the control points just by extending each line beyond its end (first line) or start (second line). Using the same length for the extensions will give a balanced look.

Here is an example. Run this code: drag the mouse across the pane to draw one line, then again to draw a second line, and the two lines will be connected by a cubic curve.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

You can also incorporate a cubic Bezier curve into a path, using the path element CubicCurveTo. Here is an example using a Path, with vertical line segments connected by cubic bezier curves (the method generating the path will work for arbitrary line segments):

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

This gives

在此处输入图片说明