pathmeasure: Add gsk_path_measure_get_curvature

This commit is contained in:
Matthias Clasen
2020-12-23 18:52:05 -05:00
parent 386a58f0f4
commit cc3b47cef6
4 changed files with 135 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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