Code

added fix from Dale Harvey to expand incomplete JIDs specified in user
[inkscape.git] / src / livarot / Path.cpp
1 /*
2  *  Path.cpp
3  *  nlivarot
4  *
5  *  Created by fred on Tue Jun 17 2003.
6  *
7  */
9 #include <glib.h>
10 #include "Path.h"
11 #include "livarot/path-description.h"
12 #include <libnr/nr-matrix-ops.h>
14 /*
15  * manipulation of the path data: path description and polyline
16  * grunt work...
17  * at the end of this file, 2 utilitary functions to get the point and tangent to path associated with a (command no;abcissis)
18  */
21 Path::Path()
22 {
23         descr_flags = 0;
24         pending_bezier_cmd = -1;
25         pending_moveto_cmd = -1;
26   
27         back = false;
28 }
30 Path::~Path()
31 {
32     for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
33         delete *i;
34     }
35 }
37 // debug function do dump the path contents on stdout
38 void Path::Affiche()
39 {
40     std::cout << "path: " << descr_cmd.size() << " commands." << std::endl;
41     for (std::vector<PathDescr*>::const_iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
42         (*i)->dump(std::cout);
43         std::cout << std::endl;
44     }
46     std::cout << std::endl;
47 }
49 void Path::Reset()
50 {
51     for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
52         delete *i;
53     }
54     
55     descr_cmd.clear();
56     pending_bezier_cmd = -1;
57     pending_moveto_cmd = -1;
58     descr_flags = 0;
59 }
61 void Path::Copy(Path * who)
62 {
63     ResetPoints();
64     
65     for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
66         delete *i;
67     }
68         
69     descr_cmd.clear();
70         
71     for (std::vector<PathDescr*>::const_iterator i = who->descr_cmd.begin();
72          i != who->descr_cmd.end();
73          i++)
74     {
75         descr_cmd.push_back((*i)->clone());
76     }
77 }
79 void Path::CloseSubpath()
80 {
81     descr_flags &= ~(descr_doing_subpath);
82     pending_moveto_cmd = -1;
83 }
85 int Path::ForcePoint()
86 {
87     if (descr_flags & descr_adding_bezier) {
88         EndBezierTo ();
89     }
90     
91     if ( (descr_flags & descr_doing_subpath) == 0 ) {
92         return -1;
93     }
94     
95     if (descr_cmd.empty()) {
96         return -1;
97     }
99     descr_cmd.push_back(new PathDescrForced);
100     return descr_cmd.size() - 1;
104 void Path::InsertForcePoint(int at)
106     if ( at < 0 || at > int(descr_cmd.size()) ) {
107         return;
108     }
109     
110     if ( at == int(descr_cmd.size()) ) {
111         ForcePoint();
112         return;
113     }
114     
115     descr_cmd.insert(descr_cmd.begin() + at, new PathDescrForced);
118 int Path::Close()
120     if ( descr_flags & descr_adding_bezier ) {
121         CancelBezier();
122     }
123     if ( descr_flags & descr_doing_subpath ) {
124         CloseSubpath();
125     } else {
126         // Nothing to close.
127         return -1;
128     }
130     descr_cmd.push_back(new PathDescrClose);
131     
132     descr_flags &= ~(descr_doing_subpath);
133     pending_moveto_cmd = -1;
134     
135     return descr_cmd.size() - 1;
138 int Path::MoveTo(NR::Point const &iPt)
140     if ( descr_flags & descr_adding_bezier ) {
141         EndBezierTo(iPt);
142     }
143     if ( descr_flags & descr_doing_subpath ) {
144         CloseSubpath();
145     }
146     pending_moveto_cmd = descr_cmd.size();
147     
148     descr_cmd.push_back(new PathDescrMoveTo(iPt));
150     descr_flags |= descr_doing_subpath;
151     return descr_cmd.size() - 1;
154 void Path::InsertMoveTo(NR::Point const &iPt, int at)
156     if ( at < 0 || at > int(descr_cmd.size()) ) {
157         return;
158     }
159     
160     if ( at == int(descr_cmd.size()) ) {
161         MoveTo(iPt);
162         return;
163     }
165   descr_cmd.insert(descr_cmd.begin() + at, new PathDescrMoveTo(iPt));
168 int Path::LineTo(NR::Point const &iPt)
170     if (descr_flags & descr_adding_bezier) {
171         EndBezierTo (iPt);
172     }
173     if (!( descr_flags & descr_doing_subpath )) {
174         return MoveTo (iPt);
175     }
176     
177     descr_cmd.push_back(new PathDescrLineTo(iPt));
178     return descr_cmd.size() - 1;
181 void Path::InsertLineTo(NR::Point const &iPt, int at)
183     if ( at < 0 || at > int(descr_cmd.size()) ) {
184         return;
185     }
186     
187     if ( at == int(descr_cmd.size()) ) {
188         LineTo(iPt);
189         return;
190     }
191     
192     descr_cmd.insert(descr_cmd.begin() + at, new PathDescrLineTo(iPt));
195 int Path::CubicTo(NR::Point const &iPt, NR::Point const &iStD, NR::Point const &iEnD)
197     if (descr_flags & descr_adding_bezier) {
198         EndBezierTo(iPt);
199     }
200     if ( (descr_flags & descr_doing_subpath) == 0) {
201         return MoveTo (iPt);
202     }
204     descr_cmd.push_back(new PathDescrCubicTo(iPt, iStD, iEnD));
205     return descr_cmd.size() - 1;
209 void Path::InsertCubicTo(NR::Point const &iPt, NR::Point const &iStD, NR::Point const &iEnD, int at)
211     if ( at < 0 || at > int(descr_cmd.size()) ) {
212         return;
213     }
214     
215     if ( at == int(descr_cmd.size()) ) {
216         CubicTo(iPt,iStD,iEnD);
217         return;
218     }
219   
220     descr_cmd.insert(descr_cmd.begin() + at, new PathDescrCubicTo(iPt, iStD, iEnD));
223 int Path::ArcTo(NR::Point const &iPt, double iRx, double iRy, double angle,
224                 bool iLargeArc, bool iClockwise)
226     if (descr_flags & descr_adding_bezier) {
227         EndBezierTo(iPt);
228     }
229     if ( (descr_flags & descr_doing_subpath) == 0 ) {
230         return MoveTo(iPt);
231     }
233     descr_cmd.push_back(new PathDescrArcTo(iPt, iRx, iRy, angle, iLargeArc, iClockwise));
234     return descr_cmd.size() - 1;
238 void Path::InsertArcTo(NR::Point const &iPt, double iRx, double iRy, double angle,
239                        bool iLargeArc, bool iClockwise, int at)
241     if ( at < 0 || at > int(descr_cmd.size()) ) {
242         return;
243     }
244     
245     if ( at == int(descr_cmd.size()) ) {
246         ArcTo(iPt, iRx, iRy, angle, iLargeArc, iClockwise);
247         return;
248     }
249   
250     descr_cmd.insert(descr_cmd.begin() + at, new PathDescrArcTo(iPt, iRx, iRy,
251                                                                 angle, iLargeArc, iClockwise));
254 int Path::TempBezierTo()
256     if (descr_flags & descr_adding_bezier) {
257         CancelBezier();
258     }
259     if ( (descr_flags & descr_doing_subpath) == 0) {
260         // No starting point -> bad.
261         return -1;
262     }
263     pending_bezier_cmd = descr_cmd.size();
264     
265     descr_cmd.push_back(new PathDescrBezierTo(NR::Point(0, 0), 0));
266     descr_flags |= descr_adding_bezier;
267     descr_flags |= descr_delayed_bezier;
268     return descr_cmd.size() - 1;
271 void Path::CancelBezier()
273     descr_flags &= ~(descr_adding_bezier);
274     descr_flags &= ~(descr_delayed_bezier);
275     if (pending_bezier_cmd < 0) {
276         return;
277     }
279     /* FIXME: I think there's a memory leak here */
280     descr_cmd.resize(pending_bezier_cmd);
281     pending_bezier_cmd = -1;
284 int Path::EndBezierTo()
286     if (descr_flags & descr_delayed_bezier) {
287         CancelBezier ();
288     } else {
289         pending_bezier_cmd = -1;
290         descr_flags &= ~(descr_adding_bezier);
291         descr_flags &= ~(descr_delayed_bezier);
292     }
293     return -1;
296 int Path::EndBezierTo(NR::Point const &iPt)
298     if ( (descr_flags & descr_adding_bezier) == 0 ) {
299         return LineTo(iPt);
300     }
301     if ( (descr_flags & descr_doing_subpath) == 0 ) {
302         return MoveTo(iPt);
303     }
304     if ( (descr_flags & descr_delayed_bezier) == 0 ) {
305         return EndBezierTo();
306     }
307     PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[pending_bezier_cmd]);
308     nData->p = iPt;
309     pending_bezier_cmd = -1;
310     descr_flags &= ~(descr_adding_bezier);
311     descr_flags &= ~(descr_delayed_bezier);
312     return -1;
316 int Path::IntermBezierTo(NR::Point const &iPt)
318     if ( (descr_flags & descr_adding_bezier) == 0 ) {
319         return LineTo (iPt);
320     }
321     
322     if ( (descr_flags & descr_doing_subpath) == 0) {
323         return MoveTo (iPt);
324     }
326     descr_cmd.push_back(new PathDescrIntermBezierTo(iPt));
328     PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[pending_bezier_cmd]);
329     nBData->nb++;
330     return descr_cmd.size() - 1;
334 void Path::InsertIntermBezierTo(NR::Point const &iPt, int at)
336     if ( at < 0 || at > int(descr_cmd.size()) ) {
337         return;
338     }
339     
340     if ( at == int(descr_cmd.size()) ) {
341         IntermBezierTo(iPt);
342         return;
343     }
344     
345     descr_cmd.insert(descr_cmd.begin() + at, new PathDescrIntermBezierTo(iPt));
349 int Path::BezierTo(NR::Point const &iPt)
351     if ( descr_flags & descr_adding_bezier ) {
352         EndBezierTo(iPt);
353     }
354     
355     if ( (descr_flags & descr_doing_subpath) == 0 ) {
356         return MoveTo (iPt);
357     }
358     
359     pending_bezier_cmd = descr_cmd.size();
360     
361     descr_cmd.push_back(new PathDescrBezierTo(iPt, 0));
362     descr_flags |= descr_adding_bezier;
363     descr_flags &= ~(descr_delayed_bezier);
364     return descr_cmd.size() - 1;
368 void Path::InsertBezierTo(NR::Point const &iPt, int iNb, int at)
370     if ( at < 0 || at > int(descr_cmd.size()) ) {
371         return;
372     }
373     
374     if ( at == int(descr_cmd.size()) ) {
375         BezierTo(iPt);
376         return;
377     }
378   
379     descr_cmd.insert(descr_cmd.begin() + at, new PathDescrBezierTo(iPt, iNb));
383 /*
384  * points de la polyligne
385  */
386 void
387 Path::SetBackData (bool nVal)
389         if (back == false) {
390                 if (nVal == true && back == false) {
391                         back = true;
392                         ResetPoints();
393                 } else if (nVal == false && back == true) {
394                         back = false;
395                         ResetPoints();
396                 }
397         } else {
398                 if (nVal == true && back == false) {
399                         back = true;
400                         ResetPoints();
401                 } else if (nVal == false && back == true) {
402                         back = false;
403                         ResetPoints();
404                 }
405         }
409 void Path::ResetPoints()
411     pts.clear();
415 int Path::AddPoint(NR::Point const &iPt, bool mvto)
417     if (back) {
418         return AddPoint (iPt, -1, 0.0, mvto);
419     }
420   
421     if ( !mvto && pts.empty() == false && pts.back().p == iPt ) {
422         return -1;
423     }
424     
425     int const n = pts.size();
426     pts.push_back(path_lineto(mvto ? polyline_moveto : polyline_lineto, iPt));
427     return n;
431 int Path::AddPoint(NR::Point const &iPt, int ip, double it, bool mvto)
433     if (back == false) {
434         return AddPoint (iPt, mvto);
435     }
436     
437     if ( !mvto && pts.empty() == false && pts.back().p == iPt ) {
438         return -1;
439     }
440     
441     int const n = pts.size();
442     pts.push_back(path_lineto(mvto ? polyline_moveto : polyline_lineto, iPt, ip, it));
443     return n;
446 int Path::AddForcedPoint(NR::Point const &iPt)
448     if (back) {
449         return AddForcedPoint (iPt, -1, 0.0);
450     }
451     
452     if ( pts.empty() || pts.back().isMoveTo != polyline_lineto ) {
453         return -1;
454     }
455     
456     int const n = pts.size();
457     pts.push_back(path_lineto(polyline_forced, pts[n - 1].p));
458     return n;
462 int Path::AddForcedPoint(NR::Point const &iPt, int /*ip*/, double /*it*/)
464     /* FIXME: ip & it aren't used.  Is this deliberate? */
465     if (!back) {
466         return AddForcedPoint (iPt);
467     }
468     
469     if ( pts.empty() || pts.back().isMoveTo != polyline_lineto ) {
470         return -1;
471     }
472     
473     int const n = pts.size();
474     pts.push_back(path_lineto(polyline_forced, pts[n - 1].p, pts[n - 1].piece, pts[n - 1].t));
475     return n;
478 void Path::PolylineBoundingBox(double &l, double &t, double &r, double &b)
480   l = t = r = b = 0.0;
481   if ( pts.empty() ) {
482       return;
483   }
485   std::vector<path_lineto>::const_iterator i = pts.begin();
486   l = r = i->p[NR::X];
487   t = b = i->p[NR::Y];
488   i++;
490   for (; i != pts.end(); i++) {
491       r = std::max(r, i->p[NR::X]);
492       l = std::min(l, i->p[NR::X]);
493       b = std::max(b, i->p[NR::Y]);
494       t = std::min(t, i->p[NR::Y]);
495   }
499 /**
500  *    \param piece Index of a one of our commands.
501  *    \param at Distance along the segment that corresponds to `piece' (0 <= at <= 1)
502  *    \param pos Filled in with the point at `at' on `piece'.
503  */
505 void Path::PointAt(int piece, double at, NR::Point &pos)
507     if (piece < 0 || piece >= int(descr_cmd.size())) {
508         // this shouldn't happen: the piece we are asked for doesn't
509         // exist in the path
510         pos = NR::Point(0,0);
511         return;
512     }
513     
514     PathDescr const *theD = descr_cmd[piece];
515     int const typ = theD->getType();
516     NR::Point tgt;
517     double len;
518     double rad;
519     
520     if (typ == descr_moveto) {
521         
522         return PointAt (piece + 1, 0.0, pos);
523         
524     } else if (typ == descr_close || typ == descr_forced) {
525         
526         return PointAt (piece - 1, 1.0, pos);
527         
528     } else if (typ == descr_lineto) {
529         
530         PathDescrLineTo const *nData = dynamic_cast<PathDescrLineTo const *>(theD);
531         TangentOnSegAt(at, PrevPoint (piece - 1), *nData, pos, tgt, len);
532         
533     } else if (typ == descr_arcto) {
534         
535         PathDescrArcTo const *nData = dynamic_cast<PathDescrArcTo const *>(theD);
536         TangentOnArcAt(at,PrevPoint (piece - 1), *nData, pos, tgt, len, rad);
537         
538     } else if (typ == descr_cubicto) {
539         
540         PathDescrCubicTo const *nData = dynamic_cast<PathDescrCubicTo const *>(theD);
541         TangentOnCubAt(at, PrevPoint (piece - 1), *nData, false, pos, tgt, len, rad);
542         
543     } else if (typ == descr_bezierto || typ == descr_interm_bezier) {
544         
545         int bez_st = piece;
546         while (bez_st >= 0) {
547             int nt = descr_cmd[bez_st]->getType();
548             if (nt == descr_bezierto)
549                 break;
550             bez_st--;
551         }
552         if ( bez_st < 0 ) {
553             // Didn't find the beginning of the spline (bad).
554             // [pas trouvé le dubut de la spline (mauvais)]
555             return PointAt(piece - 1, 1.0, pos);
556         }
557         
558         PathDescrBezierTo *stB = dynamic_cast<PathDescrBezierTo *>(descr_cmd[bez_st]);
559         if ( piece > bez_st + stB->nb ) {
560             // The spline goes past the authorized number of commands (bad).
561             // [la spline sort du nombre de commandes autorisé (mauvais)]
562             return PointAt(piece - 1, 1.0, pos);
563         }
564         
565         int k = piece - bez_st;
566         NR::Point const bStPt = PrevPoint(bez_st - 1);
567         if (stB->nb == 1 || k <= 0) {
568             PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 1]);
569             TangentOnBezAt(at, bStPt, *nData, *stB, false, pos, tgt, len, rad);
570         } else {
571             // forcement plus grand que 1
572             if (k == 1) {
573                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 1]);
574                 PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 2]);
575                 PathDescrBezierTo fin(0.5 * (nextI->p + nnextI->p), 1);
576                 TangentOnBezAt(at, bStPt, *nextI,  fin, false, pos, tgt, len, rad);
577             } else if (k == stB->nb) {
578                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
579                 PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
580                 NR::Point stP = 0.5 * ( prevI->p + nextI->p );
581                 TangentOnBezAt(at, stP, *nextI, *stB, false, pos, tgt, len, rad);
582             } else {
583                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
584                 PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
585                 PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k + 1]);
586                 NR::Point stP = 0.5 * ( prevI->p + nextI->p );
587                 PathDescrBezierTo fin(0.5 * (nextI->p + nnextI->p), 1);
588                 TangentOnBezAt(at, stP, *nextI, fin, false, pos, tgt, len, rad);
589             }
590         }
591     }
595 void Path::PointAndTangentAt(int piece, double at, NR::Point &pos, NR::Point &tgt)
597     if (piece < 0 || piece >= int(descr_cmd.size())) {
598         // this shouldn't happen: the piece we are asked for doesn't exist in the path
599         pos = NR::Point(0, 0);
600         return;
601     }
602     
603     PathDescr const *theD = descr_cmd[piece];
604     int typ = theD->getType();
605     double len;
606     double rad;
607     if (typ == descr_moveto) {
608         
609         return PointAndTangentAt(piece + 1, 0.0, pos, tgt);
610         
611     } else if (typ == descr_close ) {
612         
613         int cp = piece - 1;
614         while ( cp >= 0 && (descr_cmd[cp]->getType()) != descr_moveto ) {
615             cp--;
616         }
617         if ( cp >= 0 ) {
618             PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[cp]);
619             PathDescrLineTo dst(nData->p);
620             TangentOnSegAt(at, PrevPoint (piece - 1), dst, pos, tgt, len);
621         }
622         
623     } else if ( typ == descr_forced) {
624         
625         return PointAndTangentAt(piece - 1, 1.0, pos,tgt);
626         
627     } else if (typ == descr_lineto) {
629         PathDescrLineTo const *nData = dynamic_cast<PathDescrLineTo const *>(theD);
630         TangentOnSegAt(at, PrevPoint (piece - 1), *nData, pos, tgt, len);
631         
632     } else if (typ == descr_arcto) {
633         
634         PathDescrArcTo const *nData = dynamic_cast<PathDescrArcTo const *>(theD);
635         TangentOnArcAt (at,PrevPoint (piece - 1), *nData, pos, tgt, len, rad);
636         
637     } else if (typ == descr_cubicto) {
638         
639         PathDescrCubicTo const *nData = dynamic_cast<PathDescrCubicTo const *>(theD);
640         TangentOnCubAt (at, PrevPoint (piece - 1), *nData, false, pos, tgt, len, rad);
641         
642     } else if (typ == descr_bezierto || typ == descr_interm_bezier) {
643         int bez_st = piece;
644         while (bez_st >= 0) {
645             int nt = descr_cmd[bez_st]->getType();
646             if (nt == descr_bezierto) break;
647             bez_st--;
648         }
649         if ( bez_st < 0 ) {
650             return PointAndTangentAt(piece - 1, 1.0, pos, tgt);
651             // Didn't find the beginning of the spline (bad).
652             // [pas trouvé le dubut de la spline (mauvais)]
653         }
654         
655         PathDescrBezierTo* stB = dynamic_cast<PathDescrBezierTo*>(descr_cmd[bez_st]);
656         if ( piece > bez_st + stB->nb ) {
657             return PointAndTangentAt(piece - 1, 1.0, pos, tgt);
658             // The spline goes past the number of authorized commands (bad).
659             // [la spline sort du nombre de commandes autorisé (mauvais)]
660         }
661         
662         int k = piece - bez_st;
663         NR::Point const bStPt(PrevPoint( bez_st - 1 ));
664         if (stB->nb == 1 || k <= 0) {
665             PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 1]);
666             TangentOnBezAt (at, bStPt, *nData, *stB, false, pos, tgt, len, rad);
667         } else {
668             // forcement plus grand que 1
669             if (k == 1) {
670                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 1]);
671                 PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 2]);
672                 PathDescrBezierTo fin(0.5 * (nextI->p + nnextI->p), 1);
673                 TangentOnBezAt(at, bStPt, *nextI, fin, false, pos, tgt, len, rad);
674             } else if (k == stB->nb) {
675                 PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
676                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
677                 NR::Point stP = 0.5 * ( prevI->p + nextI->p );
678                 TangentOnBezAt(at, stP, *nextI, *stB, false, pos, tgt, len, rad);
679             } else {
680                 PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
681                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
682                 PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k + 1]);
683                 NR::Point stP = 0.5 * ( prevI->p + nextI->p );
684                 PathDescrBezierTo fin(0.5 * (nnextI->p + nnextI->p), 1);
685                 TangentOnBezAt(at, stP, *nextI, fin, false, pos, tgt, len, rad);
686             }
687         }
688     }
691 void Path::Transform(const NR::Matrix &trans)
693     for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
694         (*i)->transform(trans);
695     }
698 void Path::FastBBox(double &l,double &t,double &r,double &b)
700     l = t = r = b = 0;
701     bool empty = true;
702     NR::Point lastP(0, 0);
703     
704     for (int i = 0; i < int(descr_cmd.size()); i++) {
705         int const typ = descr_cmd[i]->getType();
706         switch ( typ ) {
707         case descr_lineto:
708         {
709             PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
710             if ( empty ) {
711                 l = r = nData->p[NR::X];
712                 t = b = nData->p[NR::Y];
713                 empty = false;
714             } else {
715                 if ( nData->p[NR::X] < l ) {
716                     l = nData->p[NR::X];
717                 }
718                 if ( nData->p[NR::X] > r ) {
719                     r = nData->p[NR::X];
720                 }
721                 if ( nData->p[NR::Y] < t ) {
722                     t = nData->p[NR::Y];
723                 }
724                 if ( nData->p[NR::Y] > b ) {
725                     b = nData->p[NR::Y];
726                 }
727             }
728             lastP = nData->p;
729         }
730         break;
731         
732         case descr_moveto:
733         {
734             PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
735             if ( empty ) {
736                 l = r = nData->p[NR::X];
737                 t = b = nData->p[NR::Y];
738                 empty = false;
739             } else {
740                 if ( nData->p[NR::X] < l ) {
741                     l = nData->p[NR::X];
742                 }
743                 if ( nData->p[NR::X] > r ) {
744                     r = nData->p[NR::X];
745                 }
746                 if ( nData->p[NR::Y] < t ) {
747                     t = nData->p[NR::Y];
748                 }
749                 if ( nData->p[NR::Y] > b ) {
750                     b = nData->p[NR::Y];
751                 }
752             }
753             lastP = nData->p;
754         }
755         break;
756         
757         case descr_arcto:
758         {
759             PathDescrArcTo *nData  =  dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
760             if ( empty ) {
761                 l = r = nData->p[NR::X];
762                 t = b = nData->p[NR::Y];
763                 empty = false;
764             } else {
765                 if ( nData->p[NR::X] < l ) {
766                     l = nData->p[NR::X];
767                 }
768                 if ( nData->p[NR::X] > r ) {
769                     r = nData->p[NR::X];
770                 }
771                 if ( nData->p[NR::Y] < t ) {
772                     t = nData->p[NR::Y];
773                 }
774                 if ( nData->p[NR::Y] > b ) {
775                     b = nData->p[NR::Y];
776                 }
777             }
778             lastP = nData->p;
779         }
780         break;
781         
782         case descr_cubicto:
783         {
784             PathDescrCubicTo *nData  =  dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
785             if ( empty ) {
786                 l = r = nData->p[NR::X];
787                 t = b = nData->p[NR::Y];
788                 empty = false;
789             } else {
790                 if ( nData->p[NR::X] < l ) {
791                     l = nData->p[NR::X];
792                 }
793                 if ( nData->p[NR::X] > r ) {
794                     r = nData->p[NR::X];
795                 }
796                 if ( nData->p[NR::Y] < t ) {
797                     t = nData->p[NR::Y];
798                 }
799                 if ( nData->p[NR::Y] > b ) {
800                     b = nData->p[NR::Y];
801                 }
802             }
803             
804             NR::Point np = nData->p - nData->end;
805             if ( np[NR::X] < l ) {
806                 l = np[NR::X];
807             }
808             if ( np[NR::X] > r ) {
809                 r = np[NR::X];
810             }
811             if ( np[NR::Y] < t ) {
812                 t = np[NR::Y];
813             }
814             if ( np[NR::Y] > b ) {
815                 b = np[NR::Y];
816             }
817             
818             np = lastP + nData->start;
819             if ( np[NR::X] < l ) {
820                 l = np[NR::X];
821             }
822             if ( np[NR::X] > r ) {
823                 r = np[NR::X];
824             }
825             if ( np[NR::Y] < t ) {
826                 t = np[NR::Y];
827             }
828             if ( np[NR::Y] > b ) {
829                 b = np[NR::Y];
830             }
831             lastP = nData->p;
832         }
833         break;
834         
835         case descr_bezierto:
836         {
837             PathDescrBezierTo *nData  =  dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
838             if ( empty ) {
839                 l = r = nData->p[NR::X];
840                 t = b = nData->p[NR::Y];
841                 empty = false;
842             } else {
843                 if ( nData->p[NR::X] < l ) {
844                     l = nData->p[NR::X];
845                 }
846                 if ( nData->p[NR::X] > r ) {
847                     r = nData->p[NR::X];
848                 }
849                 if ( nData->p[NR::Y] < t ) {
850                     t = nData->p[NR::Y];
851                 }
852                 if ( nData->p[NR::Y] > b ) {
853                     b = nData->p[NR::Y];
854                 }
855             }
856             lastP = nData->p;
857         }
858         break;
859         
860         case descr_interm_bezier:
861         {
862             PathDescrIntermBezierTo *nData  =  dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
863             if ( empty ) {
864                 l = r = nData->p[NR::X];
865                 t = b = nData->p[NR::Y];
866                 empty = false;
867             } else {
868                 if ( nData->p[NR::X] < l ) {
869                     l = nData->p[NR::X];
870                 }
871                 if ( nData->p[NR::X] > r ) {
872                     r = nData->p[NR::X];
873                 }
874                 if ( nData->p[NR::Y] < t ) {
875                     t = nData->p[NR::Y];
876                 }
877                 if ( nData->p[NR::Y] > b ) {
878                     b = nData->p[NR::Y];
879                 }
880             }
881         }
882         break;
883         }
884     }
887 char *Path::svg_dump_path() const
889     Inkscape::SVGOStringStream os;
891     for (int i = 0; i < int(descr_cmd.size()); i++) {
892         NR::Point const p = (i == 0) ? NR::Point(0, 0) : PrevPoint(i - 1);
893         descr_cmd[i]->dumpSVG(os, p);
894     }
895   
896     return g_strdup (os.str().c_str());
899 /*
900   Local Variables:
901   mode:c++
902   c-file-style:"stroustrup"
903   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
904   indent-tabs-mode:nil
905   fill-column:99
906   End:
907 */
908 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :