[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:
parent
4af444400f
commit
fc32e1c8cc
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
|
Loading…
Reference in New Issue
Block a user