From 0dbff1455501084651bf6831f8c3ff3da8070ea1 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 27 Aug 2023 20:44:41 -0400 Subject: [PATCH] Allow circles with radius of zero Not very useful, but we allow rects with width and height of zero, so lets be consistent. Curvature is infinite for such contours. Tests included. --- gsk/gskcontour.c | 21 +++++++++++++++------ gsk/gskpathbuilder.c | 4 +++- gsk/gskpathpoint.c | 2 ++ testsuite/gsk/path-special-cases.c | 24 +++++++++++++++++++++++- testsuite/gsk/path.c | 12 ++++++++++-- 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c index db67ed6b6d..32f38c562c 100644 --- a/gsk/gskcontour.c +++ b/gsk/gskcontour.c @@ -914,6 +914,7 @@ gsk_standard_contour_get_point (const GskContour *contour, { result->idx = curve_measure->idx; result->t = p->t; + g_assert (0 <= result->t && result->t <= 1); return; } } @@ -941,9 +942,9 @@ gsk_standard_contour_get_point (const GskContour *contour, result->idx = curve_measure->idx; fraction = (distance - p0->length) / (p1->length - p0->length); - g_assert (fraction >= 0.f && fraction <= 1.f); + g_assert (fraction >= 0 && fraction <= 1); result->t = p0->t * (1 - fraction) + p1->t * fraction; - g_assert (result->t >= 0.f && result->t <= 1.f); + g_assert (result->t >= 0 && result->t <= 1); } } @@ -986,7 +987,7 @@ gsk_standard_contour_get_distance (const GskContour *contour, g_assert (p0->t <= point->t && point->t <= p1->t); fraction = (point->t - p0->t) / (p1->t - p0->t); - g_assert (fraction >= 0.f && fraction <= 1.f); + g_assert (fraction >= 0 && fraction <= 1); return p0->length * (1 - fraction) + p1->length * fraction; } @@ -1295,7 +1296,10 @@ gsk_circle_contour_get_curvature (const GskContour *contour, if (center) *center = self->center; - return 1 / self->radius; + if (self->radius == 0) + return INFINITY; + + return 1.f / self->radius; } static void @@ -1377,13 +1381,17 @@ gsk_circle_contour_get_point (const GskContour *contour, const GskCircleContour *self = (const GskCircleContour *) contour; float t; - t = distance / (2 * M_PI * self->radius); + if (self->radius == 0) + t = 0; + else + t = distance / (2 * M_PI * self->radius); if (self->ccw) t = 1 - t; result->idx = 1; result->t = t; + g_assert (result->t >= 0 && result->t <= 1); } static float @@ -1433,7 +1441,7 @@ gsk_circle_contour_new (const graphene_point_t *center, { GskCircleContour *self; - g_assert (radius > 0); + g_assert (radius >= 0); self = g_new0 (GskCircleContour, 1); @@ -1936,6 +1944,7 @@ gsk_rect_contour_get_point (const GskContour *contour, result->t = 0; else result->t = CLAMP (distance / self->length, 0, 1); + g_assert (0 <= result->t && result->t <= 1); } static float diff --git a/gsk/gskpathbuilder.c b/gsk/gskpathbuilder.c index b612d4ebf8..d31699c52a 100644 --- a/gsk/gskpathbuilder.c +++ b/gsk/gskpathbuilder.c @@ -497,6 +497,8 @@ gsk_path_builder_add_rounded_rect (GskPathBuilder *self, * * The path is going around the circle in clockwise direction. * + * If @radius is zero, the contour will be a closed point. + * * Since: 4.14 */ void @@ -506,7 +508,7 @@ gsk_path_builder_add_circle (GskPathBuilder *self, { g_return_if_fail (self != NULL); g_return_if_fail (center != NULL); - g_return_if_fail (radius > 0); + g_return_if_fail (radius >= 0); gsk_path_builder_add_contour (self, gsk_circle_contour_new (center, radius)); } diff --git a/gsk/gskpathpoint.c b/gsk/gskpathpoint.c index 0e550d69f2..1b515ea947 100644 --- a/gsk/gskpathpoint.c +++ b/gsk/gskpathpoint.c @@ -285,6 +285,8 @@ gsk_path_point_get_rotation (const GskPathPoint *point, * Lines have a curvature of zero (indicating an osculating circle of * infinite radius. In this case, the @center is not modified. * + * Circles with a radius of zero have `INFINITY` as curvature + * * Note that certain points on a path may not have a single curvature, * such as sharp turns. At such points, there are two curvatures -- * the (limit of) the curvature of the path going into the point, diff --git a/testsuite/gsk/path-special-cases.c b/testsuite/gsk/path-special-cases.c index 17a242de39..538e310cf2 100644 --- a/testsuite/gsk/path-special-cases.c +++ b/testsuite/gsk/path-special-cases.c @@ -938,7 +938,6 @@ test_circle (void) g_assert_true (gsk_path_in_fill (path6, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_WINDING)); g_assert_false (gsk_path_in_fill (path6, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_EVEN_ODD)); - gsk_path_measure_unref (measure); gsk_path_measure_unref (measure1); gsk_path_measure_unref (measure2); @@ -1035,6 +1034,28 @@ test_rect_segment (void) gsk_path_measure_unref (measure2); } +static void +test_circle_point (void) +{ + GskPathBuilder *builder; + GskPath *path; + GskPathPoint point; + graphene_point_t center; + float k; + + builder = gsk_path_builder_new (); + gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (1, 2), 0); + path = gsk_path_builder_free_to_path (builder); + + gsk_path_get_start_point (path, &point); + k = gsk_path_point_get_curvature (&point, path, GSK_PATH_TO_END, ¢er); + + g_assert_true (k == INFINITY); + g_assert_true (graphene_point_equal (¢er, &GRAPHENE_POINT_INIT (1, 2))); + + gsk_path_unref (path); +} + int main (int argc, char *argv[]) { @@ -1055,6 +1076,7 @@ main (int argc, char *argv[]) g_test_add_func ("/path/circle", test_circle); g_test_add_func ("/path/length", test_length); g_test_add_func ("/path/rect/segment", test_rect_segment); + g_test_add_func ("/path/circle-point", test_circle_point); return g_test_run (); } diff --git a/testsuite/gsk/path.c b/testsuite/gsk/path.c index 1c25d6e3a2..a0fb6613c3 100644 --- a/testsuite/gsk/path.c +++ b/testsuite/gsk/path.c @@ -22,7 +22,7 @@ static GskPath * create_random_degenerate_path (guint max_contours) { -#define N_DEGENERATE_PATHS 14 +#define N_DEGENERATE_PATHS 15 GskPathBuilder *builder; guint i; @@ -132,6 +132,14 @@ create_random_degenerate_path (guint max_contours) break; case 12: + /* circle with radius 0 */ + gsk_path_builder_add_circle (builder, + &GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000, 1000), + g_test_rand_double_range (-1000, 1000)), + 0); + break; + + case 13: /* a zero-length line */ { graphene_point_t point = GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000, 1000), @@ -141,7 +149,7 @@ create_random_degenerate_path (guint max_contours) } break; - case 13: + case 14: /* a cubic with start == end */ { graphene_point_t point = GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000, 1000),