forked from minhngoc25a/freetype2
[sdf] Added function to find shortest distance from a point to a line.
This commit is contained in:
parent
186cc478ae
commit
063b65d583
@ -1,3 +1,17 @@
|
||||
2020-06-27 Anuj Verma <anujv@iitbhilai.ac.in>
|
||||
|
||||
[sdf] Added function to find shortest distance from
|
||||
a point to a line.
|
||||
|
||||
* src/sdf/ftsdf.c (get_min_distance_line): The function
|
||||
calculate the shortest signed distance from a point
|
||||
to a line segment.
|
||||
|
||||
* src/sdf/ftsdf.c (sdf_contour_get_min_distance): Typo.
|
||||
|
||||
* src/sdf/ftsdf.c (SDF_Signed_Distance): Use squared
|
||||
distance instead of actual distance for performance.
|
||||
|
||||
2020-06-27 Anuj Verma <anujv@iitbhilai.ac.in>
|
||||
|
||||
* src/sdf/ftsdf.c (SDF_Iterator_IO): Removed.
|
||||
|
172
src/sdf/ftsdf.c
172
src/sdf/ftsdf.c
@ -12,7 +12,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define FT_INT_26D6( x ) ( x * 64 ) /* convert int to 26.6 fixed point */
|
||||
#define FT_INT_26D6( x ) ( x * 64 ) /* convert int to 26.6 fixed point */
|
||||
#define FT_INT_16D16( x ) ( x * 65536 ) /* convert int to 16.16 fixed point */
|
||||
#define FT_26D6_16D16( x ) ( x * 1024 ) /* convert 26.6 to 16.16 fixed point */
|
||||
|
||||
|
||||
/* Convenient macro which calls the function */
|
||||
@ -34,6 +36,7 @@
|
||||
typedef FT_Vector FT_16D16_Vec; /* with 16.16 fixed point components */
|
||||
|
||||
typedef FT_Fixed FT_16D16; /* 16.16 fixed point representation */
|
||||
typedef FT_Fixed FT_26D6; /* 26.6 fixed point representation */
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
@ -99,9 +102,9 @@
|
||||
/* [note]: This is a *direction* vector. */
|
||||
FT_16D16_Vec direction;
|
||||
|
||||
/* Unsigned shortest distance from the point to */
|
||||
/* the above `nearest_point'. */
|
||||
FT_16D16 distance;
|
||||
/* Unsigned shortest squared distance from the */
|
||||
/* point to the above `nearest_point'. */
|
||||
FT_16D16 squared_distance;
|
||||
|
||||
/* Represent weather the `nearest_point' is outside */
|
||||
/* or inside the contour corresponding to the edge. */
|
||||
@ -604,6 +607,144 @@
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @Function:
|
||||
* get_min_distance_line
|
||||
*
|
||||
* @Description:
|
||||
* This function find the shortest distance from the `line' to
|
||||
* a given `point' and assigns it to `out'. Only use it for line
|
||||
* segments.
|
||||
*
|
||||
* @Input:
|
||||
* [TODO]
|
||||
*
|
||||
* @Return:
|
||||
* [TODO]
|
||||
*/
|
||||
static FT_Error
|
||||
get_min_distance_line( SDF_Edge* line,
|
||||
FT_26D6_Vec point,
|
||||
SDF_Signed_Distance* out )
|
||||
{
|
||||
/* in order to calculate the shortest distance from a point to */
|
||||
/* a line segment. */
|
||||
/* */
|
||||
/* a = start point of the line segment */
|
||||
/* b = end point of the line segment */
|
||||
/* p = point from which shortest distance is to be calculated */
|
||||
/* ----------------------------------------------------------- */
|
||||
/* => we first write the parametric equation of the line */
|
||||
/* point_on_line = a + ( b - a ) * t ( t is the factor ) */
|
||||
/* */
|
||||
/* => next we find the projection of point p on the line. the */
|
||||
/* projection will be perpendicular to the line, that is */
|
||||
/* why we can find it by making the dot product zero. */
|
||||
/* ( point_on_line - a ) . ( p - point_on_line ) = 0 */
|
||||
/* */
|
||||
/* ( point_on_line ) */
|
||||
/* ( a ) x-------o----------------x ( b ) */
|
||||
/* |_| */
|
||||
/* | */
|
||||
/* | */
|
||||
/* ( p ) */
|
||||
/* */
|
||||
/* => by simplifying the above equation we get the factor of */
|
||||
/* point_on_line such that */
|
||||
/* t = ( ( p - a ) . ( b - a ) ) / ( |b - a| ^ 2 ) */
|
||||
/* */
|
||||
/* => we clamp the factor t between [0.0f, 1.0f], because the */
|
||||
/* point_on_line can be outside the line segment. */
|
||||
/* */
|
||||
/* ( point_on_line ) */
|
||||
/* ( a ) x------------------------x ( b ) -----o--- */
|
||||
/* |_| */
|
||||
/* | */
|
||||
/* | */
|
||||
/* ( p ) */
|
||||
/* */
|
||||
/* => finally the distance becomes | point_on_line - p | */
|
||||
|
||||
FT_Error error = FT_Err_Ok;
|
||||
|
||||
const FT_Vector a = line->start_pos;
|
||||
const FT_Vector b = line->end_pos;
|
||||
const FT_Vector p = point;
|
||||
|
||||
FT_26D6_Vec line_segment; /* `b' - `a'*/
|
||||
FT_26D6_Vec p_sub_a; /* `p' - `a' */
|
||||
|
||||
FT_26D6 sq_line_length; /* squared length of `line_segment' */
|
||||
FT_16D16 factor; /* factor of the nearest point */
|
||||
FT_26D6 cross; /* used to determine sign */
|
||||
|
||||
FT_16D16_Vec nearest_point; /* point on the line nearest to `point' */
|
||||
FT_16D16_Vec nearest_vector; /* `p' - `nearest_point' */
|
||||
|
||||
if ( !line || !out )
|
||||
{
|
||||
error = FT_THROW( Invalid_Argument );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( line->edge_type != SDF_EDGE_LINE )
|
||||
{
|
||||
error = FT_THROW( Invalid_Argument );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
line_segment.x = b.x - a.x;
|
||||
line_segment.y = b.y - a.y;
|
||||
|
||||
p_sub_a.x = p.x - a.x;
|
||||
p_sub_a.y = p.y - a.y;
|
||||
|
||||
sq_line_length = ( line_segment.x * line_segment.x ) / 64 +
|
||||
( line_segment.y * line_segment.y ) / 64;
|
||||
|
||||
/* currently factor is 26.6 */
|
||||
factor = ( p_sub_a.x * line_segment.x ) / 64 +
|
||||
( p_sub_a.y * line_segment.y ) / 64;
|
||||
|
||||
/* now factor is 16.16 */
|
||||
factor = FT_DivFix( factor, sq_line_length );
|
||||
|
||||
/* clamp the factor between 0.0 and 1.0 in fixed point */
|
||||
if ( factor > FT_INT_16D16( 1 ) )
|
||||
factor = FT_INT_16D16( 1 );
|
||||
if ( factor < 0 )
|
||||
factor = 0;
|
||||
|
||||
nearest_point.x = FT_MulFix( FT_26D6_16D16(line_segment.x),
|
||||
factor );
|
||||
nearest_point.y = FT_MulFix( FT_26D6_16D16(line_segment.y),
|
||||
factor );
|
||||
|
||||
nearest_point.x = FT_26D6_16D16( a.x ) + nearest_point.x -
|
||||
FT_26D6_16D16( p.x );
|
||||
nearest_point.y = FT_26D6_16D16( a.y ) + nearest_point.y -
|
||||
FT_26D6_16D16( p.y );
|
||||
|
||||
nearest_vector.x = nearest_point.x - FT_26D6_16D16( p.x );
|
||||
nearest_vector.y = nearest_point.y - FT_26D6_16D16( p.y );
|
||||
|
||||
cross = FT_MulFix( nearest_vector.x, line_segment.y ) -
|
||||
FT_MulFix( nearest_vector.y, line_segment.x );
|
||||
|
||||
FT_Vector_NormLen( &line_segment );
|
||||
|
||||
/* assign the output */
|
||||
out->neartest_point = nearest_point;
|
||||
out->sign = cross < 0 ? 1 : -1;
|
||||
out->squared_distance = FT_MulFix( nearest_vector.x, nearest_vector.x ) +
|
||||
FT_MulFix( nearest_vector.y, nearest_vector.y );
|
||||
out->direction = line_segment;
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @Function:
|
||||
@ -634,12 +775,14 @@
|
||||
}
|
||||
|
||||
/* edge specific distance calculation */
|
||||
switch ( edge->edge_type ) {
|
||||
case SDF_EDGE_LINE:
|
||||
case SDF_EDGE_CONIC:
|
||||
case SDF_EDGE_CUBIC:
|
||||
switch ( edge->edge_type ) {
|
||||
case SDF_EDGE_LINE:
|
||||
get_min_distance_line( edge, point, out );
|
||||
break;
|
||||
case SDF_EDGE_CONIC:
|
||||
case SDF_EDGE_CUBIC:
|
||||
default:
|
||||
error = FT_THROW( Invalid_Argument );
|
||||
error = FT_THROW( Invalid_Argument );
|
||||
}
|
||||
|
||||
Exit:
|
||||
@ -663,7 +806,7 @@
|
||||
* [TODO]
|
||||
*/
|
||||
static FT_Error
|
||||
sdf_contour_get_min_distance( SDF_Contour* contuor,
|
||||
sdf_contour_get_min_distance( SDF_Contour* contour,
|
||||
FT_26D6_Vec point,
|
||||
SDF_Signed_Distance* out)
|
||||
{
|
||||
@ -672,13 +815,13 @@
|
||||
FT_ListRec edge_list;
|
||||
|
||||
|
||||
if ( !contuor || !out )
|
||||
if ( !contour || !out )
|
||||
{
|
||||
error = FT_THROW( Invalid_Argument );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
edge_list = contuor->edges;
|
||||
edge_list = contour->edges;
|
||||
|
||||
/* iterate through all the edges manually */
|
||||
while ( edge_list.head ) {
|
||||
@ -690,7 +833,7 @@
|
||||
point, ¤t_dist ) );
|
||||
|
||||
/* [TODO]: *IMPORTANT* Add corner checking function. */
|
||||
if ( current_dist.distance < min_dist.distance )
|
||||
if ( current_dist.squared_distance < min_dist.squared_distance )
|
||||
min_dist = current_dist;
|
||||
|
||||
edge_list.head = edge_list.head->next;
|
||||
@ -786,7 +929,8 @@
|
||||
(SDF_Contour*)contour_list.head->data,
|
||||
grid_point, ¤t_dist ) );
|
||||
|
||||
if ( current_dist.distance < min_dist.distance )
|
||||
if ( current_dist.squared_distance <
|
||||
min_dist.squared_distance )
|
||||
min_dist = current_dist;
|
||||
|
||||
contour_list.head = contour_list.head->next;
|
||||
|
Loading…
x
Reference in New Issue
Block a user