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(NR::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(NR::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(NR::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(NR::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(NR::Point const &iPt, NR::Point const &iStD, NR::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(NR::Point const &iPt, NR::Point const &iStD, NR::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(NR::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(NR::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(NR::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(NR::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(NR::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(NR::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(NR::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(NR::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(NR::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(NR::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(NR::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(NR::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(NR::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[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 }
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, NR::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 = NR::Point(0,0);
523 return;
524 }
526 PathDescr const *theD = descr_cmd[piece];
527 int const typ = theD->getType();
528 NR::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 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 }
604 }
607 void Path::PointAndTangentAt(int piece, double at, NR::Point &pos, NR::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 = NR::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 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 }
701 }
703 void Path::Transform(const NR::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 NR::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[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;
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;
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;
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 }
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 }
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;
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;
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 }
897 }
899 char *Path::svg_dump_path() const
900 {
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 }
908 return g_strdup (os.str().c_str());
909 }
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 :