diff options
author | Matthias Clasen <mclasen@redhat.com> | 2020-12-23 18:52:05 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2020-12-27 00:26:44 -0500 |
commit | 55bfc167e3f2a25dfef4de680ac0253ce5ee8a6b (patch) | |
tree | 9eb97217ccd2e6a3e9e57129f6dd2e37d23c49ad | |
parent | 5516ec2bf04b6c77da091994d8728f1bbe07883d (diff) | |
download | gtk+-55bfc167e3f2a25dfef4de680ac0253ce5ee8a6b.tar.gz |
Add gsk_path_measure_get_curvature
-rw-r--r-- | gsk/gskcontour.c | 71 | ||||
-rw-r--r-- | gsk/gskcontourprivate.h | 4 | ||||
-rw-r--r-- | gsk/gskpathmeasure.c | 53 | ||||
-rw-r--r-- | gsk/gskpathmeasure.h | 5 |
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); |