Class QuadCurves

java.lang.Object
org.jhotdraw8.geom.QuadCurves

public class QuadCurves extends Object
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 Type
    Method
    Description
    static double
    arcLength(double @NonNull [] p, int offset, double epsilon)
    Computes the arc length s.
    static double
    arcLength(double @NonNull [] p, int offset, double t, double epsilon)
    Computes the arc length s from time 0 to time t using an integration method.
    static double
    arcLengthClosedForm(double[] q, int offset, double t)
    Calculates the arc-length s of a segment from [0, t] of a quadratic bézier curve using a closed form solution.
    eval(double[] p, int offset, double t)
     
    eval(double x0, double y0, double x1, double y1, double x2, double y2, double t)
    Evaluates the given curve at the specified time.
    eval(Point2D p0, Point2D p1, Point2D p2, double t)
    Evaluates the given curve at the specified time.
    getArcLengthIntegrand(double[] p, int offset)
    Gets the integrand function for the arc-length of a quadratic bézier curve.
    static double
    invArcLength(double[] p, int offset, double s, double epsilon)
    Calculates the time t at a given arc-length s of a quadratic bézier curve using an integration method.
    static double
    invArcLength(double[] p, int offset, double s, double totalArcLength, double epsilon)
     
    static double
    invArcLengthClosedForm(double[] p, int offset, double s, double epsilon)
    Calculates the time t at a given arc-length s of 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 void
    split(double @NonNull [] 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 void
    split(double x0, double y0, double x1, double y1, double x2, double y2, double t, double[] first, double[] second)
     
    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.
    static void
    subCurve(double @NonNull [] q, int offset, double ta, double tb, double @NonNull [] first, int offsetFirst)
    Extracts the specified segment [ta,tb] from the given quad curve.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • arcLength

      public static double arcLength(double @NonNull [] p, int offset, double epsilon)
      Computes the arc length s.
      Parameters:
      p - points of the curve
      offset - index of the first point in array p
      epsilon - the error tolerance
      Returns:
      the arc length
    • arcLengthClosedForm

      public static double arcLengthClosedForm(double[] q, int offset, double t)
      Calculates the arc-length s of 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 this
       a = 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 L can 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/A
       
      Then 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 curve
      offset - the offset of the first control point in q
      t - the value of t in range [0,1]
      Returns:
      the arc length, a non-negative value
    • arcLength

      public static double arcLength(double @NonNull [] 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 curve
      offset - the offset of the first control point in b
      t - the time value
      epsilon - the error tolerance
      Returns:
      the arc length
    • eval

      public static @NonNull PointAndDerivative eval(Point2D p0, Point2D p1, Point2D p2, double t)
      Evaluates the given curve at the specified time.
      Parameters:
      p0 - point P0 of the curve
      p1 - point P1 of the curve
      p2 - point P2 of the curve
      t - the time
      Returns:
      the point at time t
    • eval

      public static @NonNull 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 curve
      y0 - point P0 of the curve
      x1 - point P1 of the curve
      y1 - point P1 of the curve
      x2 - point P2 of the curve
      y2 - point P2 of the curve
      t - the time
      Returns:
      the point at time t
    • eval

      public static @NonNull PointAndDerivative eval(double[] p, int offset, double t)
    • getArcLengthIntegrand

      public static ToDoubleFunction<Double> getArcLengthIntegrand(double[] p, int offset)
      Gets the integrand function for the arc-length of a quadratic bézier curve.

      The arc-length s can 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 curve
      offset - the offset of the first control point in p
    • invArcLengthClosedForm

      public static double invArcLengthClosedForm(double[] p, int offset, double s, double epsilon)
      Calculates the time t at a given arc-length s of 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 curve
      offset - the offset of the first control point in b
      s - the arc-length value where s >= 0
      epsilon - the error tolerance
    • invArcLength

      public static double invArcLength(double[] p, int offset, double s, double epsilon)
      Calculates the time t at a given arc-length s of a quadratic bézier curve using an integration method.
      Parameters:
      p - the coordinates of the control points of the bézier curve
      offset - the offset of the first control point in b
      s - the arc-length value where s >= 0
      epsilon -
    • 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 curve
      y0 - point P0 of the first curve
      x01 - point P1 of the first curve
      y01 - point P1 of the first curve
      x012 - point P2 of the first curve or point p0 of the second curve respectively
      y012 - point P2 of the first curve or point p0 of the second curve respectively
      x12 - point P1 of the second curve
      y12 - point P1 of the second curve
      x2 - point P2 of the second curve
      y2 - point P2 of the second curve
      tolerance - 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 curve
      y0 - point 1 of the curve
      x1 - point 2 of the curve
      y1 - point 2 of the curve
      x2 - point 3 of the curve
      y2 - point 3 of the curve
      t - where to split
      first - if not null, accepts the curve from x1,y1 to t
      second - if not null, accepts the curve from t to x3,y3
    • split

      public static void split(double @NonNull [] 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 split
      first - if not null, accepts the curve from x1,y1 to t
      second - if not null, accepts the curve from t to x3,y3
    • subCurve

      public static void subCurve(double @NonNull [] q, int offset, double ta, double tb, double @NonNull [] first, int offsetFirst)
      Extracts the specified segment [ta,tb] from the given quad curve.
      Parameters:
      ta - where to split
      tb - where to split