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;
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 }
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();
65 for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
66 delete *i;
67 }
69 descr_cmd.clear();
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 }
91 if ( (descr_flags & descr_doing_subpath) == 0 ) {
92 return -1;
93 }
95 if (descr_cmd.empty()) {
96 return -1;
97 }
99 descr_cmd.push_back(new PathDescrForced);
100 return descr_cmd.size() - 1;
101 }
104 void Path::InsertForcePoint(int at)
105 {
106 if ( at < 0 || at > int(descr_cmd.size()) ) {
107 return;
108 }
110 if ( at == int(descr_cmd.size()) ) {
111 ForcePoint();
112 return;
113 }
115 descr_cmd.insert(descr_cmd.begin() + at, new PathDescrForced);
116 }
118 int Path::Close()
119 {
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);
132 descr_flags &= ~(descr_doing_subpath);
133 pending_moveto_cmd = -1;
135 return descr_cmd.size() - 1;
136 }
138 int Path::MoveTo(Geom::Point const &iPt)
139 {
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();
148 descr_cmd.push_back(new PathDescrMoveTo(iPt));
150 descr_flags |= descr_doing_subpath;
151 return descr_cmd.size() - 1;
152 }
154 void Path::InsertMoveTo(Geom::Point const &iPt, int at)
155 {
156 if ( at < 0 || at > int(descr_cmd.size()) ) {
157 return;
158 }
160 if ( at == int(descr_cmd.size()) ) {
161 MoveTo(iPt);
162 return;
163 }
165 descr_cmd.insert(descr_cmd.begin() + at, new PathDescrMoveTo(iPt));
166 }
168 int Path::LineTo(Geom::Point const &iPt)
169 {
170 if (descr_flags & descr_adding_bezier) {
171 EndBezierTo (iPt);
172 }
173 if (!( descr_flags & descr_doing_subpath )) {
174 return MoveTo (iPt);
175 }
177 descr_cmd.push_back(new PathDescrLineTo(iPt));
178 return descr_cmd.size() - 1;
179 }
181 void Path::InsertLineTo(Geom::Point const &iPt, int at)
182 {
183 if ( at < 0 || at > int(descr_cmd.size()) ) {
184 return;
185 }
187 if ( at == int(descr_cmd.size()) ) {
188 LineTo(iPt);
189 return;
190 }
192 descr_cmd.insert(descr_cmd.begin() + at, new PathDescrLineTo(iPt));
193 }
195 int Path::CubicTo(Geom::Point const &iPt, Geom::Point const &iStD, Geom::Point const &iEnD)
196 {
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;
206 }
209 void Path::InsertCubicTo(Geom::Point const &iPt, Geom::Point const &iStD, Geom::Point const &iEnD, int at)
210 {
211 if ( at < 0 || at > int(descr_cmd.size()) ) {
212 return;
213 }
215 if ( at == int(descr_cmd.size()) ) {
216 CubicTo(iPt,iStD,iEnD);
217 return;
218 }
220 descr_cmd.insert(descr_cmd.begin() + at, new PathDescrCubicTo(iPt, iStD, iEnD));
221 }
223 int Path::ArcTo(Geom::Point const &iPt, double iRx, double iRy, double angle,
224 bool iLargeArc, bool iClockwise)
225 {
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;
235 }
238 void Path::InsertArcTo(Geom::Point const &iPt, double iRx, double iRy, double angle,
239 bool iLargeArc, bool iClockwise, int at)
240 {
241 if ( at < 0 || at > int(descr_cmd.size()) ) {
242 return;
243 }
245 if ( at == int(descr_cmd.size()) ) {
246 ArcTo(iPt, iRx, iRy, angle, iLargeArc, iClockwise);
247 return;
248 }
250 descr_cmd.insert(descr_cmd.begin() + at, new PathDescrArcTo(iPt, iRx, iRy,
251 angle, iLargeArc, iClockwise));
252 }
254 int Path::TempBezierTo()
255 {
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();
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;
269 }
271 void Path::CancelBezier()
272 {
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;
282 }
284 int Path::EndBezierTo()
285 {
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;
294 }
296 int Path::EndBezierTo(Geom::Point const &iPt)
297 {
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;
313 }
316 int Path::IntermBezierTo(Geom::Point const &iPt)
317 {
318 if ( (descr_flags & descr_adding_bezier) == 0 ) {
319 return LineTo (iPt);
320 }
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;
331 }
334 void Path::InsertIntermBezierTo(Geom::Point const &iPt, int at)
335 {
336 if ( at < 0 || at > int(descr_cmd.size()) ) {
337 return;
338 }
340 if ( at == int(descr_cmd.size()) ) {
341 IntermBezierTo(iPt);
342 return;
343 }
345 descr_cmd.insert(descr_cmd.begin() + at, new PathDescrIntermBezierTo(iPt));
346 }
349 int Path::BezierTo(Geom::Point const &iPt)
350 {
351 if ( descr_flags & descr_adding_bezier ) {
352 EndBezierTo(iPt);
353 }
355 if ( (descr_flags & descr_doing_subpath) == 0 ) {
356 return MoveTo (iPt);
357 }
359 pending_bezier_cmd = descr_cmd.size();
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;
365 }
368 void Path::InsertBezierTo(Geom::Point const &iPt, int iNb, int at)
369 {
370 if ( at < 0 || at > int(descr_cmd.size()) ) {
371 return;
372 }
374 if ( at == int(descr_cmd.size()) ) {
375 BezierTo(iPt);
376 return;
377 }
379 descr_cmd.insert(descr_cmd.begin() + at, new PathDescrBezierTo(iPt, iNb));
380 }
383 /*
384 * points de la polyligne
385 */
386 void
387 Path::SetBackData (bool nVal)
388 {
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 }
406 }
409 void Path::ResetPoints()
410 {
411 pts.clear();
412 }
415 int Path::AddPoint(Geom::Point const &iPt, bool mvto)
416 {
417 if (back) {
418 return AddPoint (iPt, -1, 0.0, mvto);
419 }
421 if ( !mvto && pts.empty() == false && pts.back().p == iPt ) {
422 return -1;
423 }
425 int const n = pts.size();
426 pts.push_back(path_lineto(mvto ? polyline_moveto : polyline_lineto, iPt));
427 return n;
428 }
431 int Path::ReplacePoint(Geom::Point const &iPt)
432 {
433 if (pts.empty()) {
434 return -1;
435 }
437 int const n = pts.size() - 1;
438 pts[n] = path_lineto(polyline_lineto, iPt);
439 return n;
440 }
443 int Path::AddPoint(Geom::Point const &iPt, int ip, double it, bool mvto)
444 {
445 if (back == false) {
446 return AddPoint (iPt, mvto);
447 }
449 if ( !mvto && pts.empty() == false && pts.back().p == iPt ) {
450 return -1;
451 }
453 int const n = pts.size();
454 pts.push_back(path_lineto(mvto ? polyline_moveto : polyline_lineto, iPt, ip, it));
455 return n;
456 }
458 int Path::AddForcedPoint(Geom::Point const &iPt)
459 {
460 if (back) {
461 return AddForcedPoint (iPt, -1, 0.0);
462 }
464 if ( pts.empty() || pts.back().isMoveTo != polyline_lineto ) {
465 return -1;
466 }
468 int const n = pts.size();
469 pts.push_back(path_lineto(polyline_forced, pts[n - 1].p));
470 return n;
471 }
474 int Path::AddForcedPoint(Geom::Point const &iPt, int /*ip*/, double /*it*/)
475 {
476 /* FIXME: ip & it aren't used. Is this deliberate? */
477 if (!back) {
478 return AddForcedPoint (iPt);
479 }
481 if ( pts.empty() || pts.back().isMoveTo != polyline_lineto ) {
482 return -1;
483 }
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;
488 }
490 void Path::PolylineBoundingBox(double &l, double &t, double &r, double &b)
491 {
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 }
508 }
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)
518 {
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 }
526 PathDescr const *theD = descr_cmd[piece];
527 int const typ = theD->getType();
528 Geom::Point tgt;
529 double len;
530 double rad;
532 if (typ == descr_moveto) {
534 return PointAt (piece + 1, 0.0, pos);
536 } else if (typ == descr_close || typ == descr_forced) {
538 return PointAt (piece - 1, 1.0, pos);
540 } else if (typ == descr_lineto) {
542 PathDescrLineTo const *nData = dynamic_cast<PathDescrLineTo const *>(theD);
543 TangentOnSegAt(at, PrevPoint (piece - 1), *nData, pos, tgt, len);
545 } else if (typ == descr_arcto) {
547 PathDescrArcTo const *nData = dynamic_cast<PathDescrArcTo const *>(theD);
548 TangentOnArcAt(at,PrevPoint (piece - 1), *nData, pos, tgt, len, rad);
550 } else if (typ == descr_cubicto) {
552 PathDescrCubicTo const *nData = dynamic_cast<PathDescrCubicTo const *>(theD);
553 TangentOnCubAt(at, PrevPoint (piece - 1), *nData, false, pos, tgt, len, rad);
555 } else if (typ == descr_bezierto || typ == descr_interm_bezier) {
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 }
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 }
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 }
604 }
607 void Path::PointAndTangentAt(int piece, double at, Geom::Point &pos, Geom::Point &tgt)
608 {
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 }
615 PathDescr const *theD = descr_cmd[piece];
616 int typ = theD->getType();
617 double len;
618 double rad;
619 if (typ == descr_moveto) {
621 return PointAndTangentAt(piece + 1, 0.0, pos, tgt);
623 } else if (typ == descr_close ) {
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 }
635 } else if ( typ == descr_forced) {
637 return PointAndTangentAt(piece - 1, 1.0, pos,tgt);
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);
644 } else if (typ == descr_arcto) {
646 PathDescrArcTo const *nData = dynamic_cast<PathDescrArcTo const *>(theD);
647 TangentOnArcAt (at,PrevPoint (piece - 1), *nData, pos, tgt, len, rad);
649 } else if (typ == descr_cubicto) {
651 PathDescrCubicTo const *nData = dynamic_cast<PathDescrCubicTo const *>(theD);
652 TangentOnCubAt (at, PrevPoint (piece - 1), *nData, false, pos, tgt, len, rad);
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 }
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 }
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 }
701 }
703 void Path::Transform(const Geom::Matrix &trans)
704 {
705 for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) {
706 (*i)->transform(trans);
707 }
708 }
710 void Path::FastBBox(double &l,double &t,double &r,double &b)
711 {
712 l = t = r = b = 0;
713 bool empty = true;
714 Geom::Point lastP(0, 0);
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;
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;
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;
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 }
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 }
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;
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;
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 }
907 }
909 char *Path::svg_dump_path() const
910 {
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 }
918 return g_strdup (os.str().c_str());
919 }
921 // Find out if the segment that corresponds to 'piece' is a straight line
922 bool Path::IsLineSegment(int piece)
923 {
924 if (piece < 0 || piece >= int(descr_cmd.size())) {
925 return false;
926 }
928 PathDescr const *theD = descr_cmd[piece];
929 int const typ = theD->getType();
931 return (typ == descr_lineto);
932 }
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 :