[base] Enable new algorithm for BBox_Cubic_Check.

* src/base/ftbbox.c: Enable new BBox_Cubic_Check algorithm, remove the
old one. Improve comments.
This commit is contained in:
Alexei Podtelezhnikov 2013-08-19 22:57:05 -04:00
parent 4af444400f
commit fc32e1c8cc
2 changed files with 32 additions and 191 deletions

View File

@ -1,3 +1,10 @@
2013-08-19 Alexei Podtelezhnikov <apodtele@gmail.com>
[base] Enable new algorithm for BBox_Cubic_Check.
* src/base/ftbbox.c: Enable new BBox_Cubic_Check algorithm, remove the
old one. Improve comments.
2013-08-18 Werner Lemberg <wl@gnu.org>
* builds/unix/unix-def.in (freetype2.pc): Don't set executable bit.

View File

@ -109,9 +109,9 @@
FT_Pos* max )
{
/* This function is only called when a control off-point is outside */
/* the bbox. This also means there must be a local extremum within */
/* the segment with the value of (y1*y3 - y2*y2)/(y1 - 2*y2 + y3). */
/* Offsetting from the closest point to the extermum, y2, we get */
/* the bbox that contains all on-points. It finds a local extremum */
/* within the segment, equal to (y1*y3 - y2*y2)/(y1 - 2*y2 + y3). */
/* Or, offsetting from y2, we get */
y1 -= y2;
y3 -= y2;
@ -185,8 +185,8 @@
/* */
/* <Description> */
/* Finds the extrema of a 1-dimensional cubic Bezier curve and */
/* updates a bounding range. This version uses splitting because we */
/* don't want to use square roots and extra accuracy. */
/* updates a bounding range. This version uses iterative splitting */
/* because it is faster than the exact solution with square roots. */
/* */
/* <Input> */
/* p1 :: The start coordinate. */
@ -203,17 +203,15 @@
/* max :: The address of the current maximum. */
/* */
#if 0
static FT_Pos
update_max( FT_Pos q1,
FT_Pos q2,
FT_Pos q3,
FT_Pos q4,
FT_Pos max )
update_cubic_max( FT_Pos q1,
FT_Pos q2,
FT_Pos q3,
FT_Pos q4,
FT_Pos max )
{
/* for a conic segment to possibly reach new maximum */
/* one of its off-points must be above the current value */
/* for a cubic segment to possibly reach new maximum, at least */
/* one of its off-points must stay above the current value */
while ( q2 > max || q3 > max )
{
/* determine which half contains the maximum and split */
@ -267,13 +265,15 @@
FT_Pos nmin, nmax;
FT_Int shift;
/* This implementation relies on iterative bisection of the segment. */
/* The fixed-point arithmentic of bisection is inherently stable but */
/* may loose accuracy in the two lowest bits. To compensate, we */
/* upscale the segment if there is room. Large values may need to be */
/* downscaled to avoid overflows during bisection bisection. This */
/* function is only called when a control off-point is outside the */
/* the bbox and, thus, has the top absolute value among arguments. */
/* This function is only called when a control off-point is outside */
/* the bbox that contains all on-points. It finds a local extremum */
/* within the segment using iterative bisection of the segment. */
/* The fixed-point arithmentic of bisection is inherently stable */
/* but may loose accuracy in the two lowest bits. To compensate, */
/* we upscale the segment if there is room. Large values may need */
/* to be downscaled to avoid overflows during bisection bisection. */
/* The control off-point outside the bbox is likely to have the top */
/* absolute value among arguments. */
shift = 27 - FT_MSB( FT_ABS( p2 ) | FT_ABS( p3 ) );
@ -282,7 +282,7 @@
/* upscaling too much just wastes time */
if ( shift > 2 )
shift = 2;
p1 <<= shift;
p2 <<= shift;
p3 <<= shift;
@ -290,7 +290,7 @@
nmin = *min << shift;
nmax = *max << shift;
}
else
else
{
p1 >>= -shift;
p2 >>= -shift;
@ -300,10 +300,10 @@
nmax = *max >> -shift;
}
nmax = update_max( p1, p2, p3, p4, nmax );
nmax = update_cubic_max( p1, p2, p3, p4, nmax );
/* now flip the signs to update the minimum */
nmin = -update_max( -p1, -p2, -p3, -p4, -nmin );
nmin = -update_cubic_max( -p1, -p2, -p3, -p4, -nmin );
if ( shift > 0 )
{
@ -322,172 +322,6 @@
*max = nmax;
}
#else
static void
test_cubic_extrema( FT_Pos y1,
FT_Pos y2,
FT_Pos y3,
FT_Pos y4,
FT_Fixed u,
FT_Pos* min,
FT_Pos* max )
{
/* FT_Pos a = y4 - 3*y3 + 3*y2 - y1; */
FT_Pos b = y3 - 2*y2 + y1;
FT_Pos c = y2 - y1;
FT_Pos d = y1;
FT_Pos y;
FT_Fixed uu;
FT_UNUSED ( y4 );
/* The polynomial is */
/* */
/* P(x) = a*x^3 + 3b*x^2 + 3c*x + d , */
/* */
/* dP/dx = 3a*x^2 + 6b*x + 3c . */
/* */
/* However, we also have */
/* */
/* dP/dx(u) = 0 , */
/* */
/* which implies by subtraction that */
/* */
/* P(u) = b*u^2 + 2c*u + d . */
if ( u > 0 && u < 0x10000L )
{
uu = FT_MulFix( u, u );
y = d + FT_MulFix( c, 2*u ) + FT_MulFix( b, uu );
if ( y < *min ) *min = y;
if ( y > *max ) *max = y;
}
}
static void
BBox_Cubic_Check( FT_Pos y1,
FT_Pos y2,
FT_Pos y3,
FT_Pos y4,
FT_Pos* min,
FT_Pos* max )
{
/* always compare first and last points */
if ( y1 < *min ) *min = y1;
else if ( y1 > *max ) *max = y1;
if ( y4 < *min ) *min = y4;
else if ( y4 > *max ) *max = y4;
/* now, try to see if there are split points here */
if ( y1 <= y4 )
{
/* flat or ascending arc test */
if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 )
return;
}
else /* y1 > y4 */
{
/* descending arc test */
if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 )
return;
}
/* There are some split points. Find them. */
/* We already made sure that a, b, and c below cannot be all zero. */
{
FT_Pos a = y4 - 3*y3 + 3*y2 - y1;
FT_Pos b = y3 - 2*y2 + y1;
FT_Pos c = y2 - y1;
FT_Pos d;
FT_Fixed t;
FT_Int shift;
/* We need to solve `ax^2+2bx+c' here, without floating points! */
/* The trick is to normalize to a different representation in order */
/* to use our 16.16 fixed-point routines. */
/* */
/* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after normalization. */
/* These values must fit into a single 16.16 value. */
/* */
/* We normalize a, b, and c to `8.16' fixed-point values to ensure */
/* that their product is held in a `16.16' value including the sign. */
/* Necessarily, we need to shift `a', `b', and `c' so that the most */
/* significant bit of their absolute values is at position 22. */
/* */
/* This also means that we are using 23 bits of precision to compute */
/* the zeros, independently of the range of the original polynomial */
/* coefficients. */
/* */
/* This algorithm should ensure reasonably accurate values for the */
/* zeros. Note that they are only expressed with 16 bits when */
/* computing the extrema (the zeros need to be in 0..1 exclusive */
/* to be considered part of the arc). */
shift = FT_MSB( FT_ABS( a ) | FT_ABS( b ) | FT_ABS( c ) );
if ( shift > 22 )
{
shift -= 22;
/* this loses some bits of precision, but we use 23 of them */
/* for the computation anyway */
a >>= shift;
b >>= shift;
c >>= shift;
}
else
{
shift = 22 - shift;
a <<= shift;
b <<= shift;
c <<= shift;
}
/* handle a == 0 */
if ( a == 0 )
{
if ( b != 0 )
{
t = - FT_DivFix( c, b ) / 2;
test_cubic_extrema( y1, y2, y3, y4, t, min, max );
}
}
else
{
/* solve the equation now */
d = FT_MulFix( b, b ) - FT_MulFix( a, c );
if ( d < 0 )
return;
if ( d == 0 )
{
/* there is a single split point at -b/a */
t = - FT_DivFix( b, a );
test_cubic_extrema( y1, y2, y3, y4, t, min, max );
}
else
{
/* there are two solutions; we need to filter them */
d = FT_SqrtFixed( (FT_Int32)d );
t = - FT_DivFix( b - d, a );
test_cubic_extrema( y1, y2, y3, y4, t, min, max );
t = - FT_DivFix( b + d, a );
test_cubic_extrema( y1, y2, y3, y4, t, min, max );
}
}
}
}
#endif
/*************************************************************************/
/* */