зеркало из https://github.com/mozilla/gecko-dev.git
Bug 941585: Better dealing with degenerate beziers. r=jrmuizel
This commit is contained in:
Родитель
b31a6b57fb
Коммит
f83466661c
|
@ -219,17 +219,6 @@ SplitBezier(const BezierControlPoints &aControlPoints,
|
|||
aSecondSegmentControlPoints->mCP1 = cp1aaa;
|
||||
aSecondSegmentControlPoints->mCP2 = cp2aa;
|
||||
aSecondSegmentControlPoints->mCP3 = cp3a;
|
||||
|
||||
// Ensure the result is a nice cubic bezier.
|
||||
if (aSecondSegmentControlPoints->mCP1 == aSecondSegmentControlPoints->mCP2 ||
|
||||
aSecondSegmentControlPoints->mCP2 == aSecondSegmentControlPoints->mCP3) {
|
||||
aSecondSegmentControlPoints->mCP2 = aSecondSegmentControlPoints->mCP1 +
|
||||
(aSecondSegmentControlPoints->mCP3 - aSecondSegmentControlPoints->mCP1) *
|
||||
Float(2. / 3.);
|
||||
aSecondSegmentControlPoints->mCP3 = aControlPoints.mCP4 +
|
||||
(aSecondSegmentControlPoints->mCP3 - aControlPoints.mCP4) *
|
||||
Float(2. / 3.);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -278,9 +267,16 @@ FindInflectionApproximationRange(BezierControlPoints aControlPoints,
|
|||
Point cp21 = aControlPoints.mCP2 - aControlPoints.mCP1;
|
||||
Point cp41 = aControlPoints.mCP4 - aControlPoints.mCP1;
|
||||
|
||||
Float s4 = (cp41.x * cp21.y - cp41.y * cp21.x) / hypotf(cp21.x, cp21.y);
|
||||
if (!cp21.x && !cp21.y) {
|
||||
// In this case s3 becomes lim[n->0] (cp41.x * n) / n - (cp41.y * n) / n = cp41.x - cp41.y.
|
||||
*aMin = aT - pow(aTolerance / (cp41.x - cp41.y), Float(1. / 3.));
|
||||
*aMax = aT + pow(aTolerance / (cp41.x - cp41.y), Float(1. / 3.));;
|
||||
return;
|
||||
}
|
||||
|
||||
Float tf = pow(abs(aTolerance / s4), Float(1. / 3.));
|
||||
Float s3 = (cp41.x * cp21.y - cp41.y * cp21.x) / hypotf(cp21.x, cp21.y);
|
||||
|
||||
Float tf = pow(abs(aTolerance / s3), Float(1. / 3.));
|
||||
|
||||
*aMin = aT - tf * (1 - aT);
|
||||
*aMax = aT + tf * (1 - aT);
|
||||
|
@ -367,6 +363,9 @@ FindInflectionPoints(const BezierControlPoints &aControlPoints,
|
|||
if (discriminant < 0) {
|
||||
// No inflection points.
|
||||
*aCount = 0;
|
||||
} else if (discriminant == 0) {
|
||||
*aCount = 1;
|
||||
*aT1 = -b / (2 * a);
|
||||
} else {
|
||||
/* Use the following formula for computing the roots:
|
||||
*
|
||||
|
@ -419,10 +418,10 @@ FlattenBezier(const BezierControlPoints &aControlPoints,
|
|||
|
||||
// For both inflection points, calulate the range where they can be linearly
|
||||
// approximated if they are positioned within [0,1]
|
||||
if (count > 0 && t1 >= 0 && t1 <= 1.0) {
|
||||
if (count > 0 && t1 >= 0 && t1 < 1.0) {
|
||||
FindInflectionApproximationRange(aControlPoints, &t1min, &t1max, t1, aTolerance);
|
||||
}
|
||||
if (count > 1 && t2 >= 0 && t2 <= 1.0) {
|
||||
if (count > 1 && t2 >= 0 && t2 < 1.0) {
|
||||
FindInflectionApproximationRange(aControlPoints, &t2min, &t2max, t2, aTolerance);
|
||||
}
|
||||
BezierControlPoints nextCPs = aControlPoints;
|
||||
|
@ -430,34 +429,33 @@ FlattenBezier(const BezierControlPoints &aControlPoints,
|
|||
|
||||
// Process ranges. [t1min, t1max] and [t2min, t2max] are approximated by line
|
||||
// segments.
|
||||
if (t1min < 1.0 && t1max > 0) {
|
||||
if (t1min > 0) {
|
||||
// Flatten the Bezier up until the first inflection point's approximation
|
||||
// point.
|
||||
SplitBezier(aControlPoints, &prevCPs,
|
||||
&remainingCP, t1min);
|
||||
FlattenBezierCurveSegment(prevCPs, aSink, aTolerance);
|
||||
}
|
||||
if (t1max < 1.0 && (count == 1 || t2min > t1max)) {
|
||||
// The second inflection point's approximation range begins after the end
|
||||
// of the first, approximate the first inflection point by a line and
|
||||
// subsequently flatten up until the end or the next inflection point.
|
||||
SplitBezier(aControlPoints, nullptr, &nextCPs, t1max);
|
||||
|
||||
aSink->LineTo(nextCPs.mCP1);
|
||||
|
||||
if (count > 1 && t2min > 1.0) {
|
||||
// No more inflection points to deal with, flatten the rest of the curve.
|
||||
FlattenBezierCurveSegment(nextCPs, aSink, aTolerance);
|
||||
}
|
||||
} else if (count > 1 && t2min > 1.0) {
|
||||
// We've already concluded t2min <= t1max, so if this is true the
|
||||
// approximation range for the first inflection point runs past the
|
||||
// end of the curve, draw a line to the end and we're done.
|
||||
aSink->LineTo(aControlPoints.mCP4);
|
||||
return;
|
||||
}
|
||||
if (t1min > 0) {
|
||||
// Flatten the Bezier up until the first inflection point's approximation
|
||||
// point.
|
||||
SplitBezier(aControlPoints, &prevCPs,
|
||||
&remainingCP, t1min);
|
||||
FlattenBezierCurveSegment(prevCPs, aSink, aTolerance);
|
||||
}
|
||||
if (t1max < 1.0 && (count == 1 || t2min > t1max)) {
|
||||
// The second inflection point's approximation range begins after the end
|
||||
// of the first, approximate the first inflection point by a line and
|
||||
// subsequently flatten up until the end or the next inflection point.
|
||||
SplitBezier(aControlPoints, nullptr, &nextCPs, t1max);
|
||||
|
||||
aSink->LineTo(nextCPs.mCP1);
|
||||
|
||||
if (count == 1 || (count > 1 && t2min >= 1.0)) {
|
||||
// No more inflection points to deal with, flatten the rest of the curve.
|
||||
FlattenBezierCurveSegment(nextCPs, aSink, aTolerance);
|
||||
}
|
||||
} else if (count > 1 && t2min > 1.0) {
|
||||
// We've already concluded t2min <= t1max, so if this is true the
|
||||
// approximation range for the first inflection point runs past the
|
||||
// end of the curve, draw a line to the end and we're done.
|
||||
aSink->LineTo(aControlPoints.mCP4);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count > 1 && t2min < 1.0 && t2max > 0) {
|
||||
if (t2min > 0 && t2min < t1max) {
|
||||
// In this case the t2 approximation range starts inside the t1
|
||||
|
|
Загрузка…
Ссылка в новой задаче