Tuesday, January 28, 2025

Bezier curve revisited - an implementation using Javafx...

 Cubic Bézier curves...

Four points P0, P1, P2 and P3 in the plane or in higher-dimensional space define a cubic Bézier curve. The curve starts at P0 going toward P1 and arrives at P3 coming from the direction of P2. Usually, it will not pass through P1 or P2; these points are only there to provide directional information. The distance between P1 and P2 determines "how far" and "how fast" the curve moves towards P1 before turning towards P2.

Writing BPi,Pj,Pk(t) for the quadratic Bézier curve defined by points PiPj, and Pk, the cubic Bézier curve can be defined as an affine combination of two quadratic Bézier curves:

The explicit form of the curve is:


Any series of 4 distinct points can be converted to a cubic Bézier curve that goes through all 4 points in order. Given the starting and ending point of some cubic Bézier curve, and the points along the curve corresponding to t = 1/3 and t = 2/3, the control points for the original Bézier curve can be recovered.

Here's how it looks like - an experimentation...


And here's the source code of the experimentation (JavaFx application)...

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

public class BezierCurveDemo extends Application {

@Override
public void start(Stage primaryStage) {
// Main pane
Pane pane = new Pane();

// Control points
Circle start = createControlPoint(100, 300, Color.RED); // Start point
Circle control1 = createControlPoint(200, 100, Color.BLUE); // First control point
Circle control2 = createControlPoint(400, 100, Color.BLUE); // Second control point
Circle end = createControlPoint(500, 300, Color.RED); // End point

// Lines to show the control points
Line line1 = new Line();
Line line2 = new Line();

line1.startXProperty().bind(start.centerXProperty());
line1.startYProperty().bind(start.centerYProperty());
line1.endXProperty().bind(control1.centerXProperty());
line1.endYProperty().bind(control1.centerYProperty());
line1.setStroke(Color.LIGHTGRAY);

line2.startXProperty().bind(control2.centerXProperty());
line2.startYProperty().bind(control2.centerYProperty());
line2.endXProperty().bind(end.centerXProperty());
line2.endYProperty().bind(end.centerYProperty());
line2.setStroke(Color.LIGHTGRAY);

// Bezier Curve
CubicCurve bezierCurve = new CubicCurve();
bezierCurve.setStroke(Color.BLACK);
bezierCurve.setFill(null);
bezierCurve.setStrokeWidth(2);

bezierCurve.startXProperty().bind(start.centerXProperty());
bezierCurve.startYProperty().bind(start.centerYProperty());
bezierCurve.controlX1Property().bind(control1.centerXProperty());
bezierCurve.controlY1Property().bind(control1.centerYProperty());
bezierCurve.controlX2Property().bind(control2.centerXProperty());
bezierCurve.controlY2Property().bind(control2.centerYProperty());
bezierCurve.endXProperty().bind(end.centerXProperty());
bezierCurve.endYProperty().bind(end.centerYProperty());

// Add everything to the pane
pane.getChildren().addAll(line1, line2, bezierCurve, start, control1, control2, end);

// Create scene and display
Scene scene = new Scene(pane, 600, 400);
primaryStage.setTitle("Bezier Curve Demo");
primaryStage.setScene(scene);
primaryStage.show();
}

// Helper function to create control points
private Circle createControlPoint(double x, double y, Color color) {
Circle circle = new Circle(8, color);
circle.setCenterX(x);
circle.setCenterY(y);

// Make control points draggable
circle.setOnMouseDragged(event -> {
circle.setCenterX(event.getX());
circle.setCenterY(event.getY());
});

return circle;
}

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

No comments: