source: trunk/third/libgnomecanvas/libgnomecanvas/gnome-canvas-path-def.c @ 20821

Revision 20821, 28.2 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20820, which included commits to RCS files with non-trunk default branches.
Line 
1#define GNOME_CANVAS_PATH_DEF_C
2
3/*
4 * GnomeCanvasPathDef
5 *
6 * (C) 1999-2000 Lauris Kaplinski <lauris@ximian.com>
7 * Released under LGPL
8 *
9 * Authors: Lauris Kaplinski <lauris@ximian.com>
10 *          Rusty Conover <rconover@bangtail.net>
11 *
12 * Copyright 1999-2001 Ximian Inc. and authors.
13 */
14
15#include <string.h>
16#include <libart_lgpl/art_misc.h>
17#include "gnome-canvas-path-def.h"
18
19/* The number of points to allocate at once */
20#define GNOME_CANVAS_PATH_DEF_LENSTEP 32
21
22struct _GnomeCanvasPathDef {
23        gint refcount;
24        ArtBpath * bpath;
25        gint end;               /* ART_END position */
26        gint length;            /* Num allocated Bpaths */
27        gint substart;          /* subpath start */
28        gdouble x, y;           /* previous moveto position */
29        guint sbpath : 1;       /* Bpath is static */
30        guint hascpt : 1;       /* Currentpoint is defined */
31        guint posset : 1;       /* Previous was moveto */
32        guint moving : 1;       /* Bpath end is moving */
33        guint allclosed : 1;    /* All subpaths are closed */
34        guint allopen : 1;      /* All subpaths are open */
35};
36
37static gboolean sp_bpath_good (ArtBpath * bpath);
38static ArtBpath * sp_bpath_check_subpath (ArtBpath * bpath);
39static gint sp_bpath_length (const ArtBpath * bpath);
40static gboolean sp_bpath_all_closed (const ArtBpath * bpath);
41static gboolean sp_bpath_all_open (const ArtBpath * bpath);
42
43/* Constructors */
44
45/**
46 * gnome_canvas_path_def_new:
47 *
48 * This function creates a new empty #gnome_canvas_path_def.
49 *
50 * Returns: the new canvas path definition.
51 */
52GnomeCanvasPathDef *
53gnome_canvas_path_def_new (void)
54{
55        GnomeCanvasPathDef * path;
56
57        path = gnome_canvas_path_def_new_sized (GNOME_CANVAS_PATH_DEF_LENSTEP);
58
59        return path;
60}
61
62/**
63 * gnome_canvas_path_def_new_sized:
64 * @length: number of points to allocate for the path
65 *
66 * This funtion creates a new #gnome_canvas_path_def with @length
67 * number of points allocated. It is useful, if you know the exact
68 * number of points in path, so you can avoid automatic point
69 * array reallocation.
70 *
71 * Returns: the new canvas path definition
72 */
73GnomeCanvasPathDef *
74gnome_canvas_path_def_new_sized (gint length)
75{
76        GnomeCanvasPathDef * path;
77
78        g_return_val_if_fail (length > 0, NULL);
79
80        path = g_new (GnomeCanvasPathDef, 1);
81
82        path->refcount = 1;
83        path->bpath = art_new (ArtBpath, length);
84        path->end = 0;
85        path->bpath[path->end].code = ART_END;
86        path->length = length;
87        path->sbpath = FALSE;
88        path->hascpt = FALSE;
89        path->posset = FALSE;
90        path->moving = FALSE;
91        path->allclosed = TRUE;
92        path->allopen = TRUE;
93
94        return path;
95}
96
97/**
98 * gnome_canvas_path_def_new_from_bpath:
99 * @bpath: libart bezier path
100 *
101 * This function constructs a new #gnome_canvas_path_def and uses the
102 * passed @bpath as the contents.  The passed bpath should not be
103 * static as the path definition is editable when constructed with
104 * this function. Also, passed bpath will be freed with art_free, if
105 * path is destroyed, so use it with caution.
106 * For constructing a #gnome_canvas_path_def
107 * from (non-modifiable) bpath use
108 * #gnome_canvas_path_def_new_from_static_bpath.
109 *
110 * Returns: the new canvas path definition that is populated with the
111 * passed bezier path, if the @bpath is bad NULL is returned.
112 */
113GnomeCanvasPathDef *
114gnome_canvas_path_def_new_from_bpath (ArtBpath * bpath)
115{
116        GnomeCanvasPathDef * path;
117
118        g_return_val_if_fail (sp_bpath_good (bpath), NULL);
119
120        path = g_new (GnomeCanvasPathDef, 1);
121
122        path->refcount = 1;
123        path->bpath = bpath;
124        path->length = sp_bpath_length (bpath);
125        path->end = path->length - 1;
126        path->sbpath = FALSE;
127        path->hascpt = FALSE;
128        path->posset = FALSE;
129        path->moving = FALSE;
130        path->allclosed = sp_bpath_all_closed (bpath);
131        path->allopen = sp_bpath_all_open (bpath);
132
133        return path;
134}
135
136/**
137 * gnome_canvas_path_def_new_from_static_bpath:
138 * @bpath: libart bezier path
139 *
140 * This function constructs a new #gnome_canvas_path_def and
141 * references the passed @bpath as its contents.  The
142 * #gnome_canvas_path_def returned from this function is to be
143 * considered static and non-editable (meaning you cannot change the
144 * path from what you passed in @bpath). The bpath will not be freed,
145 * if path will be destroyed, so use it with caution.
146 *
147 * Returns: the new canvas path definition that references the passed
148 * @bpath, or if the path is bad NULL is returned.
149 */
150GnomeCanvasPathDef *
151gnome_canvas_path_def_new_from_static_bpath (ArtBpath * bpath)
152{
153        GnomeCanvasPathDef * path;
154
155        g_return_val_if_fail (sp_bpath_good (bpath), NULL);
156
157        path = g_new (GnomeCanvasPathDef, 1);
158
159        path->refcount = 1;
160        path->bpath = bpath;
161        path->length = sp_bpath_length (bpath);
162        path->end = path->length - 1;
163        path->sbpath = TRUE;
164        path->hascpt = FALSE;
165        path->posset = FALSE;
166        path->moving = FALSE;
167        path->allclosed = sp_bpath_all_closed (bpath);
168        path->allopen = sp_bpath_all_open (bpath);
169
170        return path;
171}
172
173/**
174 * gnome_canvas_path_def_new_from_foreign_bpath:
175 * @bpath: libart bezier path
176 *
177 * This function constructs a new #gnome_canvas_path_def and
178 * duplicates the contents of the passed @bpath in the definition.
179 *
180 * Returns: the newly created #gnome_canvas_path_def or NULL if the
181 * path is invalid.
182 */
183GnomeCanvasPathDef *
184gnome_canvas_path_def_new_from_foreign_bpath (ArtBpath * bpath)
185{
186        GnomeCanvasPathDef * path;
187        gint length;
188
189        g_return_val_if_fail (sp_bpath_good (bpath), NULL);
190
191        length = sp_bpath_length (bpath);
192
193        path = gnome_canvas_path_def_new_sized (length);
194        memcpy (path->bpath, bpath, sizeof (ArtBpath) * length);
195        path->end = length - 1;
196        path->allclosed = sp_bpath_all_closed (bpath);
197        path->allopen = sp_bpath_all_open (bpath);
198
199        return path;
200}
201
202/**
203 * gnome_canvas_path_def_ref:
204 * @path: a GnomeCanvasPathDef
205 *
206 * Increment the reference count of the GnomeCanvasPathDef.
207 */
208void
209gnome_canvas_path_def_ref (GnomeCanvasPathDef * path)
210{
211        g_return_if_fail (path != NULL);
212
213        path->refcount++;
214}
215
216/**
217 * gnome_canvas_path_def_finish:
218 * @path: a GnomeCanvasPathDef
219 *
220 * Trims dynamic point array to exact length of path.
221 */
222void
223gnome_canvas_path_def_finish (GnomeCanvasPathDef * path)
224{
225        g_return_if_fail (path != NULL);
226        g_return_if_fail (path->sbpath);
227
228        if ((path->end + 1) < path->length) {
229                path->bpath = art_renew (path->bpath, ArtBpath, path->end + 1);
230                path->length = path->end + 1;
231        }
232
233        path->hascpt = FALSE;
234        path->posset = FALSE;
235        path->moving = FALSE;
236}
237/**
238 * gnome_canvas_path_def_ensure_space:
239 * @path: a GnomeCanvasPathDef
240 * @space: number of points to guarantee are allocated at the end of
241 * the path.
242 *
243 * This function ensures that enough space for @space points is
244 * allocated at the end of the path.
245 */
246void
247gnome_canvas_path_def_ensure_space (GnomeCanvasPathDef * path, gint space)
248{
249        g_return_if_fail (path != NULL);
250        g_return_if_fail (space > 0);
251
252        if (path->end + space < path->length) return;
253
254        if (space < GNOME_CANVAS_PATH_DEF_LENSTEP) space = GNOME_CANVAS_PATH_DEF_LENSTEP;
255
256        path->bpath = art_renew (path->bpath, ArtBpath, path->length + space);
257
258        path->length += space;
259}
260
261/**
262 * gnome_canvas_path_def_copy:
263 * @dst: a GnomeCanvasPathDef where the contents of @src will be stored.
264 * @src: a GnomeCanvasPathDef whose contents will be copied it @src.
265 *
266 * This function copies the contents @src to @dest. The old @dest path
267 * array is freed and @dest is marked as non-static (editable),
268 * regardless of the status of @src.
269 */
270void
271gnome_canvas_path_def_copy (GnomeCanvasPathDef * dst, const GnomeCanvasPathDef * src)
272{
273        g_return_if_fail (dst != NULL);
274        g_return_if_fail (src != NULL);
275
276        if (!dst->sbpath) g_free (dst->bpath);
277
278        memcpy (dst, src, sizeof (GnomeCanvasPathDef));
279
280        dst->bpath = g_new (ArtBpath, src->end + 1);
281        memcpy (dst->bpath, src->bpath, (src->end + 1) * sizeof (ArtBpath));
282
283        dst->sbpath = FALSE;
284}
285
286
287/**
288 * gnome_canvas_path_def_duplicate:
289 * @path: a GnomeCanvasPathDef to duplicate
290 *
291 * This function duplicates the passed @path. The new path is
292 * marked as non-static regardless of the state of original.
293 *
294 * Returns: a GnomeCanvasPathDef which is a duplicate of @path.
295 */
296GnomeCanvasPathDef *
297gnome_canvas_path_def_duplicate (const GnomeCanvasPathDef * path)
298{
299        GnomeCanvasPathDef * new;
300
301        g_return_val_if_fail (path != NULL, NULL);
302
303        new = gnome_canvas_path_def_new_from_foreign_bpath (path->bpath);
304        new->x = path->x;
305        new->y = path->y;
306        new->hascpt = path->hascpt;
307        new->posset = path->posset;
308        new->moving = path->moving;
309        new->allclosed = path->allclosed;
310        new->allopen = path->allopen;
311
312        return new;
313}
314
315/**
316 * gnome_canvas_path_def_concat:
317 * @list: a GSList of GnomeCanvasPathDefs to concatenate into one new
318 * path.
319 *
320 * This function concatenates a list of GnomeCanvasPathDefs into one
321 * newly created GnomeCanvasPathDef.
322 *
323 * Returns: a new GnomeCanvasPathDef
324 */
325GnomeCanvasPathDef *
326gnome_canvas_path_def_concat (const GSList * list)
327{
328        GnomeCanvasPathDef * c, * new;
329        ArtBpath * bp;
330        const GSList * l;
331        gint length;
332
333        g_return_val_if_fail (list != NULL, NULL);
334
335        length = 1;
336
337        for (l = list; l != NULL; l = l->next) {
338                c = (GnomeCanvasPathDef *) l->data;
339                length += c->end;
340        }
341
342        new = gnome_canvas_path_def_new_sized (length);
343
344        bp = new->bpath;
345
346        for (l = list; l != NULL; l = l->next) {
347                c = (GnomeCanvasPathDef *) l->data;
348                memcpy (bp, c->bpath, c->end * sizeof (ArtBpath));
349                bp += c->end;
350        }
351
352        bp->code = ART_END;
353
354        new->end = length - 1;
355
356        new->allclosed = sp_bpath_all_closed (new->bpath);
357        new->allopen = sp_bpath_all_open (new->bpath);
358
359        return new;
360}
361
362/**
363 * gnome_canvas_path_def_split:
364 * @path: a GnomeCanvasPathDef
365 *
366 * This function splits the passed @path into a list of
367 * GnomeCanvasPathDefs which represent each segment of the origional
368 * path.  The path is split when ever an ART_MOVETO or ART_MOVETO_OPEN
369 * is encountered. The closedness of resulting paths is set accordingly
370 * to closedness of corresponding segment.
371 *
372 * Returns: a list of GnomeCanvasPathDef(s).
373 */
374GSList *
375gnome_canvas_path_def_split (const GnomeCanvasPathDef * path)
376{
377        GnomeCanvasPathDef * new;
378        GSList * l;
379        gint p, i;
380
381        g_return_val_if_fail (path != NULL, NULL);
382
383        p = 0;
384        l = NULL;
385
386        while (p < path->end) {
387                i = 1;
388                while ((path->bpath[p + i].code == ART_LINETO) || (path->bpath[p + i].code == ART_CURVETO)) i++;
389                new = gnome_canvas_path_def_new_sized (i + 1);
390                memcpy (new->bpath, path->bpath + p, i * sizeof (ArtBpath));
391                new->end = i;
392                new->bpath[i].code = ART_END;
393                new->allclosed = (new->bpath->code == ART_MOVETO);
394                new->allopen = (new->bpath->code == ART_MOVETO_OPEN);
395                l = g_slist_append (l, new);
396                p += i;
397        }
398
399        return l;
400}
401
402/**
403 * gnome_canvas_path_def_open_parts:
404 * @path: a GnomeCanvasPathDef
405 *
406 * This function creates a new GnomeCanvasPathDef that contains all of
407 * the open segments on the passed @path.
408 *
409 * Returns: a new GnomeCanvasPathDef that contains all of the open segemtns in @path.
410 */
411GnomeCanvasPathDef *
412gnome_canvas_path_def_open_parts (const GnomeCanvasPathDef * path)
413{
414        GnomeCanvasPathDef * new;
415        ArtBpath * p, * d;
416        gint len;
417        gboolean closed;
418
419        g_return_val_if_fail (path != NULL, NULL);
420
421        closed = TRUE;
422        len = 0;
423
424        for (p = path->bpath; p->code != ART_END; p++) {
425                switch (p->code) {
426                case ART_MOVETO_OPEN:
427                        closed = FALSE;
428                        len++;
429                        break;
430                case ART_MOVETO:
431                        closed = TRUE;
432                        break;
433                case ART_LINETO:
434                case ART_CURVETO:
435                        if (!closed) len++;
436                        break;
437                default:
438                        g_assert_not_reached ();
439                }
440        }
441
442        new = gnome_canvas_path_def_new_sized (len + 1);
443
444        closed = TRUE;
445        d = new->bpath;
446
447        for (p = path->bpath; p->code != ART_END; p++) {
448                switch (p->code) {
449                case ART_MOVETO_OPEN:
450                        closed = FALSE;
451                        *d++ = *p;
452                        break;
453                case ART_MOVETO:
454                        closed = TRUE;
455                        break;
456                case ART_LINETO:
457                case ART_CURVETO:
458                        if (!closed) *d++ = *p;
459                        break;
460                default:
461                        g_assert_not_reached ();
462                }
463        }
464
465        d->code = ART_END;
466
467        new->end = len;
468        new->allclosed = FALSE;
469        new->allopen = TRUE;
470
471        return new;
472}
473
474/**
475 * gnome_canvas_path_def_closed_parts:
476 * @path: a GnomeCanvasPathDef
477 *
478 * This function returns a new GnomeCanvasPathDef that contains the
479 * all of close parts of passed @path.
480 *
481 * Returns: a new GnomeCanvasPathDef that contains all of the closed
482 * parts of passed @path.
483 */
484GnomeCanvasPathDef *
485gnome_canvas_path_def_closed_parts (const GnomeCanvasPathDef * path)
486{
487        GnomeCanvasPathDef * new;
488        ArtBpath * p, * d;
489        gint len;
490        gboolean closed;
491
492        g_return_val_if_fail (path != NULL, NULL);
493
494        closed = FALSE;
495        len = 0;
496
497        for (p = path->bpath; p->code != ART_END; p++) {
498                switch (p->code) {
499                case ART_MOVETO_OPEN:
500                        closed = FALSE;
501                        break;
502                case ART_MOVETO:
503                        closed = TRUE;
504                        len++;
505                        break;
506                case ART_LINETO:
507                case ART_CURVETO:
508                        if (closed) len++;
509                        break;
510                default:
511                        g_assert_not_reached ();
512                }
513        }
514
515        new = gnome_canvas_path_def_new_sized (len + 1);
516
517        closed = FALSE;
518        d = new->bpath;
519
520        for (p = path->bpath; p->code != ART_END; p++) {
521                switch (p->code) {
522                case ART_MOVETO_OPEN:
523                        closed = FALSE;
524                        break;
525                case ART_MOVETO:
526                        closed = TRUE;
527                        *d++ = *p;
528                        break;
529                case ART_LINETO:
530                case ART_CURVETO:
531                        if (closed) *d++ = *p;
532                        break;
533                default:
534                        g_assert_not_reached ();
535                }
536        }
537
538        d->code = ART_END;
539
540        new->end = len;
541        new->allclosed = TRUE;
542        new->allopen = FALSE;
543
544        return new;
545}
546
547/**
548 * gnome_canvas_path_def_close_all:
549 * @path: a GnomeCanvasPathDef
550 *
551 * This function closes all of the open segments in the passed path
552 * and returns a new GnomeCanvasPathDef.
553 *
554 * Returns: a GnomeCanvasPathDef that contains the contents of @path
555 * but has modified the path is fully closed
556 */
557GnomeCanvasPathDef *
558gnome_canvas_path_def_close_all (const GnomeCanvasPathDef * path)
559{
560        GnomeCanvasPathDef * new;
561        ArtBpath * p, * d, * start;
562        gint len;
563        gboolean closed;
564
565        g_return_val_if_fail (path != NULL, NULL);
566
567        if (path->allclosed) {
568                new = gnome_canvas_path_def_duplicate (path);
569                return new;
570        }
571
572        len = 1;
573
574        /* Count MOVETO_OPEN */
575
576        for (p = path->bpath; p->code != ART_END; p++) {
577                len += 1;
578                if (p->code == ART_MOVETO_OPEN) len += 2;
579        }
580
581        new = gnome_canvas_path_def_new_sized (len);
582
583        d = start = new->bpath;
584        closed = TRUE;
585
586        for (p = path->bpath; p->code != ART_END; p++) {
587                switch (p->code) {
588                case ART_MOVETO_OPEN:
589                        start = p;
590                        closed = FALSE;
591                case ART_MOVETO:
592                        if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
593                                d->code = ART_LINETO;
594                                d->x3 = start->x3;
595                                d->y3 = start->y3;
596                                d++;
597                        }
598                        if (p->code == ART_MOVETO) closed = TRUE;
599                        d->code = ART_MOVETO;
600                        d->x3 = p->x3;
601                        d->y3 = p->y3;
602                        d++;
603                        break;
604                case ART_LINETO:
605                case ART_CURVETO:
606                        *d++ = *p;
607                        break;
608                default:
609                        g_assert_not_reached ();
610                }
611        }
612
613        if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
614                d->code = ART_LINETO;
615                d->x3 = start->x3;
616                d->y3 = start->y3;
617                d++;
618        }
619
620        d->code = ART_END;
621
622        new->end = d - new->bpath;
623        new->allclosed = TRUE;
624        new->allopen = FALSE;
625
626        return new;
627}
628
629/* Destructor */
630
631/**
632 * gnome_canvas_path_def_unref:
633 * @path: a GnomeCanvasPathDef
634 *
635 * Decrease the reference count of the passed @path.  If the reference
636 * count is < 1 the path is deallocated.
637 */
638void
639gnome_canvas_path_def_unref (GnomeCanvasPathDef * path)
640{
641        g_return_if_fail (path != NULL);
642
643        if (--path->refcount < 1) {
644                if ((!path->sbpath) && (path->bpath)) art_free (path->bpath);
645                g_free (path);
646        }
647}
648
649
650/* Methods */
651/**
652 * gnome_canvas_path_def_reset:
653 * @path: a GnomeCanvasPathDef
654 *
655 * This function clears the contents of the passed @path.
656 */
657void
658gnome_canvas_path_def_reset (GnomeCanvasPathDef * path)
659{
660        g_return_if_fail (path != NULL);
661        g_return_if_fail (!path->sbpath);
662
663        path->bpath->code = ART_END;
664        path->end = 0;
665        path->hascpt = FALSE;
666        path->posset = FALSE;
667        path->moving = FALSE;
668        path->allclosed = TRUE;
669        path->allopen = TRUE;
670}
671
672/* Several consequtive movetos are ALLOWED */
673
674/**
675 * gnome_canvas_path_def_moveto:
676 * @path: a GnomeCanvasPathDef
677 * @x: x coordinate
678 * @y: y coordinate
679 *
680 * This function adds starts new subpath on @path, and sets its
681 * starting point to @x and @y. If current subpath is empty, it
682 * simply changes its starting coordinates to new values.
683 */
684void
685gnome_canvas_path_def_moveto (GnomeCanvasPathDef * path, gdouble x, gdouble y)
686{
687        g_return_if_fail (path != NULL);
688        g_return_if_fail (!path->sbpath);
689        g_return_if_fail (!path->moving);
690
691        path->substart = path->end;
692        path->hascpt = TRUE;
693        path->posset = TRUE;
694        path->x = x;
695        path->y = y;
696
697        path->allclosed = FALSE;
698}
699
700/**
701 * gnome_canvas_path_def_lineto:
702 * @path: a GnomeCanvasPathDef
703 * @x: x coordinate
704 * @y: y coordinate
705 *
706 * This function add a line segment to the passed @path with the
707 * specified @x and @y coordinates.
708 */
709void
710gnome_canvas_path_def_lineto (GnomeCanvasPathDef * path, gdouble x, gdouble y)
711{
712        ArtBpath * bp;
713
714        g_return_if_fail (path != NULL);
715        g_return_if_fail (!path->sbpath);
716        g_return_if_fail (path->hascpt);
717
718        if (path->moving) {
719                /* simply fix endpoint */
720                g_return_if_fail (!path->posset);
721                g_return_if_fail (path->end > 1);
722                bp = path->bpath + path->end - 1;
723                g_return_if_fail (bp->code == ART_LINETO);
724                bp->x3 = x;
725                bp->y3 = y;
726                path->moving = FALSE;
727                return;
728        }
729
730        if (path->posset) {
731                /* start a new segment */
732                gnome_canvas_path_def_ensure_space (path, 2);
733                bp = path->bpath + path->end;
734                bp->code = ART_MOVETO_OPEN;
735                bp->x3 = path->x;
736                bp->y3 = path->y;
737                bp++;
738                bp->code = ART_LINETO;
739                bp->x3 = x;
740                bp->y3 = y;
741                bp++;
742                bp->code = ART_END;
743                path->end += 2;
744                path->posset = FALSE;
745                path->allclosed = FALSE;
746                return;
747        }
748
749        /* Simply add line */
750
751        g_return_if_fail (path->end > 1);
752        gnome_canvas_path_def_ensure_space (path, 1);
753        bp = path->bpath + path->end;
754        bp->code = ART_LINETO;
755        bp->x3 = x;
756        bp->y3 = y;
757        bp++;
758        bp->code = ART_END;
759        path->end++;
760}
761
762
763/**
764 * gnome_canvas_path_def_lineto_moving:
765 * @path: a GnomeCanvasPathDef
766 * @x: x coordinate
767 * @y: y coordinate
768 *
769 * This functions adds a new line segment with loose endpoint to the path, or
770 * if endpoint is already loose, changes its coordinates to @x, @y. You
771 * can change the coordinates of loose endpoint as many times as you want,
772 * the last ones set will be fixed, if you continue line. This is useful
773 * for handling drawing with mouse.
774 */
775void
776gnome_canvas_path_def_lineto_moving (GnomeCanvasPathDef * path, gdouble x, gdouble y)
777{
778        ArtBpath * bp;
779
780        g_return_if_fail (path != NULL);
781        g_return_if_fail (!path->sbpath);
782        g_return_if_fail (path->hascpt);
783
784        if (path->moving) {
785                /* simply change endpoint */
786                g_return_if_fail (!path->posset);
787                g_return_if_fail (path->end > 1);
788                bp = path->bpath + path->end - 1;
789                g_return_if_fail (bp->code == ART_LINETO);
790                bp->x3 = x;
791                bp->y3 = y;
792                return;
793        }
794
795        if (path->posset) {
796                /* start a new segment */
797                gnome_canvas_path_def_ensure_space (path, 2);
798                bp = path->bpath + path->end;
799                bp->code = ART_MOVETO_OPEN;
800                bp->x3 = path->x;
801                bp->y3 = path->y;
802                bp++;
803                bp->code = ART_LINETO;
804                bp->x3 = x;
805                bp->y3 = y;
806                bp++;
807                bp->code = ART_END;
808                path->end += 2;
809                path->posset = FALSE;
810                path->moving = TRUE;
811                path->allclosed = FALSE;
812                return;
813        }
814
815        /* Simply add line */
816
817        g_return_if_fail (path->end > 1);
818        gnome_canvas_path_def_ensure_space (path, 1);
819        bp = path->bpath + path->end;
820        bp->code = ART_LINETO;
821        bp->x3 = x;
822        bp->y3 = y;
823        bp++;
824        bp->code = ART_END;
825        path->end++;
826        path->moving = TRUE;
827}
828
829/**
830 * gnome_canvas_path_def_curveto:
831 * @path: a GnomeCanvasPathDef
832 * @x0: first control point x coordinate
833 * @y0: first control point y coordinate
834 * @x1: second control point x coordinate
835 * @y1: second control point y coordinate
836 * @x2: end of curve x coordinate
837 * @y2: end of curve y coordinate
838 *
839 * This function adds a bezier curve segment to the path definition.
840 */
841 
842void
843gnome_canvas_path_def_curveto (GnomeCanvasPathDef * path, gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdouble y2)
844{
845        ArtBpath * bp;
846
847        g_return_if_fail (path != NULL);
848        g_return_if_fail (!path->sbpath);
849        g_return_if_fail (path->hascpt);
850        g_return_if_fail (!path->moving);
851
852        if (path->posset) {
853                /* start a new segment */
854                gnome_canvas_path_def_ensure_space (path, 2);
855                bp = path->bpath + path->end;
856                bp->code = ART_MOVETO_OPEN;
857                bp->x3 = path->x;
858                bp->y3 = path->y;
859                bp++;
860                bp->code = ART_CURVETO;
861                bp->x1 = x0;
862                bp->y1 = y0;
863                bp->x2 = x1;
864                bp->y2 = y1;
865                bp->x3 = x2;
866                bp->y3 = y2;
867                bp++;
868                bp->code = ART_END;
869                path->end += 2;
870                path->posset = FALSE;
871                path->allclosed = FALSE;
872                return;
873        }
874
875        /* Simply add path */
876
877        g_return_if_fail (path->end > 1);
878        gnome_canvas_path_def_ensure_space (path, 1);
879        bp = path->bpath + path->end;
880        bp->code = ART_CURVETO;
881        bp->x1 = x0;
882        bp->y1 = y0;
883        bp->x2 = x1;
884        bp->y2 = y1;
885        bp->x3 = x2;
886        bp->y3 = y2;
887        bp++;
888        bp->code = ART_END;
889        path->end++;
890}
891
892/**
893 * gnome_canvas_path_def_closepath:
894 * @path: a GnomeCanvasPathDef
895 *
896 * This function closes the last subpath of @path, adding a ART_LINETO to
897 * subpath starting point, if needed and changing starting pathcode to
898 * ART_MOVETO
899 */
900void
901gnome_canvas_path_def_closepath (GnomeCanvasPathDef * path)
902{
903        ArtBpath * bs, * be;
904
905        g_return_if_fail (path != NULL);
906        g_return_if_fail (!path->sbpath);
907        g_return_if_fail (path->hascpt);
908        g_return_if_fail (!path->posset);
909        g_return_if_fail (!path->moving);
910        g_return_if_fail (!path->allclosed);
911        /* We need at last M + L + L + E */
912        g_return_if_fail (path->end - path->substart > 2);
913
914        bs = path->bpath + path->substart;
915        be = path->bpath + path->end - 1;
916
917        if ((bs->x3 != be->x3) || (bs->y3 != be->y3)) {
918                gnome_canvas_path_def_lineto (path, bs->x3, bs->y3);
919        }
920
921        bs = path->bpath + path->substart; /* NB. def_lineto can
922                                              realloc bpath */
923        bs->code = ART_MOVETO;
924
925        path->allclosed = sp_bpath_all_closed (path->bpath);
926        path->allopen = sp_bpath_all_open (path->bpath);
927
928        path->hascpt = FALSE;
929}
930
931/**
932 * gnome_canvas_path_def_closepath_current:
933 * @path: a GnomeCanvasPathDef
934 *
935 * This function closes the last subpath by setting the coordinates of
936 * the endpoint of the last segment (line or curve) to starting point.
937 */
938void
939gnome_canvas_path_def_closepath_current (GnomeCanvasPathDef * path)
940{
941        ArtBpath * bs, * be;
942
943        g_return_if_fail (path != NULL);
944        g_return_if_fail (!path->sbpath);
945        g_return_if_fail (path->hascpt);
946        g_return_if_fail (!path->posset);
947        g_return_if_fail (!path->allclosed);
948        /* We need at last M + L + L + E */
949        g_return_if_fail (path->end - path->substart > 2);
950
951        bs = path->bpath + path->substart;
952        be = path->bpath + path->end - 1;
953
954        be->x3 = bs->x3;
955        be->y3 = bs->y3;
956
957        bs->code = ART_MOVETO;
958
959        path->allclosed = sp_bpath_all_closed (path->bpath);
960        path->allopen = sp_bpath_all_open (path->bpath);
961
962        path->hascpt = FALSE;
963        path->moving = FALSE;
964}
965
966/**
967 * gnome_canvas_path_def_bpath:
968 * @path: a GnomeCanvasPathDef
969 *
970 * This function returns a ArtBpath that consists of the path
971 * definition.
972 *
973 * Returns: ArtBpath
974 */
975ArtBpath * gnome_canvas_path_def_bpath (const GnomeCanvasPathDef * path)
976{
977        g_return_val_if_fail (path != NULL, NULL);
978
979        return path->bpath;
980}
981
982/**
983 * gnome_canvas_path_def_length:
984 * @path: a GnomeCanvasPathDef
985 *
986 * This function returns the length of the path definition.  Not
987 * Euclidian length of the path but rather the number of points on the
988 * path.
989 *
990 * Returns: integer, number of points on the path.
991 */
992gint gnome_canvas_path_def_length (const GnomeCanvasPathDef * path)
993{
994        g_return_val_if_fail (path != NULL, -1);
995
996        return path->end + 1;
997}
998
999/**
1000 * gnome_canvas_path_def_is_empty:
1001 * @path: a GnomeCanvasPathDef
1002 *
1003 * This function is a boolean test to see if the path is empty,
1004 * meaning containing no line segments.
1005 *
1006 * Returns: boolean, indicating if the path is empty.
1007 */
1008gboolean
1009gnome_canvas_path_def_is_empty (const GnomeCanvasPathDef * path)
1010{
1011        g_return_val_if_fail (path != NULL, TRUE);
1012
1013        return (path->bpath->code == ART_END);
1014}
1015
1016/**
1017 * gnome_canvas_path_def_has_currentpoint:
1018 * @path: a GnomeCanvasPathdef
1019 *
1020 * This function is a boolean test checking to see if the path has a
1021 * current point defined. Current point will be set by line operators,
1022 * and cleared by closing subpath.
1023 *
1024 * Returns: boolean, indicating if the path has a current point defined.
1025 */
1026gboolean
1027gnome_canvas_path_def_has_currentpoint (const GnomeCanvasPathDef * path)
1028{
1029        g_return_val_if_fail (path != NULL, FALSE);
1030
1031        return (path->hascpt);
1032}
1033
1034/**
1035 * gnome_canvas_path_def_currentpoint:
1036 * @path: a GnomeCanvasPathDef
1037 * @p: a ArtPoint where to store the current point
1038 *
1039 * Stores the current point of the path definition in the passed ArtPoint @p.
1040 */
1041void
1042gnome_canvas_path_def_currentpoint (const GnomeCanvasPathDef * path, ArtPoint * p)
1043{
1044        g_return_if_fail (path != NULL);
1045        g_return_if_fail (p != NULL);
1046        g_return_if_fail (path->hascpt);
1047
1048        if (path->posset) {
1049                p->x = path->x;
1050                p->y = path->y;
1051        } else {
1052                p->x = (path->bpath + path->end - 1)->x3;
1053                p->y = (path->bpath + path->end - 1)->y3;
1054        }       
1055}
1056
1057/**
1058 * gnome_canvas_path_def_last_bpath:
1059 * @path: a GnomeCanvasPathDef
1060 *
1061 * This function returns pointer to the last ArtBpath segment in the path
1062 * definition.
1063 *
1064 * Returns: ArtBpath, being the last segment in the path definition or
1065 * null if no line segments have been defined.
1066 */
1067ArtBpath *
1068gnome_canvas_path_def_last_bpath (const GnomeCanvasPathDef * path)
1069{
1070        g_return_val_if_fail (path != NULL, NULL);
1071
1072        if (path->end == 0) return NULL;
1073
1074        return path->bpath + path->end - 1;
1075}
1076
1077/**
1078 * gnome_canvas_path_def_first_bpath:
1079 * @path: a GnomeCanvasPathDef
1080 *
1081 * This function returns the first ArtBpath point in the definition.
1082 *
1083 * Returns: ArtBpath being the first point in the path definition or
1084 * null if no points are defined
1085*/
1086ArtBpath *
1087gnome_canvas_path_def_first_bpath (const GnomeCanvasPathDef * path)
1088{
1089        g_return_val_if_fail (path != NULL, NULL);
1090
1091        if (path->end == 0) return NULL;
1092
1093        return path->bpath;
1094}
1095
1096/**
1097 * gnome_canvas_path_def_any_open:
1098 * @path: a GnomeCanvasPathDef
1099 *
1100 * This function returns a boolean value indicating if the path has
1101 * any open segments.
1102 *
1103 * Returns: boolean, indicating if the path has any open segments.
1104 */
1105gboolean
1106gnome_canvas_path_def_any_open (const GnomeCanvasPathDef * path)
1107{
1108        g_return_val_if_fail (path != NULL, FALSE);
1109
1110        return (!path->allclosed);
1111}
1112
1113/**
1114 * gnome_canvas_path_def_all_open:
1115 * @path: a GnomeCanvasPathDef
1116 *
1117 * This function returns a boolean value indicating if the path only
1118 * contains open segments.
1119 *
1120 * Returns: boolean, indicating if the path has all open segments.
1121 */
1122gboolean
1123gnome_canvas_path_def_all_open (const GnomeCanvasPathDef * path)
1124{
1125        g_return_val_if_fail (path != NULL, FALSE);
1126
1127        return (path->allopen);
1128}
1129
1130/**
1131 * gnome_canvas_path_def_any_closed:
1132 * @path: a GnomeCanvasPathDef
1133 *
1134 * This function returns a boolean valid indicating if the path has
1135 * any closed segements.
1136 *
1137 * Returns: boolean, indicating if the path has any closed segments.
1138 */
1139gboolean
1140gnome_canvas_path_def_any_closed (const GnomeCanvasPathDef * path)
1141{
1142        g_return_val_if_fail (path != NULL, FALSE);
1143
1144        return (!path->allopen);
1145}
1146
1147/**
1148 * gnome_canvas_path_def_all_closed:
1149 * @path: a GnomeCanvasPathDef
1150 *
1151 * This function returns a boolean value indicating if the path only
1152 * contains closed segments.
1153 *
1154 * Returns: boolean, indicating if the path has all closed segments.
1155 */
1156gboolean
1157gnome_canvas_path_def_all_closed (const GnomeCanvasPathDef * path)
1158{
1159        g_return_val_if_fail (path != NULL, FALSE);
1160
1161        return (path->allclosed);
1162}
1163
1164/* Private methods */
1165
1166static
1167gboolean sp_bpath_good (ArtBpath * bpath)
1168{
1169        ArtBpath * bp;
1170
1171        g_return_val_if_fail (bpath != NULL, FALSE);
1172
1173        if (bpath->code == ART_END)
1174                return TRUE;
1175
1176        bp = bpath;
1177
1178        while (bp->code != ART_END) {
1179                bp = sp_bpath_check_subpath (bp);
1180                if (bp == NULL) return FALSE;
1181        }
1182
1183        return TRUE;
1184}
1185
1186static ArtBpath *
1187sp_bpath_check_subpath (ArtBpath * bpath)
1188{
1189        gint i, len;
1190        gboolean closed;
1191
1192        g_return_val_if_fail (bpath != NULL, NULL);
1193
1194        if (bpath->code == ART_MOVETO) {
1195                closed = TRUE;
1196        } else if (bpath->code == ART_MOVETO_OPEN) {
1197                closed = FALSE;
1198        } else {
1199                return NULL;
1200        }
1201
1202        len = 0;
1203
1204        for (i = 1; (bpath[i].code != ART_END) && (bpath[i].code != ART_MOVETO) && (bpath[i].code != ART_MOVETO_OPEN); i++) {
1205                switch (bpath[i].code) {
1206                        case ART_LINETO:
1207                        case ART_CURVETO:
1208                                len++;
1209                                break;
1210                        default:
1211                                return NULL;
1212                }
1213        }
1214
1215        if (closed) {
1216                if (len < 2) return NULL;
1217                if ((bpath->x3 != bpath[i-1].x3) || (bpath->y3 != bpath[i-1].y3)) return NULL;
1218        } else {
1219                if (len < 1) return NULL;
1220        }
1221
1222        return bpath + i;
1223}
1224
1225static gint
1226sp_bpath_length (const ArtBpath * bpath)
1227{
1228        gint l;
1229
1230        g_return_val_if_fail (bpath != NULL, FALSE);
1231
1232        for (l = 0; bpath[l].code != ART_END; l++) ;
1233
1234        l++;
1235
1236        return l;
1237}
1238
1239static gboolean
1240sp_bpath_all_closed (const ArtBpath * bpath)
1241{
1242        const ArtBpath * bp;
1243
1244        g_return_val_if_fail (bpath != NULL, FALSE);
1245
1246        for (bp = bpath; bp->code != ART_END; bp++)
1247                if (bp->code == ART_MOVETO_OPEN) return FALSE;
1248
1249        return TRUE;
1250}
1251
1252static gboolean
1253sp_bpath_all_open (const ArtBpath * bpath)
1254{
1255        const ArtBpath * bp;
1256
1257        g_return_val_if_fail (bpath != NULL, FALSE);
1258
1259        for (bp = bpath; bp->code != ART_END; bp++)
1260                if (bp->code == ART_MOVETO) return FALSE;
1261
1262        return TRUE;
1263}
1264
1265
Note: See TracBrowser for help on using the repository browser.