[gtk/wip/otte/lottie: 64/86] path: Add gsk_curve_segment()




commit 9ac97619d7a906caa7e0d26982ed3215436c45d8
Author: Benjamin Otte <otte redhat com>
Date:   Wed Dec 9 03:40:58 2020 +0100

    path: Add gsk_curve_segment()
    
    Using split() twice with scaled t values does not work with conics.

 gsk/gskcontour.c      | 16 ++++-----
 gsk/gskcurve.c        | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gsk/gskcurveprivate.h |  4 +++
 3 files changed, 107 insertions(+), 8 deletions(-)
---
diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c
index aaef60cdb3..e433d8c508 100644
--- a/gsk/gskcontour.c
+++ b/gsk/gskcontour.c
@@ -1334,19 +1334,19 @@ gsk_standard_contour_add_segment (const GskContour *contour,
 
       gsk_curve_init (&curve, self->ops[start_measure->op]);
 
-      gsk_curve_split (&curve, start_progress, NULL, &cut);
-      start_point = gsk_curve_get_start_point (&cut);
-      gsk_path_builder_move_to (builder, start_point->x, start_point->y);
-
       if (end_measure && end_measure->op == start_measure->op)
         {
-          GskCurve cut2;
-      
-          gsk_curve_split (&cut, (end_progress - start_progress) / (1 - start_progress), &cut2, NULL);
-          gsk_curve_builder_to (&cut2, builder);
+          gsk_curve_segment (&curve, start_progress, end_progress, &cut);
+          start_point = gsk_curve_get_start_point (&cut);
+          gsk_path_builder_move_to (builder, start_point->x, start_point->y);
+          gsk_curve_builder_to (&cut, builder);
           return;
         }
 
+      gsk_curve_split (&curve, start_progress, NULL, &cut);
+
+      start_point = gsk_curve_get_start_point (&cut);
+      gsk_path_builder_move_to (builder, start_point->x, start_point->y);
       gsk_curve_builder_to (&cut, builder);
       i = start_measure->op + 1;
     }
diff --git a/gsk/gskcurve.c b/gsk/gskcurve.c
index ed28700b3f..6e0332ab37 100644
--- a/gsk/gskcurve.c
+++ b/gsk/gskcurve.c
@@ -39,6 +39,10 @@ struct _GskCurveClass
                                                          float                   progress,
                                                          GskCurve               *result1,
                                                          GskCurve               *result2);
+  void                          (* segment)             (const GskCurve         *curve,
+                                                         float                   start,
+                                                         float                   end,
+                                                         GskCurve               *segment);
   gboolean                      (* decompose)           (const GskCurve         *curve,
                                                          float                   tolerance,
                                                          GskCurveAddLineFunc     add_line_func,
@@ -121,6 +125,21 @@ gsk_line_curve_split (const GskCurve   *curve,
     gsk_line_curve_init_from_points (&end->line, GSK_PATH_LINE, &point, &self->points[1]);
 }
 
+static void
+gsk_line_curve_segment (const GskCurve *curve,
+                        float           start,
+                        float           end,
+                        GskCurve       *segment)
+{
+  const GskLineCurve *self = &curve->line;
+  graphene_point_t start_point, end_point;
+
+  graphene_point_interpolate (&self->points[0], &self->points[1], start, &start_point);
+  graphene_point_interpolate (&self->points[0], &self->points[1], end, &end_point);
+
+  gsk_line_curve_init_from_points (&segment->line, GSK_PATH_LINE, &start_point, &end_point);
+}
+
 static gboolean
 gsk_line_curve_decompose (const GskCurve      *curve,
                           float                tolerance,
@@ -170,6 +189,7 @@ static const GskCurveClass GSK_LINE_CURVE_CLASS = {
   gsk_line_curve_get_point,
   gsk_line_curve_get_tangent,
   gsk_line_curve_split,
+  gsk_line_curve_segment,
   gsk_line_curve_decompose,
   gsk_line_curve_pathop,
   gsk_line_curve_get_start_point,
@@ -273,6 +293,18 @@ gsk_curve_curve_split (const GskCurve   *curve,
     gsk_curve_curve_init_from_points (&end->curve, (graphene_point_t[4]) { final, bccd, cd, pts[3] });
 }
 
+static void
+gsk_curve_curve_segment (const GskCurve *curve,
+                         float           start,
+                         float           end,
+                         GskCurve       *segment)
+{
+  GskCurve tmp;
+
+  gsk_curve_curve_split (curve, start, NULL, &tmp);
+  gsk_curve_curve_split (&tmp, (end - start) / (1.0f - start), segment, NULL);
+}
+
 /* taken from Skia, including the very descriptive name */
 static gboolean
 gsk_curve_curve_too_curvy (const GskCurveCurve *self,
@@ -370,6 +402,7 @@ static const GskCurveClass GSK_CURVE_CURVE_CLASS = {
   gsk_curve_curve_get_point,
   gsk_curve_curve_get_tangent,
   gsk_curve_curve_split,
+  gsk_curve_curve_segment,
   gsk_curve_curve_decompose,
   gsk_curve_curve_pathop,
   gsk_curve_curve_get_start_point,
@@ -598,6 +631,52 @@ gsk_conic_curve_split (const GskCurve   *curve,
     gsk_curve_init (end, gsk_pathop_encode (GSK_PATH_CONIC, right));
 }
 
+static void
+gsk_conic_curve_segment (const GskCurve *curve,
+                         float           start,
+                         float           end,
+                         GskCurve       *segment)
+{
+  const GskConicCurve *self = &curve->conic;
+  graphene_point_t start_num, start_denom;
+  graphene_point_t mid_num, mid_denom;
+  graphene_point_t end_num, end_denom;
+  graphene_point_t ctrl_num, ctrl_denom;
+  float mid;
+
+  if (start <= 0.0f)
+    return gsk_conic_curve_split (curve, end, segment, NULL);
+  else if (end >= 1.0f)
+    return gsk_conic_curve_split (curve, start, NULL, segment);
+
+  gsk_conic_curve_ensure_coefficents (self);
+
+  gsk_curve_eval_quad (self->num, start, &start_num);
+  gsk_curve_eval_quad (self->denom, start, &start_denom);
+  mid = (start + end) / 2;
+  gsk_curve_eval_quad (self->num, mid, &mid_num);
+  gsk_curve_eval_quad (self->denom, mid, &mid_denom);
+  gsk_curve_eval_quad (self->num, end, &end_num);
+  gsk_curve_eval_quad (self->denom, end, &end_denom);
+  ctrl_num = GRAPHENE_POINT_INIT (2 * mid_num.x - (start_num.x + end_num.x) / 2,
+                                  2 * mid_num.y - (start_num.y + end_num.y) / 2);
+  ctrl_denom = GRAPHENE_POINT_INIT (2 * mid_denom.x - (start_denom.x + end_denom.x) / 2,
+                                    2 * mid_denom.y - (start_denom.y + end_denom.y) / 2);
+
+  gsk_conic_curve_init_from_points (&segment->conic,
+                                    (graphene_point_t[4]) {
+                                      GRAPHENE_POINT_INIT (start_num.x / start_denom.x,
+                                                           start_num.y / start_denom.y),
+                                      GRAPHENE_POINT_INIT (ctrl_num.x / ctrl_denom.x,
+                                                           ctrl_num.y / ctrl_denom.y),
+                                      GRAPHENE_POINT_INIT (ctrl_denom.x / sqrtf (start_denom.x * 
end_denom.x),
+                                                           0),
+                                      GRAPHENE_POINT_INIT (end_num.x / end_denom.x,
+                                                           end_num.y / end_denom.y)
+                                    });
+
+}
+
 /* taken from Skia, including the very descriptive name */
 static gboolean
 gsk_conic_curve_too_curvy (const graphene_point_t *start,
@@ -706,6 +785,7 @@ static const GskCurveClass GSK_CONIC_CURVE_CLASS = {
   gsk_conic_curve_get_point,
   gsk_conic_curve_get_tangent,
   gsk_conic_curve_split,
+  gsk_conic_curve_segment,
   gsk_conic_curve_decompose,
   gsk_conic_curve_pathop,
   gsk_conic_curve_get_start_point,
@@ -763,6 +843,21 @@ gsk_curve_split (const GskCurve *curve,
   get_class (curve->op)->split (curve, progress, start, end);
 }
 
+void
+gsk_curve_segment (const GskCurve *curve,
+                   float           start,
+                   float           end,
+                   GskCurve       *segment)
+{
+  if (start <= 0 && end >= 1)
+    {
+      *segment = *curve;
+      return;
+    }
+
+  get_class (curve->op)->segment (curve, start, end, segment);
+}
+
 gboolean
 gsk_curve_decompose (const GskCurve      *curve,
                      float                tolerance,
diff --git a/gsk/gskcurveprivate.h b/gsk/gskcurveprivate.h
index 1fd7794836..d01f520f07 100644
--- a/gsk/gskcurveprivate.h
+++ b/gsk/gskcurveprivate.h
@@ -92,6 +92,10 @@ void                    gsk_curve_split                         (const GskCurve
                                                                  float                   progress,
                                                                  GskCurve               *start,
                                                                  GskCurve               *end);
+void                    gsk_curve_segment                       (const GskCurve         *curve,
+                                                                 float                   start,
+                                                                 float                   end,
+                                                                 GskCurve               *segment);
 gboolean                gsk_curve_decompose                     (const GskCurve         *curve,
                                                                  float                   tolerance,
                                                                  GskCurveAddLineFunc     add_line_func,


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