pathmeasure: Add gsk_path_measure_get_curvature
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user