Another way to go : give a sorted array of positions to compute along the
path.

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.delem...@gmail.com>
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@lists.XCF.Berkeley.EDU
https://lists.XCF.Berkeley.EDU/mailman/listinfo/gegl-developer

Reply via email to