freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[freetype2] anuj-distance-field f9b4f37 25/93: [sdf] Added function to f


From: Anuj Verma
Subject: [freetype2] anuj-distance-field f9b4f37 25/93: [sdf] Added function to find shortest distance from a point to a conic.
Date: Sun, 2 Aug 2020 07:04:14 -0400 (EDT)

branch: anuj-distance-field
commit f9b4f3743353899faffa375d38ddc6e6560b8d33
Author: Anuj Verma <anujv@iitbhilai.ac.in>
Commit: anujverma <anujv@iitbhilai.ac.in>

    [sdf] Added function to find shortest distance from a       point to a 
conic.
---
 [GSoC]ChangeLog |  13 ++++
 src/sdf/ftsdf.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 218 insertions(+)

diff --git a/[GSoC]ChangeLog b/[GSoC]ChangeLog
index c61d472..a9f13fd 100644
--- a/[GSoC]ChangeLog
+++ b/[GSoC]ChangeLog
@@ -1,5 +1,18 @@
 2020-07-01     Anuj Verma  <anujv@iitbhilai.ac.in>
 
+       [sdf] Added function to find shortest distance from a
+       point to a conic bezier. Now the sdf module can render
+       ttf fonts or fonts with line and conic segments.
+
+       * src/sdf/ftsdf.c (get_min_distance_conic): The function
+         calculates shortest distance from a point to a conic
+         bezier curve.
+
+       * src/sdf/ftsdf.c (sdf_edge_get_min_distance): Add the
+         `get_min_distance_conic' function call.
+
+2020-07-01     Anuj Verma  <anujv@iitbhilai.ac.in>
+
        * src/sdf/ftsdf.c (get_min_distance_line): First check
          pointer before using or dereferencing them.
 
diff --git a/src/sdf/ftsdf.c b/src/sdf/ftsdf.c
index 4ec5bdc..c5e9932 100644
--- a/src/sdf/ftsdf.c
+++ b/src/sdf/ftsdf.c
@@ -27,6 +27,10 @@
                            goto Exit;              \
                        } while ( 0 )
 
+  #define MUL_26D6( a, b ) ( ( a * b ) / 64 )
+  #define VEC_26D6_DOT( p, q ) ( MUL_26D6( p.x, q.x ) +   \
+                                 MUL_26D6( p.y, q.y ) )
+
   /**************************************************************************
    *
    * typedefs
@@ -1028,6 +1032,7 @@
     FT_16D16_Vec nearest_point;     /* `point_on_line'       */
     FT_16D16_Vec nearest_vector;    /* `p' - `nearest_point' */
 
+
     if ( !line || !out )
     {
       error = FT_THROW( Invalid_Argument );
@@ -1097,6 +1102,204 @@
   /**************************************************************************
    *
    * @Function:
+   *   get_min_distance_conic
+   *
+   * @Description:
+   *   This function find the shortest distance from the `conic' bezier
+   *   curve to a given `point' and assigns it to `out'. Only use it for
+   *   conic/quadratic curves.
+   *
+   * @Input:
+   *   [TODO]
+   *
+   * @Return:
+   *   [TODO]
+   */
+  static FT_Error
+  get_min_distance_conic( SDF_Edge*             conic,
+                          FT_26D6_Vec           point,
+                          SDF_Signed_Distance*  out )
+  {
+      /* The procedure to find the shortest distance from a point to */
+      /* a quadratic bezier curve is similar to a line segment. the  */
+      /* shortest distance will be perpendicular to the bezier curve */
+      /* The only difference from line is that there can be more     */
+      /* than one perpendicular and we also have to check the endpo- */
+      /* -ints, because the perpendicular may not be the shortest.   */
+      /*                                                             */
+      /* p0 = first endpoint                                         */
+      /* p1 = control point                                          */
+      /* p2 = second endpoint                                        */
+      /* p = point from which shortest distance is to be calculated  */
+      /* ----------------------------------------------------------- */
+      /* => the equation of a quadratic bezier curve can be written  */
+      /*    B( t ) = ( ( 1 - t )^2 )p0 + 2( 1 - t )tp1 + t^2p2       */
+      /*    here t is the factor with range [0.0f, 1.0f]             */
+      /*    the above equation can be rewritten as                   */
+      /*    B( t ) = t^2( p0 - 2p1 + p2 ) + 2t( p1 - p0 ) + p0       */
+      /*                                                             */
+      /*    now let A = ( p0 - 2p1 + p2), B = ( p1 - p0 )            */
+      /*    B( t ) = t^2( A ) + 2t( B ) + p0                         */
+      /*                                                             */
+      /* => the derivative of the above equation is written as       */
+      /*    B`( t ) = 2( tA + B )                                    */
+      /*                                                             */
+      /* => now to find the shortest distance from p to B( t ), we   */
+      /*    find the point on the curve at which the shortest        */
+      /*    distance vector ( i.e. B( t ) - p ) and the direction    */
+      /*    ( i.e. B`( t )) makes 90 degrees. in other words we make */
+      /*    the dot product zero.                                    */
+      /*    ( B( t ) - p ).( B`( t ) ) = 0                           */
+      /*    ( t^2( A ) + 2t( B ) + p0 - p ).( 2( tA + B ) ) = 0      */
+      /*                                                             */
+      /*    after simplifying we get a cubic equation as             */
+      /*    at^3 + bt^2 + ct + d = 0                                 */
+      /*    a = ( A.A ), b = ( 3A.B ), c = ( 2B.B + A.p0 - A.p )     */
+      /*    d = ( p0.B - p.B )                                       */
+      /*                                                             */
+      /* => now the roots of the equation can be computed using the  */
+      /*    `Cardano's Cubic formula' we clamp the roots in range    */
+      /*    [0.0f, 1.0f].                                            */
+      /*                                                             */
+      /* [note]: B and B( t ) are different in the above equations   */
+
+    FT_Error     error = FT_Err_Ok;
+
+    FT_26D6_Vec  aA, bB;         /* A, B in the above comment             */
+    FT_26D6_Vec  nearest_point;  /* point on curve nearest to `point'     */
+    FT_26D6_Vec  direction;      /* direction of curve at `nearest_point' */
+
+    FT_26D6_Vec  p0, p1, p2;     /* control points of a conic curve       */
+    FT_26D6_Vec  p;              /* `point' to which shortest distance    */
+
+    FT_26D6      a, b, c, d;     /* cubic coefficients                    */
+
+    FT_16D16     roots[3] = { 0, 0, 0 }; /* real roots of the cubic eq    */
+    FT_16D16     min_factor;             /* factor at `nearest_point'     */
+    FT_16D16     cross;                  /* to determin the sign          */
+    FT_16D16     min = FT_INT_MAX;       /* shortest squared distance     */
+
+    FT_UShort    num_roots;              /* number of real roots of cubic */
+    FT_UShort    i;
+
+
+    if ( !conic || !out )
+    {
+      error = FT_THROW( Invalid_Argument );
+      goto Exit;
+    }
+
+    if ( conic->edge_type != SDF_EDGE_CONIC )
+    {
+      error = FT_THROW( Invalid_Argument );
+      goto Exit;
+    }
+
+    /* assign the values after checking pointer */
+    p0 = conic->start_pos;
+    p1 = conic->control_a;
+    p2 = conic->end_pos;
+    p  = point;
+
+    /* compute substitution coefficients */
+    aA.x = p0.x - 2 * p1.x + p2.x;
+    aA.y = p0.y - 2 * p1.y + p2.y;
+
+    bB.x = p1.x - p0.x;
+    bB.y = p1.y - p0.y;
+
+    /* compute cubic coefficients */
+    a = VEC_26D6_DOT( aA, aA );
+
+    b = 3 * VEC_26D6_DOT( aA, bB );
+
+    c = 2 * VEC_26D6_DOT( bB, bB ) +
+            VEC_26D6_DOT( aA, p0 ) -
+            VEC_26D6_DOT( aA, p );
+
+    d = VEC_26D6_DOT( p0, bB ) -
+        VEC_26D6_DOT( p, bB );
+
+    /* find the roots */
+    num_roots = solve_cubic_equation( a, b, c, d, roots );
+
+    /* convert these values to 16.16 for further computation */
+    aA.x = FT_26D6_16D16( aA.x );
+    aA.y = FT_26D6_16D16( aA.y );
+
+    bB.x = FT_26D6_16D16( bB.x );
+    bB.y = FT_26D6_16D16( bB.y );
+
+    p0.x = FT_26D6_16D16( p0.x );
+    p0.y = FT_26D6_16D16( p0.y );
+
+    p.x = FT_26D6_16D16( p.x );
+    p.y = FT_26D6_16D16( p.y );
+
+    for ( i = 0; i < num_roots; i++ )
+    {
+      FT_16D16      t    = roots[i];
+      FT_16D16      t2   = 0;
+      FT_16D16      dist = 0;
+
+      FT_16D16_Vec  curve_point;
+      FT_16D16_Vec  dist_vector;
+
+
+      /* check this: 
https://lists.nongnu.org/archive/html/freetype-devel/2020-06/msg00147.html */
+      /* to see why we clamp the values and not check the endpoints */
+      if ( t < 0 )
+        t = 0;
+      if ( t > FT_INT_16D16( 1 ) )
+        t = FT_INT_16D16( 1 );
+
+      t2 = FT_MulFix( t, t );
+
+      /* B( t ) = t^2( A ) + 2t( B ) + p0 - p */
+      curve_point.x = FT_MulFix( aA.x, t2 ) +
+                      2 * FT_MulFix( bB.x, t ) + p0.x;
+      curve_point.y = FT_MulFix( aA.y, t2 ) +
+                      2 * FT_MulFix( bB.y, t ) + p0.y;
+
+      /* `curve_point' - `p' */
+      dist_vector.x = curve_point.x - p.x;
+      dist_vector.y = curve_point.y - p.y;
+
+      dist = FT_MulFix( dist_vector.x, dist_vector.x ) +
+             FT_MulFix( dist_vector.y, dist_vector.y );
+
+      if ( dist < min )
+      {
+        min = dist;
+        nearest_point = curve_point;
+        min_factor = t;
+      }
+    }
+
+    /* B`( t ) = 2( tA + B ) */
+    direction.x = 2 * FT_MulFix( aA.x, min_factor ) + 2 * bB.x;
+    direction.y = 2 * FT_MulFix( aA.y, min_factor ) + 2 * bB.y;
+
+    /* determine the sign */
+    cross = FT_MulFix( nearest_point.x - p.x, direction.y ) -
+            FT_MulFix( nearest_point.y - p.y, direction.x );
+
+    /* assign the values */
+    out->squared_distance = min;
+    out->nearest_point = nearest_point;
+    out->sign = cross < 0 ? 1 : -1;
+
+    FT_Vector_NormLen( &direction );
+
+    out->direction = direction;
+
+  Exit:
+    return error;
+  }
+
+  /**************************************************************************
+   *
+   * @Function:
    *   sdf_edge_get_min_distance
    *
    * @Description:
@@ -1129,6 +1332,8 @@
       get_min_distance_line( edge, point, out );
       break;
     case SDF_EDGE_CONIC:
+      get_min_distance_conic( edge, point, out );
+      break;
     case SDF_EDGE_CUBIC:
     default:
         error = FT_THROW( Invalid_Argument );



reply via email to

[Prev in Thread] Current Thread [Next in Thread]