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