[sdf] Added functions to subdivide a cubic curve.

* src/sdf/ftsdf.c (split_cubic, split_sdf_cubic):
  These functions can be used to subdivide a
  cubic bezier curve into line segments which can
  then be used to generate the SDF.

* src/sdf/ftsdf.c (split_sdf_shape): Added function
  to split a cubic into a line segments.

* src/sdf/ftsdf.c (sdf_shape_done): No need to pass
  `FT_Memory' as a parameter, it can be accessed
  from the `shape' struct.
This commit is contained in:
Anuj Verma 2020-07-09 09:07:55 +05:30 committed by anujverma
parent 1ba3da86e1
commit fa7251ba35
2 changed files with 147 additions and 5 deletions

View File

@ -1,3 +1,19 @@
2020-07-09 Anuj Verma <anujv@iitbhilai.ac.in>
[sdf] Added functions to subdivide a cubic curve.
* src/sdf/ftsdf.c (split_cubic, split_sdf_cubic):
These functions can be used to subdivide a
cubic bezier curve into line segments which can
then be used to generate the SDF.
* src/sdf/ftsdf.c (split_sdf_shape): Added function
to split a cubic into a line segments.
* src/sdf/ftsdf.c (sdf_shape_done): No need to pass
`FT_Memory' as a parameter, it can be accessed
from the `shape' struct.
2020-07-09 Anuj Verma <anujv@iitbhilai.ac.in>
* src/sdf/ftsdf.c (split_sdf_shape): Typo.

View File

@ -332,10 +332,17 @@
/* Frees the allocated `shape' variable and also frees */
/* the list of contours. */
static void
sdf_shape_done( FT_Memory memory,
SDF_Shape** shape )
sdf_shape_done( SDF_Shape** shape )
{
if ( !memory || !shape || !*shape )
FT_Memory memory;
if ( !shape || !*shape )
return;
memory = (*shape)->memory;
if ( !memory )
return;
/* release the list of contours */
@ -671,6 +678,40 @@
base[1].y = a / 2;
}
/* The function is exactly same as the one */
/* in the smooth renderer. It splits a cubic */
/* into two cubic exactly half way at t = 0.5 */
static void
split_cubic( FT_26D6_Vec* base )
{
FT_26D6 a, b, c;
base[6].x = base[3].x;
a = base[0].x + base[1].x;
b = base[1].x + base[2].x;
c = base[2].x + base[3].x;
base[5].x = c / 2;
c += b;
base[4].x = c / 4;
base[1].x = a / 2;
a += b;
base[2].x = a / 4;
base[3].x = ( a + c ) / 8;
base[6].y = base[3].y;
a = base[0].y + base[1].y;
b = base[1].y + base[2].y;
c = base[2].y + base[3].y;
base[5].y = c / 2;
c += b;
base[4].y = c / 4;
base[1].y = a / 2;
a += b;
base[2].y = a / 4;
base[3].y = ( a + c ) / 8;
}
/* the function splits a conic bezier curve */
/* into a number of lines and adds them to */
/* a list `out'. The function uses recursion */
@ -746,6 +787,82 @@
return error;
}
/* the function splits a cubic bezier curve */
/* into a number of lines and adds them to */
/* a list `out'. The function uses recursion */
/* that is why a `max_splits' param is required */
/* for stopping. */
static FT_Error
split_sdf_cubic( FT_Memory memory,
FT_26D6_Vec* control_points,
FT_Int max_splits,
FT_List out )
{
FT_Error error = FT_Err_Ok;
FT_26D6_Vec cpos[7];
SDF_Edge* left,* right;
FT_ListNode n1, n2;
if ( !memory || !out )
{
error = FT_THROW( Invalid_Argument );
goto Exit;
}
/* split the conic */
cpos[0] = control_points[0];
cpos[1] = control_points[1];
cpos[2] = control_points[2];
cpos[3] = control_points[3];
split_cubic( cpos );
/* If max number of splits is done */
/* then stop and add the lines to */
/* the list. */
if ( max_splits <= 2 )
goto Append;
/* If not max splits then keep splitting */
FT_CALL( split_sdf_cubic( memory, &cpos[0], max_splits / 2, out ) );
FT_CALL( split_sdf_cubic( memory, &cpos[3], max_splits / 2, out ) );
/* [NOTE]: This is not an efficient way of */
/* splitting the curve. Check the deviation */
/* instead and stop if the deviation is less */
/* than a pixel. */
goto Exit;
Append:
/* Allocation and add the lines to the list. */
FT_CALL( sdf_edge_new( memory, &left) );
FT_CALL( sdf_edge_new( memory, &right) );
if ( FT_QNEW( n1 ) || FT_QNEW( n2 ) )
goto Exit;
left->start_pos = cpos[0];
left->end_pos = cpos[3];
left->edge_type = SDF_EDGE_LINE;
right->start_pos = cpos[3];
right->end_pos = cpos[6];
right->edge_type = SDF_EDGE_LINE;
n1->data = left;
n2->data = right;
FT_List_Add( out, n1 );
FT_List_Add( out, n2 );
Exit:
return error;
}
/* This function subdivide and entire shape */
/* into line segment such that the it doesn't */
/* look visually different than the original */
@ -814,7 +931,16 @@
}
case SDF_EDGE_CUBIC:
{
/* [TODO] */
/* Subdivide the curve and add to the list. */
FT_26D6_Vec ctrls[4];
ctrls[0] = edge->start_pos;
ctrls[1] = edge->control_a;
ctrls[2] = edge->control_b;
ctrls[3] = edge->end_pos;
error = split_sdf_cubic( memory, ctrls, 16, &new_edges );
break;
}
default:
error = FT_THROW( Invalid_Argument );
@ -2721,7 +2847,7 @@
Exit:
if ( shape )
sdf_shape_done( memory, &shape );
sdf_shape_done( &shape );
return error;
}