Merge branch 'path-measure-reredone' into 'main'

Add GskPathMeasure

See merge request GNOME/gtk!6326
This commit is contained in:
Matthias Clasen 2023-08-26 01:05:19 +00:00
commit 361cdecfe4
22 changed files with 2333 additions and 48 deletions

View File

@ -338,6 +338,7 @@
<file>path_fill.c</file>
<file>path_spinner.c</file>
<file>path_walk.c</file>
<file>path_text.c</file>
<file>peg_solitaire.c</file>
<file>pickers.c</file>
<file>printing.c</file>
@ -427,6 +428,9 @@
<file>path_walk.ui</file>
<file compressed="true">path_world.txt</file>
</gresource>
<gresource prefix="/path_text">
<file>path_text.ui</file>
</gresource>
<gresource prefix="/org/gtk/Demo4">
<file>icons/16x16/actions/application-exit.png</file>
<file>icons/16x16/actions/document-new.png</file>

View File

@ -75,6 +75,7 @@ demos = files([
'path_fill.c',
'path_spinner.c',
'path_walk.c',
'path_text.c',
'peg_solitaire.c',
'pickers.c',
'printing.c',

586
demos/gtk-demo/path_text.c Normal file
View File

@ -0,0 +1,586 @@
/* Path/Text
*
* This demo shows how to use GskPath to transform a path along another path.
*
* It also demonstrates that paths can be filled with more interesting
* content than just plain colors.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#define GTK_TYPE_PATH_WIDGET (gtk_path_widget_get_type ())
G_DECLARE_FINAL_TYPE (GtkPathWidget, gtk_path_widget, GTK, PATH_WIDGET, GtkWidget)
#define POINT_SIZE 8
enum {
PROP_0,
PROP_TEXT,
PROP_EDITABLE,
N_PROPS
};
struct _GtkPathWidget
{
GtkWidget parent_instance;
char *text;
gboolean editable;
graphene_point_t points[4];
guint active_point;
GskPath *line_path;
GskPath *text_path;
GdkPaintable *background;
};
struct _GtkPathWidgetClass
{
GtkWidgetClass parent_class;
};
static GParamSpec *properties[N_PROPS] = { NULL, };
G_DEFINE_TYPE (GtkPathWidget, gtk_path_widget, GTK_TYPE_WIDGET)
static GskPath *
create_path_from_text (GtkWidget *widget,
const char *text,
graphene_point_t *out_offset)
{
PangoLayout *layout;
PangoFontDescription *desc;
GskPathBuilder *builder;
GskPath *result;
layout = gtk_widget_create_pango_layout (widget, text);
desc = pango_font_description_from_string ("sans bold 36");
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
builder = gsk_path_builder_new ();
gsk_path_builder_add_layout (builder, layout);
result = gsk_path_builder_free_to_path (builder);
if (out_offset)
graphene_point_init (out_offset, 0, - pango_layout_get_baseline (layout) / (double) PANGO_SCALE);
g_object_unref (layout);
return result;
}
typedef struct
{
GskPathMeasure *measure;
GskPathBuilder *builder;
graphene_point_t offset;
double scale;
} GtkPathTransform;
static void
gtk_path_transform_point (GskPathMeasure *measure,
const graphene_point_t *pt,
const graphene_point_t *offset,
float scale,
graphene_point_t *res)
{
graphene_vec2_t tangent;
GskPathPoint point;
if (gsk_path_measure_get_point (measure, (pt->x + offset->x) * scale, &point))
{
GskPath *path = gsk_path_measure_get_path (measure);
gsk_path_point_get_position (&point, path, res);
gsk_path_point_get_tangent (&point, path, GSK_PATH_TO_END, &tangent);
res->x -= (pt->y + offset->y) * scale * graphene_vec2_get_y (&tangent);
res->y += (pt->y + offset->y) * scale * graphene_vec2_get_x (&tangent);
}
}
static gboolean
gtk_path_transform_op (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
gpointer data)
{
GtkPathTransform *transform = data;
switch (op)
{
case GSK_PATH_MOVE:
{
graphene_point_t res;
gtk_path_transform_point (transform->measure, &pts[0], &transform->offset, transform->scale, &res);
gsk_path_builder_move_to (transform->builder, res.x, res.y);
}
break;
case GSK_PATH_LINE:
{
graphene_point_t res;
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res);
gsk_path_builder_line_to (transform->builder, res.x, res.y);
}
break;
case GSK_PATH_QUAD:
{
graphene_point_t res[2];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
gsk_path_builder_quad_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y);
}
break;
case GSK_PATH_CUBIC:
{
graphene_point_t res[3];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
gtk_path_transform_point (transform->measure, &pts[3], &transform->offset, transform->scale, &res[2]);
gsk_path_builder_cubic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, res[2].x, res[2].y);
}
break;
case GSK_PATH_CONIC:
{
graphene_point_t res[2];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[3], &transform->offset, transform->scale, &res[1]);
gsk_path_builder_conic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, weight);
}
break;
case GSK_PATH_CLOSE:
gsk_path_builder_close (transform->builder);
break;
default:
g_assert_not_reached();
return FALSE;
}
return TRUE;
}
static GskPath *
gtk_path_transform (GskPath *line_path,
GskPath *path,
const graphene_point_t *offset)
{
GskPathMeasure *measure = gsk_path_measure_new (line_path);
GtkPathTransform transform = { measure, gsk_path_builder_new (), *offset };
graphene_rect_t bounds;
gsk_path_get_bounds (path, &bounds);
if (bounds.origin.x + bounds.size.width > 0)
transform.scale = gsk_path_measure_get_length (measure) / (bounds.origin.x + bounds.size.width);
else
transform.scale = 1.0f;
gsk_path_foreach (path, -1, gtk_path_transform_op, &transform);
gsk_path_measure_unref (measure);
return gsk_path_builder_free_to_path (transform.builder);
}
static void
gtk_path_widget_clear_text_path (GtkPathWidget *self)
{
g_clear_pointer (&self->text_path, gsk_path_unref);
}
static void
gtk_path_widget_clear_paths (GtkPathWidget *self)
{
gtk_path_widget_clear_text_path (self);
g_clear_pointer (&self->line_path, gsk_path_unref);
}
static void
gtk_path_widget_create_text_path (GtkPathWidget *self)
{
GskPath *path;
graphene_point_t offset;
gtk_path_widget_clear_text_path (self);
path = create_path_from_text (GTK_WIDGET (self), self->text, &offset);
self->text_path = gtk_path_transform (self->line_path, path, &offset);
gsk_path_unref (path);
}
static void
gtk_path_widget_create_paths (GtkPathWidget *self)
{
double width = gtk_widget_get_width (GTK_WIDGET (self));
double height = gtk_widget_get_height (GTK_WIDGET (self));
GskPathBuilder *builder;
gtk_path_widget_clear_paths (self);
if (width <= 0 || height <= 0)
return;
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder,
self->points[0].x * width, self->points[0].y * height);
gsk_path_builder_cubic_to (builder,
self->points[1].x * width, self->points[1].y * height,
self->points[2].x * width, self->points[2].y * height,
self->points[3].x * width, self->points[3].y * height);
self->line_path = gsk_path_builder_free_to_path (builder);
gtk_path_widget_create_text_path (self);
}
static void
gtk_path_widget_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkPathWidget *self = GTK_PATH_WIDGET (widget);
GTK_WIDGET_CLASS (gtk_path_widget_parent_class)->size_allocate (widget, width, height, baseline);
gtk_path_widget_create_paths (self);
}
static void
gtk_path_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkPathWidget *self = GTK_PATH_WIDGET (widget);
double width = gtk_widget_get_width (widget);
double height = gtk_widget_get_height (widget);
GskPath *path;
GskStroke *stroke;
gsize i;
/* frosted glass the background */
gtk_snapshot_push_blur (snapshot, 100);
gdk_paintable_snapshot (self->background, snapshot, width, height);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1, 1, 1, 0.6 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
/* draw the text */
if (self->text_path)
{
gtk_snapshot_push_fill (snapshot, self->text_path, GSK_FILL_RULE_WINDING);
gdk_paintable_snapshot (self->background, snapshot, width, height);
/* ... with an emboss effect */
stroke = gsk_stroke_new (2.0);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT(1, 1));
gtk_snapshot_push_stroke (snapshot, self->text_path, stroke);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 0.2 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gsk_stroke_free (stroke);
gtk_snapshot_pop (snapshot);
gtk_snapshot_pop (snapshot);
}
if (self->editable && self->line_path)
{
GskPathBuilder *builder;
/* draw the control line */
stroke = gsk_stroke_new (1.0);
gtk_snapshot_push_stroke (snapshot, self->line_path, stroke);
gsk_stroke_free (stroke);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
/* draw the points */
builder = gsk_path_builder_new ();
for (i = 0; i < 4; i++)
{
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (self->points[i].x * width, self->points[i].y * height), POINT_SIZE);
}
path = gsk_path_builder_free_to_path (builder);
gtk_snapshot_push_fill (snapshot, path, GSK_FILL_RULE_WINDING);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1, 1, 1, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
stroke = gsk_stroke_new (1.0);
gtk_snapshot_push_stroke (snapshot, path, stroke);
gsk_stroke_free (stroke);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
gsk_path_unref (path);
}
}
static void
gtk_path_widget_set_text (GtkPathWidget *self,
const char *text)
{
if (g_strcmp0 (self->text, text) == 0)
return;
g_free (self->text);
self->text = g_strdup (text);
gtk_path_widget_create_paths (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEXT]);
}
static void
gtk_path_widget_set_editable (GtkPathWidget *self,
gboolean editable)
{
if (self->editable == editable)
return;
self->editable = editable;
gtk_widget_queue_draw (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EDITABLE]);
}
static void
gtk_path_widget_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkPathWidget *self = GTK_PATH_WIDGET (object);
switch (prop_id)
{
case PROP_TEXT:
gtk_path_widget_set_text (self, g_value_get_string (value));
break;
case PROP_EDITABLE:
gtk_path_widget_set_editable (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_path_widget_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkPathWidget *self = GTK_PATH_WIDGET (object);
switch (prop_id)
{
case PROP_TEXT:
g_value_set_string (value, self->text);
break;
case PROP_EDITABLE:
g_value_set_boolean (value, self->editable);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_path_widget_dispose (GObject *object)
{
GtkPathWidget *self = GTK_PATH_WIDGET (object);
gtk_path_widget_clear_paths (self);
G_OBJECT_CLASS (gtk_path_widget_parent_class)->dispose (object);
}
static void
gtk_path_widget_class_init (GtkPathWidgetClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_path_widget_dispose;
object_class->set_property = gtk_path_widget_set_property;
object_class->get_property = gtk_path_widget_get_property;
widget_class->size_allocate = gtk_path_widget_allocate;
widget_class->snapshot = gtk_path_widget_snapshot;
properties[PROP_TEXT] =
g_param_spec_string ("text",
"text",
"Text transformed along a path",
NULL,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_EDITABLE] =
g_param_spec_boolean ("editable",
"editable",
"If the path can be edited by the user",
FALSE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
drag_begin (GtkGestureDrag *gesture,
double x,
double y,
GtkPathWidget *self)
{
graphene_point_t mouse = GRAPHENE_POINT_INIT (x, y);
double width = gtk_widget_get_width (GTK_WIDGET (self));
double height = gtk_widget_get_height (GTK_WIDGET (self));
gsize i;
for (i = 0; i < 4; i++)
{
if (graphene_point_distance (&GRAPHENE_POINT_INIT (self->points[i].x * width, self->points[i].y * height), &mouse, NULL, NULL) <= POINT_SIZE)
{
self->active_point = i;
break;
}
}
if (i == 4)
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
return;
}
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
drag_update (GtkGestureDrag *drag,
double offset_x,
double offset_y,
GtkPathWidget *self)
{
double width = gtk_widget_get_width (GTK_WIDGET (self));
double height = gtk_widget_get_height (GTK_WIDGET (self));
double start_x, start_y;
gtk_gesture_drag_get_start_point (drag, &start_x, &start_y);
self->points[self->active_point] = GRAPHENE_POINT_INIT ((start_x + offset_x) / width,
(start_y + offset_y) / height);
self->points[self->active_point].x = CLAMP (self->points[self->active_point].x, 0, 1);
self->points[self->active_point].y = CLAMP (self->points[self->active_point].y, 0, 1);
gtk_path_widget_create_paths (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
pointer_motion (GtkEventControllerMotion *controller,
double x,
double y,
GtkPathWidget *self)
{
GskPathPoint point;
graphene_point_t pos;
if (gsk_path_get_closest_point (self->line_path,
&GRAPHENE_POINT_INIT (x, y),
INFINITY,
&point))
{
gsk_path_point_get_position (&point, self->line_path, &pos);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}
static void
pointer_leave (GtkEventControllerMotion *controller,
GtkPathWidget *self)
{
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
gtk_path_widget_init (GtkPathWidget *self)
{
GtkEventController *controller;
controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
g_signal_connect (controller, "drag-begin", G_CALLBACK (drag_begin), self);
g_signal_connect (controller, "drag-update", G_CALLBACK (drag_update), self);
g_signal_connect (controller, "drag-end", G_CALLBACK (drag_update), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ());
g_signal_connect (controller, "enter", G_CALLBACK (pointer_motion), self);
g_signal_connect (controller, "motion", G_CALLBACK (pointer_motion), self);
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
self->points[0] = GRAPHENE_POINT_INIT (0.1, 0.9);
self->points[1] = GRAPHENE_POINT_INIT (0.3, 0.1);
self->points[2] = GRAPHENE_POINT_INIT (0.7, 0.1);
self->points[3] = GRAPHENE_POINT_INIT (0.9, 0.9);
self->background = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));
gtk_path_widget_set_text (self, "It's almost working");
}
GtkWidget *
gtk_path_widget_new (void)
{
GtkPathWidget *self;
self = g_object_new (GTK_TYPE_PATH_WIDGET, NULL);
return GTK_WIDGET (self);
}
GtkWidget *
do_path_text (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkBuilder *builder;
g_type_ensure (GTK_TYPE_PATH_WIDGET);
builder = gtk_builder_new_from_resource ("/path_text/path_text.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">Text along a Path</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<child type="end">
<object class="GtkToggleButton" id="edit-toggle">
<property name="icon-name">document-edit-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkRevealer">
<property name="reveal-child" bind-source="edit-toggle" bind-property="active" bind-flags="sync-create"></property>
<child>
<object class="GtkEntry" id="text">
<property name="text">Through the looking glass</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPathWidget" id="view">
<property name="editable" bind-source="edit-toggle" bind-property="active" bind-flags="sync-create"></property>
<property name="text" bind-source="text" bind-property="text" bind-flags="sync-create"></property>
<property name="hexpand">true</property>
<property name="vexpand">true</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@ -1,6 +1,6 @@
/* Path/Map
/* Path/Walk
*
* This demo shows how to draw a map using paths.
* This demo draws a world map and shows how to animate objects along a GskPath.
*
* The world map that is used here is a path with 211 lines and 1569 cubic
* Bėzier segments in 121 contours.
@ -16,6 +16,7 @@ G_DECLARE_FINAL_TYPE (GtkPathWalk, gtk_path_walk, GTK, PATH_WALK, GtkWidget)
enum {
PROP_0,
PROP_N_POINTS,
PROP_PATH,
N_PROPS
};
@ -25,7 +26,10 @@ struct _GtkPathWalk
GtkWidget parent_instance;
GskPath *path;
GskPathMeasure *measure;
graphene_rect_t bounds;
GskPath *arrow_path;
guint n_points;
};
struct _GtkPathWalkClass
@ -37,6 +41,74 @@ static GParamSpec *properties[N_PROPS] = { NULL, };
G_DEFINE_TYPE (GtkPathWalk, gtk_path_walk, GTK_TYPE_WIDGET)
static void
rgba_init_from_hsla (GdkRGBA *rgba,
float hue,
float saturation,
float lightness,
float alpha)
{
float m1, m2;
if (lightness <= 0.5)
m2 = lightness * (1 + saturation);
else
m2 = lightness + saturation - lightness * saturation;
m1 = 2 * lightness - m2;
rgba->alpha = alpha;
if (saturation == 0)
{
rgba->red = lightness;
rgba->green = lightness;
rgba->blue = lightness;
}
else
{
hue = hue + 120;
while (hue > 360)
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
rgba->red = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
rgba->red = m2;
else if (hue < 240)
rgba->red = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->red = m1;
hue -= 120;
if (hue < 0)
hue += 360;
if (hue < 60)
rgba->green = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
rgba->green = m2;
else if (hue < 240)
rgba->green = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->green = m1;
hue -= 120;
if (hue < 0)
hue += 360;
if (hue < 60)
rgba->blue = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
rgba->blue = m2;
else if (hue < 240)
rgba->blue = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->blue = m1;
}
}
static void
gtk_path_walk_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
@ -44,7 +116,9 @@ gtk_path_walk_snapshot (GtkWidget *widget,
GtkPathWalk *self = GTK_PATH_WALK (widget);
double width = gtk_widget_get_width (widget);
double height = gtk_widget_get_height (widget);
float length, progress;
GskStroke *stroke;
guint i;
if (self->path == NULL)
return;
@ -57,6 +131,35 @@ gtk_path_walk_snapshot (GtkWidget *widget,
gtk_snapshot_pop (snapshot);
gsk_stroke_free (stroke);
length = gsk_path_measure_get_length (self->measure);
progress = 25.f * gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget)) / G_USEC_PER_SEC;
stroke = gsk_stroke_new (1.0);
for (i = 0; i < self->n_points; i++)
{
GskPathPoint point;
graphene_point_t position;
float angle;
GdkRGBA color;
float distance;
distance = i * length / self->n_points;
distance = fmod (distance + progress, length);
gsk_path_measure_get_point (self->measure, distance, &point);
gsk_path_point_get_position (&point, self->path, &position);
angle = gsk_path_point_get_rotation (&point, self->path, GSK_PATH_FROM_START);
rgba_init_from_hsla (&color, 360.f * i / self->n_points, 1, 0.5, 1);
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &position);
gtk_snapshot_rotate (snapshot, angle);
gtk_snapshot_append_fill (snapshot, self->arrow_path, GSK_FILL_RULE_EVEN_ODD, &color);
gtk_snapshot_append_stroke (snapshot, self->arrow_path, stroke, &(GdkRGBA) { 0, 0, 0, 1 });
gtk_snapshot_restore (snapshot);
}
gsk_stroke_free (stroke);
gtk_snapshot_restore (snapshot);
}
@ -77,6 +180,20 @@ gtk_path_walk_measure (GtkWidget *widget,
*minimum = *natural = (int) ceilf (self->bounds.size.height);
}
static void
gtk_path_walk_set_n_points (GtkPathWalk *self,
gsize n_points)
{
if (self->n_points == n_points)
return;
self->n_points = n_points;
gtk_widget_queue_draw (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_N_POINTS]);
}
static void
gtk_path_walk_set_path (GtkPathWalk *self,
GskPath *path)
@ -94,6 +211,7 @@ gtk_path_walk_set_path (GtkPathWalk *self,
stroke = gsk_stroke_new (2.0);
gsk_path_get_stroke_bounds (path, stroke, &self->bounds);
gsk_stroke_free (stroke);
self->measure = gsk_path_measure_new (self->path);
}
gtk_widget_queue_resize (GTK_WIDGET (self));
@ -112,6 +230,10 @@ gtk_path_walk_set_property (GObject *object,
switch (prop_id)
{
case PROP_N_POINTS:
gtk_path_walk_set_n_points (self, g_value_get_uint (value));
break;
case PROP_PATH:
gtk_path_walk_set_path (self, g_value_get_boxed (value));
break;
@ -132,6 +254,10 @@ gtk_path_walk_get_property (GObject *object,
switch (prop_id)
{
case PROP_N_POINTS:
g_value_set_uint (value, self->n_points);
break;
case PROP_PATH:
g_value_set_boxed (value, self->path);
break;
@ -148,6 +274,8 @@ gtk_path_walk_dispose (GObject *object)
GtkPathWalk *self = GTK_PATH_WALK (object);
g_clear_pointer (&self->path, gsk_path_unref);
g_clear_pointer (&self->measure, gsk_path_measure_unref);
g_clear_pointer (&self->arrow_path, gsk_path_unref);
G_OBJECT_CLASS (gtk_path_walk_parent_class)->dispose (object);
}
@ -165,6 +293,13 @@ gtk_path_walk_class_init (GtkPathWalkClass *klass)
widget_class->snapshot = gtk_path_walk_snapshot;
widget_class->measure = gtk_path_walk_measure;
properties[PROP_N_POINTS] =
g_param_spec_uint ("n-points",
NULL, NULL,
1, G_MAXUINT,
500,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_PATH] =
g_param_spec_boxed ("path",
NULL, NULL,
@ -174,6 +309,16 @@ gtk_path_walk_class_init (GtkPathWalkClass *klass)
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static gboolean
tick_tick_tick (GtkWidget *self,
GdkFrameClock *frame_clock,
gpointer unused)
{
gtk_widget_queue_draw (GTK_WIDGET (self));
return G_SOURCE_CONTINUE;
}
static void
gtk_path_walk_init (GtkPathWalk *self)
{
@ -185,6 +330,9 @@ gtk_path_walk_init (GtkPathWalk *self)
g_bytes_unref (data);
gtk_path_walk_set_path (self, path);
gsk_path_unref (path);
self->arrow_path = gsk_path_parse ("M 5 0 L 0 -5. 0 -2, -5 -2, -5 2, 0 2, 0 5 Z");
self->n_points = 500;
gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_tick_tick, NULL, NULL);
}
GtkWidget *

View File

@ -2,16 +2,32 @@
<interface>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">World Map</property>
<child>
<property name="titlebar">
<object class="GtkHeaderBar">
<child type="end">
<object class="GtkSpinButton">
<property name="adjustment">
<object class="GtkAdjustment" id="adjustment">
<property name="lower">0</property>
<property name="upper">5000</property>
<property name="value">500</property>
</object>
</property>
</object>
</child>
</object>
</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkPathWalk" id="view">
<property name="n-points" bind-source="adjustment" bind-property="value"/>
<property name="hexpand">true</property>
<property name="vexpand">true</property>
</object>
</child>
</object>
</child>
</property>
</object>
</interface>

View File

@ -115,6 +115,14 @@ When paths are rendered as part of an interactive interface, it is sometimes
necessary to determine whether the mouse points is over the path. GSK provides
[method@Gsk.Path.in_fill] for this purpose.
## Path length
An important property of paths is their **_length_**. Computing it efficiently
requires caching, therefore GSK provides a separate [struct@Gsk.PathMeasure] object
to deal with path lengths. After constructing a `GskPathMeasure` object for a path,
it can be used to determine the length of the path with [method@Gsk.PathMeasure.get_length]
and locate points at a given distance into the path with [method@Gsk.PathMeasure.get_point].
## Other Path APIs
Paths have uses beyond rendering, for example as trajectories in animations.
@ -127,11 +135,26 @@ You can query properties of a path at certain point once you have a
`GskPathPoint` structs can be compared for equality with [method@Gsk.PathPoint.equal]
and ordered wrt. to which one comes first, using [method@Gsk.PathPoint.compare].
To obtain a `GskPathPoint`, use [method@Gsk.Path.get_closest_point], [method@Gsk.Path.get_start_point] or [method@Gsk.Path.get_end_point].
To obtain a `GskPathPoint`, use [method@Gsk.Path.get_closest_point],
[method@Gsk.Path.get_start_point], [method@Gsk.Path.get_end_point] or
[method@Gsk.PathMeasure.get_point].
To query properties of the path at a point, use [method@Gsk.PathPoint.get_position],
[method@Gsk.PathPoint.get_tangent], [method@Gsk.PathPoint.get_rotation] and
[method@Gsk.PathPoint.get_curvature].
[method@Gsk.PathPoint.get_tangent], [method@Gsk.PathPoint.get_rotation],
[method@Gsk.PathPoint.get_curvature] and [method@Gsk.PathPoint.get_distance].
Some of the properties can have different values for the path going into
the point and the path leaving the point, typically at points where the
path takes sharp turns. Examples for this are tangents (which can have up
to 4 different values) and curvatures (which can have two different values).
<figure>
<picture>
<source srcset="directions-dark.png" media="(prefers-color-scheme: dark)">
<img alt="Path Tangents" src="directions-light.png">
</picture>
<figcaption>Path Tangents</figcaption>
</figure>
## Going beyond GskPath
@ -139,6 +162,7 @@ Lots of powerful functionality can be implemented for paths:
- Finding intersections
- Offsetting curves
- Turning stroke outlines into paths
- Molding curves (making them pass through a given point)
GSK does not provide API for all of these, but it does offer a way to get at

View File

@ -22,6 +22,7 @@
#include <gsk/gskenums.h>
#include <gsk/gskpath.h>
#include <gsk/gskpathbuilder.h>
#include <gsk/gskpathmeasure.h>
#include <gsk/gskpathpoint.h>
#include <gsk/gskrenderer.h>
#include <gsk/gskrendernode.h>

View File

@ -83,6 +83,18 @@ struct _GskContourClass
gboolean emit_move_to,
GskRealPathPoint *start,
GskRealPathPoint *end);
gpointer (* init_measure) (const GskContour *contour,
float tolerance,
float *out_length);
void (* free_measure) (const GskContour *contour,
gpointer measure_data);
void (* get_point) (const GskContour *contour,
gpointer measure_data,
float distance,
GskRealPathPoint *result);
float (* get_distance) (const GskContour *contour,
GskRealPathPoint *point,
gpointer measure_data);
};
/* {{{ Utilities */
@ -632,6 +644,252 @@ gsk_standard_contour_add_segment (const GskContour *contour,
}
}
typedef struct
{
gsize idx;
float t;
float length;
} CurvePoint;
static void
add_measure (const GskCurve *curve,
float length,
float tolerance,
float t1,
float l1,
GArray *array)
{
GskCurve c;
float ll, l0;
float t0;
float tt, ll0;
CurvePoint *p = &g_array_index (array, CurvePoint, array->len - 1);
gsize idx = p->idx;
/* Check if we can add (t1, length + l1) without further
* splitting. We check two things:
* - Is the curve close to a straight line (length-wise) ?
* - Does the roundtrip length<>t not deviate too much ?
*/
if (curve->op == GSK_PATH_LINE ||
curve->op == GSK_PATH_CLOSE)
goto done;
t0 = (p->t + t1) / 2;
if (t0 == p->t || t0 == t1)
goto done;
gsk_curve_split (curve, t0, &c, NULL);
l0 = gsk_curve_get_length (&c);
ll = (p->length + length + l1) / 2;
tt = gsk_curve_at_length (curve, l0, 0.001);
gsk_curve_split (curve, tt, &c, NULL);
ll0 = gsk_curve_get_length (&c);
if (fabsf (length + l0 - ll) < tolerance &&
fabsf (ll0 - l0) < tolerance)
{
done:
g_array_append_val (array, ((CurvePoint){ idx, t1, length + l1 }));
}
else
{
add_measure (curve, length, tolerance, t0, l0, array);
add_measure (curve, length, tolerance, t1, l1, array);
}
}
static int
cmpfloat (const void *p1, const void *p2)
{
const float *f1 = p1;
const float *f2 = p2;
return *f1 < *f2 ? -1 : (*f1 > *f2 ? 1 : 0);
}
static gpointer
gsk_standard_contour_init_measure (const GskContour *contour,
float tolerance,
float *out_length)
{
const GskStandardContour *self = (const GskStandardContour *) contour;
GArray *array;
float length;
array = g_array_new (FALSE, FALSE, sizeof (CurvePoint));
length = 0;
for (gsize i = 1; i < self->n_ops; i++)
{
GskCurve curve;
float l;
float t[3];
int n;
gsk_curve_init (&curve, self->ops[i]);
g_array_append_val (array, ((CurvePoint) { i, 0, length }));
n = gsk_curve_get_curvature_points (&curve, t);
qsort (t, n, sizeof (float), cmpfloat);
for (int j = 0; j < n; j++)
{
l = gsk_curve_get_length_to (&curve, t[j]);
add_measure (&curve, length, tolerance, t[j], l, array);
}
l = gsk_curve_get_length (&curve);
add_measure (&curve, length, tolerance, 1, l, array);
length += l;
}
*out_length = length;
#if 0
g_print ("%lu ops, %u measure points\n", self->n_ops, array->len);
for (gsize i = 0; i < array->len; i++)
{
CurvePoint *pp = &g_array_index (array, CurvePoint, i);
const char *opname[] = { "M", "Z", "L", "Q", "C" };
GskPathOperation op = gsk_pathop_op (self->ops[pp->idx]);
g_print ("%lu %s %g -> %g\n", pp->idx, opname[op], pp->t, pp->length);
}
#endif
return array;
}
static void
gsk_standard_contour_free_measure (const GskContour *contour,
gpointer data)
{
g_array_free (data, TRUE);
}
static void
gsk_standard_contour_get_point (const GskContour *contour,
gpointer measure_data,
float distance,
GskRealPathPoint *result)
{
const GskStandardContour *self = (const GskStandardContour *) contour;
GArray *array = measure_data;
gsize i0, i1;
CurvePoint *p0, *p1;
if (self->n_ops == 1)
{
result->idx = 0;
result->t = 1;
return;
}
i0 = 0;
i1 = array->len - 1;
while (i0 + 1 < i1)
{
gsize i = (i0 + i1) / 2;
CurvePoint *p = &g_array_index (array, CurvePoint, i);
if (p->length < distance)
i0 = i;
else if (p->length > distance)
i1 = i;
else
{
result->idx = p->idx;
result->t = p->t;
return;
}
}
p0 = &g_array_index (array, CurvePoint, i0);
p1 = &g_array_index (array, CurvePoint, i1);
if (distance >= p1->length)
{
if (p1->idx == self->n_ops - 1)
{
result->idx = p1->idx;
result->t = 1;
}
else
{
result->idx = p1->idx + 1;
result->t = 0;
}
}
else
{
float fraction, t0;
g_assert (p0->idx == p1->idx || p0->t == 1);
t0 = p0->idx == p1->idx ? p0->t : 0;
result->idx = p1->idx;
fraction = (distance - p0->length) / (p1->length - p0->length);
g_assert (fraction >= 0.f && fraction <= 1.f);
result->t = t0 * (1 - fraction) + p1->t * fraction;
g_assert (result->t >= 0.f && result->t <= 1.f);
}
}
static float
gsk_standard_contour_get_distance (const GskContour *contour,
GskRealPathPoint *point,
gpointer measure_data)
{
GArray *array = measure_data;
gsize i0, i1;
CurvePoint *p0, *p1;
float fraction, t0;
if (G_UNLIKELY (point->idx == 0))
return 0;
i0 = 0;
i1 = array->len - 1;
while (i0 + 1 < i1)
{
gsize i = (i0 + i1) / 2;
CurvePoint *p = &g_array_index (array, CurvePoint, i);
if (p->idx > point->idx)
i1 = i;
else if (p->idx < point->idx)
i0 = i;
else if (p->t > point->t)
i1 = i;
else if (p->t < point->t)
i0 = i;
else
return p->length;
}
p0 = &g_array_index (array, CurvePoint, i0);
p1 = &g_array_index (array, CurvePoint, i1);
g_assert (p0->idx == p1->idx || p0->t == 1);
t0 = p0->idx == p1->idx ? p0->t : 0;
g_assert (p1->idx == point->idx);
g_assert (t0 <= point->t && point->t <= p1->t);
fraction = (point->t - t0) / (p1->t - t0);
g_assert (fraction >= 0.f && fraction <= 1.f);
return p0->length * (1 - fraction) + p1->length * fraction;
}
static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
{
sizeof (GskStandardContour),
@ -652,6 +910,10 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
gsk_standard_contour_get_tangent,
gsk_standard_contour_get_curvature,
gsk_standard_contour_add_segment,
gsk_standard_contour_init_measure,
gsk_standard_contour_free_measure,
gsk_standard_contour_get_point,
gsk_standard_contour_get_distance,
};
/* You must ensure the contour has enough size allocated,
@ -841,6 +1103,38 @@ gsk_contour_add_segment (const GskContour *self,
self->klass->add_segment (self, builder, emit_move_to, start, end);
}
gpointer
gsk_contour_init_measure (const GskContour *self,
float tolerance,
float *out_length)
{
return self->klass->init_measure (self, tolerance, out_length);
}
void
gsk_contour_free_measure (const GskContour *self,
gpointer data)
{
self->klass->free_measure (self, data);
}
void
gsk_contour_get_point (const GskContour *self,
gpointer measure_data,
float distance,
GskRealPathPoint *result)
{
self->klass->get_point (self, measure_data, distance, result);
}
float
gsk_contour_get_distance (const GskContour *self,
GskRealPathPoint *point,
gpointer measure_data)
{
return self->klass->get_distance (self, point, measure_data);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@ -80,5 +80,17 @@ void gsk_contour_add_segment (const GskContou
GskRealPathPoint *start,
GskRealPathPoint *end);
gpointer gsk_contour_init_measure (const GskContour *self,
float tolerance,
float *out_length);
void gsk_contour_free_measure (const GskContour *self,
gpointer data);
void gsk_contour_get_point (const GskContour *self,
gpointer measure_data,
float distance,
GskRealPathPoint *result);
float gsk_contour_get_distance (const GskContour *self,
GskRealPathPoint *point,
gpointer measure_data);
G_END_DECLS

213
gsk/gskcurve-ct-values.c Normal file
View File

@ -0,0 +1,213 @@
/* Legendre-Gauss values,
* see https://pomax.github.io/bezierinfo/legendre-gauss.html
*/
#if 0
/* n = 64 */
static const double T[] = {
-0.0243502926634244325089558428537156614268871093149758091634531663960566965166295288529853061657116894882370493013671717560479926679408068852617342586968190919443025679363843727751902756254975073084367002129407854253246662805532069172532219089321005870178809284335033318073251039701073379759,
0.0243502926634244325089558428537156614268871093149758091634531663960566965166295288529853061657116894882370493013671717560479926679408068852617342586968190919443025679363843727751902756254975073084367002129407854253246662805532069172532219089321005870178809284335033318073251039701073379759,
-0.0729931217877990394495429419403374932441261816687788533563163323377395217254429050181833064967505478802134768007678458612956459126148837496307967995621683597067400860540057918571357609346700883624064782909888895547912499697295335516804810990011835717296819569741981551097569810739977931249,
0.0729931217877990394495429419403374932441261816687788533563163323377395217254429050181833064967505478802134768007678458612956459126148837496307967995621683597067400860540057918571357609346700883624064782909888895547912499697295335516804810990011835717296819569741981551097569810739977931249,
-0.1214628192961205544703764634922478782186836383371912940423495826006931832245070944213952236889690237679661122848626352437115925113582515415979746598665681268376919737373113667247142315234607397986222184384307059013512155412722263090766858403726100735651684437098923088469949297570988091677,
0.1214628192961205544703764634922478782186836383371912940423495826006931832245070944213952236889690237679661122848626352437115925113582515415979746598665681268376919737373113667247142315234607397986222184384307059013512155412722263090766858403726100735651684437098923088469949297570988091677,
-0.1696444204239928180373136297482698441999902667343778505894178746884342357796505591325925801106834127602396624627746208498838190598644711533868179088757129652678801285453336384132061358206434768209251779433993367981112053126660575920785488821886662635718276505127786854167528795165050389903,
0.1696444204239928180373136297482698441999902667343778505894178746884342357796505591325925801106834127602396624627746208498838190598644711533868179088757129652678801285453336384132061358206434768209251779433993367981112053126660575920785488821886662635718276505127786854167528795165050389903,
-0.217423643740007084149648748988822617578485831141222348630380401885689634737659235537163737740243604800759921292790013642836998201691226098978544332296437547642195961469059807833597096166848933098833151166287901339013986496737408125314858259377210847115061960167857239951500335854820530586,
0.217423643740007084149648748988822617578485831141222348630380401885689634737659235537163737740243604800759921292790013642836998201691226098978544332296437547642195961469059807833597096166848933098833151166287901339013986496737408125314858259377210847115061960167857239951500335854820530586,
-0.2646871622087674163739641725100201179804131362950932439559895448126206429452852982016450901649805445999078728714943692622330016257776575354105370883948495294882935681426154386660616476411740312465060150591301869544672050088454083442813632094277160007745547301572849406353682760306061929911,
0.2646871622087674163739641725100201179804131362950932439559895448126206429452852982016450901649805445999078728714943692622330016257776575354105370883948495294882935681426154386660616476411740312465060150591301869544672050088454083442813632094277160007745547301572849406353682760306061929911,
-0.3113228719902109561575126985601568835577153578680501269954571709858169098868398268719654999460149709757804582988077747605532896065842023340674450299515989484487746153929299031759475919924980452933324186984188982046762542556035347023744560814177013801414889023264804693830155588690576492164,
0.3113228719902109561575126985601568835577153578680501269954571709858169098868398268719654999460149709757804582988077747605532896065842023340674450299515989484487746153929299031759475919924980452933324186984188982046762542556035347023744560814177013801414889023264804693830155588690576492164,
-0.357220158337668115950442615046202531626264464640909112021237019340099177403802509741325589540743874845093675632547750287037622834793938695456980400958079292460482315821150714268593539935795231095157602025909339384694681190969656053235824652679875951093689200190014853543993102190088381483,
0.357220158337668115950442615046202531626264464640909112021237019340099177403802509741325589540743874845093675632547750287037622834793938695456980400958079292460482315821150714268593539935795231095157602025909339384694681190969656053235824652679875951093689200190014853543993102190088381483,
-0.4022701579639916036957667712601588487132652056150208082760431843129087214967261515969669708970990221669508217089555714806012046537594438323569293594638517933840725639831594134038262580440842200076281605641993773325072728778928440394419613403725280285705765326861533477990551765453978736181,
0.4022701579639916036957667712601588487132652056150208082760431843129087214967261515969669708970990221669508217089555714806012046537594438323569293594638517933840725639831594134038262580440842200076281605641993773325072728778928440394419613403725280285705765326861533477990551765453978736181,
-0.4463660172534640879849477147589151892067507578262501763082606820212937626970791295735937384813941473610238854736863966831464694923749954564921955859791688348936235671762050333408576202492209167272366373825152067680845198006626563761196191045700093968519269790165913301841545609485952718504,
0.4463660172534640879849477147589151892067507578262501763082606820212937626970791295735937384813941473610238854736863966831464694923749954564921955859791688348936235671762050333408576202492209167272366373825152067680845198006626563761196191045700093968519269790165913301841545609485952718504,
-0.4894031457070529574785263070219213908493732974637398373316540793240315585537584844752851087115581833443158831657759501916744927211636581386025171070582998790865902140901838128045602667002106847665927788023098753138400106615804847725751247952878407027140260429761863258319891988431055536872,
0.4894031457070529574785263070219213908493732974637398373316540793240315585537584844752851087115581833443158831657759501916744927211636581386025171070582998790865902140901838128045602667002106847665927788023098753138400106615804847725751247952878407027140260429761863258319891988431055536872,
-0.531279464019894545658013903544455247408525588734180238053268047166041778398245121448843253296460411619816073385211875151397248937264089998182375345915413219579220233566173902955487674957069948591213673456625912506280248298229907928060620469290406581396192419570799497688513058132396498814,
0.531279464019894545658013903544455247408525588734180238053268047166041778398245121448843253296460411619816073385211875151397248937264089998182375345915413219579220233566173902955487674957069948591213673456625912506280248298229907928060620469290406581396192419570799497688513058132396498814,
-0.5718956462026340342838781166591886431831910060912509932273284719418912212643223327597417735844776972648163821225207266145263395898251858906124801356522395225326954546582593857056725545247314092886133249957455688586118199388064447508712958637376347457406936802691416300157802889354368128467,
0.5718956462026340342838781166591886431831910060912509932273284719418912212643223327597417735844776972648163821225207266145263395898251858906124801356522395225326954546582593857056725545247314092886133249957455688586118199388064447508712958637376347457406936802691416300157802889354368128467,
-0.6111553551723932502488529710185489186961245593079718443367976666933088374650288148448667879830703867726577720666491772560110368248450475818132595468834493579434418252468978282181164008820769765174450056817468275783966537351796625224747700783378315186174632657840114512887287754747902924865,
0.6111553551723932502488529710185489186961245593079718443367976666933088374650288148448667879830703867726577720666491772560110368248450475818132595468834493579434418252468978282181164008820769765174450056817468275783966537351796625224747700783378315186174632657840114512887287754747902924865,
-0.6489654712546573398577612319934048855296904334732011728792502624366057598865738239773166627826358871699142531853930525866830933399401844502541092962631127742267449897116125748014270680393024011359139031312062573520509858894743036198986443014969748157931850178889912972291202354657382925509,
0.6489654712546573398577612319934048855296904334732011728792502624366057598865738239773166627826358871699142531853930525866830933399401844502541092962631127742267449897116125748014270680393024011359139031312062573520509858894743036198986443014969748157931850178889912972291202354657382925509,
-0.6852363130542332425635583710313763019356410785396718681324042749913611976548967332647625541234155413035075739348863233240851709341392873173633850612006618690218164007761541855237208605116527909791956398350719463021018362527198358286721239529091637248252469435642287693207506339068528700205,
0.6852363130542332425635583710313763019356410785396718681324042749913611976548967332647625541234155413035075739348863233240851709341392873173633850612006618690218164007761541855237208605116527909791956398350719463021018362527198358286721239529091637248252469435642287693207506339068528700205,
-0.7198818501716108268489402178319472447581380033149019526220473151184468592486433646042300919262498902882179891494724046747921544602557246455427317830132976771174504209146835854012577372395960646854355024460204286901035470812684876587693044068989973704915078171158689213412715251485203442313,
0.7198818501716108268489402178319472447581380033149019526220473151184468592486433646042300919262498902882179891494724046747921544602557246455427317830132976771174504209146835854012577372395960646854355024460204286901035470812684876587693044068989973704915078171158689213412715251485203442313,
-0.7528199072605318966118637748856939855517142713220871932461987761167722639636968539390413583009467924995905147153923286347693864945784890119950315095740891764880991728646942920208355501445550654259850385377192973526980795946453961077798744753892199929235882097232836682421729944934586281945,
0.7528199072605318966118637748856939855517142713220871932461987761167722639636968539390413583009467924995905147153923286347693864945784890119950315095740891764880991728646942920208355501445550654259850385377192973526980795946453961077798744753892199929235882097232836682421729944934586281945,
-0.7839723589433414076102205252137682840564141249898259334132759617476816578705098509357116190608002325895348207611752987335385494893726027026038902508685496606160441965948835252795524014713290879877269643684102005605450140247125536147801312017065532602835003540212221564314236937509990182173,
0.7839723589433414076102205252137682840564141249898259334132759617476816578705098509357116190608002325895348207611752987335385494893726027026038902508685496606160441965948835252795524014713290879877269643684102005605450140247125536147801312017065532602835003540212221564314236937509990182173,
-0.8132653151227975597419233380863033406981418225655972166956485149356586346082019870309280128411412936411423614767918756843380999442447282903502051218203273573634847203121451086379808399639198510674436238195505371716160648058477202993836014352158139813219612968106205248494087577632573534973,
0.8132653151227975597419233380863033406981418225655972166956485149356586346082019870309280128411412936411423614767918756843380999442447282903502051218203273573634847203121451086379808399639198510674436238195505371716160648058477202993836014352158139813219612968106205248494087577632573534973,
-0.840629296252580362751691544695873302982489823801755353928202683075593465893922171840726147868117503717663799561956411215937924134571068943700343442753760445948626598735504632170407243376224222403038093781056024445977626666740664628412660960413062370047183186652885532589557452614451434048,
0.840629296252580362751691544695873302982489823801755353928202683075593465893922171840726147868117503717663799561956411215937924134571068943700343442753760445948626598735504632170407243376224222403038093781056024445977626666740664628412660960413062370047183186652885532589557452614451434048,
-0.8659993981540928197607833850701575024125019187582496425664279511808356713122188567857456842034906362573453815878913951040194915987006979015304835979058725276345799813088989383312475641092775164460639450521468294104011206574786429237252678172922104036725327539940502197291939132802457917836,
0.8659993981540928197607833850701575024125019187582496425664279511808356713122188567857456842034906362573453815878913951040194915987006979015304835979058725276345799813088989383312475641092775164460639450521468294104011206574786429237252678172922104036725327539940502197291939132802457917836,
-0.8893154459951141058534040382728516224291944615104521893194744566084811090577722526400445910623711480590529533188832105988657269430913287263821624762648137092066620632787986348052306840101775313644572400860845559833367997001666659907951051347410546710134120144598833115095140475669485797579,
0.8893154459951141058534040382728516224291944615104521893194744566084811090577722526400445910623711480590529533188832105988657269430913287263821624762648137092066620632787986348052306840101775313644572400860845559833367997001666659907951051347410546710134120144598833115095140475669485797579,
-0.9105221370785028057563806680083298610134880848883640292531723714467102234556291968179018775780308458024302103848451312741663820589200520720207891653884985710130867134073520525932445557074805974235006810370309087879564826639263972805682465506594098949560288847385983395160311034445386606259,
0.9105221370785028057563806680083298610134880848883640292531723714467102234556291968179018775780308458024302103848451312741663820589200520720207891653884985710130867134073520525932445557074805974235006810370309087879564826639263972805682465506594098949560288847385983395160311034445386606259,
-0.9295691721319395758214901545592256073474270144297154975928116833612430986265594515998834499355844736686512805129688214992047597092114291955925880175797899765980745854426738149516325837607227287481909072315347776012991222301207304052068204069335766550173941103055407746774520789612843561385,
0.9295691721319395758214901545592256073474270144297154975928116833612430986265594515998834499355844736686512805129688214992047597092114291955925880175797899765980745854426738149516325837607227287481909072315347776012991222301207304052068204069335766550173941103055407746774520789612843561385,
-0.9464113748584028160624814913472647952793949717952331902317789712973664402149436591260928179188420533516264142755452159723722786167537167514691534968355366202934342465086995943893699962972237343218079763936958985487264411542890941861254842843026890160131607678957282346112697993618567018237,
0.9464113748584028160624814913472647952793949717952331902317789712973664402149436591260928179188420533516264142755452159723722786167537167514691534968355366202934342465086995943893699962972237343218079763936958985487264411542890941861254842843026890160131607678957282346112697993618567018237,
-0.9610087996520537189186141218971572067621146110378459494461586158623919945488992563976780806866203786216001498788310714552847469661399216303755820947005848739467276644122915754949838610353627723679982220628115164983443994552616161584523205789167087822341423097206088828267065770404672828066,
0.9610087996520537189186141218971572067621146110378459494461586158623919945488992563976780806866203786216001498788310714552847469661399216303755820947005848739467276644122915754949838610353627723679982220628115164983443994552616161584523205789167087822341423097206088828267065770404672828066,
-0.9733268277899109637418535073522726680261452944551741758819139781978152256958453749994966038154125547612207903105020176172420237675899907788807087542221018040460410464083361271842759039530092449625891215101984663282728542290395875313124045226564547294745437773482395329023327909760431499638,
0.9733268277899109637418535073522726680261452944551741758819139781978152256958453749994966038154125547612207903105020176172420237675899907788807087542221018040460410464083361271842759039530092449625891215101984663282728542290395875313124045226564547294745437773482395329023327909760431499638,
-0.9833362538846259569312993021568311169452475066237403837464872131233426128415470535606559721330818003585532628124845662897410684694651251174207713020897795837892725294581710205598344576799985346970638130204876060998657059283079767876980544166132523941283823202290746667358872631036031924711,
0.9833362538846259569312993021568311169452475066237403837464872131233426128415470535606559721330818003585532628124845662897410684694651251174207713020897795837892725294581710205598344576799985346970638130204876060998657059283079767876980544166132523941283823202290746667358872631036031924711,
-0.9910133714767443207393823834433031136413494453907904852225427459378131658644129997345108950133770434340330151289100150097018332483423277136039914249575686591612502752158650205954671083696496347591169012794322303027309768195334920157669446268175983954105533989275308193580349506657360682085,
0.9910133714767443207393823834433031136413494453907904852225427459378131658644129997345108950133770434340330151289100150097018332483423277136039914249575686591612502752158650205954671083696496347591169012794322303027309768195334920157669446268175983954105533989275308193580349506657360682085,
-0.9963401167719552793469245006763991232098575063402266121352522199507030568202208530946066801021703916301511794658310735397567341036554686814952726523955953805437164277655915410358813984246580862850974195805395101678543649116458555272523253307828290553873260588621490898443701779725568118502,
0.9963401167719552793469245006763991232098575063402266121352522199507030568202208530946066801021703916301511794658310735397567341036554686814952726523955953805437164277655915410358813984246580862850974195805395101678543649116458555272523253307828290553873260588621490898443701779725568118502,
-0.9993050417357721394569056243456363119697121916756087760628072954617646543505331997843242376462639434945376776512170265314011232493020401570891594274831367800115383317335285468800574240152992751785027563437707875403545865305271045717258142571193695943317890367167086616955235477529427992282,
0.9993050417357721394569056243456363119697121916756087760628072954617646543505331997843242376462639434945376776512170265314011232493020401570891594274831367800115383317335285468800574240152992751785027563437707875403545865305271045717258142571193695943317890367167086616955235477529427992282
};
static const double C[] = {
0.0486909570091397203833653907347499124426286922838743305086688042456914190998246107310291565645676057401607079939845156005172257043376703767287395573765236401039685866479381075274920900511719320271157129622463682509122641788910270632229694394595885032921037399187298767076084601033342936131,
0.0486909570091397203833653907347499124426286922838743305086688042456914190998246107310291565645676057401607079939845156005172257043376703767287395573765236401039685866479381075274920900511719320271157129622463682509122641788910270632229694394595885032921037399187298767076084601033342936131,
0.0485754674415034269347990667839781136875565447049294857111516761025158193093697039229163427633930410186232149083923688162761488505704450697417589593116703853157329164894580165517236877241308351214870169600093357854651930986960906313726182992933363325614247750209880050786299287510692780499,
0.0485754674415034269347990667839781136875565447049294857111516761025158193093697039229163427633930410186232149083923688162761488505704450697417589593116703853157329164894580165517236877241308351214870169600093357854651930986960906313726182992933363325614247750209880050786299287510692780499,
0.048344762234802957169769527158017809703692550609501080629442201445249828946429202156764153264348308119169811534137999799779908820312744765416129733427088646813066886130539178187597540312913636916139844188190193872629488730769015964208394624398401975043997268903006190530430762197842013971,
0.048344762234802957169769527158017809703692550609501080629442201445249828946429202156764153264348308119169811534137999799779908820312744765416129733427088646813066886130539178187597540312913636916139844188190193872629488730769015964208394624398401975043997268903006190530430762197842013971,
0.0479993885964583077281261798713460699543167134714936209446323930933335214619650277588138568504103427609283146728470455041360837549685364869161566863222680599110109210456299588352028330169041000166382937545505655464884266691630625402297821494221827392164049587946530563778771030124675514431,
0.0479993885964583077281261798713460699543167134714936209446323930933335214619650277588138568504103427609283146728470455041360837549685364869161566863222680599110109210456299588352028330169041000166382937545505655464884266691630625402297821494221827392164049587946530563778771030124675514431,
0.0475401657148303086622822069442231716408252512625387521584740318784735191312349586041971325618543660076682369564304738487584849740943805934034367382833518752314207901993991333786062812015195073547884746598535775062676699885664167707011249029305697669004958515813436770491520105115843742005,
0.0475401657148303086622822069442231716408252512625387521584740318784735191312349586041971325618543660076682369564304738487584849740943805934034367382833518752314207901993991333786062812015195073547884746598535775062676699885664167707011249029305697669004958515813436770491520105115843742005,
0.0469681828162100173253262857545810751998975284738125649829240886861900500181800807437012381630302198876925642461830694029139318555787845567143614289552410495903601238284556145544858090965965782916339169651505119399637862876053945518410353459767034026687936026945199383607112976484520939933,
0.0469681828162100173253262857545810751998975284738125649829240886861900500181800807437012381630302198876925642461830694029139318555787845567143614289552410495903601238284556145544858090965965782916339169651505119399637862876053945518410353459767034026687936026945199383607112976484520939933,
0.0462847965813144172959532492322611849696503075324468007778340818364698861774606986244241539105685321088517142947579291476238551538798963436740600968513359005801910700069462154098456091711311098901749803777735222026075473081311483686560830539773763176758567914860207820170792365910140063798,
0.0462847965813144172959532492322611849696503075324468007778340818364698861774606986244241539105685321088517142947579291476238551538798963436740600968513359005801910700069462154098456091711311098901749803777735222026075473081311483686560830539773763176758567914860207820170792365910140063798,
0.0454916279274181444797709969712690588873234618023998968168834081606504637618082102750954507142497706775055424364453740562113890878382679420378787427100982909191308430750899201141096789461078632697297091763378573830284133736378128577579722120264252594541491899441765769262904055702701625378,
0.0454916279274181444797709969712690588873234618023998968168834081606504637618082102750954507142497706775055424364453740562113890878382679420378787427100982909191308430750899201141096789461078632697297091763378573830284133736378128577579722120264252594541491899441765769262904055702701625378,
0.0445905581637565630601347100309448432940237999912217256432193286861948363377761089569585678875932857237669096941854082976565514031401996407675401022860761183118504326746863327792604337217763335682212515058414863183914930810334329596384915832703655935958010948424747251920190851700662833367,
0.0445905581637565630601347100309448432940237999912217256432193286861948363377761089569585678875932857237669096941854082976565514031401996407675401022860761183118504326746863327792604337217763335682212515058414863183914930810334329596384915832703655935958010948424747251920190851700662833367,
0.0435837245293234533768278609737374809227888974971180150532193925502569499020021803936448815937567079991401855477391110804568848623412043870399620479222000249538880795788245633051476595555730388360811011823841525667998427392843673284072004068821750061964976796287623004834501604656318714989,
0.0435837245293234533768278609737374809227888974971180150532193925502569499020021803936448815937567079991401855477391110804568848623412043870399620479222000249538880795788245633051476595555730388360811011823841525667998427392843673284072004068821750061964976796287623004834501604656318714989,
0.0424735151236535890073397679088173661655466481806496697314607722055245433487169327182398988553670128358787507582463602377168227019625334754497484024668087975720049504975593281010888062806587161032924284354938115463233015024659299046001504100674918329532481611571863222497170398830691222425,
0.0424735151236535890073397679088173661655466481806496697314607722055245433487169327182398988553670128358787507582463602377168227019625334754497484024668087975720049504975593281010888062806587161032924284354938115463233015024659299046001504100674918329532481611571863222497170398830691222425,
0.0412625632426235286101562974736380477399306355305474105429034779122704951178045914463267035032832336161816547420067160277921114474557623647771372636679857599931025531633255548770293397336318597716427093310378312957479805159734598610664983115148350548735211568465338522875618805992499897174,
0.0412625632426235286101562974736380477399306355305474105429034779122704951178045914463267035032832336161816547420067160277921114474557623647771372636679857599931025531633255548770293397336318597716427093310378312957479805159734598610664983115148350548735211568465338522875618805992499897174,
0.0399537411327203413866569261283360739186769506703336301114037026981570543670430333260307390357287606111017588757685176701688554806178713759519003171090525332423003042251947304213502522332118258365256241174986409729902714098049024753746340158430732115642207673265332738358717839602955875715,
0.0399537411327203413866569261283360739186769506703336301114037026981570543670430333260307390357287606111017588757685176701688554806178713759519003171090525332423003042251947304213502522332118258365256241174986409729902714098049024753746340158430732115642207673265332738358717839602955875715,
0.0385501531786156291289624969468089910127871122017180319662378854088005271323682681394418540442928363090545214563022868422017877042243007014244875098498616146404178795110038170109976252865902624380463581094085479557660525450020049773872343621719025128277593787164021147974906095237533202082,
0.0385501531786156291289624969468089910127871122017180319662378854088005271323682681394418540442928363090545214563022868422017877042243007014244875098498616146404178795110038170109976252865902624380463581094085479557660525450020049773872343621719025128277593787164021147974906095237533202082,
0.0370551285402400460404151018095833750834649453056563021747536272028091562122966687178302646649066832960609370472485057031765338738734008482025086366647963664178752038995704175623165041724901843573087856883034472545386037691055680911138721623610172486110313241291773258491882452773847899443,
0.0370551285402400460404151018095833750834649453056563021747536272028091562122966687178302646649066832960609370472485057031765338738734008482025086366647963664178752038995704175623165041724901843573087856883034472545386037691055680911138721623610172486110313241291773258491882452773847899443,
0.0354722132568823838106931467152459479480946310024100946926514848199381113651392962399922996268087884509143420993419937430515415557908457195618550238075571721209638845910166697234073788332647695349442265578792857058786796417110738673392400570019770741873271724201517438135222598792344040215,
0.0354722132568823838106931467152459479480946310024100946926514848199381113651392962399922996268087884509143420993419937430515415557908457195618550238075571721209638845910166697234073788332647695349442265578792857058786796417110738673392400570019770741873271724201517438135222598792344040215,
0.0338051618371416093915654821107254310210499263140045346675500650400323727745785853730452808963944098691936344225349051741060036935288424090581463711756382878498537611980973238606529148664990420534952057130296232922368792280098852092993207644225150541876980292972087619863453425206929192216,
0.0338051618371416093915654821107254310210499263140045346675500650400323727745785853730452808963944098691936344225349051741060036935288424090581463711756382878498537611980973238606529148664990420534952057130296232922368792280098852092993207644225150541876980292972087619863453425206929192216,
0.032057928354851553585467504347898716966221573881398062250169407854535275399124366530227987935629046729162364779969274126431870966979526186907589490002269660893281421728773647001279141626157958271220102615163092206489916992120482595587916535390136003611498634162765724522022671474313619317,
0.032057928354851553585467504347898716966221573881398062250169407854535275399124366530227987935629046729162364779969274126431870966979526186907589490002269660893281421728773647001279141626157958271220102615163092206489916992120482595587916535390136003611498634162765724522022671474313619317,
0.030234657072402478867974059819548659158281397768481241636026542045969161851838118212761980885178641520596873511042783163461341979185470882574743804555268086640389062237383427702813367624714014426121485626242067362445894463989335423458464954799181190120473168677930333898873084606011285311,
0.030234657072402478867974059819548659158281397768481241636026542045969161851838118212761980885178641520596873511042783163461341979185470882574743804555268086640389062237383427702813367624714014426121485626242067362445894463989335423458464954799181190120473168677930333898873084606011285311,
0.0283396726142594832275113052002373519812075841257543359907955185084500175712880712901834579816476269393013386531176072296695948860841466158639973753393323262188023471133258509422081952937349849822864752636994881600343083839805990853930436233762729622213044478376753949590318846038229829528,
0.0283396726142594832275113052002373519812075841257543359907955185084500175712880712901834579816476269393013386531176072296695948860841466158639973753393323262188023471133258509422081952937349849822864752636994881600343083839805990853930436233762729622213044478376753949590318846038229829528,
0.0263774697150546586716917926252251856755993308422457184496156736853021592428967790284780487213653480867620409279447766944383920384284787790772384251090745670478105870527396429136326932261251511732466974897397268573168068852344129736214469830280087710575094607457344820944885011053938108899,
0.0263774697150546586716917926252251856755993308422457184496156736853021592428967790284780487213653480867620409279447766944383920384284787790772384251090745670478105870527396429136326932261251511732466974897397268573168068852344129736214469830280087710575094607457344820944885011053938108899,
0.0243527025687108733381775504090689876499784155133784119819985685535536787083770723737264828464464223276155821319330210193549896426801083040150047332857692873011433649334477370145389017577189505240415125600908800786897201425473757275187332157593198572919772969833130729981971352463730545469,
0.0243527025687108733381775504090689876499784155133784119819985685535536787083770723737264828464464223276155821319330210193549896426801083040150047332857692873011433649334477370145389017577189505240415125600908800786897201425473757275187332157593198572919772969833130729981971352463730545469,
0.0222701738083832541592983303841550024229592905997594051455205429744914460867081990116647982811451138592401156680063927909718825845915896692701716212710541472344073624315399429951255221519263275095347974129106415903376085208797420439500915674568159744176912567285070988940509294826076696882,
0.0222701738083832541592983303841550024229592905997594051455205429744914460867081990116647982811451138592401156680063927909718825845915896692701716212710541472344073624315399429951255221519263275095347974129106415903376085208797420439500915674568159744176912567285070988940509294826076696882,
0.0201348231535302093723403167285438970895266801007919519220072343276769828211923597982299498416998597995443052252531684909219367615574440281549241161294448697202959593344989612626641188010558013085389491205901106884167596038790695150496733123662891637942237462337673353651179115491957031948,
0.0201348231535302093723403167285438970895266801007919519220072343276769828211923597982299498416998597995443052252531684909219367615574440281549241161294448697202959593344989612626641188010558013085389491205901106884167596038790695150496733123662891637942237462337673353651179115491957031948,
0.0179517157756973430850453020011193688971673570364158572977184273569247295870620984743089140579199272107974903016785911970727080884655646148340637373001805876560334052431930062983734905886704331100259778249929425439377011315288821865303197904492848823994202996722656114004109123107733596987,
0.0179517157756973430850453020011193688971673570364158572977184273569247295870620984743089140579199272107974903016785911970727080884655646148340637373001805876560334052431930062983734905886704331100259778249929425439377011315288821865303197904492848823994202996722656114004109123107733596987,
0.0157260304760247193219659952975397944260290098431565121528943932284210502164124556525745628476326997189475680077625258949765335021586482683126547283634704087193102431454662772463321304938516661086261262080252305539171654570677889578063634007609097342035360186636479612243231917699790225637,
0.0157260304760247193219659952975397944260290098431565121528943932284210502164124556525745628476326997189475680077625258949765335021586482683126547283634704087193102431454662772463321304938516661086261262080252305539171654570677889578063634007609097342035360186636479612243231917699790225637,
0.0134630478967186425980607666859556841084257719773496708184682785221983598894666268489697837056105038485845901773961664652581563686185523959473293683490869846700009741156668864960127745507806046701586435579547632680339906665338521813319281296935586498194608460412423723103161161922347608637,
0.0134630478967186425980607666859556841084257719773496708184682785221983598894666268489697837056105038485845901773961664652581563686185523959473293683490869846700009741156668864960127745507806046701586435579547632680339906665338521813319281296935586498194608460412423723103161161922347608637,
0.011168139460131128818590493019208135072778797816827287215251362273969701224836131369547661822970774719521543690039908073147476182135228738610704246958518755712518444434075738269866120460156365855324768445411463643114925829148750923090201475035559533993035986264487097245733097728698218563,
0.011168139460131128818590493019208135072778797816827287215251362273969701224836131369547661822970774719521543690039908073147476182135228738610704246958518755712518444434075738269866120460156365855324768445411463643114925829148750923090201475035559533993035986264487097245733097728698218563,
0.0088467598263639477230309146597306476951762660792204997984715769296110380005985367341694286322550520156167431790573509593010611842062630262878798782558974712042810219159674181580449655112696028911646066461502678711637780164986283350190669684468398617127841853445303466680698660632269500149,
0.0088467598263639477230309146597306476951762660792204997984715769296110380005985367341694286322550520156167431790573509593010611842062630262878798782558974712042810219159674181580449655112696028911646066461502678711637780164986283350190669684468398617127841853445303466680698660632269500149,
0.0065044579689783628561173603999812667711317610549523400952448792575685125717613068203530526491113296049409911387320826711045787146267036866881961532403342811327869183281273743976710008917886491097375367147212074243884772614562628844975421736416404173672075979097191581386023407454532945934,
0.0065044579689783628561173603999812667711317610549523400952448792575685125717613068203530526491113296049409911387320826711045787146267036866881961532403342811327869183281273743976710008917886491097375367147212074243884772614562628844975421736416404173672075979097191581386023407454532945934,
0.0041470332605624676352875357285514153133028192536848024628763661431834776690157393776820933106187137592011723199002845429836606307797425496666456172753165824787973801175029578301513761259541022471768825518482406145696380621686627285992715643614469568410535180218496973657001203470470418364,
0.0041470332605624676352875357285514153133028192536848024628763661431834776690157393776820933106187137592011723199002845429836606307797425496666456172753165824787973801175029578301513761259541022471768825518482406145696380621686627285992715643614469568410535180218496973657001203470470418364,
0.0017832807216964329472960791449719331799593472719279556695308063655858546954239803486698215802150348282744786016134857283616955449868451969230490863774274598030023211055562492709717566919237924255297982774711177411074145151155610163293142044147991553384925940046957893721166251082473659733,
0.0017832807216964329472960791449719331799593472719279556695308063655858546954239803486698215802150348282744786016134857283616955449868451969230490863774274598030023211055562492709717566919237924255297982774711177411074145151155610163293142044147991553384925940046957893721166251082473659733
};
#else
/* n = 32 */
static double T[] = {
-0.0483076656877383162348125704405021636908472517308488971677937345463685926042778777794060365911173780988289503411375793689757446357461295741679964108035347980667582792392651327368009453047606446744575790523465655622949909588624860214137051585425884056992683442137333250625173849291299678673,
0.0483076656877383162348125704405021636908472517308488971677937345463685926042778777794060365911173780988289503411375793689757446357461295741679964108035347980667582792392651327368009453047606446744575790523465655622949909588624860214137051585425884056992683442137333250625173849291299678673,
-0.1444719615827964934851863735988106522038459913156355521379528938242184438164519731102406769974924713989580220758441301598578946580142268413547299935841673092513202403499286272686350814272974392746706128556678811982653393383080797337231702069432462445053984587997153683967433095128570624414,
0.1444719615827964934851863735988106522038459913156355521379528938242184438164519731102406769974924713989580220758441301598578946580142268413547299935841673092513202403499286272686350814272974392746706128556678811982653393383080797337231702069432462445053984587997153683967433095128570624414,
-0.2392873622521370745446032091655015206088554219602530155470960995597029133039943915553593695844147813728958071901224632260145752503694970545640339873418480550362677768010887468668377893757173424222709744116861683634989914911762187599464033126988486345234374380695224452457957624756811128321,
0.2392873622521370745446032091655015206088554219602530155470960995597029133039943915553593695844147813728958071901224632260145752503694970545640339873418480550362677768010887468668377893757173424222709744116861683634989914911762187599464033126988486345234374380695224452457957624756811128321,
-0.3318686022821276497799168057301879961957751368050598360182296306285376829657438169809731852312743263005943551508559377834274303920771100489026913715847854727626540340157368609696698131829681988642689780208633461925468064919389286805624602715005948661328152252049795463242055567997437182143,
0.3318686022821276497799168057301879961957751368050598360182296306285376829657438169809731852312743263005943551508559377834274303920771100489026913715847854727626540340157368609696698131829681988642689780208633461925468064919389286805624602715005948661328152252049795463242055567997437182143,
-0.4213512761306353453641194361724264783358772886324433305416613404557190462549837315607633055675740638739884093394574651160978879545562247406839036854173715776910866941643197988581928900702286425821151586000969947406313405310082646561917980302543820974679501841964453794193724645925031841919,
0.4213512761306353453641194361724264783358772886324433305416613404557190462549837315607633055675740638739884093394574651160978879545562247406839036854173715776910866941643197988581928900702286425821151586000969947406313405310082646561917980302543820974679501841964453794193724645925031841919,
-0.5068999089322293900237474743778212301802836995994354639743662809707712640478764442266190213124522047999876916596854537447047905434649918210338296049592120273725464263651562560829050004258268002241145951271730860506703690843719936432852920782304931272053564539127514959875734718036950073563,
0.5068999089322293900237474743778212301802836995994354639743662809707712640478764442266190213124522047999876916596854537447047905434649918210338296049592120273725464263651562560829050004258268002241145951271730860506703690843719936432852920782304931272053564539127514959875734718036950073563,
-0.5877157572407623290407454764018268584509401154544205727031788473129228586684474311408145102018661764979429510790747919023774933113319119601088669936958908618326367715806216053155906936017362413244183150445492317940727345571648726363597097311647731726438279098059670236086983675374932643925,
0.5877157572407623290407454764018268584509401154544205727031788473129228586684474311408145102018661764979429510790747919023774933113319119601088669936958908618326367715806216053155906936017362413244183150445492317940727345571648726363597097311647731726438279098059670236086983675374932643925,
-0.6630442669302152009751151686632383689770222859605053010170834964924461749232229404368981536611965356686820332804126742949900731319113817214392193185613161549689934301410316417342588149871686184296988807305719690974644891055567340650986465615021143958920599684258616066247948224049997371166,
0.6630442669302152009751151686632383689770222859605053010170834964924461749232229404368981536611965356686820332804126742949900731319113817214392193185613161549689934301410316417342588149871686184296988807305719690974644891055567340650986465615021143958920599684258616066247948224049997371166,
-0.732182118740289680387426665091267146630270483506629100821139573270385253587797727611292298988652560055905228466313310601075333829094630570926240639601009902567982815376254840388565733846030450161774620971196087756484387383432502715118096615117242484073636640563609696801484680439912327302,
0.732182118740289680387426665091267146630270483506629100821139573270385253587797727611292298988652560055905228466313310601075333829094630570926240639601009902567982815376254840388565733846030450161774620971196087756484387383432502715118096615117242484073636640563609696801484680439912327302,
-0.7944837959679424069630972989704289020954794016388354532507582449720593922816426654241878967890821228397041480126630294067578180914548706957761322921470535094589673860419616615738928385807346185892317514562489971543238450942224396667500582904031225063621511429185567036727089257387570529468,
0.7944837959679424069630972989704289020954794016388354532507582449720593922816426654241878967890821228397041480126630294067578180914548706957761322921470535094589673860419616615738928385807346185892317514562489971543238450942224396667500582904031225063621511429185567036727089257387570529468,
-0.849367613732569970133693004967742538954886793049759233100219598613724656141562558741881463752754991143937635778596582088915769685796612254240615386941355933272723068952531445772190363422003834495043219316062885999846179078139659341918527603834809670576387535564876596379488780285979062125,
0.849367613732569970133693004967742538954886793049759233100219598613724656141562558741881463752754991143937635778596582088915769685796612254240615386941355933272723068952531445772190363422003834495043219316062885999846179078139659341918527603834809670576387535564876596379488780285979062125,
-0.8963211557660521239653072437192122684789964967957595765636154129650249794910409173494503783167666654202705333374285522819507600044591355080910768854012859468015827508424619812224062460791781333400979810176198916239783226706506012473250929962326307746466256167673927887144428859779028909399,
0.8963211557660521239653072437192122684789964967957595765636154129650249794910409173494503783167666654202705333374285522819507600044591355080910768854012859468015827508424619812224062460791781333400979810176198916239783226706506012473250929962326307746466256167673927887144428859779028909399,
-0.9349060759377396891709191348354093255286714322828372184584037398118161947182932855418880831417927728359606280450921427988850058691931014887248988124656348299653052688344696135840215712191162135178273756415771123010111796122671724143565383396162107206772781551029308751511942924942333859805,
0.9349060759377396891709191348354093255286714322828372184584037398118161947182932855418880831417927728359606280450921427988850058691931014887248988124656348299653052688344696135840215712191162135178273756415771123010111796122671724143565383396162107206772781551029308751511942924942333859805,
-0.9647622555875064307738119281182749603888952204430187193220113218370995254867038008243801877562227002840740910741483519987441236283464394249183812395373150090695515823078220949436846111682404866338388944248976976566275875721000356873959697266702651250019105084704924793016185368873243713355,
0.9647622555875064307738119281182749603888952204430187193220113218370995254867038008243801877562227002840740910741483519987441236283464394249183812395373150090695515823078220949436846111682404866338388944248976976566275875721000356873959697266702651250019105084704924793016185368873243713355,
-0.9856115115452683354001750446309019786323957143358063182107821705820305847193755946663846485510970266115353839862364606643634021712823093784875255943834038377710426488328772047833289470320023596895438028281274741367781028592272459887917924171204666683239464005128153533797603112851826904814,
0.9856115115452683354001750446309019786323957143358063182107821705820305847193755946663846485510970266115353839862364606643634021712823093784875255943834038377710426488328772047833289470320023596895438028281274741367781028592272459887917924171204666683239464005128153533797603112851826904814,
-0.9972638618494815635449811286650407271385376637294611593011185457862359083917418520130456693085426416474280482200936551645510686196373231416035137741332968299789863385253514914078766236061488136738023162574655835389902337937054326098485227311719825229066712510246574949376367552421728646398,
0.9972638618494815635449811286650407271385376637294611593011185457862359083917418520130456693085426416474280482200936551645510686196373231416035137741332968299789863385253514914078766236061488136738023162574655835389902337937054326098485227311719825229066712510246574949376367552421728646398
};
static double C[] = {
0.0965400885147278005667648300635757947368606312355700687323182099577497758679466512968173871061464644599963197828969869820251559172455698832434930732077927850876632725829187045819145660710266452161095406358159608874152584850413283587913891015545638518881205600825069096855488296437485836866,
0.0965400885147278005667648300635757947368606312355700687323182099577497758679466512968173871061464644599963197828969869820251559172455698832434930732077927850876632725829187045819145660710266452161095406358159608874152584850413283587913891015545638518881205600825069096855488296437485836866,
0.0956387200792748594190820022041311005948905081620055509529898509437067444366006256133614167190847508238474888230077112990752876436158047205555474265705582078453283640212465537132165041268773645168746774530146140911679782502276289938840330631903789120176765314495900053061764438990021439069,
0.0956387200792748594190820022041311005948905081620055509529898509437067444366006256133614167190847508238474888230077112990752876436158047205555474265705582078453283640212465537132165041268773645168746774530146140911679782502276289938840330631903789120176765314495900053061764438990021439069,
0.0938443990808045656391802376681172600361000757462364500506275696355695118623098075097804207682530277555307864917078828352419853248607668520631751470962234105835015158485760721979732297206950719908744248285672032436598213262204039212897239890934116841559005147755270269705682414708355646603,
0.0938443990808045656391802376681172600361000757462364500506275696355695118623098075097804207682530277555307864917078828352419853248607668520631751470962234105835015158485760721979732297206950719908744248285672032436598213262204039212897239890934116841559005147755270269705682414708355646603,
0.0911738786957638847128685771116370625448614132753900053231278739777031520613017513597426417145878622654027367650308019870251963114683369110451524174258161390823876554910693202594383388549640738095422966058367070348943662290656339592299608558384147559830707904449930677260444604329157917977,
0.0911738786957638847128685771116370625448614132753900053231278739777031520613017513597426417145878622654027367650308019870251963114683369110451524174258161390823876554910693202594383388549640738095422966058367070348943662290656339592299608558384147559830707904449930677260444604329157917977,
0.0876520930044038111427714627518022875484497217017572223192228034747061150211380239263021665771581379364685191248848158059408000065275041643745927401342920150588893827207354226012701872322225514682178439577327346929209121046816487338309068375228210705166692551938339727096609740531893725675,
0.0876520930044038111427714627518022875484497217017572223192228034747061150211380239263021665771581379364685191248848158059408000065275041643745927401342920150588893827207354226012701872322225514682178439577327346929209121046816487338309068375228210705166692551938339727096609740531893725675,
0.0833119242269467552221990746043486115387468839428344598401864047287594069244380966536255650452315042012372905572506028852130723585016898197140339352228963465326746426938359210160503509807644396182380868089959855742801355208471205261406307895519604387550841954817025499019984032594036141439,
0.0833119242269467552221990746043486115387468839428344598401864047287594069244380966536255650452315042012372905572506028852130723585016898197140339352228963465326746426938359210160503509807644396182380868089959855742801355208471205261406307895519604387550841954817025499019984032594036141439,
0.078193895787070306471740918828306671039786798482159190307481553869493700115196435401943819761440851294456424770323467367505109006517482028994114252939401250416132320553639542341400437522236191275346323130525969269563653003188829786549728825182082678498917784036375053244425839341945385297,
0.078193895787070306471740918828306671039786798482159190307481553869493700115196435401943819761440851294456424770323467367505109006517482028994114252939401250416132320553639542341400437522236191275346323130525969269563653003188829786549728825182082678498917784036375053244425839341945385297,
0.0723457941088485062253993564784877916043369833018248707397632823511765345816800402874475958591657429073027694582930574378890633404841054620298756279975430795706338162404545590689277985270140590721779502609564199074051863640176937117952488466002340085264819537808079947788437998042296495822,
0.0723457941088485062253993564784877916043369833018248707397632823511765345816800402874475958591657429073027694582930574378890633404841054620298756279975430795706338162404545590689277985270140590721779502609564199074051863640176937117952488466002340085264819537808079947788437998042296495822,
0.0658222227763618468376500637069387728775364473732465153710916696852412442018627316280044447764609054151761388378861151807154113495715653711918644796313239555117970398473141615070299152284100887258072240524028885129828725430021172354299810423059697133688823072212214503334259555369485963074,
0.0658222227763618468376500637069387728775364473732465153710916696852412442018627316280044447764609054151761388378861151807154113495715653711918644796313239555117970398473141615070299152284100887258072240524028885129828725430021172354299810423059697133688823072212214503334259555369485963074,
0.0586840934785355471452836373001708867501204674575467587150032786132877518019090643743123653437052116901895704813134467814193905269714480573030647540887991405215103758723074481312705449946311993670933802369300463315125015975216910705047901943865293781921122370996257470349807212516159332678,
0.0586840934785355471452836373001708867501204674575467587150032786132877518019090643743123653437052116901895704813134467814193905269714480573030647540887991405215103758723074481312705449946311993670933802369300463315125015975216910705047901943865293781921122370996257470349807212516159332678,
0.0509980592623761761961632446895216952601847767397628437069071236525030510385137821267442193868358292147899714519363571211100873456269865150186456681043804358654826791768545393024953758025593924464295555854744882720755747096079325496814455853004350452095212995888025282619932613606999567133,
0.0509980592623761761961632446895216952601847767397628437069071236525030510385137821267442193868358292147899714519363571211100873456269865150186456681043804358654826791768545393024953758025593924464295555854744882720755747096079325496814455853004350452095212995888025282619932613606999567133,
0.0428358980222266806568786466061255284928108575989407395620219408911043916962572261359138025961596979511472539467367407419206021900868371610612953162236233351132214438513203223655531564777278515080476421262443325932320214191168239648611793958596884827086182431203349730049744697408543115307,
0.0428358980222266806568786466061255284928108575989407395620219408911043916962572261359138025961596979511472539467367407419206021900868371610612953162236233351132214438513203223655531564777278515080476421262443325932320214191168239648611793958596884827086182431203349730049744697408543115307,
0.0342738629130214331026877322523727069948402029116274337814057454192310522168984446294442724624445760666244242305266023810860790282088335398182296698622433517061843276344829146573593201201081743714879684153735672789104567624853712011151505225193933019375481618760594889854480408562043658635,
0.0342738629130214331026877322523727069948402029116274337814057454192310522168984446294442724624445760666244242305266023810860790282088335398182296698622433517061843276344829146573593201201081743714879684153735672789104567624853712011151505225193933019375481618760594889854480408562043658635,
0.0253920653092620594557525897892240292875540475469487209362512822192154788532376645960457016338988332029324531233401833547954942765653767672102838323550828207273795044402516181251040411735351747299230615776597356956641506445501689924551185923348003766988424170511157069264716719906995309826,
0.0253920653092620594557525897892240292875540475469487209362512822192154788532376645960457016338988332029324531233401833547954942765653767672102838323550828207273795044402516181251040411735351747299230615776597356956641506445501689924551185923348003766988424170511157069264716719906995309826,
0.0162743947309056706051705622063866181795429637952095664295931749613369651752917857651844425586692833071042366002861684552859449530958901379260437604156888337987656773068694383447504913457771896770689760342192010638946676879735404121702279005140285599424477022083127753774756520463311689155,
0.0162743947309056706051705622063866181795429637952095664295931749613369651752917857651844425586692833071042366002861684552859449530958901379260437604156888337987656773068694383447504913457771896770689760342192010638946676879735404121702279005140285599424477022083127753774756520463311689155,
0.0070186100094700966004070637388531825133772207289396032320082356192151241454178686953297376907573215077936155545790593837513204206518026084505878987243348925784479817181234617862457418214505322067610482902501455504204433524520665822704844582452877416001060465891907497519632353148380799619,
0.0070186100094700966004070637388531825133772207289396032320082356192151241454178686953297376907573215077936155545790593837513204206518026084505878987243348925784479817181234617862457418214505322067610482902501455504204433524520665822704844582452877416001060465891907497519632353148380799619
};
#endif

View File

@ -82,6 +82,8 @@ struct _GskCurveClass
graphene_point_t *value);
int (* get_crossing) (const GskCurve *curve,
const graphene_point_t *point);
float (* get_length_to) (const GskCurve *curve,
float t);
};
/* {{{ Utilities */
@ -182,6 +184,30 @@ gsk_curve_elevate (const GskCurve *curve,
g_assert_not_reached ();
}
/* Compute arclength by using Gauss quadrature on
*
* \int_0^z \sqrt{ (dx/dt)^2 + (dy/dt)^2 } dt
*/
#include "gskcurve-ct-values.c"
static float
get_length_by_approximation (const GskCurve *curve,
float t)
{
double z = t / 2;
double sum = 0;
graphene_point_t d;
for (unsigned int i = 0; i < G_N_ELEMENTS (T); i++)
{
gsk_curve_get_derivative_at (curve, z * T[i] + z, &d);
sum += C[i] * sqrt (d.x * d.x + d.y * d.y);
}
return z * sum;
}
/* }}} */
/* {{{ Line */
@ -325,12 +351,13 @@ gsk_line_curve_segment (const GskCurve *curve,
GskCurve *segment)
{
const GskLineCurve *self = &curve->line;
graphene_point_t start_point, end_point;
const graphene_point_t *pts = self->points;
graphene_point_t p0, p1;
graphene_point_interpolate (&self->points[0], &self->points[1], start, &start_point);
graphene_point_interpolate (&self->points[0], &self->points[1], end, &end_point);
graphene_point_interpolate (&pts[0], &pts[1], start, &p0);
graphene_point_interpolate (&pts[0], &pts[1], end, &p1);
gsk_line_curve_init_from_points (&segment->line, GSK_PATH_LINE, &start_point, &end_point);
gsk_line_curve_init_from_points (&segment->line, GSK_PATH_LINE, &p0, &p1);
}
static gboolean
@ -340,8 +367,9 @@ gsk_line_curve_decompose (const GskCurve *curve,
gpointer user_data)
{
const GskLineCurve *self = &curve->line;
const graphene_point_t *pts = self->points;
return add_line_func (&self->points[0], &self->points[1], 0.0f, 1.0f, GSK_CURVE_LINE_REASON_STRAIGHT, user_data);
return add_line_func (&pts[0], &pts[1], 0.f, 1.f, GSK_CURVE_LINE_REASON_STRAIGHT, user_data);
}
static gboolean
@ -372,16 +400,30 @@ gsk_line_curve_get_derivative_at (const GskCurve *curve,
graphene_point_t *value)
{
const GskLineCurve *self = &curve->line;
const graphene_point_t *pts = self->points;
value->x = self->points[1].x - self->points[0].x;
value->y = self->points[1].y - self->points[0].y;
value->x = pts[1].x - pts[0].x;
value->y = pts[1].y - pts[0].y;
}
static int
gsk_line_curve_get_crossing (const GskCurve *curve,
const graphene_point_t *point)
{
return line_get_crossing (point, gsk_curve_get_start_point (curve), gsk_curve_get_end_point (curve));
const GskLineCurve *self = &curve->line;
const graphene_point_t *pts = self->points;
return line_get_crossing (point, &pts[0], &pts[1]);
}
static float
gsk_line_curve_get_length_to (const GskCurve *curve,
float t)
{
const GskLineCurve *self = &curve->line;
const graphene_point_t *pts = self->points;
return t * graphene_point_distance (&pts[0], &pts[1], NULL, NULL);
}
static const GskCurveClass GSK_LINE_CURVE_CLASS = {
@ -405,6 +447,7 @@ static const GskCurveClass GSK_LINE_CURVE_CLASS = {
gsk_line_curve_get_bounds,
gsk_line_curve_get_derivative_at,
gsk_line_curve_get_crossing,
gsk_line_curve_get_length_to,
};
/* }}} */
@ -778,6 +821,13 @@ gsk_quad_curve_get_crossing (const GskCurve *curve,
return get_crossing_by_bisection (curve, point);
}
static float
gsk_quad_curve_get_length_to (const GskCurve *curve,
float t)
{
return get_length_by_approximation (curve, t);
}
static const GskCurveClass GSK_QUAD_CURVE_CLASS = {
gsk_quad_curve_init,
gsk_quad_curve_init_foreach,
@ -799,9 +849,10 @@ static const GskCurveClass GSK_QUAD_CURVE_CLASS = {
gsk_quad_curve_get_tight_bounds,
gsk_quad_curve_get_derivative_at,
gsk_quad_curve_get_crossing,
gsk_quad_curve_get_length_to,
};
/* }}} */
/* }}} */
/* {{{ Cubic */
static void
@ -1240,6 +1291,13 @@ gsk_cubic_curve_get_crossing (const GskCurve *curve,
return get_crossing_by_bisection (curve, point);
}
static float
gsk_cubic_curve_get_length_to (const GskCurve *curve,
float t)
{
return get_length_by_approximation (curve, t);
}
static const GskCurveClass GSK_CUBIC_CURVE_CLASS = {
gsk_cubic_curve_init,
gsk_cubic_curve_init_foreach,
@ -1261,9 +1319,10 @@ static const GskCurveClass GSK_CUBIC_CURVE_CLASS = {
gsk_cubic_curve_get_tight_bounds,
gsk_cubic_curve_get_derivative_at,
gsk_cubic_curve_get_crossing,
gsk_cubic_curve_get_length_to,
};
/* }}} */
/* }}} */
/* {{{ Conic */
static inline float
@ -1926,6 +1985,13 @@ gsk_conic_curve_get_crossing (const GskCurve *curve,
return get_crossing_by_bisection (curve, point);
}
static float
gsk_conic_curve_get_length_to (const GskCurve *curve,
float t)
{
return get_length_by_approximation (curve, t);
}
static const GskCurveClass GSK_CONIC_CURVE_CLASS = {
gsk_conic_curve_init,
gsk_conic_curve_init_foreach,
@ -1947,9 +2013,10 @@ static const GskCurveClass GSK_CONIC_CURVE_CLASS = {
gsk_conic_curve_get_tight_bounds,
gsk_conic_curve_get_derivative_at,
gsk_conic_curve_get_crossing,
gsk_conic_curve_get_length_to,
};
/* }}} */
/* }}} */
/* {{{ API */
static const GskCurveClass *
@ -2275,6 +2342,161 @@ gsk_curve_get_closest_point (const GskCurve *curve,
return find_closest_point (curve, point, threshold, 0, 1, out_dist, out_t);
}
float
gsk_curve_get_length_to (const GskCurve *curve,
float t)
{
return get_class (curve->op)->get_length_to (curve, t);
}
float
gsk_curve_get_length (const GskCurve *curve)
{
return gsk_curve_get_length_to (curve, 1);
}
/* Compute the inverse of the arclength using bisection,
* to a given precision
*/
float
gsk_curve_at_length (const GskCurve *curve,
float length,
float epsilon)
{
float t1, t2, t, l;
GskCurve c1;
g_assert (epsilon >= FLT_EPSILON);
t1 = 0;
t2 = 1;
while (t1 < t2)
{
t = (t1 + t2) / 2;
if (t == t1 || t == t2)
break;
gsk_curve_split (curve, t, &c1, NULL);
l = gsk_curve_get_length (&c1);
if (fabsf (length - l) < epsilon)
break;
else if (l < length)
t1 = t;
else
t2 = t;
}
return t;
}
static inline void
_sincosf (float angle,
float *out_s,
float *out_c)
{
#ifdef HAVE_SINCOSF
sincosf (angle, out_s, out_c);
#else
*out_s = sinf (angle);
*out_c = cosf (angle);
#endif
}
static void
align_points (const graphene_point_t *p,
const graphene_point_t *a,
const graphene_point_t *b,
graphene_point_t *q,
int n)
{
graphene_vec2_t n1;
float angle;
float s, c;
get_tangent (a, b, &n1);
angle = - atan2f (graphene_vec2_get_y (&n1), graphene_vec2_get_x (&n1));
_sincosf (angle, &s, &c);
for (int i = 0; i < n; i++)
{
q[i].x = (p[i].x - a->x) * c - (p[i].y - a->y) * s;
q[i].y = (p[i].x - a->x) * s + (p[i].y - a->y) * c;
}
}
static int
filter_allowable (float t[3],
int n)
{
float g[3];
int j = 0;
for (int i = 0; i < n; i++)
if (0 < t[i] && t[i] < 1)
g[j++] = t[i];
for (int i = 0; i < j; i++)
t[i] = g[i];
return j;
}
/* find solutions for at^2 + bt + c = 0 */
static int
solve_quadratic (float a, float b, float c, float t[2])
{
float d;
int n = 0;
if (fabsf (a) > 0.0001)
{
if (b*b > 4*a*c)
{
d = sqrtf (b*b - 4*a*c);
t[n++] = (-b + d)/(2*a);
t[n++] = (-b - d)/(2*a);
}
else
{
t[n++] = -b / (2*a);
}
}
else if (fabsf (b) > 0.0001)
{
t[n++] = -c / b;
}
return n;
}
int
gsk_curve_get_curvature_points (const GskCurve *curve,
float t[3])
{
const graphene_point_t *pts = curve->cubic.points;
graphene_point_t p[4];
float a, b, c, d;
float x, y, z;
int n;
if (curve->op != GSK_PATH_CUBIC)
return 0; /* FIXME */
align_points (pts, &pts[0], &pts[3], p, 4);
a = p[2].x * p[1].y;
b = p[3].x * p[1].y;
c = p[1].x * p[2].y;
d = p[3].x * p[2].y;
x = - 3*a + 2*b + 3*c - d;
y = 3*a - b - 3*c;
z = c - a;
n = solve_quadratic (x, y, z, t);
return filter_allowable (t, n);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@ -174,6 +174,16 @@ gboolean gsk_curve_get_closest_point (const GskCurve
float threshold,
float *out_dist,
float *out_t);
float gsk_curve_get_length (const GskCurve *curve);
float gsk_curve_get_length_to (const GskCurve *curve,
float t);
float gsk_curve_at_length (const GskCurve *curve,
float distance,
float epsilon);
int gsk_curve_get_curvature_points (const GskCurve * curve,
float t[3]);
G_END_DECLS

327
gsk/gskpathmeasure.c Normal file
View File

@ -0,0 +1,327 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gskpathmeasure.h"
#include "gskpathbuilder.h"
#include "gskpathpointprivate.h"
#include "gskpathprivate.h"
/**
* GskPathMeasure:
*
* `GskPathMeasure` is an object that allows measurements
* on `GskPath`s such as determining the length of the path.
*
* Many measuring operations require sampling the path length
* at intermediate points. Therefore, a `GskPathMeasure` has
* a tolerance that determines what precision is required
* for such approximations.
*
* A `GskPathMeasure` struct is a reference counted struct
* and should be treated as opaque.
*/
typedef struct _GskContourMeasure GskContourMeasure;
struct _GskContourMeasure
{
float length;
gpointer contour_data;
};
struct _GskPathMeasure
{
/*< private >*/
guint ref_count;
GskPath *path;
float tolerance;
float length;
gsize n_contours;
GskContourMeasure measures[];
};
G_DEFINE_BOXED_TYPE (GskPathMeasure, gsk_path_measure,
gsk_path_measure_ref,
gsk_path_measure_unref)
/**
* gsk_path_measure_new:
* @path: the path to measure
*
* Creates a measure object for the given @path.
*
* Returns: a new `GskPathMeasure` representing @path
*
* Since: 4.14
*/
GskPathMeasure *
gsk_path_measure_new (GskPath *path)
{
return gsk_path_measure_new_with_tolerance (path, GSK_PATH_TOLERANCE_DEFAULT);
}
/**
* gsk_path_measure_new_with_tolerance:
* @path: the path to measure
* @tolerance: the tolerance for measuring operations
*
* Creates a measure object for the given @path and @tolerance.
*
* Returns: a new `GskPathMeasure` representing @path
*
* Since: 4.14
*/
GskPathMeasure *
gsk_path_measure_new_with_tolerance (GskPath *path,
float tolerance)
{
GskPathMeasure *self;
gsize i, n_contours;
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (tolerance > 0, NULL);
n_contours = gsk_path_get_n_contours (path);
self = g_malloc0 (sizeof (GskPathMeasure) + n_contours * sizeof (GskContourMeasure));
self->ref_count = 1;
self->path = gsk_path_ref (path);
self->tolerance = tolerance;
self->n_contours = n_contours;
for (i = 0; i < n_contours; i++)
{
self->measures[i].contour_data = gsk_contour_init_measure (gsk_path_get_contour (path, i),
self->tolerance,
&self->measures[i].length);
self->length += self->measures[i].length;
}
return self;
}
/**
* gsk_path_measure_ref:
* @self: a `GskPathMeasure`
*
* Increases the reference count of a `GskPathMeasure` by one.
*
* Returns: the passed in `GskPathMeasure`.
*
* Since: 4.14
*/
GskPathMeasure *
gsk_path_measure_ref (GskPathMeasure *self)
{
g_return_val_if_fail (self != NULL, NULL);
self->ref_count++;
return self;
}
/**
* gsk_path_measure_unref:
* @self: a `GskPathMeasure`
*
* Decreases the reference count of a `GskPathMeasure` by one.
*
* If the resulting reference count is zero, frees the object.
*
* Since: 4.14
*/
void
gsk_path_measure_unref (GskPathMeasure *self)
{
gsize i;
g_return_if_fail (self != NULL);
g_return_if_fail (self->ref_count > 0);
self->ref_count--;
if (self->ref_count > 0)
return;
for (i = 0; i < self->n_contours; i++)
{
gsk_contour_free_measure (gsk_path_get_contour (self->path, i),
self->measures[i].contour_data);
}
gsk_path_unref (self->path);
g_free (self);
}
/**
* gsk_path_measure_get_path:
* @self: a `GskPathMeasure`
*
* Returns the path that the measure was created for.
*
* Returns: (transfer none): the path of @self
*
* Since: 4.14
*/
GskPath *
gsk_path_measure_get_path (GskPathMeasure *self)
{
return self->path;
}
/**
* gsk_path_measure_get_tolerance:
* @self: a `GskPathMeasure`
*
* Returns the tolerance that the measure was created with.
*
* Returns: the tolerance of @self
*
* Since: 4.14
*/
float
gsk_path_measure_get_tolerance (GskPathMeasure *self)
{
return self->tolerance;
}
/**
* gsk_path_measure_get_length:
* @self: a `GskPathMeasure`
*
* Gets the length of the path being measured.
*
* The length is cached, so this function does not do any work.
*
* Returns: The length of the path measured by @self
*
* Since: 4.14
*/
float
gsk_path_measure_get_length (GskPathMeasure *self)
{
g_return_val_if_fail (self != NULL, 0);
return self->length;
}
static float
gsk_path_measure_clamp_distance (GskPathMeasure *self,
float distance)
{
if (isnan (distance))
return 0;
return CLAMP (distance, 0, self->length);
}
/**
* gsk_path_measure_get_point:
* @self: a `GskPathMeasure`
* @distance: the distance
* @result: (out caller-allocates): return location for the result
*
* Sets @result to the point at the given distance into the path.
*
* An empty path has no points, so `FALSE` is returned in that case.
*
* Returns: `TRUE` if @result was set
*
* Since: 4.14
*/
gboolean
gsk_path_measure_get_point (GskPathMeasure *self,
float distance,
GskPathPoint *result)
{
GskRealPathPoint *res = (GskRealPathPoint *) result;
gsize i;
const GskContour *contour;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (result != NULL, FALSE);
if (self->n_contours == 0)
return FALSE;
distance = gsk_path_measure_clamp_distance (self, distance);
for (i = 0; i < self->n_contours - 1; i++)
{
if (distance < self->measures[i].length)
break;
distance -= self->measures[i].length;
}
g_assert (0 <= i && i < self->n_contours);
distance = CLAMP (distance, 0, self->measures[i].length);
contour = gsk_path_get_contour (self->path, i);
gsk_contour_get_point (contour, self->measures[i].contour_data, distance, res);
res->contour = i;
return TRUE;
}
/**
* gsk_path_point_get_distance:
* @point: a `GskPathPoint on the path
* @measure: a `GskPathMeasure` for the path
*
* Returns the distance from the beginning of the path
* to @point.
*
* Returns: the distance of @point
*
* Since: 4.14
*/
float
gsk_path_point_get_distance (const GskPathPoint *point,
GskPathMeasure *measure)
{
GskRealPathPoint *p = (GskRealPathPoint *)point;
const GskContour *contour;
float contour_offset = 0;
g_return_val_if_fail (point != NULL, 0);
g_return_val_if_fail (measure != NULL, 0);
g_return_val_if_fail (p->contour < measure->n_contours, 0);
contour = gsk_path_get_contour (measure->path, p->contour);
for (gsize i = 0; i < measure->n_contours; i++)
{
if (contour == gsk_path_get_contour (measure->path, i))
return contour_offset + gsk_contour_get_distance (contour,
p,
measure->measures[i].contour_data);
contour_offset += measure->measures[i].length;
}
g_return_val_if_reached (0);
}

62
gsk/gskpathmeasure.h Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gskpath.h>
#include <gsk/gskpathpoint.h>
G_BEGIN_DECLS
#define GSK_TYPE_PATH_MEASURE (gsk_path_measure_get_type ())
GDK_AVAILABLE_IN_4_14
GType gsk_path_measure_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_14
GskPathMeasure * gsk_path_measure_new (GskPath *path);
GDK_AVAILABLE_IN_4_14
GskPathMeasure * gsk_path_measure_new_with_tolerance (GskPath *path,
float tolerance);
GDK_AVAILABLE_IN_4_14
GskPathMeasure * gsk_path_measure_ref (GskPathMeasure *self);
GDK_AVAILABLE_IN_4_14
void gsk_path_measure_unref (GskPathMeasure *self);
GDK_AVAILABLE_IN_4_14
GskPath * gsk_path_measure_get_path (GskPathMeasure *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
float gsk_path_measure_get_tolerance (GskPathMeasure *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
float gsk_path_measure_get_length (GskPathMeasure *self);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_measure_get_point (GskPathMeasure *self,
float distance,
GskPathPoint *result);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPathMeasure, gsk_path_measure_unref)
G_END_DECLS

View File

@ -78,5 +78,8 @@ float gsk_path_point_get_curvature (const GskPathPoint *poin
GskPathDirection direction,
graphene_point_t *center);
GDK_AVAILABLE_IN_4_14
float gsk_path_point_get_distance (const GskPathPoint *point,
GskPathMeasure *measure);
G_END_DECLS

View File

@ -27,6 +27,7 @@
typedef struct _GskPath GskPath;
typedef struct _GskPathBuilder GskPathBuilder;
typedef struct _GskPathMeasure GskPathMeasure;
typedef struct _GskPathPoint GskPathPoint;
typedef struct _GskRenderer GskRenderer;
typedef struct _GskRenderNode GskRenderNode;

View File

@ -28,6 +28,7 @@ gsk_public_sources = files([
'gskglshader.c',
'gskpath.c',
'gskpathbuilder.c',
'gskpathmeasure.c',
'gskpathpoint.c',
'gskrenderer.c',
'gskrendernode.c',
@ -75,6 +76,7 @@ gsk_public_headers = files([
'gskglshader.h',
'gskpath.h',
'gskpathbuilder.h',
'gskpathmeasure.h',
'gskpathpoint.h',
'gskrenderer.h',
'gskrendernode.h',

View File

@ -165,6 +165,8 @@ test_circle (void)
gsk_curve_get_end_tangent (&c, &tangent);
g_assert_true (graphene_vec2_equal (&tangent, graphene_vec2_init (&tangent2, -1, 0)));
g_assert_cmpfloat_with_epsilon (gsk_curve_get_length (&c), M_PI_2, 0.001);
for (int i = 1; i < 10; i++)
{
float t = i / 10.f;
@ -180,6 +182,25 @@ test_circle (void)
}
}
static void
test_curve_length (void)
{
GskCurve c, c1, c2;
float l, l1, l2, l1a;
parse_curve (&c, "M 1462.632080 -1593.118896 C 751.533630 -74.179169 -914.280090 956.537720 -83.091866 207.213776");
gsk_curve_split (&c, 0.5, &c1, &c2);
l = gsk_curve_get_length (&c);
l1a = gsk_curve_get_length_to (&c, 0.5);
l1 = gsk_curve_get_length (&c1);
l2 = gsk_curve_get_length (&c2);
g_assert_cmpfloat_with_epsilon (l1, l1a, 0.1);
g_assert_cmpfloat_with_epsilon (l, l1 + l2, 0.5);
}
int
main (int argc,
char *argv[])
@ -190,6 +211,7 @@ main (int argc,
g_test_add_func ("/curve/special/degenerate-tangents", test_curve_degenerate_tangents);
g_test_add_func ("/curve/special/crossing", test_curve_crossing);
g_test_add_func ("/curve/special/circle", test_circle);
g_test_add_func ("/curve/special/length", test_curve_length);
return g_test_run ();
}

View File

@ -197,8 +197,8 @@ test_curve_decompose (void)
gsk_curve_get_point (&c, (pol->t + last->t) / 2, &p);
/* The decomposer does this cheaper Manhattan distance test,
* so graphene_point_near() does not work */
g_assert_cmpfloat (fabs (mid.x - p.x), <=, tolerance);
g_assert_cmpfloat (fabs (mid.y - p.y), <=, tolerance);
g_assert_cmpfloat (fabs (mid.x - p.x), <=, tolerance + 0.0002);
g_assert_cmpfloat (fabs (mid.y - p.y), <=, tolerance + 0.0002);
}
}
}
@ -300,42 +300,56 @@ test_curve_decompose_into_cubic (void)
static void
test_curve_split (void)
{
for (int i = 0; i < 100; i++)
for (int i = 0; i < 20; i++)
{
GskCurve c;
GskCurve c1, c2;
graphene_point_t p;
graphene_vec2_t t, t1, t2;
init_random_curve (&c);
gsk_curve_split (&c, 0.5, &c1, &c2);
for (int j = 0; j < 20; j++)
{
GskCurve c1, c2;
graphene_point_t p;
graphene_vec2_t t, t1, t2;
float split;
g_assert_true (c1.op == c.op);
g_assert_true (c2.op == c.op);
split = g_test_rand_double_range (0.1, 0.9);
g_assert_true (graphene_point_near (gsk_curve_get_start_point (&c),
gsk_curve_get_start_point (&c1), 0.005));
g_assert_true (graphene_point_near (gsk_curve_get_end_point (&c1),
gsk_curve_get_start_point (&c2), 0.005));
g_assert_true (graphene_point_near (gsk_curve_get_end_point (&c),
gsk_curve_get_end_point (&c2), 0.005));
gsk_curve_get_point (&c, 0.5, &p);
gsk_curve_get_tangent (&c, 0.5, &t);
g_assert_true (graphene_point_near (gsk_curve_get_end_point (&c1), &p, 0.005));
g_assert_true (graphene_point_near (gsk_curve_get_start_point (&c2), &p, 0.005));
gsk_curve_split (&c, split, &c1, &c2);
gsk_curve_get_start_tangent (&c, &t1);
gsk_curve_get_start_tangent (&c1, &t2);
g_assert_true (graphene_vec2_near (&t1, &t2, 0.005));
gsk_curve_get_end_tangent (&c1, &t1);
gsk_curve_get_start_tangent (&c2, &t2);
g_assert_true (graphene_vec2_near (&t1, &t2, 0.005));
g_assert_true (graphene_vec2_near (&t, &t1, 0.005));
g_assert_true (graphene_vec2_near (&t, &t2, 0.005));
gsk_curve_get_end_tangent (&c, &t1);
gsk_curve_get_end_tangent (&c2, &t2);
g_assert_true (graphene_vec2_near (&t1, &t2, 0.005));
g_assert_true (c1.op == c.op);
g_assert_true (c2.op == c.op);
g_assert_true (graphene_point_near (gsk_curve_get_start_point (&c),
gsk_curve_get_start_point (&c1), 0.005));
g_assert_true (graphene_point_near (gsk_curve_get_end_point (&c1),
gsk_curve_get_start_point (&c2), 0.005));
g_assert_true (graphene_point_near (gsk_curve_get_end_point (&c),
gsk_curve_get_end_point (&c2), 0.005));
gsk_curve_get_point (&c, split, &p);
gsk_curve_get_tangent (&c, split, &t);
g_assert_true (graphene_point_near (gsk_curve_get_end_point (&c1), &p, 0.005));
g_assert_true (graphene_point_near (gsk_curve_get_start_point (&c2), &p, 0.005));
gsk_curve_get_start_tangent (&c, &t1);
gsk_curve_get_start_tangent (&c1, &t2);
g_assert_true (graphene_vec2_near (&t1, &t2, 0.005));
gsk_curve_get_end_tangent (&c1, &t1);
gsk_curve_get_start_tangent (&c2, &t2);
g_assert_true (graphene_vec2_near (&t1, &t2, 0.005));
g_assert_true (graphene_vec2_near (&t, &t1, 0.005));
g_assert_true (graphene_vec2_near (&t, &t2, 0.005));
gsk_curve_get_end_tangent (&c, &t1);
gsk_curve_get_end_tangent (&c2, &t2);
g_assert_true (graphene_vec2_near (&t1, &t2, 0.005));
#if 0
/* hard to guarantee this for totally random random curves */
g_assert_cmpfloat_with_epsilon (gsk_curve_get_length (&c),
gsk_curve_get_length (&c1) + gsk_curve_get_length (&c2),
1);
#endif
}
}
}
@ -363,6 +377,26 @@ test_curve_derivative (void)
}
}
static void
test_curve_length (void)
{
GskCurve c;
float l, l0;
for (int i = 0; i < 1000; i++)
{
init_random_curve (&c);
l = gsk_curve_get_length (&c);
l0 = graphene_point_distance (gsk_curve_get_start_point (&c),
gsk_curve_get_end_point (&c),
NULL, NULL);
g_assert_true (l >= l0 - 0.001);
if (c.op == GSK_PATH_LINE)
g_assert_cmpfloat_with_epsilon (l, l0, 0.001);
}
}
int
main (int argc, char *argv[])
{
@ -376,6 +410,7 @@ main (int argc, char *argv[])
g_test_add_func ("/curve/decompose-cubic", test_curve_decompose_into_cubic);
g_test_add_func ("/curve/split", test_curve_split);
g_test_add_func ("/curve/derivative", test_curve_derivative);
g_test_add_func ("/curve/length", test_curve_length);
return g_test_run ();
}

View File

@ -809,6 +809,72 @@ test_rounded_rect (void)
gsk_path_unref (path);
}
static void
test_circle (void)
{
GskPathBuilder *builder;
GskPath *path;
GskPathMeasure *measure;
float length;
builder = gsk_path_builder_new ();
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (0, 0), 1);
path = gsk_path_builder_free_to_path (builder);
measure = gsk_path_measure_new (path);
length = gsk_path_measure_get_length (measure);
g_assert_cmpfloat_with_epsilon (length, 2 * M_PI, 0.001);
gsk_path_measure_unref (measure);
gsk_path_unref (path);
}
static void
test_length (void)
{
GskPath *path, *path1, *path2;
GskPathMeasure *measure, *measure1, *measure2;
GskPathBuilder *builder;
GskPathPoint point, start, end;
float length, length1, length2;
float distance;
float tolerance = 0.1;
path = gsk_path_parse ("M 0 0 Q 0 0 5 5");
measure = gsk_path_measure_new_with_tolerance (path, tolerance);
length = gsk_path_measure_get_length (measure);
gsk_path_get_start_point (path, &start);
gsk_path_get_end_point (path, &end);
gsk_path_measure_get_point (measure, length / 2, &point);
distance = gsk_path_point_get_distance (&point, measure);
g_assert_cmpfloat_with_epsilon (length / 2, distance, 0.1);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &start, &point);
path1 = gsk_path_builder_free_to_path (builder);
measure1 = gsk_path_measure_new_with_tolerance (path1, tolerance);
length1 = gsk_path_measure_get_length (measure1);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point, &end);
path2 = gsk_path_builder_free_to_path (builder);
measure2 = gsk_path_measure_new_with_tolerance (path2, tolerance);
length2 = gsk_path_measure_get_length (measure2);
g_assert_cmpfloat_with_epsilon (length, length1 + length2, tolerance);
gsk_path_unref (path);
gsk_path_unref (path1);
gsk_path_unref (path2);
gsk_path_measure_unref (measure);
gsk_path_measure_unref (measure1);
gsk_path_measure_unref (measure2);
}
int
main (int argc, char *argv[])
{
@ -825,6 +891,8 @@ main (int argc, char *argv[])
g_test_add_func ("/path/builder/add", test_path_builder_add);
g_test_add_func ("/path/rotated-arc", test_rotated_arc);
g_test_add_func ("/path/rounded-rect", test_rounded_rect);
g_test_add_func ("/path/circle", test_circle);
g_test_add_func ("/path/length", test_length);
return g_test_run ();
}

View File

@ -780,6 +780,199 @@ test_in_fill_rotated (void)
#undef N_FILL_RULES
}
static void
test_split (void)
{
GskPath *path, *path1, *path2;
GskPathMeasure *measure, *measure1, *measure2;
float length, length1, length2;
GskPathBuilder *builder;
float split, epsilon;
GskPathPoint point0, point1, point2;
float tolerance = 0.5;
for (int i = 0; i < 100; i++)
{
if (g_test_verbose ())
g_test_message ("path %u", i);
path = create_random_path (1);
measure = gsk_path_measure_new_with_tolerance (path, tolerance);
length = gsk_path_measure_get_length (measure);
/* chosen high enough to stop the testsuite from failing */
epsilon = MAX (length / 1000, 1.f / 1024);
split = g_test_rand_double_range (0, length);
if (!gsk_path_get_start_point (path, &point0) ||
!gsk_path_measure_get_point (measure, split, &point1) ||
!gsk_path_get_end_point (path, &point2))
{
gsk_path_unref (path);
gsk_path_measure_unref (measure);
continue;
}
if (gsk_path_point_equal (&point0, &point1) ||
gsk_path_point_equal (&point1, &point2))
{
gsk_path_unref (path);
gsk_path_measure_unref (measure);
continue;
}
g_assert_true (gsk_path_point_compare (&point0, &point1) < 0);
g_assert_true (gsk_path_point_compare (&point1, &point2) < 0);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point0, &point1);
path1 = gsk_path_builder_free_to_path (builder);
measure1 = gsk_path_measure_new_with_tolerance (path1, tolerance);
length1 = gsk_path_measure_get_length (measure1);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point1, &point2);
path2 = gsk_path_builder_free_to_path (builder);
measure2 = gsk_path_measure_new_with_tolerance (path2, tolerance);
length2 = gsk_path_measure_get_length (measure2);
g_assert_cmpfloat_with_epsilon (length, length1 + length2, epsilon);
gsk_path_unref (path2);
gsk_path_unref (path1);
gsk_path_unref (path);
gsk_path_measure_unref (measure2);
gsk_path_measure_unref (measure1);
gsk_path_measure_unref (measure);
}
}
static void
test_roundtrip (void)
{
GskPath *path;
GskPathMeasure *measure;
float length;
float split, epsilon;
GskPathPoint point;
float distance;
float tolerance = 0.5;
for (int i = 0; i < 100; i++)
{
if (g_test_verbose ())
g_test_message ("path %u", i);
path = create_random_path (1);
measure = gsk_path_measure_new_with_tolerance (path, tolerance);
length = gsk_path_measure_get_length (measure);
/* chosen high enough to stop the testsuite from failing */
epsilon = MAX (length / 1000, 1.f / 1024);
split = g_test_rand_double_range (0, length);
if (!gsk_path_measure_get_point (measure, split, &point))
{
gsk_path_unref (path);
gsk_path_measure_unref (measure);
continue;
}
distance = gsk_path_point_get_distance (&point, measure);
g_assert_cmpfloat_with_epsilon (split, distance, epsilon);
gsk_path_unref (path);
gsk_path_measure_unref (measure);
}
}
static void
test_segment (void)
{
GskPath *path, *path1, *path2, *path3;
GskPathMeasure *measure, *measure1, *measure2, *measure3;
GskPathPoint point0, point1, point2, point3;
float length, length1, length2, length3;
GskPathBuilder *builder;
float split1, split2, epsilon;
float tolerance = 0.5;
for (int i = 0; i < 100; i++)
{
if (g_test_verbose ())
g_test_message ("path %u", i);
path = create_random_path (G_MAXUINT);
measure = gsk_path_measure_new_with_tolerance (path, tolerance);
length = gsk_path_measure_get_length (measure);
/* We are accumulating both the split error and the roundtrip error
* here (on both ends, for the middle segment). So we should expect
* the epsilon here to be at least 4 times the epsilon we can use
* in the split and roundtrip tests.
*/
epsilon = MAX (length / 200, 1.f / 1024);
split1 = g_test_rand_double_range (0, length);
split2 = g_test_rand_double_range (split1, length);
if (!gsk_path_get_start_point (path, &point0) ||
!gsk_path_measure_get_point (measure, split1, &point1) ||
!gsk_path_measure_get_point (measure, split2, &point2) ||
!gsk_path_get_end_point (path, &point3))
{
gsk_path_unref (path);
gsk_path_measure_unref (measure);
continue;
}
if (gsk_path_point_equal (&point0, &point1) ||
gsk_path_point_equal (&point1, &point2) ||
gsk_path_point_equal (&point2, &point3))
{
gsk_path_unref (path);
gsk_path_measure_unref (measure);
continue;
}
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point0, &point1);
path1 = gsk_path_builder_free_to_path (builder);
measure1 = gsk_path_measure_new_with_tolerance (path1, tolerance);
length1 = gsk_path_measure_get_length (measure1);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point1, &point2);
path2 = gsk_path_builder_free_to_path (builder);
measure2 = gsk_path_measure_new_with_tolerance (path2, tolerance);
length2 = gsk_path_measure_get_length (measure2);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point2, &point3);
path3 = gsk_path_builder_free_to_path (builder);
measure3 = gsk_path_measure_new_with_tolerance (path3, tolerance);
length3 = gsk_path_measure_get_length (measure3);
g_assert_cmpfloat_with_epsilon (split1, length1, epsilon);
g_assert_cmpfloat_with_epsilon (split2, length1 + length2, epsilon);
g_assert_cmpfloat_with_epsilon (length, length1 + length2 + length3, epsilon);
gsk_path_unref (path3);
gsk_path_unref (path2);
gsk_path_unref (path1);
gsk_path_unref (path);
gsk_path_measure_unref (measure3);
gsk_path_measure_unref (measure2);
gsk_path_measure_unref (measure1);
gsk_path_measure_unref (measure);
}
}
int
main (int argc,
char *argv[])
@ -790,6 +983,9 @@ main (int argc,
g_test_add_func ("/path/parse", test_parse);
g_test_add_func ("/path/in-fill-union", test_in_fill_union);
g_test_add_func ("/path/in-fill-rotated", test_in_fill_rotated);
g_test_add_func ("/path/measure/split", test_split);
g_test_add_func ("/path/measure/roundtrip", test_roundtrip);
g_test_add_func ("/path/measure/segment", test_segment);
return g_test_run ();
}