static void path_calc_values_by_position (GeglPathList *path,
gdouble *pos_samples,
guint num_samples,
gdouble *xs,
gdouble *ys)
In the case of brush strokes, that would particularly fit spacing dynamics, and other cases which requires computing unevenly distributed points along the path.
It could also be applied to curves
use case :
compute_paint_dabs_positions (spacing_curve, n_dabs, dabs_pos);
gegl_path_calc_by_pos (path, dabs_pos, n_dabs, xs, ys);
gegl_curve_calc_by_pos (size_curve, dabs_pos, n_dabs, dabs_sizes);
...
for (i=0; i<n_dabs, i++)
stamp (buffer, stamp_buffer, dabs_pos[i], dabs_sizes[i], ...);
Attached patch obsoletes the previous one.
Regards.
Damien
From e132ff5b6b83405e12d4c3dce0e18ed2a453fae1 Mon Sep 17 00:00:00 2001 From: Damien de Lemeny <d.delemeny@xxxxxxxxx> Date: Sun, 30 May 2010 04:52:11 +0200 Subject: [PATCH] Refactor [gegl_]path_calc_values * moded gegl/property-types/gegl-path.[c|h] Add pos_min and pos_max parameters to get sample points on an arbitrary portion of the path This reduces code and should be very useful to extract gegl_path_stroke in a proper operation. Make path_calc_values return start point if num_samples == 1 Add gegl_path_calc_by_pos function --- gegl/property-types/gegl-path.c | 255 +++++++++++++++++---------------------- gegl/property-types/gegl-path.h | 23 ++++- 2 files changed, 135 insertions(+), 143 deletions(-) diff --git a/gegl/property-types/gegl-path.c b/gegl/property-types/gegl-path.c index bf514ca..8b2a1dc 100644 --- a/gegl/property-types/gegl-path.c +++ b/gegl/property-types/gegl-path.c @@ -383,205 +383,168 @@ GeglPathList * gegl_path_list_append (GeglPathList *head, return head; } -static void -path_calc (GeglPathList *path, - gdouble pos, - gdouble *xd, - gdouble *yd) +static void path_calc_values (GeglPathList *path, + gdouble pos_min, + gdouble pos_max, + guint num_samples, + gdouble *xs, + gdouble *ys) { + gdouble length = path_get_length (path); GeglPathList *iter = path; - gfloat traveled_length = 0; - gfloat need_to_travel = 0; + + gint count_samples=0; + gfloat x = 0, y = 0; + gfloat spacing = 0; + gfloat pos = 0, next_pos = 0, next_sample = 0, start = pos_min, stop = pos_max; + gboolean to_end = FALSE; + + if ((pos_max > length) || (pos_max < pos_min)) + /* Use the last point of the path as end */ + { + stop = length; + count_samples++; + to_end = TRUE; + } + + spacing = (start - stop) / num_samples; + next_sample = start; while (iter) { - /*fprintf (stderr, "%c, %i %i\n", iter->d.type, iter->d.point[0].x, iter->d.point[0].y);*/ switch (iter->d.type) { case 'M': x = iter->d.point[0].x; y = iter->d.point[0].y; - need_to_travel = 0; - traveled_length = 0; break; - case 'L': { Point a,b; - - gfloat spacing; - gfloat local_pos; gfloat distance; - gfloat offset; - gfloat leftover; - - + a.x = x; a.y = y; - b.x = iter->d.point[0].x; b.y = iter->d.point[0].y; - - spacing = 0.2; - + distance = point_dist (&a, &b); - - leftover = need_to_travel - traveled_length; - offset = spacing - leftover; - - local_pos = offset; - - if (distance > 0) - for (; - local_pos <= distance; - local_pos += spacing) - { - Point spot; - gfloat ratio = local_pos / distance; - - lerp (&spot, &a, &b, ratio); - - traveled_length += spacing; - if (traveled_length > pos) - { - *xd = spot.x; - *yd = spot.y; - return; - } - } - - need_to_travel += distance; - - x = b.x; - y = b.y; - } - + next_pos += distance; + + while (next_pos > next_sample) + { + Point spot; + gfloat ratio = (next_sample - pos) / (next_pos - pos); + + lerp (&spot, &a, &b, ratio); + + xs[count_samples]=spot.x; + ys[count_samples]=spot.y; + + count_samples++; + if (count_samples < num_samples) + next_sample += spacing; + else + { + if (num_samples > 1 && to_end) + { + while (iter->next); + xs[num_samples-1]=b.x; + ys[num_samples-1]=b.y; + } + return; + } + } + x = b.x; + y = b.y; + } + break; + case 'u': + g_error ("can't compute length for uninitialized path\n"); break; case 's': break; default: - g_warning ("can't compute length for instruction: %c\n", iter->d.type); + g_error ("can't compute length for instruction: %i\n", iter->d.type); break; } iter=iter->next; } } -static void path_calc_values (GeglPathList *path, +static void path_calc_values_by_position (GeglPathList *path, + gdouble *pos_samples, guint num_samples, gdouble *xs, gdouble *ys) { gdouble length = path_get_length (path); + GeglPathList *iter = path; + gint i=0; - gfloat traveled_length = 0; - gfloat need_to_travel = 0; - gfloat x = 0,y = 0; - GeglPathList *iter; - gfloat spacing = length / num_samples; + + gfloat x = 0, y = 0; + gfloat pos = 0, next_pos = 0; - iter = path; while (iter) { - /*fprintf (stderr, "%c, %i %i\n", iter->d.type, iter->d.point[0].x, iter->d.point[0].y);*/ switch (iter->d.type) { case 'M': x = iter->d.point[0].x; y = iter->d.point[0].y; - need_to_travel = 0; - traveled_length = 0; break; case 'L': { Point a,b; - - gfloat local_pos; gfloat distance; - gfloat offset; - gfloat leftover; - - + a.x = x; a.y = y; - b.x = iter->d.point[0].x; b.y = iter->d.point[0].y; - + distance = point_dist (&a, &b); - - leftover = need_to_travel - traveled_length; - offset = spacing - leftover; - - local_pos = offset; - - if (distance > 0) - for (; - local_pos <= distance; - local_pos += spacing) - { - Point spot; - gfloat ratio = local_pos / distance; - - lerp (&spot, &a, &b, ratio); - - /*gegl_path_stamp (buffer, clip_rect, - spot.x, spot.y, radius, hardness, color, gopacity);*/ - xs[i]=spot.x; - ys[i]=spot.y; - - traveled_length += spacing; - i++; - } - if (!iter->next) + next_pos += distance; + + while (next_pos > pos_samples[i]) { - xs[num_samples-1]=b.x; - ys[num_samples-1]=b.y; + Point spot; + gfloat ratio = (pos_samples[i] - pos) / (next_pos - pos); + + lerp (&spot, &a, &b, ratio); + + xs[i]=spot.x; + ys[i]=spot.y; + + i++; + if (i >= num_samples) + return; + if (pos_samples[i] > length) + g_error("can't compute position out of path\n"); + return; + if (pos_samples[i] < pos_samples[i-1]) + g_error("requires sorted positions\n"); + return; } - - need_to_travel += distance; - - x = b.x; - y = b.y; - } - + x = b.x; + y = b.y; + } break; case 'u': - g_error ("stroking uninitialized path\n"); + g_error ("can't compute length for uninitialized path\n"); break; case 's': break; default: - g_error ("can't stroke for instruction: %i\n", iter->d.type); + g_error ("can't compute length for instruction: %i\n", iter->d.type); break; } iter=iter->next; } } -#if 0 -/* FIXME: this is terribly inefficient */ -static void -path_calc_values ( - GeglPathList *path, - guint num_samples, - gdouble *xs, - gdouble *ys) -{ - gdouble length = path_get_length (path); - gint i; - for (i=0; i<num_samples; i++) - { - gdouble x, y; - path_calc (path, (i*1.0)/num_samples * length, &x, &y); - - xs[i] = x; - ys[i] = y; - } -} -#endif - static gdouble path_get_length (GeglPathList *path) { @@ -796,12 +759,6 @@ static void ensure_flattened (GeglPath *vector) } static void -path_calc_values (GeglPathList *path, - guint num_samples, - gdouble *xs, - gdouble *ys); - -static void gegl_path_init (GeglPath *self) { GeglPathPrivate *priv; @@ -1002,7 +959,6 @@ void gegl_path_get_bounds (GeglPath *self, } - void gegl_path_calc (GeglPath *self, gdouble pos, @@ -1013,12 +969,14 @@ gegl_path_calc (GeglPath *self, if (!self) return; ensure_flattened (self); - path_calc (priv->flat_path, pos, xd, yd); + path_calc_values_by_position (priv->flat_path, &pos, 1, xd, yd); } void gegl_path_calc_values (GeglPath *self, + gdouble pos_min, + gdouble pos_max, guint num_samples, gdouble *xs, gdouble *ys) @@ -1027,10 +985,23 @@ gegl_path_calc_values (GeglPath *self, if (!self) return; ensure_flattened (self); - path_calc_values (priv->flat_path, num_samples, xs, ys); + path_calc_values (priv->flat_path, pos_min, pos_max, num_samples, xs, ys); } - +void +gegl_path_calc_by_pos (GeglPath *self, + gdouble *pos_samples, + guint num_samples, + gdouble *xs, + gdouble *ys) +{ + GeglPathPrivate *priv = GEGL_PATH_GET_PRIVATE (self); + if (!self) + return; + ensure_flattened (self); + /*XXX : should we make sure that pos_samples is sorted ? */ + path_calc_values_by_position (priv->flat_path, pos_samples, num_samples, xs, ys); +} /* -------------------------------------------------------------------------- * A GParamSpec class to describe behavior of GeglPath as an object property * follows. @@ -1621,7 +1592,7 @@ gegl_path_closest_point (GeglPath *path, return 0.0; } - gegl_path_calc_values (path, n, samples_x, samples_y); + gegl_path_calc_values (path, 0, -1, n, samples_x, samples_y); for (i=0;i<n;i++) { @@ -1800,7 +1771,7 @@ void gegl_path_fill (GeglBuffer *buffer, xs = g_newa (gdouble, samples); ys = g_newa (gdouble, samples); - path_calc_values (priv->flat_path, samples, xs, ys); + path_calc_values (priv->flat_path, 0, -1, samples, xs, ys); /* clear scanline intersection lists */ scanlines = g_newa (GSList*, extent.height * versubi); diff --git a/gegl/property-types/gegl-path.h b/gegl/property-types/gegl-path.h index e872e8a..fc51ed8 100644 --- a/gegl/property-types/gegl-path.h +++ b/gegl/property-types/gegl-path.h @@ -239,19 +239,40 @@ void gegl_path_calc (GeglPath *path, /** * gegl_path_calc_values: * @path: a #GeglPath + * @pos_min: start sampling position + * @pos_max: stop sampling position, -1 for the end of the path * @num_samples: number of samples to compute * @xs: return location for x coordinates * @ys: return location for y coordinates * * Copmute @num_samples for a path into the provided arrays @xs and @ys - * the returned values include the start and end positions of the path. + * the returned values include @pos_min and @pos_max. */ void gegl_path_calc_values (GeglPath *path, + gdouble pos_min, + gdouble pos_max, guint num_samples, gdouble *xs, gdouble *ys); /** + * gegl_path_calc_by_pos: + * @path: a #GeglPath + * @pos_samples: positions of the samples to compute, require a sorted array + * @num_samples: number of samples to compute + * @xs: return location for x coordinates + * @ys: return location for y coordinates + * + * Compute @num_samples for a path into the provided arrays @xs and @ys + * the returned values include the start and end positions of the path. + */ +void gegl_path_calc_by_pos (GeglPath *self, + gdouble *pos_samples, + guint num_samples, + gdouble *xs, + gdouble *ys); + +/** * gegl_path_get_bounds: * @self: a #GeglPath. * @min_x: return location for minimum x coordinate -- 1.6.3.3
_______________________________________________ Gegl-developer mailing list Gegl-developer@xxxxxxxxxxxxxxxxxxxxxx https://lists.XCF.Berkeley.EDU/mailman/listinfo/gegl-developer