Ejemplo n.º 1
0
static inline void
FindInflectionApproximationRange(BezierControlPoints aControlPoints,
                                 Float *aMin, Float *aMax, Float aT,
                                 Float aTolerance)
{
    SplitBezier(aControlPoints, nullptr, &aControlPoints, aT);

    Point cp21 = aControlPoints.mCP2 - aControlPoints.mCP1;
    Point cp41 = aControlPoints.mCP4 - aControlPoints.mCP1;

    if (cp21.x == 0 && cp21.y == 0) {
      // In this case s3 becomes lim[n->0] (cp41.x * n) / n - (cp41.y * n) / n = cp41.x - cp41.y.
      *aMin = aT - CubicRoot(double(aTolerance / (cp41.x - cp41.y)));
      *aMax = aT + CubicRoot(aTolerance / (cp41.x - cp41.y));
      return;
    }

    Float s3 = (cp41.x * cp21.y - cp41.y * cp21.x) / hypotf(cp21.x, cp21.y);

    if (s3 == 0) {
      // This means within the precision we have it can be approximated
      // infinitely by a linear segment. Deal with this by specifying the
      // approximation range as extending beyond the entire curve.
      *aMin = -1.0f;
      *aMax = 2.0f;
      return;
    }

    Float tf = CubicRoot(abs(aTolerance / s3));

    *aMin = aT - tf * (1 - aT);
    *aMax = aT + tf * (1 - aT);
}
Ejemplo n.º 2
0
static float CubicRoot(float aValue) {
  if (aValue < 0.0) {
    return -CubicRoot(-aValue);
  }
  else {
    return powf(aValue, 1.0f / 3.0f);
  }
}
Ejemplo n.º 3
0
float SolveBezier(float x, float p0, float p1, float p2, float p3)
{
	// check for valid f-curve
	// we only take care of monotonic bezier curves, so there has to be exactly 1 real solution
	tl_assert(p0 <= x && x <= p3);
	tl_assert((p0 <= p1 && p1 <= p3) && (p0 <= p2 && p2 <= p3));

	double a, b, c, t;
	double x3 = -p0 + 3*p1 - 3*p2 + p3;
	double x2 = 3*p0 - 6*p1 + 3*p2;
	double x1 = -3*p0 + 3*p1;
	double x0 = p0 - x;

	if(x3 == 0.0 && x2 == 0.0)
	{
		// linear
		// a*t + b = 0
		a = x1;
		b = x0;

		if(a == 0.0)
			return 0.0f;
		else
			return -b/a;
	}
	else if(x3 == 0.0)
	{
		// quadratic
		// t*t + b*t +c = 0
		b = x1/x2;
		c = x0/x2;

		if(c == 0.0)
			return 0.0f;

		double D = b*b - 4*c;

		t = (-b + sqrt(D))/2;

		if(0.0 <= t && t <= 1.0001f)
			return t;
		else
			return (-b - sqrt(D))/2;
	}
	else
	{
		// cubic
		// t*t*t + a*t*t + b*t*t + c = 0
		a = x2 / x3;
		b = x1 / x3;
		c = x0 / x3;

		// substitute t = y - a/3
		double sub = a/3.0;

		// depressed form x^3 + px + q = 0
		// cardano's method
		double p = b/3 - a*a/9;
		double q = (2*a*a*a/27 - a*b/3 + c)/2;

		double D = q*q + p*p*p;

		if(D > 0.0)
		{
			// only one 'real' solution
			double s = sqrt(D);
			return CubicRoot(s-q) - CubicRoot(s+q) - sub;
		}
		else if(D == 0.0)
		{
			// one single, one double solution or triple solution
			double s = CubicRoot(-q);
			t = 2*s - sub;

			if(0.0 <= t && t <= 1.0001f)
				return t;
			else
				return (-s - sub);

		}
		else
		{
			// Casus irreductibilis ... ,_,
			double phi = acos(-q / sqrt(-(p*p*p))) / 3;
			double s = 2*sqrt(-p);

			t = s*cos(phi) - sub;

			if(0.0 <= t && t <= 1.0001f)
				return t;

			t = -s*cos(phi+pi/3) - sub;

			if(0.0 <= t && t <= 1.0001f)
				return t;
			else
				return -s*cos(phi-pi/3) - sub;
		}
	}
}