#define GNOME_CANVAS_PATH_DEF_C
/*
* GnomeCanvasPathDef
*
* (C) 1999-2000 Lauris Kaplinski <lauris@ximian.com>
* Released under LGPL
*
* Authors: Lauris Kaplinski <lauris@ximian.com>
* Rusty Conover <rconover@bangtail.net>
*
* Copyright 1999-2001 Ximian Inc. and authors.
*/
#include <string.h>
#include <libart_lgpl/art_misc.h>
#include "gnome-canvas-path-def.h"
/* The number of points to allocate at once */
#define GNOME_CANVAS_PATH_DEF_LENSTEP 32
struct _GnomeCanvasPathDef {
gint refcount;
ArtBpath * bpath;
gint end; /* ART_END position */
gint length; /* Num allocated Bpaths */
gint substart; /* subpath start */
gdouble x, y; /* previous moveto position */
guint sbpath : 1; /* Bpath is static */
guint hascpt : 1; /* Currentpoint is defined */
guint posset : 1; /* Previous was moveto */
guint moving : 1; /* Bpath end is moving */
guint allclosed : 1; /* All subpaths are closed */
guint allopen : 1; /* All subpaths are open */
};
static gboolean sp_bpath_good (ArtBpath * bpath);
static ArtBpath * sp_bpath_check_subpath (ArtBpath * bpath);
static gint sp_bpath_length (const ArtBpath * bpath);
static gboolean sp_bpath_all_closed (const ArtBpath * bpath);
static gboolean sp_bpath_all_open (const ArtBpath * bpath);
/* Boxed Type Support */
static GnomeCanvasPathDef *
path_def_boxed_copy (GnomeCanvasPathDef * path_def)
{
if (path_def)
gnome_canvas_path_def_ref (path_def);
return path_def;
}
GType
gnome_canvas_path_def_get_type (void)
{
static GType t = 0;
if (t == 0)
t = g_boxed_type_register_static
("GnomeCanvasPathDef",
(GBoxedCopyFunc)path_def_boxed_copy,
(GBoxedFreeFunc)gnome_canvas_path_def_unref);
return t;
}
/* Constructors */
/**
* gnome_canvas_path_def_new:
*
* This function creates a new empty #gnome_canvas_path_def.
*
* Returns: the new canvas path definition.
*/
GnomeCanvasPathDef *
gnome_canvas_path_def_new (void)
{
GnomeCanvasPathDef * path;
path = gnome_canvas_path_def_new_sized (GNOME_CANVAS_PATH_DEF_LENSTEP);
return path;
}
/**
* gnome_canvas_path_def_new_sized:
* @length: number of points to allocate for the path
*
* This function creates a new #gnome_canvas_path_def with @length
* number of points allocated. It is useful, if you know the exact
* number of points in path, so you can avoid automatic point
* array reallocation.
*
* Returns: the new canvas path definition
*/
GnomeCanvasPathDef *
gnome_canvas_path_def_new_sized (gint length)
{
GnomeCanvasPathDef * path;
g_return_val_if_fail (length > 0, NULL);
path = g_new (GnomeCanvasPathDef, 1);
path->refcount = 1;
path->bpath = art_new (ArtBpath, length);
path->end = 0;
path->bpath[path->end].code = ART_END;
path->length = length;
path->sbpath = FALSE;
path->hascpt = FALSE;
path->posset = FALSE;
path->moving = FALSE;
path->allclosed = TRUE;
path->allopen = TRUE;
return path;
}
/**
* gnome_canvas_path_def_new_from_bpath:
* @bpath: libart bezier path
*
* This function constructs a new #gnome_canvas_path_def and uses the
* passed @bpath as the contents. The passed bpath should not be
* static as the path definition is editable when constructed with
* this function. Also, passed bpath will be freed with art_free, if
* path is destroyed, so use it with caution.
* For constructing a #gnome_canvas_path_def
* from (non-modifiable) bpath use
* #gnome_canvas_path_def_new_from_static_bpath.
*
* Returns: the new canvas path definition that is populated with the
* passed bezier path, if the @bpath is bad NULL is returned.
*/
GnomeCanvasPathDef *
gnome_canvas_path_def_new_from_bpath (ArtBpath * bpath)
{
GnomeCanvasPathDef * path;
g_return_val_if_fail (sp_bpath_good (bpath), NULL);
path = g_new (GnomeCanvasPathDef, 1);
path->refcount = 1;
path->bpath = bpath;
path->length = sp_bpath_length (bpath);
path->end = path->length - 1;
path->sbpath = FALSE;
path->hascpt = FALSE;
path->posset = FALSE;
path->moving = FALSE;
path->allclosed = sp_bpath_all_closed (bpath);
path->allopen = sp_bpath_all_open (bpath);
return path;
}
/**
* gnome_canvas_path_def_new_from_static_bpath:
* @bpath: libart bezier path
*
* This function constructs a new #gnome_canvas_path_def and
* references the passed @bpath as its contents. The
* #gnome_canvas_path_def returned from this function is to be
* considered static and non-editable (meaning you cannot change the
* path from what you passed in @bpath). The bpath will not be freed,
* if path will be destroyed, so use it with caution.
*
* Returns: the new canvas path definition that references the passed
* @bpath, or if the path is bad NULL is returned.
*/
GnomeCanvasPathDef *
gnome_canvas_path_def_new_from_static_bpath (ArtBpath * bpath)
{
GnomeCanvasPathDef * path;
g_return_val_if_fail (sp_bpath_good (bpath), NULL);
path = g_new (GnomeCanvasPathDef, 1);
path->refcount = 1;
path->bpath = bpath;
path->length = sp_bpath_length (bpath);
path->end = path->length - 1;
path->sbpath = TRUE;
path->hascpt = FALSE;
path->posset = FALSE;
path->moving = FALSE;
path->allclosed = sp_bpath_all_closed (bpath);
path->allopen = sp_bpath_all_open (bpath);
return path;
}
/**
* gnome_canvas_path_def_new_from_foreign_bpath:
* @bpath: libart bezier path
*
* This function constructs a new #gnome_canvas_path_def and
* duplicates the contents of the passed @bpath in the definition.
*
* Returns: the newly created #gnome_canvas_path_def or NULL if the
* path is invalid.
*/
GnomeCanvasPathDef *
gnome_canvas_path_def_new_from_foreign_bpath (ArtBpath * bpath)
{
GnomeCanvasPathDef * path;
gint length;
g_return_val_if_fail (sp_bpath_good (bpath), NULL);
length = sp_bpath_length (bpath);
path = gnome_canvas_path_def_new_sized (length);
memcpy (path->bpath, bpath, sizeof (ArtBpath) * length);
path->end = length - 1;
path->allclosed = sp_bpath_all_closed (bpath);
path->allopen = sp_bpath_all_open (bpath);
return path;
}
/**
* gnome_canvas_path_def_ref:
* @path: a GnomeCanvasPathDef
*
* Increment the reference count of the GnomeCanvasPathDef.
*/
void
gnome_canvas_path_def_ref (GnomeCanvasPathDef * path)
{
g_return_if_fail (path != NULL);
path->refcount++;
}
/**
* gnome_canvas_path_def_finish:
* @path: a GnomeCanvasPathDef
*
* Trims dynamic point array to exact length of path.
*/
void
gnome_canvas_path_def_finish (GnomeCanvasPathDef * path)
{
g_return_if_fail (path != NULL);
g_return_if_fail (path->sbpath);
if ((path->end + 1) < path->length) {
path->bpath = art_renew (path->bpath, ArtBpath, path->end + 1);
path->length = path->end + 1;
}
path->hascpt = FALSE;
path->posset = FALSE;
path->moving = FALSE;
}
/**
* gnome_canvas_path_def_ensure_space:
* @path: a GnomeCanvasPathDef
* @space: number of points to guarantee are allocated at the end of
* the path.
*
* This function ensures that enough space for @space points is
* allocated at the end of the path.
*/
void
gnome_canvas_path_def_ensure_space (GnomeCanvasPathDef * path, gint space)
{
g_return_if_fail (path != NULL);
g_return_if_fail (space > 0);
if (path->end + space < path->length) return;
if (space < GNOME_CANVAS_PATH_DEF_LENSTEP) space = GNOME_CANVAS_PATH_DEF_LENSTEP;
path->bpath = art_renew (path->bpath, ArtBpath, path->length + space);
path->length += space;
}
/**
* gnome_canvas_path_def_copy:
* @dst: a GnomeCanvasPathDef where the contents of @src will be stored.
* @src: a GnomeCanvasPathDef whose contents will be copied it @src.
*
* This function copies the contents @src to @dest. The old @dest path
* array is freed and @dest is marked as non-static (editable),
* regardless of the status of @src.
*/
void
gnome_canvas_path_def_copy (GnomeCanvasPathDef * dst, const GnomeCanvasPathDef * src)
{
g_return_if_fail (dst != NULL);
g_return_if_fail (src != NULL);
if (!dst->sbpath) g_free (dst->bpath);
memcpy (dst, src, sizeof (GnomeCanvasPathDef));
dst->bpath = g_new (ArtBpath, src->end + 1);
memcpy (dst->bpath, src->bpath, (src->end + 1) * sizeof (ArtBpath));
dst->sbpath = FALSE;
}
/**
* gnome_canvas_path_def_duplicate:
* @path: a GnomeCanvasPathDef to duplicate
*
* This function duplicates the passed @path. The new path is
* marked as non-static regardless of the state of original.
*
* Returns: a GnomeCanvasPathDef which is a duplicate of @path.
*/
GnomeCanvasPathDef *
gnome_canvas_path_def_duplicate (const GnomeCanvasPathDef * path)
{
GnomeCanvasPathDef * new;
g_return_val_if_fail (path != NULL, NULL);
new = gnome_canvas_path_def_new_from_foreign_bpath (path->bpath);
new->x = path->x;
new->y = path->y;
new->hascpt = path->hascpt;
new->posset = path->posset;
new->moving = path->moving;
new->allclosed = path->allclosed;
new->allopen = path->allopen;
return new;
}
/**
* gnome_canvas_path_def_concat:
* @list: a GSList of GnomeCanvasPathDefs to concatenate into one new
* path.
*
* This function concatenates a list of GnomeCanvasPathDefs into one
* newly created GnomeCanvasPathDef.
*
* Returns: a new GnomeCanvasPathDef
*/
GnomeCanvasPathDef *
gnome_canvas_path_def_concat (const GSList * list)
{
GnomeCanvasPathDef * c, * new;
ArtBpath * bp;
const GSList * l;
gint length;
g_return_val_if_fail (list != NULL, NULL);
length = 1;
for (l = list; l != NULL; l = l->next) {
c = (GnomeCanvasPathDef *) l->data;
length += c->end;
}
new = gnome_canvas_path_def_new_sized (length);
bp = new->bpath;
for (l = list; l != NULL; l = l->next) {
c = (GnomeCanvasPathDef *) l->data;
memcpy (bp, c->bpath, c->end * sizeof (ArtBpath));
bp += c->end;
}
bp->code = ART_END;
new->end = length - 1;
new->allclosed = sp_bpath_all_closed (new->bpath);
new->allopen = sp_bpath_all_open (new->bpath);
return new;
}
/**
* gnome_canvas_path_def_split:
* @path: a GnomeCanvasPathDef
*
* This function splits the passed @path into a list of
* GnomeCanvasPathDefs which represent each segment of the origional
* path. The path is split when ever an ART_MOVETO or ART_MOVETO_OPEN
* is encountered. The closedness of resulting paths is set accordingly
* to closedness of corresponding segment.
*
* Returns: a list of GnomeCanvasPathDef(s).
*/
GSList *
gnome_canvas_path_def_split (const GnomeCanvasPathDef * path)
{
GnomeCanvasPathDef * new;
GSList * l;
gint p, i;
g_return_val_if_fail (path != NULL, NULL);
p = 0;
l = NULL;
while (p < path->end) {
i = 1;
while ((path->bpath[p + i].code == ART_LINETO) ||
(path->bpath[p + i].code == ART_CURVETO))
i++;
new = gnome_canvas_path_def_new_sized (i + 1);
memcpy (new->bpath, path->bpath + p, i * sizeof (ArtBpath));
new->end = i;
new->bpath[i].code = ART_END;
new->allclosed = (new->bpath->code == ART_MOVETO);
new->allopen = (new->bpath->code == ART_MOVETO_OPEN);
l = g_slist_append (l, new);
p += i;
}
return l;
}
/**
* gnome_canvas_path_def_open_parts:
* @path: a GnomeCanvasPathDef
*
* This function creates a new GnomeCanvasPathDef that contains all of
* the open segments on the passed @path.
*
* Returns: a new GnomeCanvasPathDef that contains all of the open segemtns in @path.
*/
GnomeCanvasPathDef *
gnome_canvas_path_def_open_parts (const GnomeCanvasPathDef * path)
{
GnomeCanvasPathDef * new;
ArtBpath * p, * d;
gint len;
gboolean closed;
g_return_val_if_fail (path != NULL, NULL);
closed = TRUE;
len = 0;
for (p = path->bpath; p->code != ART_END; p++) {
switch (p->code) {
case ART_MOVETO_OPEN:
closed = FALSE;
len++;
break;
case ART_MOVETO:
closed = TRUE;
break;
case ART_LINETO:
case ART_CURVETO:
if (!closed) len++;
break;
default:
g_assert_not_reached ();
}
}
new = gnome_canvas_path_def_new_sized (len + 1);
closed = TRUE;
d = new->bpath;
for (p = path->bpath; p->code != ART_END; p++) {
switch (p->code) {
case ART_MOVETO_OPEN:
closed = FALSE;
*d++ = *p;
break;
case ART_MOVETO:
closed = TRUE;
break;
case ART_LINETO:
case ART_CURVETO:
if (!closed) *d++ = *p;
break;
default:
g_assert_not_reached ();
}
}
d->code = ART_END;
new->end = len;
new->allclosed = FALSE;
new->allopen = TRUE;
return new;
}
/**
* gnome_canvas_path_def_closed_parts:
* @path: a GnomeCanvasPathDef
*
* This function returns a new GnomeCanvasPathDef that contains the
* all of close parts of passed @path.
*
* Returns: a new GnomeCanvasPathDef that contains all of the closed
* parts of passed @path.
*/
GnomeCanvasPathDef *
gnome_canvas_path_def_closed_parts (const GnomeCanvasPathDef * path)
{
GnomeCanvasPathDef * new;
ArtBpath * p, * d;
gint len;
gboolean closed;
g_return_val_if_fail (path != NULL, NULL);
closed = FALSE;
len = 0;
for (p = path->bpath; p->code != ART_END; p++) {
switch (p->code) {
case ART_MOVETO_OPEN:
closed = FALSE;
break;
case ART_MOVETO:
closed = TRUE;
len++;
break;
case ART_LINETO:
case ART_CURVETO:
if (closed) len++;
break;
default:
g_assert_not_reached ();
}
}
new = gnome_canvas_path_def_new_sized (len + 1);
closed = FALSE;
d = new->bpath;
for (p = path->bpath; p->code != ART_END; p++) {
switch (p->code) {
case ART_MOVETO_OPEN:
closed = FALSE;
break;
case ART_MOVETO:
closed = TRUE;
*d++ = *p;
break;
case ART_LINETO:
case ART_CURVETO:
if (closed) *d++ = *p;
break;
default:
g_assert_not_reached ();
}
}
d->code = ART_END;
new->end = len;
new->allclosed = TRUE;
new->allopen = FALSE;
return new;
}
/**
* gnome_canvas_path_def_close_all:
* @path: a GnomeCanvasPathDef
*
* This function closes all of the open segments in the passed path
* and returns a new GnomeCanvasPathDef.
*
* Returns: a GnomeCanvasPathDef that contains the contents of @path
* but has modified the path is fully closed
*/
GnomeCanvasPathDef *
gnome_canvas_path_def_close_all (const GnomeCanvasPathDef * path)
{
GnomeCanvasPathDef * new;
ArtBpath * p, * d, * start;
gint len;
gboolean closed;
g_return_val_if_fail (path != NULL, NULL);
if (path->allclosed) {
new = gnome_canvas_path_def_duplicate (path);
return new;
}
len = 1;
/* Count MOVETO_OPEN */
for (p = path->bpath; p->code != ART_END; p++) {
len += 1;
if (p->code == ART_MOVETO_OPEN) len += 2;
}
new = gnome_canvas_path_def_new_sized (len);
d = start = new->bpath;
closed = TRUE;
for (p = path->bpath; p->code != ART_END; p++) {
switch (p->code) {
case ART_MOVETO_OPEN:
start = p;
closed = FALSE;
case ART_MOVETO:
if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
d->code = ART_LINETO;
d->x3 = start->x3;
d->y3 = start->y3;
d++;
}
if (p->code == ART_MOVETO) closed = TRUE;
d->code = ART_MOVETO;
d->x3 = p->x3;
d->y3 = p->y3;
d++;
break;
case ART_LINETO:
case ART_CURVETO:
*d++ = *p;
break;
default:
g_assert_not_reached ();
}
}
if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
d->code = ART_LINETO;
d->x3 = start->x3;
d->y3 = start->y3;
d++;
}
d->code = ART_END;
new->end = d - new->bpath;
new->allclosed = TRUE;
new->allopen = FALSE;
return new;
}
/* Destructor */
/**
* gnome_canvas_path_def_unref:
* @path: a GnomeCanvasPathDef
*
* Decrease the reference count of the passed @path. If the reference
* count is < 1 the path is deallocated.
*/
void
gnome_canvas_path_def_unref (GnomeCanvasPathDef * path)
{
g_return_if_fail (path != NULL);
if (--path->refcount < 1) {
if ((!path->sbpath) && (path->bpath)) art_free (path->bpath);
g_free (path);
}
}
/* Methods */
/**
* gnome_canvas_path_def_reset:
* @path: a GnomeCanvasPathDef
*
* This function clears the contents of the passed @path.
*/
void
gnome_canvas_path_def_reset (GnomeCanvasPathDef * path)
{
g_return_if_fail (path != NULL);
g_return_if_fail (!path->sbpath);
path->bpath->code = ART_END;
path->end = 0;
path->hascpt = FALSE;
path->posset = FALSE;
path->moving = FALSE;
path->allclosed = TRUE;
path->allopen = TRUE;
}
/* Several consequtive movetos are ALLOWED */
/**
* gnome_canvas_path_def_moveto:
* @path: a GnomeCanvasPathDef
* @x: x coordinate
* @y: y coordinate
*
* This function adds starts new subpath on @path, and sets its
* starting point to @x and @y. If current subpath is empty, it
* simply changes its starting coordinates to new values.
*/
void
gnome_canvas_path_def_moveto (GnomeCanvasPathDef * path, gdouble x, gdouble y)
{
g_return_if_fail (path != NULL);
g_return_if_fail (!path->sbpath);
g_return_if_fail (!path->moving);
path->substart = path->end;
path->hascpt = TRUE;
path->posset = TRUE;
path->x = x;
path->y = y;
path->allclosed = FALSE;
}
/**
* gnome_canvas_path_def_lineto:
* @path: a GnomeCanvasPathDef
* @x: x coordinate
* @y: y coordinate
*
* This function add a line segment to the passed @path with the
* specified @x and @y coordinates.
*/
void
gnome_canvas_path_def_lineto (GnomeCanvasPathDef * path, gdouble x, gdouble y)
{
ArtBpath * bp;
g_return_if_fail (path != NULL);
g_return_if_fail (!path->sbpath);
g_return_if_fail (path->hascpt);
if (path->moving) {
/* simply fix endpoint */
g_return_if_fail (!path->posset);
g_return_if_fail (path->end > 1);
bp = path->bpath + path->end - 1;
g_return_if_fail (bp->code == ART_LINETO);
bp->x3 = x;
bp->y3 = y;
path->moving = FALSE;
return;
}
if (path->posset) {
/* start a new segment */
gnome_canvas_path_def_ensure_space (path, 2);
bp = path->bpath + path->end;
bp->code = ART_MOVETO_OPEN;
bp->x3 = path->x;
bp->y3 = path->y;
bp++;
bp->code = ART_LINETO;
bp->x3 = x;
bp->y3 = y;
bp++;
bp->code = ART_END;
path->end += 2;
path->posset = FALSE;
path->allclosed = FALSE;
return;
}
/* Simply add line */
g_return_if_fail (path->end > 1);
gnome_canvas_path_def_ensure_space (path, 1);
bp = path->bpath + path->end;
bp->code = ART_LINETO;
bp->x3 = x;
bp->y3 = y;
bp++;
bp->code = ART_END;
path->end++;
}
/**
* gnome_canvas_path_def_lineto_moving:
* @path: a GnomeCanvasPathDef
* @x: x coordinate
* @y: y coordinate
*
* This functions adds a new line segment with loose endpoint to the path, or
* if endpoint is already loose, changes its coordinates to @x, @y. You
* can change the coordinates of loose endpoint as many times as you want,
* the last ones set will be fixed, if you continue line. This is useful
* for handling drawing with mouse.
*/
void
gnome_canvas_path_def_lineto_moving (GnomeCanvasPathDef * path, gdouble x, gdouble y)
{
ArtBpath * bp;
g_return_if_fail (path != NULL);
g_return_if_fail (!path->sbpath);
g_return_if_fail (path->hascpt);
if (path->moving) {
/* simply change endpoint */
g_return_if_fail (!path->posset);
g_return_if_fail (path->end > 1);
bp = path->bpath + path->end - 1;
g_return_if_fail (bp->code == ART_LINETO);
bp->x3 = x;
bp->y3 = y;
return;
}
if (path->posset) {
/* start a new segment */
gnome_canvas_path_def_ensure_space (path, 2);
bp = path->bpath + path->end;
bp->code = ART_MOVETO_OPEN;
bp->x3 = path->x;
bp->y3 = path->y;
bp++;
bp->code = ART_LINETO;
bp->x3 = x;
bp->y3 = y;
bp++;
bp->code = ART_END;
path->end += 2;
path->posset = FALSE;
path->moving = TRUE;
path->allclosed = FALSE;
return;
}
/* Simply add line */
g_return_if_fail (path->end > 1);
gnome_canvas_path_def_ensure_space (path, 1);
bp = path->bpath + path->end;
bp->code = ART_LINETO;
bp->x3 = x;
bp->y3 = y;
bp++;
bp->code = ART_END;
path->end++;
path->moving = TRUE;
}
/**
* gnome_canvas_path_def_curveto:
* @path: a GnomeCanvasPathDef
* @x0: first control point x coordinate
* @y0: first control point y coordinate
* @x1: second control point x coordinate
* @y1: second control point y coordinate
* @x2: end of curve x coordinate
* @y2: end of curve y coordinate
*
* This function adds a bezier curve segment to the path definition.
*/
void
gnome_canvas_path_def_curveto (GnomeCanvasPathDef * path,
gdouble x0,
gdouble y0,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2)
{
ArtBpath * bp;
g_return_if_fail (path != NULL);
g_return_if_fail (!path->sbpath);
g_return_if_fail (path->hascpt);
g_return_if_fail (!path->moving);
if (path->posset) {
/* start a new segment */
gnome_canvas_path_def_ensure_space (path, 2);
bp = path->bpath + path->end;
bp->code = ART_MOVETO_OPEN;
bp->x3 = path->x;
bp->y3 = path->y;
bp++;
bp->code = ART_CURVETO;
bp->x1 = x0;
bp->y1 = y0;
bp->x2 = x1;
bp->y2 = y1;
bp->x3 = x2;
bp->y3 = y2;
bp++;
bp->code = ART_END;
path->end += 2;
path->posset = FALSE;
path->allclosed = FALSE;
return;
}
/* Simply add path */
g_return_if_fail (path->end > 1);
gnome_canvas_path_def_ensure_space (path, 1);
bp = path->bpath + path->end;
bp->code = ART_CURVETO;
bp->x1 = x0;
bp->y1 = y0;
bp->x2 = x1;
bp->y2 = y1;
bp->x3 = x2;
bp->y3 = y2;
bp++;
bp->code = ART_END;
path->end++;
}
/**
* gnome_canvas_path_def_closepath:
* @path: a GnomeCanvasPathDef
*
* This function closes the last subpath of @path, adding a ART_LINETO to
* subpath starting point, if needed and changing starting pathcode to
* ART_MOVETO
*/
void
gnome_canvas_path_def_closepath (GnomeCanvasPathDef * path)
{
ArtBpath * bs, * be;
g_return_if_fail (path != NULL);
g_return_if_fail (!path->sbpath);
g_return_if_fail (path->hascpt);
g_return_if_fail (!path->posset);
g_return_if_fail (!path->moving);
g_return_if_fail (!path->allclosed);
/* We need at last M + L + L + E */
g_return_if_fail (path->end - path->substart > 2);
bs = path->bpath + path->substart;
be = path->bpath + path->end - 1;
if ((bs->x3 != be->x3) || (bs->y3 != be->y3)) {
gnome_canvas_path_def_lineto (path, bs->x3, bs->y3);
}
bs = path->bpath + path->substart; /* NB. def_lineto can
realloc bpath */
bs->code = ART_MOVETO;
path->allclosed = sp_bpath_all_closed (path->bpath);
path->allopen = sp_bpath_all_open (path->bpath);
path->hascpt = FALSE;
}
/**
* gnome_canvas_path_def_closepath_current:
* @path: a GnomeCanvasPathDef
*
* This function closes the last subpath by setting the coordinates of
* the endpoint of the last segment (line or curve) to starting point.
*/
void
gnome_canvas_path_def_closepath_current (GnomeCanvasPathDef * path)
{
ArtBpath * bs, * be;
g_return_if_fail (path != NULL);
g_return_if_fail (!path->sbpath);
g_return_if_fail (path->hascpt);
g_return_if_fail (!path->posset);
g_return_if_fail (!path->allclosed);
/* We need at last M + L + L + E */
g_return_if_fail (path->end - path->substart > 2);
bs = path->bpath + path->substart;
be = path->bpath + path->end - 1;
be->x3 = bs->x3;
be->y3 = bs->y3;
bs->code = ART_MOVETO;
path->allclosed = sp_bpath_all_closed (path->bpath);
path->allopen = sp_bpath_all_open (path->bpath);
path->hascpt = FALSE;
path->moving = FALSE;
}
/**
* gnome_canvas_path_def_bpath:
* @path: a GnomeCanvasPathDef
*
* This function returns a ArtBpath that consists of the path
* definition.
*
* Returns: ArtBpath
*/
ArtBpath * gnome_canvas_path_def_bpath (const GnomeCanvasPathDef * path)
{
g_return_val_if_fail (path != NULL, NULL);
return path->bpath;
}
/**
* gnome_canvas_path_def_length:
* @path: a GnomeCanvasPathDef
*
* This function returns the length of the path definition. Not
* Euclidian length of the path but rather the number of points on the
* path.
*
* Returns: integer, number of points on the path.
*/
gint gnome_canvas_path_def_length (const GnomeCanvasPathDef * path)
{
g_return_val_if_fail (path != NULL, -1);
return path->end + 1;
}
/**
* gnome_canvas_path_def_is_empty:
* @path: a GnomeCanvasPathDef
*
* This function is a boolean test to see if the path is empty,
* meaning containing no line segments.
*
* Returns: boolean, indicating if the path is empty.
*/
gboolean
gnome_canvas_path_def_is_empty (const GnomeCanvasPathDef * path)
{
g_return_val_if_fail (path != NULL, TRUE);
return (path->bpath->code == ART_END);
}
/**
* gnome_canvas_path_def_has_currentpoint:
* @path: a GnomeCanvasPathdef
*
* This function is a boolean test checking to see if the path has a
* current point defined. Current point will be set by line operators,
* and cleared by closing subpath.
*
* Returns: boolean, indicating if the path has a current point defined.
*/
gboolean
gnome_canvas_path_def_has_currentpoint (const GnomeCanvasPathDef * path)
{
g_return_val_if_fail (path != NULL, FALSE);
return (path->hascpt);
}
/**
* gnome_canvas_path_def_currentpoint:
* @path: a GnomeCanvasPathDef
* @p: a ArtPoint where to store the current point
*
* Stores the current point of the path definition in the passed ArtPoint @p.
*/
void
gnome_canvas_path_def_currentpoint (const GnomeCanvasPathDef * path, ArtPoint * p)
{
g_return_if_fail (path != NULL);
g_return_if_fail (p != NULL);
g_return_if_fail (path->hascpt);
if (path->posset) {
p->x = path->x;
p->y = path->y;
} else {
p->x = (path->bpath + path->end - 1)->x3;
p->y = (path->bpath + path->end - 1)->y3;
}
}
/**
* gnome_canvas_path_def_last_bpath:
* @path: a GnomeCanvasPathDef
*
* This function returns pointer to the last ArtBpath segment in the path
* definition.
*
* Returns: ArtBpath, being the last segment in the path definition or
* null if no line segments have been defined.
*/
ArtBpath *
gnome_canvas_path_def_last_bpath (const GnomeCanvasPathDef * path)
{
g_return_val_if_fail (path != NULL, NULL);
if (path->end == 0) return NULL;
return path->bpath + path->end - 1;
}
/**
* gnome_canvas_path_def_first_bpath:
* @path: a GnomeCanvasPathDef
*
* This function returns the first ArtBpath point in the definition.
*
* Returns: ArtBpath being the first point in the path definition or
* null if no points are defined
*/
ArtBpath *
gnome_canvas_path_def_first_bpath (const GnomeCanvasPathDef * path)
{
g_return_val_if_fail (path != NULL, NULL);
if (path->end == 0) return NULL;
return path->bpath;
}
/**
* gnome_canvas_path_def_any_open:
* @path: a GnomeCanvasPathDef
*
* This function returns a boolean value indicating if the path has
* any open segments.
*
* Returns: boolean, indicating if the path has any open segments.
*/
gboolean
gnome_canvas_path_def_any_open (const GnomeCanvasPathDef * path)
{
g_return_val_if_fail (path != NULL, FALSE);
return (!path->allclosed);
}
/**
* gnome_canvas_path_def_all_open:
* @path: a GnomeCanvasPathDef
*
* This function returns a boolean value indicating if the path only
* contains open segments.
*
* Returns: boolean, indicating if the path has all open segments.
*/
gboolean
gnome_canvas_path_def_all_open (const GnomeCanvasPathDef * path)
{
g_return_val_if_fail (path != NULL, FALSE);
return (path->allopen);
}
/**
* gnome_canvas_path_def_any_closed:
* @path: a GnomeCanvasPathDef
*
* This function returns a boolean valid indicating if the path has
* any closed segements.
*
* Returns: boolean, indicating if the path has any closed segments.
*/
gboolean
gnome_canvas_path_def_any_closed (const GnomeCanvasPathDef * path)
{
g_return_val_if_fail (path != NULL, FALSE);
return (!path->allopen);
}
/**
* gnome_canvas_path_def_all_closed:
* @path: a GnomeCanvasPathDef
*
* This function returns a boolean value indicating if the path only
* contains closed segments.
*
* Returns: boolean, indicating if the path has all closed segments.
*/
gboolean
gnome_canvas_path_def_all_closed (const GnomeCanvasPathDef * path)
{
g_return_val_if_fail (path != NULL, FALSE);
return (path->allclosed);
}
/* Private methods */
static
gboolean sp_bpath_good (ArtBpath * bpath)
{
ArtBpath * bp;
g_return_val_if_fail (bpath != NULL, FALSE);
if (bpath->code == ART_END)
return TRUE;
bp = bpath;
while (bp->code != ART_END) {
bp = sp_bpath_check_subpath (bp);
if (bp == NULL) return FALSE;
}
return TRUE;
}
static ArtBpath *
sp_bpath_check_subpath (ArtBpath * bpath)
{
gint i, len;
gboolean closed;
g_return_val_if_fail (bpath != NULL, NULL);
if (bpath->code == ART_MOVETO) {
closed = TRUE;
} else if (bpath->code == ART_MOVETO_OPEN) {
closed = FALSE;
} else {
return NULL;
}
len = 0;
for (i = 1; (bpath[i].code != ART_END) &&
(bpath[i].code != ART_MOVETO) &&
(bpath[i].code != ART_MOVETO_OPEN); i++) {
switch (bpath[i].code) {
case ART_LINETO:
case ART_CURVETO:
len++;
break;
default:
return NULL;
}
}
if (closed) {
if (len < 2) return NULL;
if ((bpath->x3 != bpath[i-1].x3) || (bpath->y3 != bpath[i-1].y3)) return NULL;
} else {
if (len < 1) return NULL;
}
return bpath + i;
}
static gint
sp_bpath_length (const ArtBpath * bpath)
{
gint l;
g_return_val_if_fail (bpath != NULL, FALSE);
for (l = 0; bpath[l].code != ART_END; l++);
l++;
return l;
}
static gboolean
sp_bpath_all_closed (const ArtBpath * bpath)
{
const ArtBpath * bp;
g_return_val_if_fail (bpath != NULL, FALSE);
for (bp = bpath; bp->code != ART_END; bp++)
if (bp->code == ART_MOVETO_OPEN) return FALSE;
return TRUE;
}
static gboolean
sp_bpath_all_open (const ArtBpath * bpath)
{
const ArtBpath * bp;
g_return_val_if_fail (bpath != NULL, FALSE);
for (bp = bpath; bp->code != ART_END; bp++)
if (bp->code == ART_MOVETO) return FALSE;
return TRUE;
}