gegl r2611 - in trunk: . gegl/property-types
- From: ok svn gnome org
- To: svn-commits-list gnome org
- Subject: gegl r2611 - in trunk: . gegl/property-types
- Date: Sat, 11 Oct 2008 14:42:13 +0000 (UTC)
Author: ok
Date: Sat Oct 11 14:42:12 2008
New Revision: 2611
URL: http://svn.gnome.org/viewvc/gegl?rev=2611&view=rev
Log:
* gegl/property-types/gegl-vector.c: bezier curve interpretation
rework. The path is now stored non-flattened, no API to introspect
and modify the points on the path yet though.
Modified:
trunk/ChangeLog
trunk/gegl/property-types/gegl-vector.c
Modified: trunk/gegl/property-types/gegl-vector.c
==============================================================================
--- trunk/gegl/property-types/gegl-vector.c (original)
+++ trunk/gegl/property-types/gegl-vector.c Sat Oct 11 14:42:12 2008
@@ -30,7 +30,9 @@
#include "gegl-color.h"
#include "gegl-utils.h"
-
+/* FIXME: relative commands are currently broken as they depend on
+ * a head sentinel
+ */
/* ###################################################################### */
/* path code copied from horizon */
@@ -59,62 +61,81 @@
gfloat y;
} Point;
-struct _Path
+typedef struct PathKnot
{
- Point point;
- Path *next;
- gchar type;
-};
-
-
+ gchar type; /* should perhaps be padded out? */
+ Point point[4];
+} PathKnot;
-typedef struct _Path Head;
-
-typedef struct _GeglVectorPrivate GeglVectorPrivate;
-typedef struct _VectorNameEntity VectorNameEntity;
-struct _GeglVectorPrivate
+struct _Path
{
- Path *path;
-
- Path *axis[8];
- gint n_axes;
-
- GeglRectangle dirtied;
+ PathKnot d;
+ Path *next;
};
-enum
+typedef struct KnotType
{
- PROP_0,
-};
+ gchar type;
+ gint pairs;
+ gchar *name;
+ Path *(*flatten) (Path *head, Path *prev, Path *self);
+} KnotType;
+#if 0
+/* it would be possible to compile paths like this into the library */
+static PathKnot test[] =
+ {{'m', {{0.0, 0.0}}},
+ {'l', {{20.0, 20.0}}},
+ {'C', {{20.0, 20.0}, {40, 40}, {50, 50}}}
+ };
+#endif
-enum
-{
- GEGL_VECTOR_CHANGED,
- GEGL_VECTOR_LAST_SIGNAL
+static Path *flatten_copy (Path *head, Path *prev, Path *self);
+static Path *flatten_nop (Path *head, Path *prev, Path *self);
+static Path *flatten_curve (Path *head, Path *prev, Path *self);
+
+/* FIXME: handling of relative commands should be moved to the flattening stage */
+
+/* this table should be possible to replace at runtime */
+
+static KnotType knot_types[]=
+{
+ {'m', 1, "rel move to", flatten_copy},
+ {'l', 1, "rel line to", flatten_copy},
+ {'M', 1, "move to", flatten_copy},
+ {'L', 1, "line to", flatten_copy},
+ {'c', 3, "curve to", flatten_curve},
+ {'s', 1, "sentinel", flatten_nop},
+ {'\0', 1, "curve to", flatten_copy},
};
-guint gegl_vector_signals[GEGL_VECTOR_LAST_SIGNAL] = { 0 };
-
-
-static void finalize (GObject *self);
-static void set_property (GObject *gobject,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void get_property (GObject *gobject,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-
-G_DEFINE_TYPE (GeglVector, gegl_vector, G_TYPE_OBJECT);
+static KnotType *find_knot_type(gchar type)
+{
+ gint i;
+ for (i=0; knot_types[i].type != '\0'; i++)
+ if (knot_types[i].type == type)
+ return &knot_types[i];
+ g_warning ("eeek didnt find knot type %c\n", type);
+ return NULL;
+}
-#define GEGL_VECTOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o),\
- GEGL_TYPE_VECTOR, GeglVectorPrivate))
+static Path *
+path_append (Path *head,
+ Path **res);
+static Path *flatten_nop (Path *head, Path *prev, Path *self)
+{
+ return head;
+}
-/*** subdivision bezier approximation: ***/
+static Path *flatten_copy (Path *head, Path *prev, Path *self)
+{
+ Path *newp;
+ head = path_append (head, &newp);
+ newp->d = self->d;
+ return head;
+}
/* linear interpolation between two point */
static void
@@ -135,33 +156,71 @@
(a->y-b->y)*(a->y-b->y));
}
-
-/* evaluate a point on a bezier-curve.
- * t goes from 0 to 65536
- *
- * curve contains four control points
- */
static void
-bezier (Point **curve,
- Point *dest,
- gfloat t)
+bezier2 (Path *prev, /* we need the previous node as well when rendering a path */
+ Path *curve,
+ Point *dest,
+ gfloat t)
{
Point ab,bc,cd,abbc,bccd;
- lerp (&ab, curve[0], curve[1], t);
- lerp (&bc, curve[1], curve[2], t);
- lerp (&cd, curve[2], curve[3], t);
+ if (prev->d.type == 'c')
+ lerp (&ab, &prev->d.point[2], &curve->d.point[0], t);
+ else
+ lerp (&ab, &prev->d.point[0], &curve->d.point[0], t);
+ lerp (&bc, &curve->d.point[0], &curve->d.point[1], t);
+ lerp (&cd, &curve->d.point[1], &curve->d.point[2], t);
lerp (&abbc, &ab, &bc,t);
lerp (&bccd, &bc, &cd,t);
lerp (dest, &abbc, &bccd, t);
}
+static Path *
+path_add1 (Path *head,
+ gchar type,
+ gfloat x,
+ gfloat y);
+
+static Path *flatten_curve (Path *head, Path *prev, Path *self)
+{ /* create piecevise linear approximation of bezier curve */
+ gfloat f;
+
+ for (f=0; f<1.0; f += 1.0 / BEZIER_SEGMENTS)
+ {
+ Point res;
+ bezier2 (prev, self, &res, f);
+ head = path_add1 (head, 'l', res.x, res.y);
+ }
+ return head;
+}
+
+static Path *path_flatten (Path *original)
+{
+ Path *iter;
+ Path *prev = NULL;
+ Path *self = NULL;
+
+ for (iter=original; iter; iter=iter->next)
+ {
+ self = find_knot_type (iter->d.type)->flatten (self, prev, iter);
+ prev = iter;
+ }
+ return self;
+}
+
+
+static Path *path_flatten (Path *original);
+static gdouble path_get_length (Path *path);
+
+typedef struct _Path Head;
+
+
#if 0
static gint
path_last_x (Path *path)
{
if (path)
- return path->point.x;
+ return path->d.point[0].x;
return 0;
}
@@ -169,184 +228,101 @@
path_last_y (Path *path)
{
if (path)
- return path->point.y;
+ return path->d.point[0].y;
return 0;
}
#endif
-/* types:
- * 'u' : unitilitlalized state
- * 's' : initialized state (last pen coordinates)
- * 'm' : move_to
- * 'l' : line_to
- * 'c' : curve_to
- * '.' : curve_to_
- * 'C' : curve_to_
- */
-
static Path *
-path_add (Path *head,
- gchar type,
- gfloat x,
- gfloat y)
+path_append (Path *head,
+ Path **res)
{
Path *iter = head;
- Path *prev = NULL;
-
- Path *curve[4] = { NULL, NULL, NULL, NULL };
+ while (iter && iter->next)
+ iter=iter->next;
if (iter)
{
- while (iter->next)
- {
- switch (iter->type)
- {
- case 'c':
- if (prev)
- curve[0]=prev;
- curve[1]=iter;
- break;
- case '.':
- curve[2]=iter;
- break;
- case 'C':
- curve[3]=iter;
- break;
- }
- prev=iter;
- iter=iter->next;
- }
- /* XXX: code duplication from above*/
- switch (iter->type)
- {
- case 'c':
- if (prev)
- curve[0]=prev;
- curve[1]=iter;
- break;
- case '.':
- curve[2]=iter;
- break;
- case 'C':
- curve[3]=iter;
- break;
- }
- }
- if (iter)
- {
iter->next = g_slice_new0 (Path);
iter = iter->next;
}
else /* creating new path */
{
head = g_slice_new0 (Head);
- head->type = 'u';
- if (type == 'u')
- {
- iter=head;
- }
- else
- {
- head->next = g_slice_new0 (Path);
- iter = head->next;
- }
+ iter=head;
}
+ g_assert (res);
+ *res = iter;
- if (head->type=='u' &&
- type!='u' &&
- type!='m')
- {
- if (type=='l')
- {
- type='m'; /* turn an initial line_to into a move_to */
- }
- else
- {
- g_error ("move_to or line_to is the only legal initial element for a path");
- return NULL;
- }
- }
-
- iter->type=type;
-
- switch (type)
- {
- case 'm':
- if (head->type=='u')
- head->type='s';
+ return head;
+}
- iter->point.x = x;
- iter->point.y = y;
- break;
- case 'c':
- iter->point.x = x;
- iter->point.y = y;
- break;
- case '.':
- iter->point.x = x;
- iter->point.y = y;
- break;
- case 'C':
- curve[3]=iter;
- iter->point.x = x;
- iter->point.y = y;
-
- /* chop off unneeded elements */
- curve[0]->next = NULL;
-
- { /* create piecevise linear approximation of bezier curve */
- gint i;
- gfloat f;
- Point foo[4];
- Point *pts[4];
-
- for (i=0;i<4;i++)
- {
- pts[i] = &foo[i];
- pts[i]->x = curve[i]->point.x;
- pts[i]->y = curve[i]->point.y;
- }
-
- for (f=0; f<1.0; f += 1.0 / BEZIER_SEGMENTS)
- {
- Point iter;
+static Path *
+path_add4 (Path *head,
+ gchar type,
+ gfloat x0,
+ gfloat y0,
+ gfloat x1,
+ gfloat y1,
+ gfloat x2,
+ gfloat y2,
+ gfloat x3,
+ gfloat y3)
+{
+ Path *iter;
+
+ head = path_append (head, &iter);
+
+ iter->d.type = type;
+ iter->d.point[0].x =x0;
+ iter->d.point[0].y =y0;
+ iter->d.point[1].x =x1;
+ iter->d.point[1].y =y1;
+ iter->d.point[2].x =x2;
+ iter->d.point[2].y =y2;
+ iter->d.point[3].x =x3;
+ iter->d.point[3].y =y3;
- bezier (pts, &iter, f);
+ return head;
+}
- head = path_add (head, 'l', iter.x, iter.y);
- }
- }
- /* free amputated stubs when they are no longer useful */
- g_slice_free (Path, curve[1]);
- g_slice_free (Path, curve[2]);
- g_slice_free (Path, curve[3]);
- break;
- case 'l':
- iter->point.x = x;
- iter->point.y = y;
- break;
- case 'u':
- break;
- default:
- g_error ("unknown path instruction '%c'", type);
- break;
- }
-
- head->point.x=x;
- head->point.y=y;
- return head;
+static Path *
+path_add1 (Path *head,
+ gchar type,
+ gfloat x,
+ gfloat y)
+{
+ return path_add4 (head, type, x, y, 0, 0, 0, 0, 0, 0);
}
#if 0
static Path *
-path_new (void)
+path_add2 (Path *head,
+ gchar type,
+ gfloat x,
+ gfloat y,
+ gfloat x1,
+ gfloat y1)
{
- return path_add (NULL, 'u', 0, 0);
+ return path_add4 (head, type, x, y, x1, y1, 0, 0, 0, 0);
}
#endif
static Path *
+path_add3 (Path *head,
+ gchar type,
+ gfloat x,
+ gfloat y,
+ gfloat x1,
+ gfloat y1,
+ gfloat x2,
+ gfloat y2)
+{
+ return path_add4 (head, type, x, y, x1, y1, x2, y2, 0, 0);
+}
+
+static Path *
path_destroy (Path *path)
{
g_slice_free_chain (Path, path, next);
@@ -359,8 +335,7 @@
gfloat x,
gfloat y)
{
- path = path_add (path, 'm', x, y);
- return path;
+ return path_add1 (path, 'm', x, y);
}
static Path *
@@ -368,8 +343,7 @@
gfloat x,
gfloat y)
{
- path = path_add (path, 'l', x, y);
- return path;
+ return path_add1 (path, 'l', x, y);
}
static Path *
@@ -381,10 +355,7 @@
gfloat x3,
gfloat y3)
{
- path = path_add (path, 'c', x1, y1);
- path = path_add (path, '.', x2, y2);
- path = path_add (path, 'C', x3, y3);
- return path;
+ return path_add3 (path, 'c', x1, y1, x2, y2, x3, y3);
}
static Path *
@@ -392,7 +363,7 @@
gfloat x,
gfloat y)
{
- return path_move_to (path, path->point.x + x, path->point.y + y);
+ return path_move_to (path, path->d.point[0].x + x, path->d.point[0].y + y);
}
#if 0
@@ -401,7 +372,7 @@
gfloat x,
gfloat y)
{
- return path_line_to (path, path->point.x + x, path->point.y + y);
+ return path_line_to (path, path->d.point[0].x + x, path->d.point[0].y + y);
}
static Path *
@@ -414,12 +385,174 @@
gfloat y3)
{
return path_curve_to (path,
- path->point.x + x1, path->point.y + y1,
- path->point.x + x2, path->point.y + y2,
- path->point.x + x3, path->point.y + y3);
+ path->d.point[0].x + x1, path->d.point[0].y + y1,
+ path->d.point[0].x + x2, path->d.point[0].y + y2,
+ path->d.point[0].x + x3, path->d.point[0].y + y3);
}
#endif
+
+
+static void
+path_calc (Path *path,
+ gdouble pos,
+ gdouble *xd,
+ gdouble *yd)
+{
+ Path *iter = path;
+ gfloat traveled_length = 0;
+ gfloat need_to_travel = 0;
+ gfloat x = 0, y = 0;
+
+ gboolean had_move_to = FALSE;
+
+ 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;
+ had_move_to = TRUE;
+ 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;
+ }
+
+ break;
+ case 's':
+ break;
+ default:
+ g_error ("can't compute for instruction: %i\n", iter->d.type);
+ break;
+ }
+ iter=iter->next;
+ }
+}
+
+static void
+path_calc_values (Path *path,
+ guint num_samples,
+ gdouble *xs,
+ gdouble *ys)
+{
+ /* FIXME: flatten first */
+ gdouble length = path_get_length (path);
+ gint i;
+ for (i=0; i<num_samples; i++)
+ {
+ /* FIXME: speed this up, combine with a "stroking" of the path
+ * or even inlining for the fill case as well
+ */
+ gdouble x, y;
+ path_calc (path, (i*1.0)/num_samples * length, &x, &y);
+
+ xs[i] = x;
+ ys[i] = y;
+ }
+}
+
+
+
+/******************/
+
+
+typedef struct _GeglVectorPrivate GeglVectorPrivate;
+typedef struct _VectorNameEntity VectorNameEntity;
+
+struct _GeglVectorPrivate
+{
+ Path *path;
+
+ Path *axis[8];
+ gint n_axes;
+
+ GeglRectangle dirtied;
+};
+
+enum
+{
+ PROP_0,
+};
+
+
+enum
+{
+ GEGL_VECTOR_CHANGED,
+ GEGL_VECTOR_LAST_SIGNAL
+};
+
+guint gegl_vector_signals[GEGL_VECTOR_LAST_SIGNAL] = { 0 };
+
+
+static void finalize (GObject *self);
+static void set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+G_DEFINE_TYPE (GeglVector, gegl_vector, G_TYPE_OBJECT);
+
+#define GEGL_VECTOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o),\
+ GEGL_TYPE_VECTOR, GeglVectorPrivate))
+
+
+
#include <gegl-buffer.h>
static gint compare_ints (gconstpointer a,
@@ -428,11 +561,6 @@
return GPOINTER_TO_INT (a)-GPOINTER_TO_INT (b);
}
-/* speedy way of doing vectors on gegl, would be to build a runlength
- * encoded instruction stream for fill n pixels which could be used on
- * linear buffers.
- */
-
static void gegl_buffer_accumulate (GeglBuffer *buffer,
GeglRectangle *roi,
const gfloat *col)
@@ -464,22 +592,28 @@
gegl_buffer_set (buffer, roi, format, buf, 0);
}
-#define TOFLOAT (x) ((float) ((int)(x) / 65536.0))
-#define TOFIXED (x) ((int) ((float)(x) * 65536.0))
-
-
+static void
+path_calc_values (Path *path,
+ guint num_samples,
+ gdouble *xs,
+ gdouble *ys);
void gegl_vector_fill (GeglBuffer *buffer,
GeglVector *vector,
GeglColor *color,
gboolean winding)
{
+ GeglVectorPrivate *priv = GEGL_VECTOR_GET_PRIVATE (vector);
gdouble xmin, xmax, ymin, ymax;
GeglRectangle extent;
+ Path *flat_path;
gfloat horsub = 4;
gint versubi = horsub;
gfloat versub = versubi;
- gint samples = gegl_vector_get_length (vector);
+ gint samples;
+
+ flat_path = path_flatten (priv->path);
+ samples = path_get_length (flat_path);
gegl_vector_get_bounds (vector, &xmin, &xmax, &ymin, &ymax);
extent.x = floor (xmin);
@@ -487,6 +621,7 @@
extent.width = ceil (xmax) - extent.x;
extent.height = ceil (ymax) - extent.y;
+
{
GSList *scanlines[extent.height * versubi];
@@ -501,7 +636,7 @@
gint lastline=-1;
gint lastdir=-2;
- gegl_vector_calc_values (vector, samples, xs, ys);
+ path_calc_values (flat_path, samples, xs, ys);
/* clear scanline intersection lists */
for (i=0; i < extent.height * versub; i++)
@@ -611,8 +746,9 @@
}
if (gegl_buffer_is_shared (buffer))
gegl_buffer_unlock (buffer);
-}
}
+ }
+ path_destroy (flat_path);
}
@@ -726,6 +862,8 @@
gdouble xmin, xmax, ymin, ymax;
GeglRectangle extent;
+ /* FIXME: flatten path first */
+
gegl_vector_get_bounds (vector, &xmin, &xmax, &ymin, &ymax);
extent.x = floor (xmin);
extent.y = floor (ymin);
@@ -743,12 +881,12 @@
while (iter)
{
- //fprintf (stderr, "%c, %i %i\n", iter->type, iter->point.x, iter->point.y);
- switch (iter->type)
+ //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->point.x;
- y = iter->point.y;
+ x = iter->d.point[0].x;
+ y = iter->d.point[0].y;
need_to_travel = 0;
traveled_length = 0;
had_move_to = TRUE;
@@ -768,8 +906,8 @@
a.x = x;
a.y = y;
- b.x = iter->point.x;
- b.y = iter->point.y;
+ b.x = iter->d.point[0].x;
+ b.y = iter->d.point[0].y;
spacing = 0.2 * radius;
@@ -813,7 +951,7 @@
case 's':
break;
default:
- g_error ("can't stroke for instruction: %i\n", iter->type);
+ g_error ("can't stroke for instruction: %i\n", iter->d.type);
break;
}
iter=iter->next;
@@ -951,8 +1089,8 @@
priv = GEGL_VECTOR_GET_PRIVATE (self);
if (priv->path)
- gen_rect (&priv->dirtied, x, y, priv->path->point.x,
- priv->path->point.y);
+ gen_rect (&priv->dirtied, x, y, priv->path->d.point[0].x,
+ priv->path->d.point[0].y);
priv->path = path_line_to (priv->path, x, y);
if (priv->path)
@@ -993,7 +1131,7 @@
{
GeglVectorPrivate *priv;
priv = GEGL_VECTOR_GET_PRIVATE (self);
- gegl_vector_line_to (self, priv->path->point.x + x, priv->path->point.y + y);
+ gegl_vector_line_to (self, priv->path->d.point[0].x + x, priv->path->d.point[0].y + y);
}
void
@@ -1019,27 +1157,44 @@
GeglVectorPrivate *priv;
priv = GEGL_VECTOR_GET_PRIVATE (self);
gegl_vector_curve_to (self,
- priv->path->point.x + x1, priv->path->point.y + y1,
- priv->path->point.x + x2, priv->path->point.y + y2,
- priv->path->point.x + x3, priv->path->point.y + y3);
+ priv->path->d.point[0].x + x1, priv->path->d.point[0].y + y1,
+ priv->path->d.point[0].x + x2, priv->path->d.point[0].y + y2,
+ priv->path->d.point[0].x + x3, priv->path->d.point[0].y + y3);
}
-
-gdouble
-gegl_vector_get_length (GeglVector *self)
+static gdouble
+path_get_length (Path *path)
{
- GeglVectorPrivate *priv = GEGL_VECTOR_GET_PRIVATE (self);
- Path *iter = priv->path;
+ Path *iter = path;
gfloat traveled_length = 0;
gfloat x = 0, y = 0;
while (iter)
{
- switch (iter->type)
+ switch (iter->d.type)
{
case 'm':
- x = iter->point.x;
- y = iter->point.y;
+ x = iter->d.point[0].x;
+ y = iter->d.point[0].y;
+ break;
+ case 'c':
+ {
+ Point a,b;
+ gfloat distance;
+ g_print ("eeek computing distance of c\n");
+
+ a.x = x;
+ a.y = y;
+
+ b.x = iter->d.point[2].x;
+ b.y = iter->d.point[2].y;
+
+ distance = point_dist (&a, &b);
+ traveled_length += distance;
+
+ x = b.x;
+ y = b.y;
+ }
break;
case 'l':
{
@@ -1049,8 +1204,8 @@
a.x = x;
a.y = y;
- b.x = iter->point.x;
- b.y = iter->point.y;
+ b.x = iter->d.point[0].x;
+ b.y = iter->d.point[0].y;
distance = point_dist (&a, &b);
traveled_length += distance;
@@ -1064,7 +1219,7 @@
case 's':
break;
default:
- g_error ("can't compute length for instruction: %i\n", iter->type);
+ g_error ("can't compute length for instruction: %i\n", iter->d.type);
break;
}
iter=iter->next;
@@ -1072,130 +1227,124 @@
return traveled_length;
}
-void gegl_vector_get_bounds (GeglVector *self,
- gdouble *min_x,
- gdouble *max_x,
- gdouble *min_y,
- gdouble *max_y)
-{
- GeglVectorPrivate *priv = GEGL_VECTOR_GET_PRIVATE (self);
- Path *iter = priv->path;
- *min_x = 256.0;
- *min_y = 256.0;
- *max_x = -256.0;
- *max_y = -256.0;
-
- if (*max_x < *min_x)
- *max_x = *min_x;
- if (*max_y < *min_y)
- *max_y = *min_y;
-
- while (iter)
- {
- if (iter->type == 'l')
- {
- if (iter->point.x < *min_x)
- *min_x = iter->point.x;
- if (iter->point.x > *max_x)
- *max_x = iter->point.x;
- if (iter->point.y < *min_y)
- *min_y = iter->point.y;
- if (iter->point.y > *max_y)
- *max_y = iter->point.y;
- }
- iter=iter->next;
- }
-}
-
-void
-gegl_vector_calc (GeglVector *self,
- gdouble pos,
- gdouble *xd,
- gdouble *yd)
+gdouble
+gegl_vector_get_length (GeglVector *self)
{
GeglVectorPrivate *priv = GEGL_VECTOR_GET_PRIVATE (self);
Path *iter = priv->path;
gfloat traveled_length = 0;
- gfloat need_to_travel = 0;
gfloat x = 0, y = 0;
- gboolean had_move_to = FALSE;
-
while (iter)
{
- //fprintf (stderr, "%c, %i %i\n", iter->type, iter->point.x, iter->point.y);
- switch (iter->type)
+ switch (iter->d.type)
{
case 'm':
- x = iter->point.x;
- y = iter->point.y;
- need_to_travel = 0;
- traveled_length = 0;
- had_move_to = TRUE;
+ x = iter->d.point[0].x;
+ y = iter->d.point[0].y;
break;
- case 'l':
+ case 'c':
{
Point a,b;
-
- gfloat spacing;
- gfloat local_pos;
gfloat distance;
- gfloat offset;
- gfloat leftover;
-
a.x = x;
a.y = y;
- b.x = iter->point.x;
- b.y = iter->point.y;
-
- spacing = 0.2;
+ b.x = iter->d.point[2].x;
+ b.y = iter->d.point[2].y;
distance = point_dist (&a, &b);
+ traveled_length += distance;
- leftover = need_to_travel - traveled_length;
- offset = spacing - leftover;
-
- local_pos = offset;
+ x = b.x;
+ y = b.y;
+ }
+ break;
+ case 'l':
+ {
+ Point a,b;
+ gfloat distance;
- if (distance > 0)
- for (;
- local_pos <= distance;
- local_pos += spacing)
- {
- Point spot;
- gfloat ratio = local_pos / distance;
+ a.x = x;
+ a.y = y;
- lerp (&spot, &a, &b, ratio);
+ b.x = iter->d.point[0].x;
+ b.y = iter->d.point[0].y;
- traveled_length += spacing;
- if (traveled_length > pos)
- {
- *xd = spot.x;
- *yd = spot.y;
- return;
- }
- }
-
- need_to_travel += distance;
+ distance = point_dist (&a, &b);
+ traveled_length += distance;
x = b.x;
y = b.y;
}
-
break;
case 'u':
- g_error ("computing uninitialized path\n");
break;
case 's':
break;
default:
- g_error ("can't compute for instruction: %i\n", iter->type);
+ g_error ("can't compute length for instruction: %i\n", iter->d.type);
break;
}
iter=iter->next;
}
+ return traveled_length;
+}
+
+void gegl_vector_get_bounds (GeglVector *self,
+ gdouble *min_x,
+ gdouble *max_x,
+ gdouble *min_y,
+ gdouble *max_y)
+{
+ GeglVectorPrivate *priv = GEGL_VECTOR_GET_PRIVATE (self);
+ Path *iter = priv->path;
+ *min_x = 256.0;
+ *min_y = 256.0;
+ *max_x = -256.0;
+ *max_y = -256.0;
+
+ if (*max_x < *min_x)
+ *max_x = *min_x;
+ if (*max_y < *min_y)
+ *max_y = *min_y;
+
+ while (iter)
+ {
+ gint i;
+ gint max = 0;
+
+ if (iter->d.type == 'l')
+ max = 1;
+ else if (iter->d.type == 'c')
+ max = 3;
+
+ for (i=0;i<max;i++)
+ {
+ if (iter->d.point[i].x < *min_x)
+ *min_x = iter->d.point[i].x;
+ if (iter->d.point[i].x > *max_x)
+ *max_x = iter->d.point[i].x;
+ if (iter->d.point[i].y < *min_y)
+ *min_y = iter->d.point[i].y;
+ if (iter->d.point[i].y > *max_y)
+ *max_y = iter->d.point[i].y;
+ }
+ iter=iter->next;
+ }
+}
+
+
+
+void
+gegl_vector_calc (GeglVector *self,
+ gdouble pos,
+ gdouble *xd,
+ gdouble *yd)
+{
+ GeglVectorPrivate *priv = GEGL_VECTOR_GET_PRIVATE (self);
+ return path_calc (priv->path, pos, xd, yd);
}
@@ -1209,7 +1358,9 @@
gint i;
for (i=0; i<num_samples; i++)
{
- /* FIXME: speed this up, combine with a "stroking" of the path */
+ /* FIXME: speed this up, combine with a "stroking" of the path
+ * or even inlining for the fill case as well
+ */
gdouble x, y;
gegl_vector_calc (self, (i*1.0)/num_samples * length, &x, &y);
@@ -1384,8 +1535,10 @@
void gegl_vector_parse_svg_path (GeglVector *vector,
const gchar *path)
{
- /* This isn't really a fully compliant SVG path parser, but it will work
- * for at least */
+ /* FIXME: extend this to be a more tolerant SVG path parser that can
+ * also be extended with new knot types.
+ */
+
const gchar *p = path;
gdouble x0, y0, x1, y1, x2, y2;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]