[gtk/path-work-rebased: 57/71] pathmeasure: Add gsk_path_measure_get_curvature




commit cc3b47cef6ef8e030ac8b06989b5a4951db0a2c9
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Dec 23 18:52:05 2020 -0500

    pathmeasure: Add gsk_path_measure_get_curvature

 gsk/gskcontour.c        | 71 +++++++++++++++++++++++++++++++++++++++++++++++++
 gsk/gskcontourprivate.h |  4 +++
 gsk/gskpathmeasure.c    | 55 ++++++++++++++++++++++++++++++++++++++
 gsk/gskpathmeasure.h    |  5 ++++
 4 files changed, 135 insertions(+)
---
diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c
index 44206f3395..b36082a077 100644
--- a/gsk/gskcontour.c
+++ b/gsk/gskcontour.c
@@ -62,6 +62,10 @@ struct _GskContourClass
                                                  float                   distance,
                                                  graphene_point_t       *pos,
                                                  graphene_vec2_t        *tangent);
+  float                 (* get_curvature)       (const GskContour       *contour,
+                                                 gpointer                measure_data,
+                                                 float                   distance,
+                                                 graphene_point_t       *center);
   gboolean              (* get_closest_point)   (const GskContour       *contour,
                                                  gpointer                measure_data,
                                                  float                   tolerance,
@@ -301,6 +305,15 @@ gsk_rect_contour_get_point (const GskContour *contour,
     graphene_vec2_init (tangent, 0.0f, - copysignf (self->height, 1.0f));
 }
 
+static float
+gsk_rect_contour_get_curvature (const GskContour *contour,
+                                gpointer          measure_data,
+                                float             distance,
+                                graphene_point_t *center)
+{
+  return 0;
+}
+
 static gboolean
 gsk_rect_contour_get_closest_point (const GskContour       *contour,
                                     gpointer                measure_data,
@@ -564,6 +577,7 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
   gsk_rect_contour_init_measure,
   gsk_rect_contour_free_measure,
   gsk_rect_contour_get_point,
+  gsk_rect_contour_get_curvature,
   gsk_rect_contour_get_closest_point,
   gsk_rect_contour_copy,
   gsk_rect_contour_add_segment,
@@ -766,6 +780,20 @@ gsk_circle_contour_get_point (const GskContour *contour,
     }
 }
 
+static float
+gsk_circle_contour_get_curvature (const GskContour *contour,
+                                  gpointer          measure_data,
+                                  float             distance,
+                                  graphene_point_t *center)
+{
+  const GskCircleContour *self = (const GskCircleContour *) contour;
+
+  if (center)
+    *center = self->center;
+
+  return 1 / self->radius;
+}
+
 static gboolean
 gsk_circle_contour_get_closest_point (const GskContour       *contour,
                                       gpointer                measure_data,
@@ -951,6 +979,7 @@ static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
   gsk_circle_contour_init_measure,
   gsk_circle_contour_free_measure,
   gsk_circle_contour_get_point,
+  gsk_circle_contour_get_curvature,
   gsk_circle_contour_get_closest_point,
   gsk_circle_contour_copy,
   gsk_circle_contour_add_segment,
@@ -1288,6 +1317,38 @@ gsk_standard_contour_get_point (const GskContour *contour,
     gsk_curve_get_tangent (&curve, progress, tangent);
 }
 
+static float
+gsk_standard_contour_get_curvature (const GskContour *contour,
+                                    gpointer          measure_data,
+                                    float             distance,
+                                    graphene_point_t *center)
+{
+  GskStandardContour *self = (GskStandardContour *) contour;
+  GArray *array = measure_data;
+  guint index;
+  float progress;
+  GskStandardContourMeasure *measure;
+  GskCurve curve;
+
+  if (array->len == 0)
+    {
+      g_assert (distance == 0);
+      g_assert (gsk_pathop_op (self->ops[0]) == GSK_PATH_MOVE);
+      return 0;
+    }
+
+  if (!g_array_binary_search (array, &distance, gsk_standard_contour_find_measure, &index))
+    index = array->len - 1;
+  measure = &g_array_index (array, GskStandardContourMeasure, index);
+  progress = (distance - measure->start) / (measure->end - measure->start);
+  progress = measure->start_progress + (measure->end_progress - measure->start_progress) * progress;
+  g_assert (progress >= 0 && progress <= 1);
+
+  gsk_curve_init (&curve, self->ops[measure->op]);
+
+  return gsk_curve_get_curvature (&curve, progress, center);
+}
+
 static gboolean
 gsk_standard_contour_get_closest_point (const GskContour       *contour,
                                         gpointer                measure_data,
@@ -1694,6 +1755,7 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
   gsk_standard_contour_init_measure,
   gsk_standard_contour_free_measure,
   gsk_standard_contour_get_point,
+  gsk_standard_contour_get_curvature,
   gsk_standard_contour_get_closest_point,
   gsk_standard_contour_copy,
   gsk_standard_contour_add_segment,
@@ -1823,6 +1885,15 @@ gsk_contour_get_point (const GskContour *self,
   self->klass->get_point (self, measure_data, distance, pos, tangent);
 }
 
+float
+gsk_contour_get_curvature (const GskContour *self,
+                           gpointer          measure_data,
+                           float             distance,
+                           graphene_point_t *center)
+{
+  return self->klass->get_curvature (self, measure_data, distance, center);
+}
+
 gboolean
 gsk_contour_get_closest_point (const GskContour       *self,
                                gpointer                measure_data,
diff --git a/gsk/gskcontourprivate.h b/gsk/gskcontourprivate.h
index e5c56b999a..5219eb448a 100644
--- a/gsk/gskcontourprivate.h
+++ b/gsk/gskcontourprivate.h
@@ -78,6 +78,10 @@ void                    gsk_contour_get_point                   (const GskContou
                                                                  float                   distance,
                                                                  graphene_point_t       *pos,
                                                                  graphene_vec2_t        *tangent);
+float                   gsk_contour_get_curvature               (const GskContour       *self,
+                                                                 gpointer                measure_data,
+                                                                 float                   distance,
+                                                                 graphene_point_t       *center);
 gboolean                gsk_contour_get_closest_point           (const GskContour       *self,
                                                                  gpointer                measure_data,
                                                                  float                   tolerance,
diff --git a/gsk/gskpathmeasure.c b/gsk/gskpathmeasure.c
index 01c3bdc6c4..a1e6bb41e9 100644
--- a/gsk/gskpathmeasure.c
+++ b/gsk/gskpathmeasure.c
@@ -372,6 +372,61 @@ gsk_path_measure_get_point (GskPathMeasure   *self,
                          tangent);
 }
 
+/**
+ * gsk_path_measure_get_curvature:
+ * @self: a `GskPathMeasure`
+ * @distance: distance into the path
+ * @center: (optional) (out caller-allocates): The center
+ *   of the osculating circle at the point
+ *
+ * Calculates the curvature at the point @distance units into
+ * the path.
+ *
+ * Optionally, returns the center of the osculating circle as well.
+ *
+ * If the curvature is infinite (at line segments), or does
+ * not exist (at sharp turns), zero is returned, and @center
+ * is not modified.
+ *
+ * Returns: The curvature of the path at the given point
+ */
+float
+gsk_path_measure_get_curvature (GskPathMeasure   *self,
+                                float             distance,
+                                graphene_point_t *center)
+{
+  gsize i;
+
+  g_return_val_if_fail (self != NULL, 0);
+
+  distance = gsk_path_measure_clamp_distance (self, distance);
+
+  for (i = self->first; i < self->last; i++)
+    {
+      if (distance < self->measures[i].length)
+        break;
+
+      distance -= self->measures[i].length;
+    }
+
+  /* weird corner cases */
+  if (i == self->last)
+    {
+      /* the empty path goes here */
+      if (self->first == self->last)
+        return 0;
+
+      /* rounding errors can make this happen */
+      i = self->last - 1;
+      distance = self->measures[i].length;
+    }
+
+  return gsk_contour_get_curvature (gsk_path_get_contour (self->path, i),
+                                    self->measures[i].contour_data,
+                                    distance,
+                                    center);
+}
+
 /**
  * gsk_path_measure_get_closest_point:
  * @self: a `GskPathMeasure`
diff --git a/gsk/gskpathmeasure.h b/gsk/gskpathmeasure.h
index 4ea83af1c5..1194048934 100644
--- a/gsk/gskpathmeasure.h
+++ b/gsk/gskpathmeasure.h
@@ -65,6 +65,11 @@ void                    gsk_path_measure_get_point              (GskPathMeasure
                                                                  graphene_point_t       *pos,
                                                                  graphene_vec2_t        *tangent);
 GDK_AVAILABLE_IN_ALL
+float                   gsk_path_measure_get_curvature          (GskPathMeasure         *self,
+                                                                 float                   distance,
+                                                                 graphene_point_t       *center);
+
+GDK_AVAILABLE_IN_ALL
 float                   gsk_path_measure_get_closest_point      (GskPathMeasure         *self,
                                                                  const graphene_point_t *point,
                                                                  graphene_point_t       *out_pos);


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