mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-13 14:00:09 +00:00
path: Add a circle contour
This special contour takes advantage of the circle definition to speed up things like hit testing and closest point determination.
This commit is contained in:
parent
99ad585252
commit
0fce24674a
539
gsk/gskcontour.c
539
gsk/gskcontour.c
@ -96,6 +96,12 @@ struct _GskContourClass
|
|||||||
gpointer measure_data);
|
gpointer measure_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static gsize
|
||||||
|
gsk_contour_get_size_default (const GskContour *contour)
|
||||||
|
{
|
||||||
|
return contour->klass->struct_size;
|
||||||
|
}
|
||||||
|
|
||||||
/* {{{ Utilities */
|
/* {{{ Utilities */
|
||||||
|
|
||||||
#define DEG_TO_RAD(x) ((x) * (G_PI / 180.f))
|
#define DEG_TO_RAD(x) ((x) * (G_PI / 180.f))
|
||||||
@ -120,6 +126,59 @@ _g_string_append_point (GString *string,
|
|||||||
_g_string_append_double (string, pt->y);
|
_g_string_append_double (string, pt->y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
add_segment (GskPathOperation op,
|
||||||
|
const graphene_point_t *pts,
|
||||||
|
gsize n_pts,
|
||||||
|
float weight,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GskPathBuilder *builder = user_data;
|
||||||
|
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case GSK_PATH_MOVE:
|
||||||
|
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
|
||||||
|
break;
|
||||||
|
case GSK_PATH_LINE:
|
||||||
|
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
|
||||||
|
break;
|
||||||
|
case GSK_PATH_QUAD:
|
||||||
|
gsk_path_builder_quad_to (builder,
|
||||||
|
pts[1].x, pts[1].y,
|
||||||
|
pts[2].x, pts[2].y);
|
||||||
|
break;
|
||||||
|
case GSK_PATH_CUBIC:
|
||||||
|
gsk_path_builder_cubic_to (builder,
|
||||||
|
pts[1].x, pts[1].y,
|
||||||
|
pts[2].x, pts[2].y,
|
||||||
|
pts[3].x, pts[3].y);
|
||||||
|
break;
|
||||||
|
case GSK_PATH_CONIC:
|
||||||
|
gsk_path_builder_conic_to (builder,
|
||||||
|
pts[1].x, pts[1].y,
|
||||||
|
pts[2].x, pts[2].y,
|
||||||
|
weight);
|
||||||
|
break;
|
||||||
|
case GSK_PATH_CLOSE:
|
||||||
|
gsk_path_builder_close (builder);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GskPath *
|
||||||
|
convert_to_standard_contour (const GskContour *contour)
|
||||||
|
{
|
||||||
|
GskPathBuilder *builder;
|
||||||
|
|
||||||
|
builder = gsk_path_builder_new ();
|
||||||
|
gsk_contour_foreach (contour, 0.5, add_segment, builder);
|
||||||
|
return gsk_path_builder_free_to_path (builder);
|
||||||
|
}
|
||||||
|
|
||||||
/* }}} */
|
/* }}} */
|
||||||
/* {{{ Standard */
|
/* {{{ Standard */
|
||||||
@ -1025,6 +1084,486 @@ gsk_standard_contour_new (GskPathFlags flags,
|
|||||||
return contour;
|
return contour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* }}} */
|
||||||
|
/* {{{ Circle */
|
||||||
|
|
||||||
|
typedef struct _GskCircleContour GskCircleContour;
|
||||||
|
struct _GskCircleContour
|
||||||
|
{
|
||||||
|
GskContour contour;
|
||||||
|
|
||||||
|
graphene_point_t center;
|
||||||
|
float radius;
|
||||||
|
gboolean ccw;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_circle_contour_copy (const GskContour *contour,
|
||||||
|
GskContour *dest)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
GskCircleContour *target = (GskCircleContour *) dest;
|
||||||
|
|
||||||
|
*target = *self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GskPathFlags
|
||||||
|
gsk_circle_contour_get_flags (const GskContour *contour)
|
||||||
|
{
|
||||||
|
return GSK_PATH_CLOSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
foreach_print (GskPathOperation op,
|
||||||
|
const graphene_point_t *pts,
|
||||||
|
gsize n_pts,
|
||||||
|
float weight,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GString *string = data;
|
||||||
|
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case GSK_PATH_MOVE:
|
||||||
|
g_string_append (string, "M ");
|
||||||
|
_g_string_append_point (string, &pts[0]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GSK_PATH_CLOSE:
|
||||||
|
g_string_append (string, " Z");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GSK_PATH_LINE:
|
||||||
|
g_string_append (string, " L ");
|
||||||
|
_g_string_append_point (string, &pts[1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GSK_PATH_QUAD:
|
||||||
|
g_string_append (string, " Q ");
|
||||||
|
_g_string_append_point (string, &pts[1]);
|
||||||
|
g_string_append (string, ", ");
|
||||||
|
_g_string_append_point (string, &pts[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GSK_PATH_CUBIC:
|
||||||
|
g_string_append (string, " C ");
|
||||||
|
_g_string_append_point (string, &pts[1]);
|
||||||
|
g_string_append (string, ", ");
|
||||||
|
_g_string_append_point (string, &pts[2]);
|
||||||
|
g_string_append (string, ", ");
|
||||||
|
_g_string_append_point (string, &pts[3]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GSK_PATH_CONIC:
|
||||||
|
g_string_append (string, " O ");
|
||||||
|
_g_string_append_point (string, &pts[1]);
|
||||||
|
g_string_append (string, ", ");
|
||||||
|
_g_string_append_point (string, &pts[2]);
|
||||||
|
g_string_append (string, ", ");
|
||||||
|
_g_string_append_double (string, weight);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_circle_contour_print (const GskContour *contour,
|
||||||
|
GString *string)
|
||||||
|
{
|
||||||
|
gsk_contour_foreach (contour, 0.5, foreach_print, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gsk_circle_contour_get_bounds (const GskContour *contour,
|
||||||
|
GskBoundingBox *bounds)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
|
||||||
|
gsk_bounding_box_init (bounds,
|
||||||
|
&GRAPHENE_POINT_INIT (self->center.x - self->radius,
|
||||||
|
self->center.y - self->radius),
|
||||||
|
&GRAPHENE_POINT_INIT (self->center.x + self->radius,
|
||||||
|
self->center.y + self->radius));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gsk_circle_contour_get_stroke_bounds (const GskContour *contour,
|
||||||
|
const GskStroke *stroke,
|
||||||
|
GskBoundingBox *bounds)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
|
||||||
|
gsk_bounding_box_init (bounds,
|
||||||
|
&GRAPHENE_POINT_INIT (self->center.x - self->radius - stroke->line_width/2,
|
||||||
|
self->center.y - self->radius - stroke->line_width/2),
|
||||||
|
&GRAPHENE_POINT_INIT (self->center.x + self->radius + stroke->line_width/2,
|
||||||
|
self->center.y + self->radius + stroke->line_width/2));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_circle_contour_get_start_end (const GskContour *contour,
|
||||||
|
graphene_point_t *start,
|
||||||
|
graphene_point_t *end)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
|
||||||
|
if (start)
|
||||||
|
*start = GRAPHENE_POINT_INIT (self->center.x + self->radius, self->center.y);
|
||||||
|
|
||||||
|
if (end)
|
||||||
|
*end = GRAPHENE_POINT_INIT (self->center.x + self->radius, self->center.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gsk_circle_contour_foreach (const GskContour *contour,
|
||||||
|
float tolerance,
|
||||||
|
GskPathForeachFunc func,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
float rx, ry;
|
||||||
|
|
||||||
|
rx = ry = self->radius;
|
||||||
|
if (self->ccw)
|
||||||
|
ry = - self->radius;
|
||||||
|
|
||||||
|
if (!func (GSK_PATH_MOVE,
|
||||||
|
(const graphene_point_t[1]) {
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x + rx, self->center.y),
|
||||||
|
},
|
||||||
|
1, 0.f, user_data))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!func (GSK_PATH_CONIC,
|
||||||
|
(const graphene_point_t[3]) {
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x + rx, self->center.y),
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x + rx, self->center.y + ry),
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x, self->center.y + ry),
|
||||||
|
},
|
||||||
|
3, M_SQRT1_2, user_data))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!func (GSK_PATH_CONIC,
|
||||||
|
(const graphene_point_t[3]) {
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x, self->center.y + ry),
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x - rx, self->center.y + ry),
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x - rx, self->center.y),
|
||||||
|
},
|
||||||
|
3, M_SQRT1_2, user_data))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!func (GSK_PATH_CONIC,
|
||||||
|
(const graphene_point_t[3]) {
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x - rx, self->center.y),
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x - rx, self->center.y - ry),
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x, self->center.y - ry),
|
||||||
|
},
|
||||||
|
3, M_SQRT1_2, user_data))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!func (GSK_PATH_CONIC,
|
||||||
|
(const graphene_point_t[3]) {
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x, self->center.y - ry),
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x + rx, self->center.y - ry),
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x + rx, self->center.y),
|
||||||
|
},
|
||||||
|
3, M_SQRT1_2, user_data))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!func (GSK_PATH_CLOSE,
|
||||||
|
(const graphene_point_t[2]) {
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x + rx, self->center.y),
|
||||||
|
GRAPHENE_POINT_INIT (self->center.x + rx, self->center.y),
|
||||||
|
},
|
||||||
|
2, 0.f, user_data))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GskContour *
|
||||||
|
gsk_circle_contour_reverse (const GskContour *contour)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
GskCircleContour *copy;
|
||||||
|
|
||||||
|
copy = g_new0 (GskCircleContour, 1);
|
||||||
|
gsk_circle_contour_copy (contour, (GskContour *)copy);
|
||||||
|
copy->ccw = !self->ccw;
|
||||||
|
|
||||||
|
return (GskContour *)copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gsk_circle_contour_get_winding (const GskContour *contour,
|
||||||
|
const graphene_point_t *point)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
|
||||||
|
if (graphene_point_distance (point, &self->center, NULL, NULL) >= self->radius)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (self->ccw)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gsize
|
||||||
|
gsk_circle_contour_get_n_ops (const GskContour *contour)
|
||||||
|
{
|
||||||
|
/* Not related to how many curves foreach produces.
|
||||||
|
* GskPath assumes that the start- and endpoints
|
||||||
|
* of a contour are { x, 1, 0 } and { x, n_ops - 1, 1 }.
|
||||||
|
*
|
||||||
|
* The circle contour uses a single 'segment' in path
|
||||||
|
* points, with a t that ranges from 0 to 1 to cover
|
||||||
|
* the angles from 0 to 360 (or 360 to 0 in the ccw
|
||||||
|
* case).
|
||||||
|
*/
|
||||||
|
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gsk_circle_contour_get_closest_point (const GskContour *contour,
|
||||||
|
const graphene_point_t *point,
|
||||||
|
float threshold,
|
||||||
|
GskRealPathPoint *result,
|
||||||
|
float *out_dist)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
float dist, angle, t;
|
||||||
|
|
||||||
|
dist = fabsf (graphene_point_distance (&self->center, point, NULL, NULL) - self->radius);
|
||||||
|
|
||||||
|
if (dist > threshold)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
angle = RAD_TO_DEG (atan2f (point->y - self->center.y, point->x - self->center.x));
|
||||||
|
|
||||||
|
if (angle < 0)
|
||||||
|
angle = 360 - angle;
|
||||||
|
|
||||||
|
t = CLAMP (angle / 360, 0, 1);
|
||||||
|
|
||||||
|
if (self->ccw)
|
||||||
|
t = 1 - t;
|
||||||
|
|
||||||
|
result->idx = 1;
|
||||||
|
result->t = t;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GSK_CIRCLE_POINT_INIT(self, angle) \
|
||||||
|
GRAPHENE_POINT_INIT ((self)->center.x + cosf (DEG_TO_RAD (angle)) * self->radius, \
|
||||||
|
(self)->center.y + sinf (DEG_TO_RAD (angle)) * self->radius)
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_circle_contour_get_position (const GskContour *contour,
|
||||||
|
GskRealPathPoint *point,
|
||||||
|
graphene_point_t *position)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
float t;
|
||||||
|
|
||||||
|
t = point->t;
|
||||||
|
|
||||||
|
if (self->ccw)
|
||||||
|
t = 1 - t;
|
||||||
|
|
||||||
|
if (t == 0 || t == 1)
|
||||||
|
*position = GRAPHENE_POINT_INIT (self->center.x + self->radius, self->center.y);
|
||||||
|
else
|
||||||
|
*position = GSK_CIRCLE_POINT_INIT (self, t * 360);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_circle_contour_get_tangent (const GskContour *contour,
|
||||||
|
GskRealPathPoint *point,
|
||||||
|
GskPathDirection direction,
|
||||||
|
graphene_vec2_t *tangent)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
graphene_point_t p;
|
||||||
|
|
||||||
|
gsk_circle_contour_get_position (contour, point, &p);
|
||||||
|
|
||||||
|
graphene_vec2_init (tangent, p.y - self->center.y, - p.x + self->center.x);
|
||||||
|
graphene_vec2_normalize (tangent, tangent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float
|
||||||
|
gsk_circle_contour_get_curvature (const GskContour *contour,
|
||||||
|
GskRealPathPoint *point,
|
||||||
|
GskPathDirection direction,
|
||||||
|
graphene_point_t *center)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
|
||||||
|
if (center)
|
||||||
|
*center = self->center;
|
||||||
|
|
||||||
|
return 1 / self->radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_circle_contour_add_segment (const GskContour *contour,
|
||||||
|
GskPathBuilder *builder,
|
||||||
|
gboolean emit_move_to,
|
||||||
|
GskRealPathPoint *start,
|
||||||
|
GskRealPathPoint *end)
|
||||||
|
{
|
||||||
|
GskPath *path;
|
||||||
|
graphene_point_t p;
|
||||||
|
GskRealPathPoint start2, end2;
|
||||||
|
const GskContour *std;
|
||||||
|
float dist;
|
||||||
|
|
||||||
|
/* This is a cheesy way of doing things: convert to a standard contour,
|
||||||
|
* and translate the path points from circle to standard. We just have
|
||||||
|
* to be careful to tell start- and endpoint apart.
|
||||||
|
*/
|
||||||
|
|
||||||
|
path = convert_to_standard_contour (contour);
|
||||||
|
std = gsk_path_get_contour (path, 0);
|
||||||
|
|
||||||
|
start2.contour = 0;
|
||||||
|
|
||||||
|
if (start->idx == 1 && start->t == 0)
|
||||||
|
{
|
||||||
|
start2.idx = 1;
|
||||||
|
start2.t = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gsk_circle_contour_get_position (contour, start, &p);
|
||||||
|
gsk_standard_contour_get_closest_point (std, &p, INFINITY, &start2, &dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
end2.contour = 0;
|
||||||
|
|
||||||
|
if (end->idx == 1 && end->t == 1)
|
||||||
|
{
|
||||||
|
end2.idx = 4;
|
||||||
|
end2.t = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gsk_circle_contour_get_position (contour, end, &p);
|
||||||
|
gsk_standard_contour_get_closest_point (std, &p, INFINITY, &end2, &dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
gsk_standard_contour_add_segment (std, builder, emit_move_to, &start2, &end2);
|
||||||
|
|
||||||
|
gsk_path_unref (path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
gsk_circle_contour_init_measure (const GskContour *contour,
|
||||||
|
float tolerance,
|
||||||
|
float *out_length)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
|
||||||
|
*out_length = 2 * M_PI * self->radius;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_circle_contour_free_measure (const GskContour *contour,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_circle_contour_get_point (const GskContour *contour,
|
||||||
|
gpointer measure_data,
|
||||||
|
float distance,
|
||||||
|
GskRealPathPoint *result)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
float t;
|
||||||
|
|
||||||
|
t = distance / (2 * M_PI * self->radius);
|
||||||
|
|
||||||
|
if (self->ccw)
|
||||||
|
t = 1 - t;
|
||||||
|
|
||||||
|
result->idx = 1;
|
||||||
|
result->t = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float
|
||||||
|
gsk_circle_contour_get_distance (const GskContour *contour,
|
||||||
|
GskRealPathPoint *point,
|
||||||
|
gpointer measure_data)
|
||||||
|
{
|
||||||
|
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||||
|
float t;
|
||||||
|
|
||||||
|
t = point->t;
|
||||||
|
|
||||||
|
if (self->ccw)
|
||||||
|
t = 1 - t;
|
||||||
|
|
||||||
|
return 2 * M_PI * self->radius * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
|
||||||
|
{
|
||||||
|
sizeof (GskCircleContour),
|
||||||
|
"GskCircleContour",
|
||||||
|
gsk_circle_contour_copy,
|
||||||
|
gsk_contour_get_size_default,
|
||||||
|
gsk_circle_contour_get_flags,
|
||||||
|
gsk_circle_contour_print,
|
||||||
|
gsk_circle_contour_get_bounds,
|
||||||
|
gsk_circle_contour_get_stroke_bounds,
|
||||||
|
gsk_circle_contour_get_start_end,
|
||||||
|
gsk_circle_contour_foreach,
|
||||||
|
gsk_circle_contour_reverse,
|
||||||
|
gsk_circle_contour_get_winding,
|
||||||
|
gsk_circle_contour_get_n_ops,
|
||||||
|
gsk_circle_contour_get_closest_point,
|
||||||
|
gsk_circle_contour_get_position,
|
||||||
|
gsk_circle_contour_get_tangent,
|
||||||
|
gsk_circle_contour_get_curvature,
|
||||||
|
gsk_circle_contour_add_segment,
|
||||||
|
gsk_circle_contour_init_measure,
|
||||||
|
gsk_circle_contour_free_measure,
|
||||||
|
gsk_circle_contour_get_point,
|
||||||
|
gsk_circle_contour_get_distance,
|
||||||
|
};
|
||||||
|
|
||||||
|
GskContour *
|
||||||
|
gsk_circle_contour_new (const graphene_point_t *center,
|
||||||
|
float radius)
|
||||||
|
{
|
||||||
|
GskCircleContour *self;
|
||||||
|
|
||||||
|
self = g_new0 (GskCircleContour, 1);
|
||||||
|
|
||||||
|
self->contour.klass = &GSK_CIRCLE_CONTOUR_CLASS;
|
||||||
|
|
||||||
|
self->contour.klass = &GSK_CIRCLE_CONTOUR_CLASS;
|
||||||
|
self->center = *center;
|
||||||
|
self->radius = radius;
|
||||||
|
self->ccw = FALSE;
|
||||||
|
|
||||||
|
return (GskContour *) self;
|
||||||
|
}
|
||||||
|
|
||||||
/* }}} */
|
/* }}} */
|
||||||
/* {{{ API */
|
/* {{{ API */
|
||||||
|
|
||||||
|
@ -34,6 +34,9 @@ GskContour * gsk_standard_contour_new (GskPathFlags
|
|||||||
gsize n_ops,
|
gsize n_ops,
|
||||||
gssize offset);
|
gssize offset);
|
||||||
|
|
||||||
|
GskContour * gsk_circle_contour_new (const graphene_point_t *center,
|
||||||
|
float radius);
|
||||||
|
|
||||||
void gsk_contour_copy (GskContour * dest,
|
void gsk_contour_copy (GskContour * dest,
|
||||||
const GskContour *src);
|
const GskContour *src);
|
||||||
GskContour * gsk_contour_dup (const GskContour *src);
|
GskContour * gsk_contour_dup (const GskContour *src);
|
||||||
|
@ -560,34 +560,11 @@ gsk_path_builder_add_circle (GskPathBuilder *self,
|
|||||||
const graphene_point_t *center,
|
const graphene_point_t *center,
|
||||||
float radius)
|
float radius)
|
||||||
{
|
{
|
||||||
graphene_point_t current;
|
|
||||||
|
|
||||||
g_return_if_fail (self != NULL);
|
g_return_if_fail (self != NULL);
|
||||||
g_return_if_fail (center != NULL);
|
g_return_if_fail (center != NULL);
|
||||||
g_return_if_fail (radius > 0);
|
g_return_if_fail (radius > 0);
|
||||||
|
|
||||||
current = self->current_point;
|
gsk_path_builder_add_contour (self, gsk_circle_contour_new (center, radius));
|
||||||
|
|
||||||
gsk_path_builder_move_to (self, center->x + radius, center->y);
|
|
||||||
// bottom right quarter
|
|
||||||
gsk_path_builder_arc_to (self,
|
|
||||||
center->x + radius, center->y + radius,
|
|
||||||
center->x, center->y + radius);
|
|
||||||
// bottom left quarter
|
|
||||||
gsk_path_builder_arc_to (self,
|
|
||||||
center->x - radius, center->y + radius,
|
|
||||||
center->x - radius, center->y);
|
|
||||||
// top left quarter
|
|
||||||
gsk_path_builder_arc_to (self,
|
|
||||||
center->x - radius, center->y - radius,
|
|
||||||
center->x, center->y - radius);
|
|
||||||
// top right quarter
|
|
||||||
gsk_path_builder_arc_to (self,
|
|
||||||
center->x + radius, center->y - radius,
|
|
||||||
center->x + radius, center->y);
|
|
||||||
// done
|
|
||||||
gsk_path_builder_close (self);
|
|
||||||
self->current_point = current;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user