Implement gsk_path_measure_in_fill
Implement this in the obvious way, using the decomposed form of standard contours. Since the decomposed form is part of the measure object, this api moves from gsk_path_in_fill to gsk_path_measure_in_fill.
This commit is contained in:
156
gsk/gskpath.c
156
gsk/gskpath.c
@@ -87,6 +87,10 @@ struct _GskContourClass
|
||||
gpointer measure_data,
|
||||
float start,
|
||||
float end);
|
||||
int (* get_winding) (const GskContour *contour,
|
||||
gpointer measure_data,
|
||||
const graphene_point_t *point,
|
||||
gboolean *on_edge);
|
||||
};
|
||||
|
||||
struct _GskPath
|
||||
@@ -481,6 +485,23 @@ gsk_rect_contour_add_segment (const GskContour *contour,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
gsk_rect_contour_get_winding (const GskContour *contour,
|
||||
gpointer measure_data,
|
||||
const graphene_point_t *point,
|
||||
gboolean *on_edge)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
graphene_rect_t rect;
|
||||
|
||||
graphene_rect_init (&rect, self->x, self->y, self->width, self->height);
|
||||
|
||||
if (graphene_rect_contains_point (&rect, point))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const GskContourClass GSK_RECT_CONTOUR_CLASS =
|
||||
{
|
||||
sizeof (GskRectContour),
|
||||
@@ -496,7 +517,8 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
|
||||
gsk_rect_contour_get_point,
|
||||
gsk_rect_contour_get_closest_point,
|
||||
gsk_rect_contour_copy,
|
||||
gsk_rect_contour_add_segment
|
||||
gsk_rect_contour_add_segment,
|
||||
gsk_rect_contour_get_winding
|
||||
};
|
||||
|
||||
GskContour *
|
||||
@@ -785,6 +807,50 @@ gsk_circle_contour_add_segment (const GskContour *contour,
|
||||
gsk_path_builder_add_contour (builder, segment);
|
||||
}
|
||||
|
||||
static int
|
||||
gsk_circle_contour_get_winding (const GskContour *contour,
|
||||
gpointer measure_data,
|
||||
const graphene_point_t *point,
|
||||
gboolean *on_edge)
|
||||
{
|
||||
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||
|
||||
if (graphene_point_distance (point, &self->center, NULL, NULL) >= self->radius)
|
||||
return 0;
|
||||
|
||||
if (fabs (self->start_angle - self->end_angle) >= 360)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if the point and the midpoint are on the same side
|
||||
* of the chord through start and end.
|
||||
*/
|
||||
double mid_angle = (self->end_angle - self->start_angle) / 2;
|
||||
graphene_point_t start = GRAPHENE_POINT_INIT (self->center.x + cos (DEG_TO_RAD (self->start_angle)) * self->radius,
|
||||
self->center.y + sin (DEG_TO_RAD (self->start_angle)) * self->radius);
|
||||
graphene_point_t mid = GRAPHENE_POINT_INIT (self->center.x + cos (DEG_TO_RAD (mid_angle)) * self->radius,
|
||||
self->center.y + sin (DEG_TO_RAD (mid_angle)) * self->radius);
|
||||
graphene_point_t end = GRAPHENE_POINT_INIT (self->center.x + cos (DEG_TO_RAD (self->end_angle)) * self->radius,
|
||||
self->center.y + sin (DEG_TO_RAD (self->end_angle)) * self->radius);
|
||||
|
||||
graphene_vec2_t n, m;
|
||||
float a, b;
|
||||
|
||||
graphene_vec2_init (&n, start.y - end.y, end.x - start.x);
|
||||
graphene_vec2_init (&m, mid.x, mid.y);
|
||||
a = graphene_vec2_dot (&m, &n);
|
||||
graphene_vec2_init (&m, point->x, point->y);
|
||||
b = graphene_vec2_dot (&m, &n);
|
||||
|
||||
if ((a < 0) != (b < 0))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
|
||||
{
|
||||
sizeof (GskCircleContour),
|
||||
@@ -800,7 +866,8 @@ static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
|
||||
gsk_circle_contour_get_point,
|
||||
gsk_circle_contour_get_closest_point,
|
||||
gsk_circle_contour_copy,
|
||||
gsk_circle_contour_add_segment
|
||||
gsk_circle_contour_add_segment,
|
||||
gsk_circle_contour_get_winding
|
||||
};
|
||||
|
||||
GskContour *
|
||||
@@ -1440,6 +1507,79 @@ gsk_standard_contour_add_segment (const GskContour *contour,
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
line_get_crossing (const graphene_point_t *p,
|
||||
const graphene_point_t *p1,
|
||||
const graphene_point_t *p2,
|
||||
gboolean *on_edge)
|
||||
{
|
||||
int dir = 1;
|
||||
|
||||
if (p1->x >= p->x && p2->x >= p->x)
|
||||
return 0;
|
||||
|
||||
if (p2->y < p1->y)
|
||||
{
|
||||
const graphene_point_t *tmp;
|
||||
tmp = p1;
|
||||
p1 = p2;
|
||||
p2 = tmp;
|
||||
dir = -1;
|
||||
}
|
||||
|
||||
if ((p1->x >= p->x && p1->y == p->y) ||
|
||||
(p2->x >= p->x && p2->y == p->y))
|
||||
{
|
||||
*on_edge = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (p2->y <= p->y || p1->y > p->y)
|
||||
return 0;
|
||||
|
||||
if (p1->x <= p->x && p2->x <= p->x)
|
||||
return dir;
|
||||
|
||||
if (p->x > p1->x + (p->y - p1->y) * (p2->x - p1->x) / (p2->y - p1->y))
|
||||
return dir;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gsk_standard_contour_get_winding (const GskContour *contour,
|
||||
gpointer measure_data,
|
||||
const graphene_point_t *point,
|
||||
gboolean *on_edge)
|
||||
{
|
||||
GskStandardContour *self = (GskStandardContour *) contour;
|
||||
GArray *array = measure_data;
|
||||
graphene_point_t last_point;
|
||||
int winding;
|
||||
int i;
|
||||
|
||||
if (array->len == 0)
|
||||
return 0;
|
||||
|
||||
winding = 0;
|
||||
last_point = self->points[0];
|
||||
for (i = 0; i < array->len; i++)
|
||||
{
|
||||
GskStandardContourMeasure *measure;
|
||||
|
||||
measure = &g_array_index (array, GskStandardContourMeasure, i);
|
||||
winding += line_get_crossing (point, &last_point, &measure->end_point, on_edge);
|
||||
if (*on_edge)
|
||||
return 0;
|
||||
|
||||
last_point = measure->end_point;
|
||||
}
|
||||
|
||||
winding += line_get_crossing (point, &last_point, &self->points[0], on_edge);
|
||||
|
||||
return winding;
|
||||
}
|
||||
|
||||
static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
|
||||
{
|
||||
sizeof (GskStandardContour),
|
||||
@@ -1455,7 +1595,8 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
|
||||
gsk_standard_contour_get_point,
|
||||
gsk_standard_contour_get_closest_point,
|
||||
gsk_standard_contour_copy,
|
||||
gsk_standard_contour_add_segment
|
||||
gsk_standard_contour_add_segment,
|
||||
gsk_standard_contour_get_winding
|
||||
};
|
||||
|
||||
/* You must ensure the contour has enough size allocated,
|
||||
@@ -1591,6 +1732,15 @@ gsk_contour_add_segment (const GskContour *self,
|
||||
self->klass->add_segment (self, builder, measure_data, start, end);
|
||||
}
|
||||
|
||||
int
|
||||
gsk_contour_get_winding (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
const graphene_point_t *point,
|
||||
gboolean *on_edge)
|
||||
{
|
||||
return self->klass->get_winding (self, measure_data, point, on_edge);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_contour_copy (GskContour *dest,
|
||||
const GskContour *src)
|
||||
|
||||
@@ -374,6 +374,48 @@ gsk_path_measure_get_closest_point_full (GskPathMeasure *self,
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_measure_in_fill:
|
||||
* @self: a #GskPathMeasure
|
||||
* @point: the point to test
|
||||
* @fill_rule: the fill rule to follow
|
||||
*
|
||||
* Returns whether the given point is inside the area that would be
|
||||
* affected if the path of @self was filled according to @fill_rule.
|
||||
*
|
||||
* Returns: %TRUE if @point is inside
|
||||
*/
|
||||
gboolean
|
||||
gsk_path_measure_in_fill (GskPathMeasure *self,
|
||||
const graphene_point_t *point,
|
||||
GskFillRule fill_rule)
|
||||
{
|
||||
int winding = 0;
|
||||
gboolean on_edge = FALSE;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < self->n_contours; i++)
|
||||
{
|
||||
winding += gsk_contour_get_winding (gsk_path_get_contour (self->path, i),
|
||||
self->measures[i].contour_data,
|
||||
point,
|
||||
&on_edge);
|
||||
if (on_edge)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
switch (fill_rule)
|
||||
{
|
||||
case GSK_FILL_RULE_EVEN_ODD:
|
||||
return winding & 1;
|
||||
case GSK_FILL_RULE_WINDING:
|
||||
return winding != 0;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gsk_path_measure_add_segment:
|
||||
* @self: a #GskPathMeasure
|
||||
@@ -433,4 +475,3 @@ gsk_path_measure_add_segment (GskPathMeasure *self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,11 @@ void gsk_path_measure_add_segment (GskPathMeasure
|
||||
float start,
|
||||
float end);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_path_measure_in_fill (GskPathMeasure *self,
|
||||
const graphene_point_t *point,
|
||||
GskFillRule fill_rule);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPathMeasure, gsk_path_measure_unref)
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -92,6 +92,10 @@ gboolean gsk_contour_get_closest_point (GskPath
|
||||
graphene_point_t *out_pos,
|
||||
float *out_offset,
|
||||
graphene_vec2_t *out_tangent);
|
||||
int gsk_contour_get_winding (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
const graphene_point_t *point,
|
||||
gboolean *on_edge);
|
||||
void gsk_contour_add_segment (const GskContour *self,
|
||||
GskPathBuilder *builder,
|
||||
gpointer measure_data,
|
||||
|
||||
Reference in New Issue
Block a user