Code

Win32 post-GSoC fixups.
[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(Geom::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(Geom::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(Geom::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(Geom::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(Geom::Point const &iPt, Geom::Point const &iStD, Geom::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(Geom::Point const &iPt, Geom::Point const &iStD, Geom::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(Geom::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(Geom::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(Geom::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(Geom::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(Geom::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(Geom::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(Geom::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(Geom::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(Geom::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(Geom::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(Geom::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(Geom::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(Geom::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[Geom::X];
499   t = b = i->p[Geom::Y];
500   i++;
502   for (; i != pts.end(); i++) {
503       r = std::max(r, i->p[Geom::X]);
504       l = std::min(l, i->p[Geom::X]);
505       b = std::max(b, i->p[Geom::Y]);
506       t = std::min(t, i->p[Geom::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, Geom::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 = Geom::Point(0,0);
523         return;
524     }
525     
526     PathDescr const *theD = descr_cmd[piece];
527     int const typ = theD->getType();
528     Geom::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         Geom::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                 Geom::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                 Geom::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, Geom::Point &pos, Geom::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 = Geom::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         Geom::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                 Geom::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                 Geom::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 Geom::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     Geom::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[Geom::X];
724                 t = b = nData->p[Geom::Y];
725                 empty = false;
726             } else {
727                 if ( nData->p[Geom::X] < l ) {
728                     l = nData->p[Geom::X];
729                 }
730                 if ( nData->p[Geom::X] > r ) {
731                     r = nData->p[Geom::X];
732                 }
733                 if ( nData->p[Geom::Y] < t ) {
734                     t = nData->p[Geom::Y];
735                 }
736                 if ( nData->p[Geom::Y] > b ) {
737                     b = nData->p[Geom::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[Geom::X];
749                 t = b = nData->p[Geom::Y];
750                 empty = false;
751             } else {
752                 if ( nData->p[Geom::X] < l ) {
753                     l = nData->p[Geom::X];
754                 }
755                 if ( nData->p[Geom::X] > r ) {
756                     r = nData->p[Geom::X];
757                 }
758                 if ( nData->p[Geom::Y] < t ) {
759                     t = nData->p[Geom::Y];
760                 }
761                 if ( nData->p[Geom::Y] > b ) {
762                     b = nData->p[Geom::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[Geom::X];
774                 t = b = nData->p[Geom::Y];
775                 empty = false;
776             } else {
777                 if ( nData->p[Geom::X] < l ) {
778                     l = nData->p[Geom::X];
779                 }
780                 if ( nData->p[Geom::X] > r ) {
781                     r = nData->p[Geom::X];
782                 }
783                 if ( nData->p[Geom::Y] < t ) {
784                     t = nData->p[Geom::Y];
785                 }
786                 if ( nData->p[Geom::Y] > b ) {
787                     b = nData->p[Geom::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[Geom::X];
799                 t = b = nData->p[Geom::Y];
800                 empty = false;
801             } else {
802                 if ( nData->p[Geom::X] < l ) {
803                     l = nData->p[Geom::X];
804                 }
805                 if ( nData->p[Geom::X] > r ) {
806                     r = nData->p[Geom::X];
807                 }
808                 if ( nData->p[Geom::Y] < t ) {
809                     t = nData->p[Geom::Y];
810                 }
811                 if ( nData->p[Geom::Y] > b ) {
812                     b = nData->p[Geom::Y];
813                 }
814             }
815             
816 /* bug 249665: "...the calculation of the bounding-box for cubic-paths
817 has some extra steps to make it work corretly in Win32 that unfortunately
818 are unnecessary in Linux, generating wrong results. This only shows in 
819 Type1 fonts because they use cubic-paths instead of the
820 bezier-paths used by True-Type fonts."
821 */
823 #ifdef WIN32
824             Geom::Point np = nData->p - nData->end;
825             if ( np[Geom::X] < l ) {
826                 l = np[Geom::X];
827             }
828             if ( np[Geom::X] > r ) {
829                 r = np[Geom::X];
830             }
831             if ( np[Geom::Y] < t ) {
832                 t = np[Geom::Y];
833             }
834             if ( np[Geom::Y] > b ) {
835                 b = np[Geom::Y];
836             }
837             
838             np = lastP + nData->start;
839             if ( np[Geom::X] < l ) {
840                 l = np[Geom::X];
841             }
842             if ( np[Geom::X] > r ) {
843                 r = np[Geom::X];
844             }
845             if ( np[Geom::Y] < t ) {
846                 t = np[Geom::Y];
847             }
848             if ( np[Geom::Y] > b ) {
849                 b = np[Geom::Y];
850             }
851 #endif
853             lastP = nData->p;
854         }
855         break;
856         
857         case descr_bezierto:
858         {
859             PathDescrBezierTo *nData  =  dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
860             if ( empty ) {
861                 l = r = nData->p[Geom::X];
862                 t = b = nData->p[Geom::Y];
863                 empty = false;
864             } else {
865                 if ( nData->p[Geom::X] < l ) {
866                     l = nData->p[Geom::X];
867                 }
868                 if ( nData->p[Geom::X] > r ) {
869                     r = nData->p[Geom::X];
870                 }
871                 if ( nData->p[Geom::Y] < t ) {
872                     t = nData->p[Geom::Y];
873                 }
874                 if ( nData->p[Geom::Y] > b ) {
875                     b = nData->p[Geom::Y];
876                 }
877             }
878             lastP = nData->p;
879         }
880         break;
881         
882         case descr_interm_bezier:
883         {
884             PathDescrIntermBezierTo *nData  =  dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
885             if ( empty ) {
886                 l = r = nData->p[Geom::X];
887                 t = b = nData->p[Geom::Y];
888                 empty = false;
889             } else {
890                 if ( nData->p[Geom::X] < l ) {
891                     l = nData->p[Geom::X];
892                 }
893                 if ( nData->p[Geom::X] > r ) {
894                     r = nData->p[Geom::X];
895                 }
896                 if ( nData->p[Geom::Y] < t ) {
897                     t = nData->p[Geom::Y];
898                 }
899                 if ( nData->p[Geom::Y] > b ) {
900                     b = nData->p[Geom::Y];
901                 }
902             }
903         }
904         break;
905         }
906     }
909 char *Path::svg_dump_path() const
911     Inkscape::SVGOStringStream os;
913     for (int i = 0; i < int(descr_cmd.size()); i++) {
914         Geom::Point const p = (i == 0) ? Geom::Point(0, 0) : PrevPoint(i - 1);
915         descr_cmd[i]->dumpSVG(os, p);
916     }
917   
918     return g_strdup (os.str().c_str());
921 // Find out if the segment that corresponds to 'piece' is a straight line
922 bool Path::IsLineSegment(int piece)
924     if (piece < 0 || piece >= int(descr_cmd.size())) {
925         return false;
926     }
927     
928     PathDescr const *theD = descr_cmd[piece];
929     int const typ = theD->getType();
930     
931     return (typ == descr_lineto);
935 /*
936   Local Variables:
937   mode:c++
938   c-file-style:"stroustrup"
939   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
940   indent-tabs-mode:nil
941   fill-column:99
942   End:
943 */
944 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :