summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2020-12-23 18:52:05 -0500
committerMatthias Clasen <mclasen@redhat.com>2020-12-27 00:26:44 -0500
commit55bfc167e3f2a25dfef4de680ac0253ce5ee8a6b (patch)
tree9eb97217ccd2e6a3e9e57129f6dd2e37d23c49ad
parent5516ec2bf04b6c77da091994d8728f1bbe07883d (diff)
downloadgtk+-55bfc167e3f2a25dfef4de680ac0253ce5ee8a6b.tar.gz
Add gsk_path_measure_get_curvature
-rw-r--r--gsk/gskcontour.c71
-rw-r--r--gsk/gskcontourprivate.h4
-rw-r--r--gsk/gskpathmeasure.c53
-rw-r--r--gsk/gskpathmeasure.h5
4 files changed, 133 insertions, 0 deletions
diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c
index 81a7ddaa27..bcbed9153a 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,
@@ -765,6 +779,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,
@@ -950,6 +978,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,
@@ -1286,6 +1315,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,
@@ -1675,6 +1736,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,
@@ -1803,6 +1865,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 077025e412..3bf233f3fe 100644
--- a/gsk/gskcontourprivate.h
+++ b/gsk/gskcontourprivate.h
@@ -74,6 +74,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 20fb4ff81b..74d49b9cf4 100644
--- a/gsk/gskpathmeasure.c
+++ b/gsk/gskpathmeasure.c
@@ -378,6 +378,59 @@ gsk_path_measure_get_point (GskPathMeasure *self,
}
/**
+ * @self: a #GskPathMeasure
+ * @distance: distance into the path
+ * @center: (out) (optional) (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
* @point: the point to fond the closest point to
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);