java.lang.Object
org.jhotdraw8.geom.QuadCurves
Provides utility methods for quadratic Bézier curves.
Quadratic Bezier curves are defined by second order polynomial, and can be written as:
B(t) = (1 − t)*P₀ + 2*(1 − t)*t*P₁ + t²*P₂where t is real parameter with values in range [0,1]. P’s are respectively curve starting point, anchor point and the end point. Derivative of the quadratic Bézier curve can be written as Quadratic Bézier Curve derivative:
∂B∂t(t) = 2*t*(P₀ − 2*P₁ + P₂) + 2*P₁ − 2*P₀
References:
- Quadratic Bezier curves, Copyright malczak
- malczak.info
- Author:
- Werner Randelshofer
-
Method Summary
Modifier and TypeMethodDescriptionstatic doublearcLength(double[] p, int offset, double epsilon) Computes the arc length s.static doublearcLength(double[] p, int offset, double t, double epsilon) Computes the arc length s from time 0 to time t using an integration method.static doublearcLengthClosedForm(double[] q, int offset, double t) Calculates the arc-lengthsof a segment from [0, t] of a quadratic bézier curve using a closed form solution.static PointAndDerivativeeval(double[] p, int offset, double t) static PointAndDerivativeeval(double x0, double y0, double x1, double y1, double x2, double y2, double t) Evaluates the given curve at the specified time.static PointAndDerivativeEvaluates the given curve at the specified time.static ToDoubleFunction<Double> getArcLengthIntegrand(double[] p, int offset) Gets the integrand function for the arc-length of a quadratic bézier curve.static doubleinvArcLength(double[] p, int offset, double s, double epsilon) Calculates the timetat a given arc-lengthsof a quadratic bézier curve using an integration method.static doubleinvArcLength(double[] p, int offset, double s, double totalArcLength, double epsilon) static doubleinvArcLengthClosedForm(double[] p, int offset, double s, double epsilon) Calculates the timetat a given arc-lengthsof a quadratic bézier curve using a closed form solution.static double @Nullable []merge(double x0, double y0, double x01, double y01, double x012, double y012, double x12, double y12, double x2, double y2, double tolerance) Tries to join two bézier curves.static voidsplit(double[] p, int o, double t, double @Nullable [] first, int offsetFirst, double @Nullable [] second, int offsetSecond) Splits the provided Bézier curve into two parts.static voidsplit(double x0, double y0, double x1, double y1, double x2, double y2, double t, double[] first, double[] second) static voidsplit(double x0, double y0, double x1, double y1, double x2, double y2, double t, @Nullable DoubleConsumer4 first, @Nullable DoubleConsumer4 second) Splits the provided Bézier curve into two parts.static voidsubCurve(double[] q, int offset, double ta, double tb, double[] first, int offsetFirst) Extracts the specified segment [ta,tb] from the given quad curve.
-
Method Details
-
arcLength
public static double arcLength(double[] p, int offset, double epsilon) Computes the arc length s.- Parameters:
p- points of the curveoffset- index of the first point in arraypepsilon- the error tolerance- Returns:
- the arc length
-
arcLengthClosedForm
public static double arcLengthClosedForm(double[] q, int offset, double t) Calculates the arc-lengthsof a segment from [0, t] of a quadratic bézier curve using a closed form solution.FIXME this method is not numerically stable!
Length of any parametric (in general length of any well defined curve) curve can be computated using curve length integral. In case of 2nd order Bezier curve, using its derivatives, this integral can be written as Quadratic Bezier Curve integral
s = integrate ( √( Bx'(t)² + By′(t)² ) , d:t, from:0, to:t)
To simplify this integral we can make some substitutions. In this case it we will look like thisa = P₀ − 2*P₁ + P₂ b = 2*P₁ − 2*P₀ ∂B∂t(t) = 2*t*a + b
Next after doing some algebra and grouping elements in order to parameter t we will do another substitutions (to make this integral easier):A = 4*(ax² + ay²) B = 4*(ax*bx + ay*by) C = bx² + by²
The arc-length
Lcan now be computed with the following equation:L = integrate( √( A*t² + B*t +C ), d:t, from:0, to:t)Which we can write as:L = √(A) * integrate( √( t² + 2*b*t +c ), d:t, from:0, to:t) where b = B/(2*A) c = C/AThen we get:L = √(A) * integrate( √(u²+k), d:t, from:b, to:u) where u = t + b k = c - b²Now we can use the integral identity from the link to obtain:L = √(A)/2 * ( u*√(u²+k) - b*√(b²+k) + k*log( (u+√(u²+k)) / (b+√(b²+k)) ) )References:
- Stackoverflow. Calculate the length of a segment of a quadratic bezier. Copyright Michael Anderson. CC BY-SA 4.0 license.
- stackoverflow.com
- Quadratic Bezier curves, Copyright malczak
- malczak.info
- Parameters:
q- the coordinates of the control points of the bézier curveoffset- the offset of the first control point inqt- the value of t in range [0,1]- Returns:
- the arc length, a non-negative value
-
arcLength
public static double arcLength(double[] p, int offset, double t, double epsilon) Computes the arc length s from time 0 to time t using an integration method.- Parameters:
p- the coordinates of the control points of the bézier curveoffset- the offset of the first control point inbt- the time valueepsilon- the error tolerance- Returns:
- the arc length
-
eval
Evaluates the given curve at the specified time.- Parameters:
p0- point P0 of the curvep1- point P1 of the curvep2- point P2 of the curvet- the time- Returns:
- the point at time t
-
eval
public static PointAndDerivative eval(double x0, double y0, double x1, double y1, double x2, double y2, double t) Evaluates the given curve at the specified time.- Parameters:
x0- point P0 of the curvey0- point P0 of the curvex1- point P1 of the curvey1- point P1 of the curvex2- point P2 of the curvey2- point P2 of the curvet- the time- Returns:
- the point at time t
-
eval
-
getArcLengthIntegrand
Gets the integrand function for the arc-length of a quadratic bézier curve.The arc-length
scan be computed with the following equation:s = integrate( √( A*t² + B*t +C ), d:t, from:0, to:t)The integrand function is therefore:s = √( A*t² + B*t +C )References:
- Calculate the length of a segment of a quadratic bezier, Copyright Michael Anderson, CC BY-SA 4.0 license
- stackoverflow.com
- Parameters:
p- the coordinates of the control points of the bézier curveoffset- the offset of the first control point inp
-
invArcLengthClosedForm
public static double invArcLengthClosedForm(double[] p, int offset, double s, double epsilon) Calculates the timetat a given arc-lengthsof a quadratic bézier curve using a closed form solution.FIXME this method is not numerically stable!
- Parameters:
p- the coordinates of the control points of the bézier curveoffset- the offset of the first control point inbs- the arc-length value where s >= 0epsilon- the error tolerance
-
invArcLength
public static double invArcLength(double[] p, int offset, double s, double epsilon) Calculates the timetat a given arc-lengthsof a quadratic bézier curve using an integration method.- Parameters:
p- the coordinates of the control points of the bézier curveoffset- the offset of the first control point inbs- the arc-length value where s >= 0epsilon-
-
invArcLength
public static double invArcLength(double[] p, int offset, double s, double totalArcLength, double epsilon) -
merge
public static double @Nullable [] merge(double x0, double y0, double x01, double y01, double x012, double y012, double x12, double y12, double x2, double y2, double tolerance) Tries to join two bézier curves. Returns the new control point.- Parameters:
x0- point P0 of the first curvey0- point P0 of the first curvex01- point P1 of the first curvey01- point P1 of the first curvex012- point P2 of the first curve or point p0 of the second curve respectivelyy012- point P2 of the first curve or point p0 of the second curve respectivelyx12- point P1 of the second curvey12- point P1 of the second curvex2- point P2 of the second curvey2- point P2 of the second curvetolerance- distance (radius) at which the joined point may be off from x012,y012.- Returns:
- the control points of the new curve (x0,y0)(x1,y1)(x2,y2), null if joining failed
-
split
public static void split(double x0, double y0, double x1, double y1, double x2, double y2, double t, double[] first, double[] second) -
split
public static void split(double x0, double y0, double x1, double y1, double x2, double y2, double t, @Nullable DoubleConsumer4 first, @Nullable DoubleConsumer4 second) Splits the provided Bézier curve into two parts.- Parameters:
x0- point 1 of the curvey0- point 1 of the curvex1- point 2 of the curvey1- point 2 of the curvex2- point 3 of the curvey2- point 3 of the curvet- where to splitfirst- if not null, accepts the curve from x1,y1 to tsecond- if not null, accepts the curve from t to x3,y3
-
split
public static void split(double[] p, int o, double t, double @Nullable [] first, int offsetFirst, double @Nullable [] second, int offsetSecond) Splits the provided Bézier curve into two parts.- Parameters:
t- where to splitfirst- if not null, accepts the curve from x1,y1 to tsecond- if not null, accepts the curve from t to x3,y3
-
subCurve
public static void subCurve(double[] q, int offset, double ta, double tb, double[] first, int offsetFirst) Extracts the specified segment [ta,tb] from the given quad curve.- Parameters:
ta- where to splittb- where to split
-