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.
This commit is contained in:
Matthias Clasen 2023-08-27 20:44:41 -04:00
parent 6f3be310f4
commit 0dbff14555
5 changed files with 53 additions and 10 deletions

View File

@ -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

View File

@ -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));
}

View File

@ -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,

View File

@ -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, &center);
g_assert_true (k == INFINITY);
g_assert_true (graphene_point_equal (&center, &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 ();
}

View File

@ -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),