Code

Refactoring SPColor to C++ and removing legacy CMYK implementation
[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::ReplacePoint(NR::Point const &iPt)
433     if (pts.empty()) {
434         return -1;
435     }
436   
437     int const n = pts.size() - 1;
438     pts[n] = path_lineto(polyline_lineto, iPt);
439     return n;
443 int Path::AddPoint(NR::Point const &iPt, int ip, double it, bool mvto)
445     if (back == false) {
446         return AddPoint (iPt, mvto);
447     }
448     
449     if ( !mvto && pts.empty() == false && pts.back().p == iPt ) {
450         return -1;
451     }
452     
453     int const n = pts.size();
454     pts.push_back(path_lineto(mvto ? polyline_moveto : polyline_lineto, iPt, ip, it));
455     return n;
458 int Path::AddForcedPoint(NR::Point const &iPt)
460     if (back) {
461         return AddForcedPoint (iPt, -1, 0.0);
462     }
463     
464     if ( pts.empty() || pts.back().isMoveTo != polyline_lineto ) {
465         return -1;
466     }
467     
468     int const n = pts.size();
469     pts.push_back(path_lineto(polyline_forced, pts[n - 1].p));
470     return n;
474 int Path::AddForcedPoint(NR::Point const &iPt, int /*ip*/, double /*it*/)
476     /* FIXME: ip & it aren't used.  Is this deliberate? */
477     if (!back) {
478         return AddForcedPoint (iPt);
479     }
480     
481     if ( pts.empty() || pts.back().isMoveTo != polyline_lineto ) {
482         return -1;
483     }
484     
485     int const n = pts.size();
486     pts.push_back(path_lineto(polyline_forced, pts[n - 1].p, pts[n - 1].piece, pts[n - 1].t));
487     return n;
490 void Path::PolylineBoundingBox(double &l, double &t, double &r, double &b)
492   l = t = r = b = 0.0;
493   if ( pts.empty() ) {
494       return;
495   }
497   std::vector<path_lineto>::const_iterator i = pts.begin();
498   l = r = i->p[NR::X];
499   t = b = i->p[NR::Y];
500   i++;
502   for (; i != pts.end(); i++) {
503       r = std::max(r, i->p[NR::X]);
504       l = std::min(l, i->p[NR::X]);
505       b = std::max(b, i->p[NR::Y]);
506       t = std::min(t, i->p[NR::Y]);
507   }
511 /**
512  *    \param piece Index of a one of our commands.
513  *    \param at Distance along the segment that corresponds to `piece' (0 <= at <= 1)
514  *    \param pos Filled in with the point at `at' on `piece'.
515  */
517 void Path::PointAt(int piece, double at, NR::Point &pos)
519     if (piece < 0 || piece >= int(descr_cmd.size())) {
520         // this shouldn't happen: the piece we are asked for doesn't
521         // exist in the path
522         pos = NR::Point(0,0);
523         return;
524     }
525     
526     PathDescr const *theD = descr_cmd[piece];
527     int const typ = theD->getType();
528     NR::Point tgt;
529     double len;
530     double rad;
531     
532     if (typ == descr_moveto) {
533         
534         return PointAt (piece + 1, 0.0, pos);
535         
536     } else if (typ == descr_close || typ == descr_forced) {
537         
538         return PointAt (piece - 1, 1.0, pos);
539         
540     } else if (typ == descr_lineto) {
541         
542         PathDescrLineTo const *nData = dynamic_cast<PathDescrLineTo const *>(theD);
543         TangentOnSegAt(at, PrevPoint (piece - 1), *nData, pos, tgt, len);
544         
545     } else if (typ == descr_arcto) {
546         
547         PathDescrArcTo const *nData = dynamic_cast<PathDescrArcTo const *>(theD);
548         TangentOnArcAt(at,PrevPoint (piece - 1), *nData, pos, tgt, len, rad);
549         
550     } else if (typ == descr_cubicto) {
551         
552         PathDescrCubicTo const *nData = dynamic_cast<PathDescrCubicTo const *>(theD);
553         TangentOnCubAt(at, PrevPoint (piece - 1), *nData, false, pos, tgt, len, rad);
554         
555     } else if (typ == descr_bezierto || typ == descr_interm_bezier) {
556         
557         int bez_st = piece;
558         while (bez_st >= 0) {
559             int nt = descr_cmd[bez_st]->getType();
560             if (nt == descr_bezierto)
561                 break;
562             bez_st--;
563         }
564         if ( bez_st < 0 ) {
565             // Didn't find the beginning of the spline (bad).
566             // [pas trouvé le dubut de la spline (mauvais)]
567             return PointAt(piece - 1, 1.0, pos);
568         }
569         
570         PathDescrBezierTo *stB = dynamic_cast<PathDescrBezierTo *>(descr_cmd[bez_st]);
571         if ( piece > bez_st + stB->nb ) {
572             // The spline goes past the authorized number of commands (bad).
573             // [la spline sort du nombre de commandes autorisé (mauvais)]
574             return PointAt(piece - 1, 1.0, pos);
575         }
576         
577         int k = piece - bez_st;
578         NR::Point const bStPt = PrevPoint(bez_st - 1);
579         if (stB->nb == 1 || k <= 0) {
580             PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 1]);
581             TangentOnBezAt(at, bStPt, *nData, *stB, false, pos, tgt, len, rad);
582         } else {
583             // forcement plus grand que 1
584             if (k == 1) {
585                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 1]);
586                 PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 2]);
587                 PathDescrBezierTo fin(0.5 * (nextI->p + nnextI->p), 1);
588                 TangentOnBezAt(at, bStPt, *nextI,  fin, false, pos, tgt, len, rad);
589             } else if (k == stB->nb) {
590                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
591                 PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
592                 NR::Point stP = 0.5 * ( prevI->p + nextI->p );
593                 TangentOnBezAt(at, stP, *nextI, *stB, false, pos, tgt, len, rad);
594             } else {
595                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
596                 PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
597                 PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k + 1]);
598                 NR::Point stP = 0.5 * ( prevI->p + nextI->p );
599                 PathDescrBezierTo fin(0.5 * (nextI->p + nnextI->p), 1);
600                 TangentOnBezAt(at, stP, *nextI, fin, false, pos, tgt, len, rad);
601             }
602         }
603     }
607 void Path::PointAndTangentAt(int piece, double at, NR::Point &pos, NR::Point &tgt)
609     if (piece < 0 || piece >= int(descr_cmd.size())) {
610         // this shouldn't happen: the piece we are asked for doesn't exist in the path
611         pos = NR::Point(0, 0);
612         return;
613     }
614     
615     PathDescr const *theD = descr_cmd[piece];
616     int typ = theD->getType();
617     double len;
618     double rad;
619     if (typ == descr_moveto) {
620         
621         return PointAndTangentAt(piece + 1, 0.0, pos, tgt);
622         
623     } else if (typ == descr_close ) {
624         
625         int cp = piece - 1;
626         while ( cp >= 0 && (descr_cmd[cp]->getType()) != descr_moveto ) {
627             cp--;
628         }
629         if ( cp >= 0 ) {
630             PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[cp]);
631             PathDescrLineTo dst(nData->p);
632             TangentOnSegAt(at, PrevPoint (piece - 1), dst, pos, tgt, len);
633         }
634         
635     } else if ( typ == descr_forced) {
636         
637         return PointAndTangentAt(piece - 1, 1.0, pos,tgt);
638         
639     } else if (typ == descr_lineto) {
641         PathDescrLineTo const *nData = dynamic_cast<PathDescrLineTo const *>(theD);
642         TangentOnSegAt(at, PrevPoint (piece - 1), *nData, pos, tgt, len);
643         
644     } else if (typ == descr_arcto) {
645         
646         PathDescrArcTo const *nData = dynamic_cast<PathDescrArcTo const *>(theD);
647         TangentOnArcAt (at,PrevPoint (piece - 1), *nData, pos, tgt, len, rad);
648         
649     } else if (typ == descr_cubicto) {
650         
651         PathDescrCubicTo const *nData = dynamic_cast<PathDescrCubicTo const *>(theD);
652         TangentOnCubAt (at, PrevPoint (piece - 1), *nData, false, pos, tgt, len, rad);
653         
654     } else if (typ == descr_bezierto || typ == descr_interm_bezier) {
655         int bez_st = piece;
656         while (bez_st >= 0) {
657             int nt = descr_cmd[bez_st]->getType();
658             if (nt == descr_bezierto) break;
659             bez_st--;
660         }
661         if ( bez_st < 0 ) {
662             return PointAndTangentAt(piece - 1, 1.0, pos, tgt);
663             // Didn't find the beginning of the spline (bad).
664             // [pas trouvé le dubut de la spline (mauvais)]
665         }
666         
667         PathDescrBezierTo* stB = dynamic_cast<PathDescrBezierTo*>(descr_cmd[bez_st]);
668         if ( piece > bez_st + stB->nb ) {
669             return PointAndTangentAt(piece - 1, 1.0, pos, tgt);
670             // The spline goes past the number of authorized commands (bad).
671             // [la spline sort du nombre de commandes autorisé (mauvais)]
672         }
673         
674         int k = piece - bez_st;
675         NR::Point const bStPt(PrevPoint( bez_st - 1 ));
676         if (stB->nb == 1 || k <= 0) {
677             PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 1]);
678             TangentOnBezAt (at, bStPt, *nData, *stB, false, pos, tgt, len, rad);
679         } else {
680             // forcement plus grand que 1
681             if (k == 1) {
682                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 1]);
683                 PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + 2]);
684                 PathDescrBezierTo fin(0.5 * (nextI->p + nnextI->p), 1);
685                 TangentOnBezAt(at, bStPt, *nextI, fin, false, pos, tgt, len, rad);
686             } else if (k == stB->nb) {
687                 PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
688                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
689                 NR::Point stP = 0.5 * ( prevI->p + nextI->p );
690                 TangentOnBezAt(at, stP, *nextI, *stB, false, pos, tgt, len, rad);
691             } else {
692                 PathDescrIntermBezierTo *prevI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k - 1]);
693                 PathDescrIntermBezierTo *nextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k]);
694                 PathDescrIntermBezierTo *nnextI = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[bez_st + k + 1]);
695                 NR::Point stP = 0.5 * ( prevI->p + nextI->p );
696                 PathDescrBezierTo fin(0.5 * (nnextI->p + nnextI->p), 1);
697                 TangentOnBezAt(at, stP, *nextI, fin, false, pos, tgt, len, rad);
698             }
699         }
700     }
703 void Path::Transform(const NR::Matrix &trans)
705     for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
706         (*i)->transform(trans);
707     }
710 void Path::FastBBox(double &l,double &t,double &r,double &b)
712     l = t = r = b = 0;
713     bool empty = true;
714     NR::Point lastP(0, 0);
715     
716     for (int i = 0; i < int(descr_cmd.size()); i++) {
717         int const typ = descr_cmd[i]->getType();
718         switch ( typ ) {
719         case descr_lineto:
720         {
721             PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
722             if ( empty ) {
723                 l = r = nData->p[NR::X];
724                 t = b = nData->p[NR::Y];
725                 empty = false;
726             } else {
727                 if ( nData->p[NR::X] < l ) {
728                     l = nData->p[NR::X];
729                 }
730                 if ( nData->p[NR::X] > r ) {
731                     r = nData->p[NR::X];
732                 }
733                 if ( nData->p[NR::Y] < t ) {
734                     t = nData->p[NR::Y];
735                 }
736                 if ( nData->p[NR::Y] > b ) {
737                     b = nData->p[NR::Y];
738                 }
739             }
740             lastP = nData->p;
741         }
742         break;
743         
744         case descr_moveto:
745         {
746             PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
747             if ( empty ) {
748                 l = r = nData->p[NR::X];
749                 t = b = nData->p[NR::Y];
750                 empty = false;
751             } else {
752                 if ( nData->p[NR::X] < l ) {
753                     l = nData->p[NR::X];
754                 }
755                 if ( nData->p[NR::X] > r ) {
756                     r = nData->p[NR::X];
757                 }
758                 if ( nData->p[NR::Y] < t ) {
759                     t = nData->p[NR::Y];
760                 }
761                 if ( nData->p[NR::Y] > b ) {
762                     b = nData->p[NR::Y];
763                 }
764             }
765             lastP = nData->p;
766         }
767         break;
768         
769         case descr_arcto:
770         {
771             PathDescrArcTo *nData  =  dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
772             if ( empty ) {
773                 l = r = nData->p[NR::X];
774                 t = b = nData->p[NR::Y];
775                 empty = false;
776             } else {
777                 if ( nData->p[NR::X] < l ) {
778                     l = nData->p[NR::X];
779                 }
780                 if ( nData->p[NR::X] > r ) {
781                     r = nData->p[NR::X];
782                 }
783                 if ( nData->p[NR::Y] < t ) {
784                     t = nData->p[NR::Y];
785                 }
786                 if ( nData->p[NR::Y] > b ) {
787                     b = nData->p[NR::Y];
788                 }
789             }
790             lastP = nData->p;
791         }
792         break;
793         
794         case descr_cubicto:
795         {
796             PathDescrCubicTo *nData  =  dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
797             if ( empty ) {
798                 l = r = nData->p[NR::X];
799                 t = b = nData->p[NR::Y];
800                 empty = false;
801             } else {
802                 if ( nData->p[NR::X] < l ) {
803                     l = nData->p[NR::X];
804                 }
805                 if ( nData->p[NR::X] > r ) {
806                     r = nData->p[NR::X];
807                 }
808                 if ( nData->p[NR::Y] < t ) {
809                     t = nData->p[NR::Y];
810                 }
811                 if ( nData->p[NR::Y] > b ) {
812                     b = nData->p[NR::Y];
813                 }
814             }
815             
816             NR::Point np = nData->p - nData->end;
817             if ( np[NR::X] < l ) {
818                 l = np[NR::X];
819             }
820             if ( np[NR::X] > r ) {
821                 r = np[NR::X];
822             }
823             if ( np[NR::Y] < t ) {
824                 t = np[NR::Y];
825             }
826             if ( np[NR::Y] > b ) {
827                 b = np[NR::Y];
828             }
829             
830             np = lastP + nData->start;
831             if ( np[NR::X] < l ) {
832                 l = np[NR::X];
833             }
834             if ( np[NR::X] > r ) {
835                 r = np[NR::X];
836             }
837             if ( np[NR::Y] < t ) {
838                 t = np[NR::Y];
839             }
840             if ( np[NR::Y] > b ) {
841                 b = np[NR::Y];
842             }
843             lastP = nData->p;
844         }
845         break;
846         
847         case descr_bezierto:
848         {
849             PathDescrBezierTo *nData  =  dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
850             if ( empty ) {
851                 l = r = nData->p[NR::X];
852                 t = b = nData->p[NR::Y];
853                 empty = false;
854             } else {
855                 if ( nData->p[NR::X] < l ) {
856                     l = nData->p[NR::X];
857                 }
858                 if ( nData->p[NR::X] > r ) {
859                     r = nData->p[NR::X];
860                 }
861                 if ( nData->p[NR::Y] < t ) {
862                     t = nData->p[NR::Y];
863                 }
864                 if ( nData->p[NR::Y] > b ) {
865                     b = nData->p[NR::Y];
866                 }
867             }
868             lastP = nData->p;
869         }
870         break;
871         
872         case descr_interm_bezier:
873         {
874             PathDescrIntermBezierTo *nData  =  dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
875             if ( empty ) {
876                 l = r = nData->p[NR::X];
877                 t = b = nData->p[NR::Y];
878                 empty = false;
879             } else {
880                 if ( nData->p[NR::X] < l ) {
881                     l = nData->p[NR::X];
882                 }
883                 if ( nData->p[NR::X] > r ) {
884                     r = nData->p[NR::X];
885                 }
886                 if ( nData->p[NR::Y] < t ) {
887                     t = nData->p[NR::Y];
888                 }
889                 if ( nData->p[NR::Y] > b ) {
890                     b = nData->p[NR::Y];
891                 }
892             }
893         }
894         break;
895         }
896     }
899 char *Path::svg_dump_path() const
901     Inkscape::SVGOStringStream os;
903     for (int i = 0; i < int(descr_cmd.size()); i++) {
904         NR::Point const p = (i == 0) ? NR::Point(0, 0) : PrevPoint(i - 1);
905         descr_cmd[i]->dumpSVG(os, p);
906     }
907   
908     return g_strdup (os.str().c_str());
911 /*
912   Local Variables:
913   mode:c++
914   c-file-style:"stroustrup"
915   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
916   indent-tabs-mode:nil
917   fill-column:99
918   End:
919 */
920 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :