com.caffeineowl.graphics.bezier
Class BezierUtils

java.lang.Object
  extended by com.caffeineowl.graphics.bezier.BezierUtils

public class BezierUtils
extends java.lang.Object

Utility functions for processing Bézier curves.

Author:
Adrian Colomitchi (acolomitchi(monkey_tail)gmail.com)

Nested Class Summary
static class BezierUtils.CubicArrayListConsumer
          A CubicSegmentConsumer that stores the received cubic segments in an array list.
(package private) static class BezierUtils.MidPointApproxSubdivCriterion
          The adaptive halving criterion for approximating a cubic by the mid-point approximation quadratic.
(package private) static class BezierUtils.MidPointApproxTransformer
          A CubicSegmentConsumer that wraps around a QuadSegmentConsumer and, upon receiving a cubic segment, applies the mid point approximation and passed the resulted segment into the wrapped consumer.
static class BezierUtils.QuadArrayListConsumer
          A QuadSegmentConsumer that stores the received quad segments in an array list.
 
Field Summary
static double minPrecision
           
 
Constructor Summary
BezierUtils()
           
 
Method Summary
static java.awt.geom.QuadCurve2D[] adaptiveDegreeReduction(java.awt.geom.CubicCurve2D cubic, double precision)
          The adaptive degree reduction algorithm, implemented to return the resulted "daisy-chain" of the approximating quadratic segments as an array.
static void adaptiveDegreeReduction(java.awt.geom.CubicCurve2D cubic, double precision, QuadSegmentConsumer resultHere)
          The adaptive degree reduction algorithm, implemented to return the resulted "daisy-chain" of the approximating quadratic segments as an array.
static java.awt.geom.CubicCurve2D[] adaptiveHalving(java.awt.geom.CubicCurve2D curve, CubicSubdivisionCriterion subdivCriterion)
          Performs an adaptive halving of a cubic Bézier, base on a provided CubicSubdivisionCriterion (which tells when a cubic Bézier is good enough not to need splitting in two anymore).
static void adaptiveHalving(java.awt.geom.CubicCurve2D curve, CubicSubdivisionCriterion subdivCriterion, CubicSegmentConsumer segConsumer)
          Method to perform an adaptive halving of a cubic Bézier, based on a CubicSubdivisionCriterion (which tells when a cubic is good enough not to need splitting in two anymore).
static java.awt.geom.QuadCurve2D[] adaptiveHalving(java.awt.geom.QuadCurve2D curve, QuadSubdivisionCriterion subdivCriterion)
          Performs an adaptive halving of a quadratic Bézier, base on a provided QuadSubdivisionCriterion (which tells when a quad Bézier is good enough not to need splitting in two anymore).
static void adaptiveHalving(java.awt.geom.QuadCurve2D curve, QuadSubdivisionCriterion subdivCriterion, QuadSegmentConsumer segConsumer)
          Method to perform an adaptive halving of a quadratic Bézier, based on a QuadSubdivisionCriterion (which tells when a quad Bézier is good enough not to need splitting in two anymore).
static void adaptiveHalvingDegreeReduction(java.awt.geom.CubicCurve2D cubic, double precision, QuadSegmentConsumer resultHere)
           
static int computeInflexion(java.awt.geom.CubicCurve2D curve, double[] params)
          Computes the parameter values corresponding to the inflexion points of a cubic Bézier (if any) and returns them within a provided double[] array.
static boolean halfSplitCurve(java.awt.geom.CubicCurve2D cubic, java.awt.geom.CubicCurve2D first, java.awt.geom.CubicCurve2D second)
          Subdivides a cubic Bézier at a value for the curve's parameter of 1/2.
static boolean halfSplitCurve(java.awt.geom.QuadCurve2D quad, java.awt.geom.QuadCurve2D first, java.awt.geom.QuadCurve2D second)
          Subdivides a quadratic Bézier at a value for the curve's parameter of 1/2.
static void midPointAndTangentOnCurve(java.awt.geom.CubicCurve2D curve, java.awt.geom.Point2D point, java.awt.geom.Line2D tangent)
           
static void minPointAndTangentOnCurve(java.awt.geom.QuadCurve2D curve, java.awt.geom.Point2D point, java.awt.geom.Line2D tangent)
           
static void pointAndTangentOnCurve(double t, java.awt.geom.CubicCurve2D curve, java.awt.geom.Point2D point, java.awt.geom.Line2D tangent)
           
static void pointAndTangentOnCurve(double t, java.awt.geom.QuadCurve2D curve, java.awt.geom.Point2D point, java.awt.geom.Line2D tangent)
           
static java.awt.geom.Point2D pointOnCurve(double t, java.awt.geom.CubicCurve2D curve, java.awt.geom.Point2D resultHere)
          Computes the location of the point on a cubic Bézier corresponding to a given value of the parameter t, and returns the position in an output parameter (if provided).
static java.awt.geom.Point2D pointOnCurve(double t, java.awt.geom.QuadCurve2D curve, java.awt.geom.Point2D resultHere)
          Computes the location of the point on a quadratic Bézier corresponding to a given value of the parameter t, and returns the position in an output parameter (if provided).
static java.awt.geom.CubicCurve2D[] splitCurve(java.awt.geom.CubicCurve2D curve, double[] params, java.awt.geom.CubicCurve2D[] resultsHere)
          Subdivides a cubic Bézier in more than one subdivision points.
static boolean splitCurve(java.awt.geom.CubicCurve2D cubic, double tSplit, java.awt.geom.CubicCurve2D first, java.awt.geom.CubicCurve2D second)
          Subdivides a cubic Bézier at a given value for the curve's parameter.
static java.awt.geom.QuadCurve2D[] splitCurve(java.awt.geom.QuadCurve2D curve, double[] params, java.awt.geom.QuadCurve2D[] resultsHere)
          Subdivides a quadratic Bézier in more than one subdivision points.
static boolean splitCurve(java.awt.geom.QuadCurve2D quad, double tSplit, java.awt.geom.QuadCurve2D first, java.awt.geom.QuadCurve2D second)
          Subdivides a quadratic Bézier at a given value for the curve's parameter.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

minPrecision

public static final double minPrecision
Constructor Detail

BezierUtils

public BezierUtils()
Method Detail

halfSplitCurve

public static boolean halfSplitCurve(java.awt.geom.CubicCurve2D cubic,
                                     java.awt.geom.CubicCurve2D first,
                                     java.awt.geom.CubicCurve2D second)
Subdivides a cubic Bézier at a value for the curve's parameter of 1/2. The method will return the resulted cubic segments in the two output parameters (first and second). It is safe for whichever of them to be the same as the provided cubic, the computation will be correct, however the original cubic will be overwritten. The method will not check if the both of the result cubic segments point to the same instance: in this case the last to be computed (the second) will overwrite the previous.
The method uses de Casteljau algorithm.

Parameters:
cubic - the cubic Bézier to split
first - the place where the first half cubic that results upon subdivision is stored. If null, the method will interpret this as "don't care about first segment" and will not compute it.
second - the place where the second half cubic that results upon subdivision is stored. If null, the method will interpret this as "don't care about second segment" and will not compute it.
Returns:
true if the computation was performed and finished successfuly, false otherwise (i.e a null value for the cubic parameter).

halfSplitCurve

public static boolean halfSplitCurve(java.awt.geom.QuadCurve2D quad,
                                     java.awt.geom.QuadCurve2D first,
                                     java.awt.geom.QuadCurve2D second)
Subdivides a quadratic Bézier at a value for the curve's parameter of 1/2. The method will return the resulted quadratic Bézier segments in the two output parameters (first and second). It is safe for whichever of them to be the same as the provided quadratic, the computation will be correct, however the original quadratic will be overwritten. The method will not check if the both of the result quadratic curves point to the same instance: in this case the last to be computed (the second) will overwrite the previous.
The method uses de Casteljau algorithm.

Parameters:
quad - the cubic Bézier to split
first - the place where the first quadratic half that results upon subdivision is stored. If null, the method will interpret this as "don't care about first segment" and will not compute it.
second - the place where the second quadratic half that results upon subdivision is stored. If null, the method will interpret this as "don't care about second segment" and will not compute it.
Returns:
true if the computation was performed and finished Successfully, false otherwise (i.e a null value for the quad parameter).

splitCurve

public static boolean splitCurve(java.awt.geom.CubicCurve2D cubic,
                                 double tSplit,
                                 java.awt.geom.CubicCurve2D first,
                                 java.awt.geom.CubicCurve2D second)
Subdivides a cubic Bézier at a given value for the curve's parameter. The method will return the resulted cubic segments in the two output parameters (first and second). It is safe for whichever of them to be the same as the provided cubic, the computation will be correct, however the original cubic will be overwritten. The method will not check if the both of the result cubic segments point to the same instance: in this case the last to be computed (the second) will overwrite the previous.
The method uses de Casteljau algorithm.

Parameters:
cubic - the cubic Bézier to split
tSplit - the value for parameter where the split should occur. If out of the 0..1 range, the function does nothing and returns false.
first - the place where the first cubic segment that results upon subdivision is stored. If null, the method will interpret this as "don't care about first segment" and will not compute it.
second - the place where the second cubic segment that results upon subdivision is stored. If null, the method will interpret this as "don't care about second segment" and will not compute it.
Returns:
true if the computation was performed and finished successfully, false otherwise (i.e a null value for the cubic parameter, or a value for the tSplit out of the [0..1] range).

splitCurve

public static boolean splitCurve(java.awt.geom.QuadCurve2D quad,
                                 double tSplit,
                                 java.awt.geom.QuadCurve2D first,
                                 java.awt.geom.QuadCurve2D second)
Subdivides a quadratic Bézier at a given value for the curve's parameter. The method will return the resulted quadratic Bézier segments in the two output parameters (first and second). It is safe for whichever of them to be the same as the provided quadratic, the computation will be correct, however the original quadratic will be overwritten. The method will not check if the both of the result quadratic curves point to the same instance: in this case the last to be computed (the second) will overwrite the previous.
The method uses de Casteljau algorithm.

Parameters:
quad - the cubic Bézier to split
tSplit - the value for parameter where the split should occur. If out of the 0..1 range, the function does nothing and returns false.
first - the place where the first quadratic segment that results upon subdivision is placed. If null, the method will interpret this as "don't care about first segment" and will not compute it.
second - the place where the second quadratic segment that results upon subdivision is placed. If null, the method will interpret this as "don't care about second segment" and will not compute it.
Returns:
true if the computation was performed and finished successfully, false otherwise (i.e a null value for the quad parameter, or a value for the tSplit out of the [0..1] range).

splitCurve

public static java.awt.geom.CubicCurve2D[] splitCurve(java.awt.geom.CubicCurve2D curve,
                                                      double[] params,
                                                      java.awt.geom.CubicCurve2D[] resultsHere)
Subdivides a cubic Bézier in more than one subdivision points. The method calls repeatedly the single point split method.

Parameters:
curve - the curve to subdivide
params - the array of curve parameters where to split the curve. Of course, they need to be in the [0..1) range (1.0 excluded) - otherwise unpredictable results might happen (in fact they are quite predictable, by I'm too lazy to check the effect). The method does not check this. Uh, by the way, the params are supposed to be sorted in ascending order: the method calls java.utils.Arrays.sort(double[]) to make sure they are (so, if they are not, be warned - the method will have a side effect on the parameters).
resultsHere - array to store the
Returns:
the cubic segments resulted in the splitting process If the resultHere has enough space to accommodate, then the first params.length+1 are filled in and resultsHere is returned. If the resultHere is not large enough to contain all the resulted points (or is null), the array is re-allocated (old content is copied into the newly allocated one), filled in and returned.

splitCurve

public static java.awt.geom.QuadCurve2D[] splitCurve(java.awt.geom.QuadCurve2D curve,
                                                     double[] params,
                                                     java.awt.geom.QuadCurve2D[] resultsHere)
Subdivides a quadratic Bézier in more than one subdivision points. The method calls repeatedly the single point split method.

Parameters:
curve - the curve to subdivide
params - the array of curve parameters where to split the curve. Of course, they need to be in the [0..1) range (1.0 excluded) - otherwise unpredictable results might happen (in fact they are quite predictable, by I'm too lazy to check the effect). The method does not check this. Uh, by the way, the params are supposed to be sorted in ascending order: the method calls java.utils.Arrays.sort(double[]) to make sure they are (so, if they are not, be warned - the method will have a side effect on the parameters).
resultsHere - array to store the
Returns:
the quadratic segments resulted in the splitting process If the resultHere has enough space to accommodate, then the first params.length+1 are filled in and resultsHere is returned. If the resultHere is not large enough to contain all the resulted points (or is null), the array is re-allocated (old content is copied into the newly allocated one), filled in and returned.

pointOnCurve

public static java.awt.geom.Point2D pointOnCurve(double t,
                                                 java.awt.geom.CubicCurve2D curve,
                                                 java.awt.geom.Point2D resultHere)
Computes the location of the point on a cubic Bézier corresponding to a given value of the parameter t, and returns the position in an output parameter (if provided). If the provided output parameter is null, the method will allocate a Point2D and return it. Otherwise, if successful, the method will return the provided Point2D instance to be used for storing the result.
The method will not restrict the the t parameter to values between [0..1], using whichever value is provided.

The method uses the parametrical expression of the cubic Bézier: this is because it requires 20 additions/substractions and 10 multiplications, while the de Casteljau algorithm requires 24 additions and 12 multiplications.

Parameters:
t - value for the curve parameter for which to compute the corresponding position
curve - the cubic curve. If null, the method will return null.
resultHere - the output parameter where the position is to be stored. If null, the method will create a new Point2D instance, use it for storing the requested value and return it.
Returns:
the position on the cubic curve corresponding to the provided value of the parametert, or null if the provided curve is null.

pointOnCurve

public static java.awt.geom.Point2D pointOnCurve(double t,
                                                 java.awt.geom.QuadCurve2D curve,
                                                 java.awt.geom.Point2D resultHere)
Computes the location of the point on a quadratic Bézier corresponding to a given value of the parameter t, and returns the position in an output parameter (if provided). If the provided output parameter is null, the method will allocate a Point2D and return it. Otherwise, if successful, the method will return the provided Point2D instance to be used for storing the result.
The method will not restrict the the t parameter to values between [0..1], using whichever value is provided.

Uses the parametric expression of the quadratic Bézier: this is because it requires 10 additions/substractions and 6 multiplications, while the de Casteljau algorithm requires 12 additions and 6 multiplications.

Parameters:
t - value for the curve parameter for which to compute the corresponding position.
curve - the quadratic curve. If null, the method will return null.
resultHere - the output parameter where the position is to be stored. If null, the method will create a new Point2D instance, use it for storing the requested value and return it.
Returns:
the position on the quadratic curve corresponding to the provided value of the parametert, or null if the provided curve is null.

pointAndTangentOnCurve

public static void pointAndTangentOnCurve(double t,
                                          java.awt.geom.CubicCurve2D curve,
                                          java.awt.geom.Point2D point,
                                          java.awt.geom.Line2D tangent)

pointAndTangentOnCurve

public static void pointAndTangentOnCurve(double t,
                                          java.awt.geom.QuadCurve2D curve,
                                          java.awt.geom.Point2D point,
                                          java.awt.geom.Line2D tangent)

midPointAndTangentOnCurve

public static void midPointAndTangentOnCurve(java.awt.geom.CubicCurve2D curve,
                                             java.awt.geom.Point2D point,
                                             java.awt.geom.Line2D tangent)

minPointAndTangentOnCurve

public static void minPointAndTangentOnCurve(java.awt.geom.QuadCurve2D curve,
                                             java.awt.geom.Point2D point,
                                             java.awt.geom.Line2D tangent)

computeInflexion

public static int computeInflexion(java.awt.geom.CubicCurve2D curve,
                                   double[] params)
Computes the parameter values corresponding to the inflexion points of a cubic Bézier (if any) and returns them within a provided double[] array. To be on a safe side, the array have to be preallocated to a minimum length of 2 (a cubic Bézier can have up to 2 inflexion points).
Note that the method will return the values for the parameter only if they fall in the (0, 1) range (excluding the range ends).
Note that if the curve has 2 inflexion points, they will be placed into the results array in increasing order of their corresponding curve's parameter values.

To obtain the (x, y) location of the inflexion point(s), use the pointOnCurve(double, CubicCurve2D, Point2D) method.

See also: http://www.caffeineowl.com/graphics/2d/vectorial/cubic-inflexion.html

Parameters:
curve - the cubic Bézier for which the inflexion points are to be computed for. If null, the method will throw a NullPointerException.
params - the array where the values (in the (0, 1) range) for the curve parameter corresponding to the inflexion points are to be returned. If null, a NullPointerException will be thrown if the curve has inflexion points. If the length of the array is not enough to accommodate all the values (at most 2), an ArrayIndexOutOfBoundsException is thrown.
Returns:
the number of the inflexion points that were found.

adaptiveHalving

public static void adaptiveHalving(java.awt.geom.CubicCurve2D curve,
                                   CubicSubdivisionCriterion subdivCriterion,
                                   CubicSegmentConsumer segConsumer)
Method to perform an adaptive halving of a cubic Bézier, based on a CubicSubdivisionCriterion (which tells when a cubic is good enough not to need splitting in two anymore). The result of the subdivision is guaranteed to make a "daisy-chain" from the original curve (i.e. the end of the prev cubic segment will always be the start of the new one). The results of the subdivision are fed into a CubicSegmentConsumer for custom further processing.

Parameters:
curve - the curve to be split
subdivCriterion - the subdivision criterion telling when the curve no longer needs splitting
segConsumer - the consumer of cubic segments that will be "fed" with the cubic segments resulting from sub-division (may just accumulate them perform a processing on them - like transforming them into lie segments).

adaptiveHalving

public static void adaptiveHalving(java.awt.geom.QuadCurve2D curve,
                                   QuadSubdivisionCriterion subdivCriterion,
                                   QuadSegmentConsumer segConsumer)
Method to perform an adaptive halving of a quadratic Bézier, based on a QuadSubdivisionCriterion (which tells when a quad Bézier is good enough not to need splitting in two anymore). The result of the subdivision is guaranteed to make a "daisy-chain" from the original curve (i.e. the end of the prev cubic segment will always be the start of the new one).The results of the subdivision are fed into a CubicSegmentConsumer for custom further processing.

Parameters:
curve - the curve to be split
subdivCriterion - the subdivision criterion telling when the curve no longer needs splitting
segConsumer - the consumer of cubic segments that will be "fed" with the cubic segments resulting from sub-division (may just accumulate them perform a processing on them - like transforming them into lie segments).

adaptiveHalving

public static java.awt.geom.CubicCurve2D[] adaptiveHalving(java.awt.geom.CubicCurve2D curve,
                                                           CubicSubdivisionCriterion subdivCriterion)
Performs an adaptive halving of a cubic Bézier, base on a provided CubicSubdivisionCriterion (which tells when a cubic Bézier is good enough not to need splitting in two anymore). The result of the subdivision is returned as an array of cubics, guaranteed to make a "daisy-chain" from the original curve (i.e. the end of the prev cubic segment will always be the start of the new one).

The method simply calls into adaptiveHalving(CubicCurve2D, CubicSubdivisionCriterion, CubicSegmentConsumer) using an BezierUtils.CubicArrayListConsumer as an accumulator, returning the accumulated values once the halving ends.

Parameters:
curve - the curve to be subdivided
subdivCriterion - the subdivision criterion
Returns:
the result of the halving process as an array of cubic segments

adaptiveHalving

public static java.awt.geom.QuadCurve2D[] adaptiveHalving(java.awt.geom.QuadCurve2D curve,
                                                          QuadSubdivisionCriterion subdivCriterion)
Performs an adaptive halving of a quadratic Bézier, base on a provided QuadSubdivisionCriterion (which tells when a quad Bézier is good enough not to need splitting in two anymore). The result of the subdivision is returned as an array of cubics, guaranteed to make a "daisy-chain" from the original curve (i.e. the end of the prev cubic segment will always be the start of the new one).

The method simply calls into adaptiveHalving(QuadCurve2D, QuadSubdivisionCriterion, QuadSegmentConsumer) using an BezierUtils.QuadArrayListConsumer as an accumulator, returning the accumulated values once the halving finishes.

Parameters:
curve - the curve to be subdivided
subdivCriterion - the subdivision criterion
Returns:
the result of the halving process as an array of quad segments

adaptiveDegreeReduction

public static java.awt.geom.QuadCurve2D[] adaptiveDegreeReduction(java.awt.geom.CubicCurve2D cubic,
                                                                  double precision)
The adaptive degree reduction algorithm, implemented to return the resulted "daisy-chain" of the approximating quadratic segments as an array. The method calls into adaptiveDegreeReduction(CubicCurve2D, double, QuadSegmentConsumer) with a BezierUtils.QuadArrayListConsumer accumulator, and returns the accumulated segments once the algorithm ends.

Parameters:
cubic - the cubic to be approximated by quad segments
precision - the desired precision of approximation. If drawing the resulted quad segments, it doesn't make any sense to use less than half of the resolution of the device used to display it (e.g. if drawing on a screen, and the x, y< coordinates are pixels, use 0.5 as a minimum for the precision, even if for most of the cases a value of 0.75 or even 1.0 will be sufficient).
Returns:
the resulted quad segments approximating the original curve with the specified precision.

adaptiveHalvingDegreeReduction

public static void adaptiveHalvingDegreeReduction(java.awt.geom.CubicCurve2D cubic,
                                                  double precision,
                                                  QuadSegmentConsumer resultHere)

adaptiveDegreeReduction

public static void adaptiveDegreeReduction(java.awt.geom.CubicCurve2D cubic,
                                           double precision,
                                           QuadSegmentConsumer resultHere)
The adaptive degree reduction algorithm, implemented to return the resulted "daisy-chain" of the approximating quadratic segments as an array. The resulted segments are "fed" into a QuadSegmentConsumer for further processing (or just storing).

Parameters:
cubic - the cubic to be approximated by quad segments
precision - the desired precision of approximation. If drawing the resulted quad segments, it doesn't make any sense to use less than half of the resolution of the device used to display it (e.g. if drawing on a screen, and the x, y< coordinates are pixels, use 0.5 as a minimum for the precision, even if for most of the cases a value of 0.75 or even 1.0 will be sufficient).