Code

Store cached icons to disk between runs, and invalidate/purge as needed.
[inkscape.git] / src / livarot / PathConversion.cpp
1 /*
2  *  PathConversion.cpp
3  *  nlivarot
4  *
5  *  Created by fred on Mon Nov 03 2003.
6  *
7  */
9 #include "Path.h"
10 #include "Shape.h"
11 #include "livarot/path-description.h"
13 #include <libnr/nr-matrix.h>
14 #include <2geom/transforms.h>
16 /*
17  * path description -> polyline
18  * and Path -> Shape (the Fill() function at the bottom)
19  * nathing fancy here: take each command and append an approximation of it to the polyline
20  */
22 void Path::ConvertWithBackData(double treshhold)
23 {
24     if ( descr_flags & descr_adding_bezier ) {
25         CancelBezier();
26     }
28     if ( descr_flags & descr_doing_subpath ) {
29         CloseSubpath();
30     }
32     SetBackData(true);
33     ResetPoints();
34     if ( descr_cmd.empty() ) {
35         return;
36     }
38     Geom::Point curX;
39     int curP = 1;
40     int lastMoveTo = -1;
42     // The initial moveto.
43     {
44         int const firstTyp = descr_cmd[0]->getType();
45         if ( firstTyp == descr_moveto ) {
46             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
47         } else {
48             curP = 0;
49             curX[Geom::X] = curX[Geom::Y] = 0;
50         }
51         lastMoveTo = AddPoint(curX, 0, 0.0, true);
52     }
54     // And the rest, one by one.
55     while ( curP < int(descr_cmd.size()) ) {
57         int const nType = descr_cmd[curP]->getType();
58         Geom::Point nextX;
60         switch (nType) {
61             case descr_forced: {
62                 AddForcedPoint(curX, curP, 1.0);
63                 curP++;
64                 break;
65             }
67             case descr_moveto: {
68                 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo*>(descr_cmd[curP]);
69                 nextX = nData->p;
70                 lastMoveTo = AddPoint(nextX, curP, 0.0, true);
71                 // et on avance
72                 curP++;
73                 break;
74             }
76             case descr_close: {
77                 nextX = pts[lastMoveTo].p;
78                 int n = AddPoint(nextX, curP, 1.0, false);
79                 if (n > 0) pts[n].closed = true;
80                 curP++;
81                 break;
82             }
84             case descr_lineto: {
85                 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
86                 nextX = nData->p;
87                 AddPoint(nextX,curP,1.0,false);
88                 // et on avance
89                 curP++;
90                 break;
91             }
93             case descr_cubicto: {
94                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
95                 nextX = nData->p;
96                 RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8, 0.0, 1.0, curP);
97                 AddPoint(nextX, curP, 1.0, false);
98                 // et on avance
99                 curP++;
100                 break;
101             }
103             case descr_arcto: {
104                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
105                 nextX = nData->p;
106                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold, curP);
107                 AddPoint(nextX, curP, 1.0, false);
108                 // et on avance
109                 curP++;
110                 break;
111             }
113             case descr_bezierto: {
114                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
115                 int nbInterm = nBData->nb;
116                 nextX = nBData->p;
118                 int ip = curP + 1;
119                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
121                 if ( nbInterm >= 1 ) {
122                     Geom::Point bx = curX;
123                     Geom::Point cx = curX;
124                     Geom::Point dx = curX;
126                     dx = nData->p;
127                     ip++;
128                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
130                     cx = 2 * bx - dx;
132                     for (int k = 0; k < nbInterm - 1; k++) {
133                         bx = cx;
134                         cx = dx;
136                         dx = nData->p;
137                         ip++;
138                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
140                         Geom::Point stx;
141                         stx = (bx + cx) / 2;
142                         if ( k > 0 ) {
143                             AddPoint(stx,curP - 1+k,1.0,false);
144                         }
146                         {
147                             Geom::Point mx;
148                             mx = (cx + dx) / 2;
149                             RecBezierTo(cx, stx, mx, treshhold, 8, 0.0, 1.0, curP + k);
150                         }
151                     }
152                     {
153                         bx = cx;
154                         cx = dx;
156                         dx = nextX;
157                         dx = 2 * dx - cx;
159                         Geom::Point stx;
160                         stx = (bx + cx) / 2;
162                         if ( nbInterm > 1 ) {
163                             AddPoint(stx, curP + nbInterm - 2, 1.0, false);
164                         }
166                         {
167                             Geom::Point mx;
168                             mx = (cx + dx) / 2;
169                             RecBezierTo(cx, stx, mx, treshhold, 8, 0.0, 1.0, curP + nbInterm - 1);
170                         }
171                     }
173                 }
176                 AddPoint(nextX, curP - 1 + nbInterm, 1.0, false);
178                 // et on avance
179                 curP += 1 + nbInterm;
180                 break;
181             }
182         }
183         curX = nextX;
184     }
188 void Path::Convert(double treshhold)
190     if ( descr_flags & descr_adding_bezier ) {
191         CancelBezier();
192     }
194     if ( descr_flags & descr_doing_subpath ) {
195         CloseSubpath();
196     }
198     SetBackData(false);
199     ResetPoints();
200     if ( descr_cmd.empty() ) {
201         return;
202     }
204     Geom::Point curX;
205     int curP = 1;
206     int lastMoveTo = 0;
208     // le moveto
209     {
210         int const firstTyp = descr_cmd[0]->getType();
211         if ( firstTyp == descr_moveto ) {
212             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
213         } else {
214             curP = 0;
215             curX[0] = curX[1] = 0;
216         }
217         lastMoveTo = AddPoint(curX, true);
218     }
219     descr_cmd[0]->associated = lastMoveTo;
221     // et le reste, 1 par 1
222     while ( curP < int(descr_cmd.size()) ) {
224         int const nType = descr_cmd[curP]->getType();
225         Geom::Point nextX;
227         switch (nType) {
228             case descr_forced: {
229                 descr_cmd[curP]->associated = AddForcedPoint(curX);
230                 curP++;
231                 break;
232             }
234             case descr_moveto: {
235                 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
236                 nextX = nData->p;
237                 lastMoveTo = AddPoint(nextX, true);
238                 descr_cmd[curP]->associated = lastMoveTo;
240                 // et on avance
241                 curP++;
242                 break;
243             }
245             case descr_close: {
246                 nextX = pts[lastMoveTo].p;
247                 descr_cmd[curP]->associated = AddPoint(nextX, false);
248                 if ( descr_cmd[curP]->associated < 0 ) {
249                     if ( curP == 0 ) {
250                         descr_cmd[curP]->associated = 0;
251                     } else {
252                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
253                     }
254                 }
255                 if ( descr_cmd[curP]->associated > 0 ) {
256                     pts[descr_cmd[curP]->associated].closed = true;
257                 }
258                 curP++;
259                 break;
260             }
262             case descr_lineto: {
263                 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
264                 nextX = nData->p;
265                 descr_cmd[curP]->associated = AddPoint(nextX, false);
266                 if ( descr_cmd[curP]->associated < 0 ) {
267                     if ( curP == 0 ) {
268                         descr_cmd[curP]->associated = 0;
269                     } else {
270                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
271                     }
272                 }
273                 // et on avance
274                 curP++;
275                 break;
276             }
278             case descr_cubicto: {
279                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
280                 nextX = nData->p;
281                 RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8);
282                 descr_cmd[curP]->associated = AddPoint(nextX,false);
283                 if ( descr_cmd[curP]->associated < 0 ) {
284                     if ( curP == 0 ) {
285                         descr_cmd[curP]->associated = 0;
286                     } else {
287                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
288                     }
289                 }
290                 // et on avance
291                 curP++;
292                 break;
293             }
295             case descr_arcto: {
296                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
297                 nextX = nData->p;
298                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
299                 descr_cmd[curP]->associated = AddPoint(nextX, false);
300                 if ( descr_cmd[curP]->associated < 0 ) {
301                     if ( curP == 0 ) {
302                         descr_cmd[curP]->associated = 0;
303                     } else {
304                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
305                     }
306                 }
307                 // et on avance
308                 curP++;
309                 break;
310             }
312             case descr_bezierto: {
313                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
314                 int nbInterm = nBData->nb;
315                 nextX = nBData->p;
316                 int curBD = curP;
318                 curP++;
319                 int ip = curP;
320                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
322                 if ( nbInterm == 1 ) {
323                     Geom::Point const midX = nData->p;
324                     RecBezierTo(midX, curX, nextX, treshhold, 8);
325                 } else if ( nbInterm > 1 ) {
326                     Geom::Point bx = curX;
327                     Geom::Point cx = curX;
328                     Geom::Point dx = curX;
330                     dx = nData->p;
331                     ip++;
332                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
334                     cx = 2 * bx - dx;
336                     for (int k = 0; k < nbInterm - 1; k++) {
337                         bx = cx;
338                         cx = dx;
340                         dx = nData->p;
341                         ip++;
342                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
344                         Geom::Point stx = (bx + cx) / 2;
345                         if ( k > 0 ) {
346                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
347                             if ( descr_cmd[ip - 2]->associated < 0 ) {
348                                 if ( curP == 0 ) {
349                                     descr_cmd[ip - 2]->associated = 0;
350                                 } else {
351                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
352                                 }
353                             }
354                         }
356                         {
357                             Geom::Point const mx = (cx + dx) / 2;
358                             RecBezierTo(cx, stx, mx, treshhold, 8);
359                         }
360                     }
362                     {
363                         bx = cx;
364                         cx = dx;
366                         dx = nextX;
367                         dx = 2 * dx - cx;
369                         Geom::Point stx = (bx + cx) / 2;
371                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
372                         if ( descr_cmd[ip - 1]->associated < 0 ) {
373                             if ( curP == 0 ) {
374                                 descr_cmd[ip - 1]->associated = 0;
375                             } else {
376                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
377                             }
378                         }
380                         {
381                             Geom::Point mx = (cx + dx) / 2;
382                             RecBezierTo(cx, stx, mx, treshhold, 8);
383                         }
384                     }
385                 }
387                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
388                 if ( descr_cmd[curBD]->associated < 0 ) {
389                     if ( curP == 0 ) {
390                         descr_cmd[curBD]->associated = 0;
391                     } else {
392                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
393                     }
394                 }
396                 // et on avance
397                 curP += nbInterm;
398                 break;
399             }
400         }
402         curX = nextX;
403     }
406 #define POINT_RELATION_TO_AREA(pt, area) ((pt)[0] < (area)->x0 ? 1 : ((pt)[0] > (area)->x1 ? 2 : ((pt)[1] < (area)->y0 ? 3 : ((pt)[1] > (area)->y1 ? 4 : 0))))
408 void Path::Convert(NRRectL *area, double treshhold)
410     if ( descr_flags & descr_adding_bezier ) {
411         CancelBezier();
412     }
414     if ( descr_flags & descr_doing_subpath ) {
415         CloseSubpath();
416     }
418     SetBackData(false);
419     ResetPoints();
420     if ( descr_cmd.empty() ) {
421         return;
422     }
424     Geom::Point curX;
425     int curP = 1;
426     int lastMoveTo = 0;
427     short last_point_relation = 0;
428     short curent_point_relation = 0;
429     bool last_start_elimination = false;
430     bool start_elimination = false;
431     bool replace = false;
433     // first point
434     {
435         int const firstTyp = descr_cmd[0]->getType();
436         if ( firstTyp == descr_moveto ) {
437             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
438         } else {
439             curP = 0;
440             curX[0] = curX[1] = 0;
441         }
443         last_point_relation = POINT_RELATION_TO_AREA(curX, area);
444         lastMoveTo = AddPoint(curX, true);
445     }
446     descr_cmd[0]->associated = lastMoveTo;
448     // process nodes one by one
449     while ( curP < int(descr_cmd.size()) ) {
451         int const nType = descr_cmd[curP]->getType();
452         Geom::Point nextX;
454         switch (nType) {
455             case descr_forced: {
456                 descr_cmd[curP]->associated = AddForcedPoint(curX);
457                 last_point_relation = 0;
458                 curP++;
459                 break;
460             }
462             case descr_moveto: {
463                 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
464                 nextX = nData->p;
465                 lastMoveTo = AddPoint(nextX, true);
466                 descr_cmd[curP]->associated = lastMoveTo;
468                 last_point_relation = POINT_RELATION_TO_AREA(nextX, area);
469                 start_elimination = false;
471                 curP++;
472                 break;
473             }
475             case descr_close: {
476                 nextX = pts[lastMoveTo].p;
477                 descr_cmd[curP]->associated = AddPoint(nextX, false);
478                 if ( descr_cmd[curP]->associated < 0 ) {
479                     if ( curP == 0 ) {
480                         descr_cmd[curP]->associated = 0;
481                     } else {
482                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
483                     }
484                 }
485                 if ( descr_cmd[curP]->associated > 0 ) {
486                     pts[descr_cmd[curP]->associated].closed = true;
487                 }
488                 last_point_relation = 0;
489                 curP++;
490                 break;
491             }
493             case descr_lineto: {
494                 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
495                 nextX = nData->p;
496                 curent_point_relation = POINT_RELATION_TO_AREA(nextX, area);
497                 replace = false;
498                 last_start_elimination = start_elimination;
499                 if (curent_point_relation > 0 && curent_point_relation == last_point_relation) {
500                     if (!start_elimination) {
501                         start_elimination = true;
502                     } else {
503                         replace = true;
504                         descr_cmd[curP]->associated = ReplacePoint(nextX);
505                     }
506                 } else {
507                     start_elimination = false;
508                 }
510                 if (!replace) {
511                     descr_cmd[curP]->associated = AddPoint(nextX, false);
512                 }
514                 if ( descr_cmd[curP]->associated < 0 ) {
515                     // point is not added as position is equal to the last added
516                     start_elimination = last_start_elimination;
517                     if ( curP == 0 ) {
518                         descr_cmd[curP]->associated = 0;
519                     } else {
520                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
521                     }
522                 }
523                 last_point_relation = curent_point_relation;
524                 curP++;
525                 break;
526             }
528             case descr_cubicto: {
529                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
530                 nextX = nData->p;
532                 curent_point_relation = POINT_RELATION_TO_AREA(nextX, area);
533                 replace = false;
534                 last_start_elimination = start_elimination;
535                 if (curent_point_relation > 0 && curent_point_relation == last_point_relation &&
536                     curent_point_relation == POINT_RELATION_TO_AREA(curX + (nData->start), area) &&
537                     curent_point_relation == POINT_RELATION_TO_AREA(nextX + (nData->end), area))
538                 {
539                     if (!start_elimination) {
540                         start_elimination = true;
541                     } else {
542                         replace = true;
543                         descr_cmd[curP]->associated = ReplacePoint(nextX);
544                     }
545                 } else {
546                     start_elimination = false;
547                 }
549                 if (!replace) {
550                     RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8);
551                     descr_cmd[curP]->associated = AddPoint(nextX,false);
552                 }
554                 if ( descr_cmd[curP]->associated < 0 ) {
555                     // point is not added as position is equal to the last added
556                     start_elimination = last_start_elimination;
557                     if ( curP == 0 ) {
558                         descr_cmd[curP]->associated = 0;
559                     } else {
560                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
561                     }
562                 }
563                 last_point_relation = curent_point_relation;
564                 curP++;
565                 break;
566             }
568             case descr_arcto: {
569                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
570                 nextX = nData->p;
571                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
572                 descr_cmd[curP]->associated = AddPoint(nextX, false);
573                 if ( descr_cmd[curP]->associated < 0 ) {
574                     if ( curP == 0 ) {
575                         descr_cmd[curP]->associated = 0;
576                     } else {
577                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
578                     }
579                 }
580                 last_point_relation = 0;
582                 curP++;
583                 break;
584             }
586             case descr_bezierto: {
587                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
588                 int nbInterm = nBData->nb;
589                 nextX = nBData->p;
590                 int curBD = curP;
592                 curP++;
593                 int ip = curP;
594                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
596                 if ( nbInterm == 1 ) {
597                     Geom::Point const midX = nData->p;
598                     RecBezierTo(midX, curX, nextX, treshhold, 8);
599                 } else if ( nbInterm > 1 ) {
600                     Geom::Point bx = curX;
601                     Geom::Point cx = curX;
602                     Geom::Point dx = curX;
604                     dx = nData->p;
605                     ip++;
606                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
608                     cx = 2 * bx - dx;
610                     for (int k = 0; k < nbInterm - 1; k++) {
611                         bx = cx;
612                         cx = dx;
614                         dx = nData->p;
615                         ip++;
616                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
618                         Geom::Point stx = (bx + cx) / 2;
619                         if ( k > 0 ) {
620                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
621                             if ( descr_cmd[ip - 2]->associated < 0 ) {
622                                 if ( curP == 0 ) {
623                                     descr_cmd[ip - 2]->associated = 0;
624                                 } else {
625                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
626                                 }
627                             }
628                         }
630                         {
631                             Geom::Point const mx = (cx + dx) / 2;
632                             RecBezierTo(cx, stx, mx, treshhold, 8);
633                         }
634                     }
636                     {
637                         bx = cx;
638                         cx = dx;
640                         dx = nextX;
641                         dx = 2 * dx - cx;
643                         Geom::Point stx = (bx + cx) / 2;
645                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
646                         if ( descr_cmd[ip - 1]->associated < 0 ) {
647                             if ( curP == 0 ) {
648                                 descr_cmd[ip - 1]->associated = 0;
649                             } else {
650                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
651                             }
652                         }
654                         {
655                             Geom::Point mx = (cx + dx) / 2;
656                             RecBezierTo(cx, stx, mx, treshhold, 8);
657                         }
658                     }
659                 }
661                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
662                 if ( descr_cmd[curBD]->associated < 0 ) {
663                     if ( curP == 0 ) {
664                         descr_cmd[curBD]->associated = 0;
665                     } else {
666                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
667                     }
668                 }
670                 last_point_relation = 0;
672                 curP += nbInterm;
673                 break;
674             }
675         }
677         curX = nextX;
678     }
682 void Path::ConvertEvenLines(double treshhold)
684     if ( descr_flags & descr_adding_bezier ) {
685         CancelBezier();
686     }
688     if ( descr_flags & descr_doing_subpath ) {
689         CloseSubpath();
690     }
692     SetBackData(false);
693     ResetPoints();
694     if ( descr_cmd.empty() ) {
695         return;
696     }
698     Geom::Point curX;
699     int curP = 1;
700     int lastMoveTo = 0;
702     // le moveto
703     {
704         int const firstTyp = descr_cmd[0]->getType();
705         if ( firstTyp == descr_moveto ) {
706             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
707         } else {
708             curP = 0;
709             curX[0] = curX[1] = 0;
710         }
711         lastMoveTo = AddPoint(curX, true);
712     }
713     descr_cmd[0]->associated = lastMoveTo;
715     // et le reste, 1 par 1
716     while ( curP < int(descr_cmd.size()) ) {
718         int const nType = descr_cmd[curP]->getType();
719         Geom::Point nextX;
721         switch (nType) {
722             case descr_forced: {
723                 descr_cmd[curP]->associated = AddForcedPoint(curX);
724                 curP++;
725                 break;
726             }
728             case descr_moveto: {
729                 PathDescrMoveTo* nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
730                 nextX = nData->p;
731                 lastMoveTo = AddPoint(nextX,true);
732                 descr_cmd[curP]->associated = lastMoveTo;
734                 // et on avance
735                 curP++;
736                 break;
737             }
739             case descr_close: {
740                 nextX = pts[lastMoveTo].p;
741                 {
742                     Geom::Point nexcur;
743                     nexcur = nextX - curX;
744                     const double segL = Geom::L2(nexcur);
745                     if ( (segL > treshhold) && (treshhold > 0) ) {
746                         for (double i = treshhold; i < segL; i += treshhold) {
747                             Geom::Point nX;
748                             nX = (segL - i) * curX + i * nextX;
749                             nX /= segL;
750                             AddPoint(nX);
751                         }
752                     }
753                 }
755                 descr_cmd[curP]->associated = AddPoint(nextX,false);
756                 if ( descr_cmd[curP]->associated < 0 ) {
757                     if ( curP == 0 ) {
758                         descr_cmd[curP]->associated = 0;
759                     } else {
760                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
761                     }
762                 }
763                 if ( descr_cmd[curP]->associated > 0 ) {
764                     pts[descr_cmd[curP]->associated].closed = true;
765                 }
766                 curP++;
767                 break;
768             }
770             case descr_lineto: {
771                 PathDescrLineTo* nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
772                 nextX = nData->p;
773                 Geom::Point nexcur = nextX - curX;
774                 const double segL = L2(nexcur);
775                 if ( (segL > treshhold) && (treshhold > 0)) {
776                     for (double i = treshhold; i < segL; i += treshhold) {
777                         Geom::Point nX = ((segL - i) * curX + i * nextX) / segL;
778                         AddPoint(nX);
779                     }
780                 }
782                 descr_cmd[curP]->associated = AddPoint(nextX,false);
783                 if ( descr_cmd[curP]->associated < 0 ) {
784                     if ( curP == 0 ) {
785                         descr_cmd[curP]->associated = 0;
786                     } else {
787                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
788                     }
789                 }
790                 // et on avance
791                 curP++;
792                 break;
793             }
795             case descr_cubicto: {
796                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
797                 nextX = nData->p;
798                 RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8, 4 * treshhold);
799                 descr_cmd[curP]->associated = AddPoint(nextX, false);
800                 if ( descr_cmd[curP]->associated < 0 ) {
801                     if ( curP == 0 ) {
802                         descr_cmd[curP]->associated = 0;
803                     } else {
804                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
805                     }
806                 }
807                 // et on avance
808                 curP++;
809                 break;
810             }
812             case descr_arcto: {
813                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
814                 nextX = nData->p;
815                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
816                 descr_cmd[curP]->associated =AddPoint(nextX, false);
817                 if ( descr_cmd[curP]->associated < 0 ) {
818                     if ( curP == 0 ) {
819                         descr_cmd[curP]->associated = 0;
820                     } else {
821                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
822                     }
823                 }
825                 // et on avance
826                 curP++;
827                 break;
828             }
830             case descr_bezierto: {
831                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
832                 int nbInterm = nBData->nb;
833                 nextX = nBData->p;
834                 int curBD = curP;
836                 curP++;
837                 int ip = curP;
838                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
840                 if ( nbInterm == 1 ) {
841                     Geom::Point const midX = nData->p;
842                     RecBezierTo(midX, curX, nextX, treshhold, 8, 4 * treshhold);
843                 } else if ( nbInterm > 1 ) {
844                     Geom::Point bx = curX;
845                     Geom::Point cx = curX;
846                     Geom::Point dx = curX;
848                     dx = nData->p;
849                     ip++;
850                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
852                     cx = 2 * bx - dx;
854                     for (int k = 0; k < nbInterm - 1; k++) {
855                         bx = cx;
856                         cx = dx;
857                         dx = nData->p;
859                         ip++;
860                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
862                         Geom::Point stx = (bx+cx) / 2;
863                         if ( k > 0 ) {
864                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
865                             if ( descr_cmd[ip - 2]->associated < 0 ) {
866                                 if ( curP == 0 ) {
867                                     descr_cmd[ip- 2]->associated = 0;
868                                 } else {
869                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
870                                 }
871                             }
872                         }
874                         {
875                             Geom::Point const mx = (cx + dx) / 2;
876                             RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
877                         }
878                     }
880                     {
881                         bx = cx;
882                         cx = dx;
884                         dx = nextX;
885                         dx = 2 * dx - cx;
887                         Geom::Point const stx = (bx + cx) / 2;
889                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
890                         if ( descr_cmd[ip - 1]->associated < 0 ) {
891                             if ( curP == 0 ) {
892                                 descr_cmd[ip - 1]->associated = 0;
893                             } else {
894                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
895                             }
896                         }
898                         {
899                             Geom::Point const mx = (cx + dx) / 2;
900                             RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
901                         }
902                     }
903                 }
905                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
906                 if ( descr_cmd[curBD]->associated < 0 ) {
907                     if ( curP == 0 ) {
908                         descr_cmd[curBD]->associated = 0;
909                     } else {
910                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
911                     }
912                 }
914                 // et on avance
915                 curP += nbInterm;
916                 break;
917             }
918         }
919         if ( Geom::LInfty(curX - nextX) > 0.00001 ) {
920             curX = nextX;
921         }
922     }
925 const Geom::Point Path::PrevPoint(int i) const
927     /* TODO: I suspect this should assert `(unsigned) i < descr_nb'.  We can probably change
928        the argument to unsigned.  descr_nb should probably be changed to unsigned too. */
929     g_assert( i >= 0 );
930     switch ( descr_cmd[i]->getType() ) {
931         case descr_moveto: {
932             PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
933             return nData->p;
934         }
935         case descr_lineto: {
936             PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
937             return nData->p;
938         }
939         case descr_arcto: {
940             PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
941             return nData->p;
942         }
943         case descr_cubicto: {
944             PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
945             return nData->p;
946         }
947         case descr_bezierto: {
948             PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
949             return nData->p;
950         }
951         case descr_interm_bezier:
952         case descr_close:
953         case descr_forced:
954             return PrevPoint(i - 1);
955         default:
956             g_assert_not_reached();
957             return Geom::Point(0, 0);
958     }
961 // utilitaries: given a quadratic bezier curve (start point, control point, end point, ie that's a clamped curve),
962 // and an abcissis on it, get the point with that abcissis.
963 // warning: it's NOT a curvilign abcissis (or whatever you call that in english), so "t" is NOT the length of "start point"->"result point"
964 void Path::QuadraticPoint(double t, Geom::Point &oPt,
965                           const Geom::Point &iS, const Geom::Point &iM, const Geom::Point &iE)
967     Geom::Point const ax = iE - 2 * iM + iS;
968     Geom::Point const bx = 2 * iM - 2 * iS;
969     Geom::Point const cx = iS;
971     oPt = t * t * ax + t * bx + cx;
973 // idem for cubic bezier patch
974 void Path::CubicTangent(double t, Geom::Point &oPt, const Geom::Point &iS, const Geom::Point &isD,
975                         const Geom::Point &iE, const Geom::Point &ieD)
977     Geom::Point const ax = ieD - 2 * iE + 2 * iS + isD;
978     Geom::Point const bx = 3 * iE - ieD - 2 * isD - 3 * iS;
979     Geom::Point const cx = isD;
981     oPt = 3 * t * t * ax + 2 * t * bx + cx;
984 // extract interesting info of a SVG arc description
985 static void ArcAnglesAndCenter(Geom::Point const &iS, Geom::Point const &iE,
986                                double rx, double ry, double angle,
987                                bool large, bool wise,
988                                double &sang, double &eang, Geom::Point &dr);
990 void Path::ArcAngles(const Geom::Point &iS, const Geom::Point &iE,
991                      double rx, double ry, double angle, bool large, bool wise, double &sang, double &eang)
993     Geom::Point dr;
994     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
997 /* N.B. If iS == iE then sang,eang,dr each become NaN.  Probably a bug. */
998 static void ArcAnglesAndCenter(Geom::Point const &iS, Geom::Point const &iE,
999                                double rx, double ry, double angle,
1000                                bool large, bool wise,
1001                                double &sang, double &eang, Geom::Point &dr)
1003     Geom::Point se = iE - iS;
1004     Geom::Point ca(cos(angle), sin(angle));
1005     Geom::Point cse(dot(se, ca), cross(se, ca));
1006     cse[0] /= rx;
1007     cse[1] /= ry;
1008     double const lensq = dot(cse,cse);
1009     Geom::Point csd = ( ( lensq < 4
1010                         ? sqrt( 1/lensq - .25 )
1011                         : 0.0 )
1012                       * cse.ccw() );
1014     Geom::Point ra = -csd - 0.5 * cse;
1015     if ( ra[0] <= -1 ) {
1016         sang = M_PI;
1017     } else if ( ra[0] >= 1 ) {
1018         sang = 0;
1019     } else {
1020         sang = acos(ra[0]);
1021         if ( ra[1] < 0 ) {
1022             sang = 2 * M_PI - sang;
1023         }
1024     }
1026     ra = -csd + 0.5 * cse;
1027     if ( ra[0] <= -1 ) {
1028         eang = M_PI;
1029     } else if ( ra[0] >= 1 ) {
1030         eang = 0;
1031     } else {
1032         eang = acos(ra[0]);
1033         if ( ra[1] < 0 ) {
1034             eang = 2 * M_PI - eang;
1035         }
1036     }
1038     csd[0] *= rx;
1039     csd[1] *= ry;
1040     ca[1] = -ca[1]; // because it's the inverse rotation
1042     dr[0] = dot(csd, ca);
1043     dr[1] = cross(csd, ca);
1045     ca[1] = -ca[1];
1047     if ( wise ) {
1049         if (large) {
1050             dr = -dr;
1051             double swap = eang;
1052             eang = sang;
1053             sang = swap;
1054             eang += M_PI;
1055             sang += M_PI;
1056             if ( eang >= 2*M_PI ) {
1057                 eang -= 2*M_PI;
1058             }
1059             if ( sang >= 2*M_PI ) {
1060                 sang -= 2*M_PI;
1061             }
1062         }
1064     } else {
1065         if (!large) {
1066             dr = -dr;
1067             double swap = eang;
1068             eang = sang;
1069             sang = swap;
1070             eang += M_PI;
1071             sang += M_PI;
1072             if ( eang >= 2*M_PI ) {
1073                 eang -= 2 * M_PI;
1074             }
1075             if ( sang >= 2*M_PI ) {
1076                 sang -= 2 * M_PI;
1077             }
1078         }
1079     }
1081     dr += 0.5 * (iS + iE);
1086 void Path::DoArc(Geom::Point const &iS, Geom::Point const &iE,
1087                  double const rx, double const ry, double const angle,
1088                  bool const large, bool const wise, double const /*tresh*/)
1090     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1091        apart than the diameter.  Also check that we do the right thing for negative radius.
1092        (Same for the other DoArc functions in this file.) */
1093     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1094         return;
1095         // We always add a lineto afterwards, so this is fine.
1096         // [on ajoute toujours un lineto apres, donc c bon]
1097     }
1099     double sang;
1100     double eang;
1101     Geom::Point dr_temp;
1102     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr_temp);
1103     Geom::Point dr = dr_temp;
1104     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1105        the case of low curvature (i.e. very large radius). */
1107     Geom::Scale const ar(rx, ry);
1108     Geom::Rotate cb( angle + sang );
1109     if (wise) {
1111         double const incr = -0.1;
1112         if ( sang < eang ) {
1113             sang += 2*M_PI;
1114         }
1115         Geom::Rotate const omega(incr);
1116         for (double b = sang + incr ; b > eang ; b += incr) {
1117             cb = omega * cb;
1118             AddPoint( cb.vector() * ar + dr );
1119         }
1121     } else {
1123         double const incr = 0.1;
1124         if ( sang > eang ) {
1125             sang -= 2*M_PI;
1126         }
1127         Geom::Rotate const omega(incr);
1128         for (double b = sang + incr ; b < eang ; b += incr) {
1129             cb = omega * cb;
1130             AddPoint( cb.vector() * ar + dr);
1131         }
1132     }
1136 void Path::RecCubicTo( Geom::Point const &iS, Geom::Point const &isD,
1137                        Geom::Point const &iE, Geom::Point const &ieD,
1138                        double tresh, int lev, double maxL)
1140     Geom::Point se = iE - iS;
1141     const double dC = Geom::L2(se);
1142     if ( dC < 0.01 ) {
1144         const double sC = dot(isD,isD);
1145         const double eC = dot(ieD,ieD);
1146         if ( sC < tresh && eC < tresh ) {
1147             return;
1148         }
1150     } else {
1151         const double sC = fabs(cross(se, isD)) / dC;
1152         const double eC = fabs(cross(se, ieD)) / dC;
1153         if ( sC < tresh && eC < tresh ) {
1154             // presque tt droit -> attention si on nous demande de bien subdiviser les petits segments
1155             if ( maxL > 0 && dC > maxL ) {
1156                 if ( lev <= 0 ) {
1157                     return;
1158                 }
1159                 Geom::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1160                 Geom::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1162                 Geom::Point hisD = 0.5 * isD;
1163                 Geom::Point hieD = 0.5 * ieD;
1165                 RecCubicTo(iS, hisD, m, md, tresh, lev - 1, maxL);
1166                 AddPoint(m);
1167                 RecCubicTo(m, md, iE, hieD, tresh, lev - 1,maxL);
1168             }
1169             return;
1170         }
1171     }
1173     if ( lev <= 0 ) {
1174         return;
1175     }
1177     {
1178         Geom::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1179         Geom::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1181         Geom::Point hisD = 0.5 * isD;
1182         Geom::Point hieD = 0.5 * ieD;
1184         RecCubicTo(iS, hisD, m, md, tresh, lev - 1, maxL);
1185         AddPoint(m);
1186         RecCubicTo(m, md, iE, hieD, tresh, lev - 1,maxL);
1187     }
1192 void Path::RecBezierTo(const Geom::Point &iP,
1193                        const Geom::Point &iS,
1194                        const Geom::Point &iE,
1195                        double tresh, int lev, double maxL)
1197     if ( lev <= 0 ) {
1198         return;
1199     }
1201     Geom::Point ps = iS - iP;
1202     Geom::Point pe = iE - iP;
1203     Geom::Point se = iE - iS;
1204     double s = fabs(cross(pe, ps));
1205     if ( s < tresh ) {
1206         const double l = L2(se);
1207         if ( maxL > 0 && l > maxL ) {
1208             const Geom::Point m = 0.25 * (iS + iE + 2 * iP);
1209             Geom::Point md = 0.5 * (iS + iP);
1210             RecBezierTo(md, iS, m, tresh, lev - 1, maxL);
1211             AddPoint(m);
1212             md = 0.5 * (iP + iE);
1213             RecBezierTo(md, m, iE, tresh, lev - 1, maxL);
1214         }
1215         return;
1216     }
1218     {
1219         const Geom::Point m = 0.25 * (iS + iE + 2 * iP);
1220         Geom::Point md = 0.5 * (iS + iP);
1221         RecBezierTo(md, iS, m, tresh, lev - 1, maxL);
1222         AddPoint(m);
1223         md = 0.5 * (iP + iE);
1224         RecBezierTo(md, m, iE, tresh, lev - 1, maxL);
1225     }
1229 void Path::DoArc(Geom::Point const &iS, Geom::Point const &iE,
1230                  double const rx, double const ry, double const angle,
1231                  bool const large, bool const wise, double const /*tresh*/, int const piece)
1233     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1234        apart than the diameter.  Also check that we do the right thing for negative radius.
1235        (Same for the other DoArc functions in this file.) */
1236     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1237         return;
1238         // We always add a lineto afterwards, so this is fine.
1239         // [on ajoute toujours un lineto apres, donc c bon]
1240     }
1242     double sang;
1243     double eang;
1244     Geom::Point dr_temp;
1245     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr_temp);
1246     Geom::Point dr = dr_temp;
1247     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1248        the case of low curvature (i.e. very large radius). */
1250     Geom::Scale const ar(rx, ry);
1251     Geom::Rotate cb(angle + sang);
1252     if (wise) {
1254         double const incr = -0.1;
1255         if ( sang < eang ) {
1256             sang += 2*M_PI;
1257         }
1258         Geom::Rotate const omega(incr);
1259         for (double b = sang + incr; b > eang; b += incr) {
1260             cb = omega * cb;
1261             AddPoint(cb.vector() * ar + dr, piece, (sang - b) / (sang - eang));
1262         }
1264     } else {
1266         double const incr = 0.1;
1267         if ( sang > eang ) {
1268             sang -= 2 * M_PI;
1269         }
1270         Geom::Rotate const omega(incr);
1271         for (double b = sang + incr ; b < eang ; b += incr) {
1272             cb = omega * cb;
1273             AddPoint(cb.vector() * ar + dr, piece, (b - sang) / (eang - sang));
1274         }
1275     }
1278 void Path::RecCubicTo(Geom::Point const &iS, Geom::Point const &isD,
1279                       Geom::Point const &iE, Geom::Point const &ieD,
1280                       double tresh, int lev, double st, double et, int piece)
1282     const Geom::Point se = iE - iS;
1283     const double dC = Geom::L2(se);
1284     if ( dC < 0.01 ) {
1285         const double sC = dot(isD, isD);
1286         const double eC = dot(ieD, ieD);
1287         if ( sC < tresh && eC < tresh ) {
1288             return;
1289         }
1290     } else {
1291         const double sC = fabs(cross(se, isD)) / dC;
1292         const double eC = fabs(cross(se, ieD)) / dC;
1293         if ( sC < tresh && eC < tresh ) {
1294             return;
1295         }
1296     }
1298     if ( lev <= 0 ) {
1299         return;
1300     }
1302     Geom::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1303     Geom::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1304     double mt = (st + et) / 2;
1306     Geom::Point hisD = 0.5 * isD;
1307     Geom::Point hieD = 0.5 * ieD;
1309     RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece);
1310     AddPoint(m, piece, mt);
1311     RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece);
1317 void Path::RecBezierTo(Geom::Point const &iP,
1318                        Geom::Point const &iS,
1319                        Geom::Point const &iE,
1320                        double tresh, int lev, double st, double et, int piece)
1322     if ( lev <= 0 ) {
1323         return;
1324     }
1326     Geom::Point ps = iS - iP;
1327     Geom::Point pe = iE - iP;
1328     const double s = fabs(cross(pe, ps));
1329     if ( s < tresh ) {
1330         return;
1331     }
1333     {
1334         const double mt = (st + et) / 2;
1335         const Geom::Point m = 0.25 * (iS + iE + 2 * iP);
1336         RecBezierTo(0.5 * (iS + iP), iS, m, tresh, lev - 1, st, mt, piece);
1337         AddPoint(m, piece, mt);
1338         RecBezierTo(0.5 * (iP + iE), m, iE, tresh, lev - 1, mt, et, piece);
1339     }
1344 void Path::DoArc(Geom::Point const &iS, Geom::Point const &iE,
1345                  double const rx, double const ry, double const angle,
1346                  bool const large, bool const wise, double const /*tresh*/,
1347                  int const piece, offset_orig &/*orig*/)
1349     // Will never arrive here, as offsets are made of cubics.
1350     // [on n'arrivera jamais ici, puisque les offsets sont fait de cubiques]
1351     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1352        apart than the diameter.  Also check that we do the right thing for negative radius.
1353        (Same for the other DoArc functions in this file.) */
1354     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1355         return;
1356         // We always add a lineto afterwards, so this is fine.
1357         // [on ajoute toujours un lineto apres, donc c bon]
1358     }
1360     double sang;
1361     double eang;
1362     Geom::Point dr_temp;
1363     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr_temp);
1364     Geom::Point dr = dr_temp;
1365     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1366        the case of low curvature (i.e. very large radius). */
1368     Geom::Scale const ar(rx, ry);
1369     Geom::Rotate cb(angle + sang);
1370     if (wise) {
1372         double const incr = -0.1;
1373         if ( sang < eang ) {
1374             sang += 2*M_PI;
1375         }
1376         Geom::Rotate const omega(incr);
1377         for (double b = sang + incr; b > eang ;b += incr) {
1378             cb = omega * cb;
1379             AddPoint(cb.vector() * ar + dr, piece, (sang - b) / (sang - eang));
1380         }
1382     } else {
1383         double const incr = 0.1;
1384         if ( sang > eang ) {
1385             sang -= 2*M_PI;
1386         }
1387         Geom::Rotate const omega(incr);
1388         for (double b = sang + incr ; b < eang ; b += incr) {
1389             cb = omega * cb;
1390             AddPoint(cb.vector() * ar + dr, piece, (b - sang) / (eang - sang));
1391         }
1392     }
1396 void Path::RecCubicTo(Geom::Point const &iS, Geom::Point const &isD,
1397                       Geom::Point const &iE, Geom::Point const &ieD,
1398                       double tresh, int lev, double st, double et,
1399                       int piece, offset_orig &orig)
1401     const Geom::Point se = iE - iS;
1402     const double dC = Geom::L2(se);
1403     bool doneSub = false;
1404     if ( dC < 0.01 ) {
1405         const double sC = dot(isD, isD);
1406         const double eC = dot(ieD, ieD);
1407         if ( sC < tresh && eC < tresh ) {
1408             return;
1409         }
1410     } else {
1411         const double sC = fabs(cross(se, isD)) / dC;
1412         const double eC = fabs(cross(se, ieD)) / dC;
1413         if ( sC < tresh && eC < tresh ) {
1414             doneSub = true;
1415         }
1416     }
1418     if ( lev <= 0 ) {
1419         doneSub = true;
1420     }
1422     // test des inversions
1423     bool stInv = false;
1424     bool enInv = false;
1425     {
1426         Geom::Point os_pos;
1427         Geom::Point os_tgt;
1428         Geom::Point oe_pos;
1429         Geom::Point oe_tgt;
1431         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
1432         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
1435         Geom::Point n_tgt = isD;
1436         double si = dot(n_tgt, os_tgt);
1437         if ( si < 0 ) {
1438             stInv = true;
1439         }
1440         n_tgt = ieD;
1441         si = dot(n_tgt, oe_tgt);
1442         if ( si < 0 ) {
1443             enInv = true;
1444         }
1445         if ( stInv && enInv ) {
1447             AddPoint(os_pos, -1, 0.0);
1448             AddPoint(iE, piece, et);
1449             AddPoint(iS, piece, st);
1450             AddPoint(oe_pos, -1, 0.0);
1451             return;
1453         } else if ( ( stInv && !enInv ) || ( !stInv && enInv ) ) {
1454             return;
1455         }
1457     }
1459     if ( ( !stInv && !enInv && doneSub ) || lev <= 0 ) {
1460         return;
1461     }
1463     {
1464         const Geom::Point m = 0.5 * (iS+iE) + 0.125 * (isD - ieD);
1465         const Geom::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1466         const double mt = (st + et) / 2;
1467         const Geom::Point hisD = 0.5 * isD;
1468         const Geom::Point hieD = 0.5 * ieD;
1470         RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece, orig);
1471         AddPoint(m, piece, mt);
1472         RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece, orig);
1473     }
1478 void Path::RecBezierTo(Geom::Point const &iP, Geom::Point const &iS,Geom::Point const &iE,
1479                        double tresh, int lev, double st, double et,
1480                        int piece, offset_orig& orig)
1482     bool doneSub = false;
1483     if ( lev <= 0 ) {
1484         return;
1485     }
1487     const Geom::Point ps = iS - iP;
1488     const Geom::Point pe = iE - iP;
1489     const double s = fabs(cross(pe, ps));
1490     if ( s < tresh ) {
1491         doneSub = true ;
1492     }
1494     // test des inversions
1495     bool stInv = false;
1496     bool enInv = false;
1497     {
1498         Geom::Point os_pos;
1499         Geom::Point os_tgt;
1500         Geom::Point oe_pos;
1501         Geom::Point oe_tgt;
1502         Geom::Point n_tgt;
1503         Geom::Point n_pos;
1505         double n_len;
1506         double n_rad;
1507         PathDescrIntermBezierTo mid(iP);
1508         PathDescrBezierTo fin(iE, 1);
1510         TangentOnBezAt(0.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
1511         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
1512         double si = dot(n_tgt, os_tgt);
1513         if ( si < 0 ) {
1514             stInv = true;
1515         }
1517         TangentOnBezAt(1.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
1518         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
1519         si = dot(n_tgt, oe_tgt);
1520         if ( si < 0 ) {
1521             enInv = true;
1522         }
1524         if ( stInv && enInv ) {
1525             AddPoint(os_pos, -1, 0.0);
1526             AddPoint(iE, piece, et);
1527             AddPoint(iS, piece, st);
1528             AddPoint(oe_pos, -1, 0.0);
1529             return;
1530         }
1531     }
1533     if ( !stInv && !enInv && doneSub ) {
1534         return;
1535     }
1537     {
1538         double mt = (st + et) / 2;
1539         Geom::Point m = 0.25 * (iS + iE + 2 * iP);
1540         Geom::Point md = 0.5 * (iS + iP);
1541         RecBezierTo(md, iS, m, tresh, lev - 1, st, mt, piece, orig);
1542         AddPoint(m, piece, mt);
1543         md = 0.5 * (iP + iE);
1544         RecBezierTo(md, m, iE, tresh, lev - 1, mt, et, piece, orig);
1545     }
1549 /*
1550  * put a polyline in a Shape instance, for further fun
1551  * pathID is the ID you want this Path instance to be associated with, for when you're going to recompose the polyline
1552  * in a path description ( you need to have prepared the back data for that, of course)
1553  */
1555 void Path::Fill(Shape* dest, int pathID, bool justAdd, bool closeIfNeeded, bool invert)
1557     if ( dest == NULL ) {
1558         return;
1559     }
1561     if ( justAdd == false ) {
1562         dest->Reset(pts.size(), pts.size());
1563     }
1565     if ( pts.size() <= 1 ) {
1566         return;
1567     }
1569     int first = dest->numberOfPoints();
1571     if ( back ) {
1572         dest->MakeBackData(true);
1573     }
1575     if ( invert ) {
1576         if ( back ) {
1577             {
1578                 // invert && back && !weighted
1579                 for (int i = 0; i < int(pts.size()); i++) {
1580                     dest->AddPoint(pts[i].p);
1581                 }
1582                 int lastM = 0;
1583                 int curP = 1;
1584                 int pathEnd = 0;
1585                 bool closed = false;
1586                 int lEdge = -1;
1588                 while ( curP < int(pts.size()) ) {
1589                     int sbp = curP;
1590                     int lm = lastM;
1591                     int prp = pathEnd;
1593                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1595                         if ( closeIfNeeded ) {
1596                             if ( closed && lEdge >= 0 ) {
1597                                 dest->DisconnectStart(lEdge);
1598                                 dest->ConnectStart(first + lastM, lEdge);
1599                             } else {
1600                                 lEdge = dest->AddEdge(first + lastM, first+pathEnd);
1601                                 if ( lEdge >= 0 ) {
1602                                     dest->ebData[lEdge].pathID = pathID;
1603                                     dest->ebData[lEdge].pieceID = pts[lm].piece;
1604                                     dest->ebData[lEdge].tSt = 1.0;
1605                                     dest->ebData[lEdge].tEn = 0.0;
1606                                 }
1607                             }
1608                         }
1610                         lastM = curP;
1611                         pathEnd = curP;
1612                         closed = false;
1613                         lEdge = -1;
1615                     } else {
1617                         if ( Geom::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1618                             lEdge = dest->AddEdge(first + curP, first + pathEnd);
1619                             if ( lEdge >= 0 ) {
1620                                 dest->ebData[lEdge].pathID = pathID;
1621                                 dest->ebData[lEdge].pieceID = pts[sbp].piece;
1622                                 if ( pts[sbp].piece == pts[prp].piece ) {
1623                                     dest->ebData[lEdge].tSt = pts[sbp].t;
1624                                     dest->ebData[lEdge].tEn = pts[prp].t;
1625                                 } else {
1626                                     dest->ebData[lEdge].tSt = pts[sbp].t;
1627                                     dest->ebData[lEdge].tEn = 0.0;
1628                                 }
1629                             }
1630                             pathEnd = curP;
1631                             if ( Geom::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1632                                 closed = true;
1633                             } else {
1634                                 closed = false;
1635                             }
1636                         }
1637                     }
1639                     curP++;
1640                 }
1642                 if ( closeIfNeeded ) {
1643                     if ( closed && lEdge >= 0 ) {
1644                         dest->DisconnectStart(lEdge);
1645                         dest->ConnectStart(first + lastM, lEdge);
1646                     } else {
1647                         int lm = lastM;
1648                         lEdge = dest->AddEdge(first + lastM, first + pathEnd);
1649                         if ( lEdge >= 0 ) {
1650                             dest->ebData[lEdge].pathID = pathID;
1651                             dest->ebData[lEdge].pieceID = pts[lm].piece;
1652                             dest->ebData[lEdge].tSt = 1.0;
1653                             dest->ebData[lEdge].tEn = 0.0;
1654                         }
1655                     }
1656                 }
1657             }
1659         } else {
1661             {
1662                 // invert && !back && !weighted
1663                 for (int i = 0; i < int(pts.size()); i++) {
1664                     dest->AddPoint(pts[i].p);
1665                 }
1666                 int lastM = 0;
1667                 int curP = 1;
1668                 int pathEnd = 0;
1669                 bool closed = false;
1670                 int lEdge = -1;
1671                 while ( curP < int(pts.size()) ) {
1672                     int sbp = curP;
1673                     int lm = lastM;
1674                     int prp = pathEnd;
1675                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1676                         if ( closeIfNeeded ) {
1677                             if ( closed && lEdge >= 0 ) {
1678                                 dest->DisconnectStart(lEdge);
1679                                 dest->ConnectStart(first + lastM, lEdge);
1680                             } else {
1681                                 dest->AddEdge(first + lastM, first + pathEnd);
1682                             }
1683                         }
1684                         lastM = curP;
1685                         pathEnd = curP;
1686                         closed = false;
1687                         lEdge = -1;
1688                     } else {
1689                         if ( Geom::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1690                             lEdge = dest->AddEdge(first+curP, first+pathEnd);
1691                             pathEnd = curP;
1692                             if ( Geom::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1693                                 closed = true;
1694                             } else {
1695                                 closed = false;
1696                             }
1697                         }
1698                     }
1699                     curP++;
1700                 }
1702                 if ( closeIfNeeded ) {
1703                     if ( closed && lEdge >= 0 ) {
1704                         dest->DisconnectStart(lEdge);
1705                         dest->ConnectStart(first + lastM, lEdge);
1706                     } else {
1707                         dest->AddEdge(first + lastM, first + pathEnd);
1708                     }
1709                 }
1711             }
1712         }
1714     } else {
1716         if ( back ) {
1717             {
1718                 // !invert && back && !weighted
1719                 for (int i = 0; i < int(pts.size()); i++) {
1720                     dest->AddPoint(pts[i].p);
1721                 }
1723                 int lastM = 0;
1724                 int curP = 1;
1725                 int pathEnd = 0;
1726                 bool closed = false;
1727                 int lEdge = -1;
1728                 while ( curP < int(pts.size()) ) {
1729                     int sbp = curP;
1730                     int lm = lastM;
1731                     int prp = pathEnd;
1732                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1733                         if ( closeIfNeeded ) {
1734                             if ( closed && lEdge >= 0 ) {
1735                                 dest->DisconnectEnd(lEdge);
1736                                 dest->ConnectEnd(first + lastM, lEdge);
1737                             } else {
1738                                 lEdge = dest->AddEdge(first + pathEnd, first+lastM);
1739                                 if ( lEdge >= 0 ) {
1740                                     dest->ebData[lEdge].pathID = pathID;
1741                                     dest->ebData[lEdge].pieceID = pts[lm].piece;
1742                                     dest->ebData[lEdge].tSt = 0.0;
1743                                     dest->ebData[lEdge].tEn = 1.0;
1744                                 }
1745                             }
1746                         }
1747                         lastM = curP;
1748                         pathEnd = curP;
1749                         closed = false;
1750                         lEdge = -1;
1751                     } else {
1752                         if ( Geom::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1753                             lEdge = dest->AddEdge(first + pathEnd, first + curP);
1754                             dest->ebData[lEdge].pathID = pathID;
1755                             dest->ebData[lEdge].pieceID = pts[sbp].piece;
1756                             if ( pts[sbp].piece == pts[prp].piece ) {
1757                                 dest->ebData[lEdge].tSt = pts[prp].t;
1758                                 dest->ebData[lEdge].tEn = pts[sbp].t;
1759                             } else {
1760                                 dest->ebData[lEdge].tSt = 0.0;
1761                                 dest->ebData[lEdge].tEn = pts[sbp].t;
1762                             }
1763                             pathEnd = curP;
1764                             if ( Geom::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1765                                 closed = true;
1766                             } else {
1767                                 closed = false;
1768                             }
1769                         }
1770                     }
1771                     curP++;
1772                 }
1774                 if ( closeIfNeeded ) {
1775                     if ( closed && lEdge >= 0 ) {
1776                         dest->DisconnectEnd(lEdge);
1777                         dest->ConnectEnd(first + lastM, lEdge);
1778                     } else {
1779                         int lm = lastM;
1780                         lEdge = dest->AddEdge(first + pathEnd, first + lastM);
1781                         if ( lEdge >= 0 ) {
1782                             dest->ebData[lEdge].pathID = pathID;
1783                             dest->ebData[lEdge].pieceID = pts[lm].piece;
1784                             dest->ebData[lEdge].tSt = 0.0;
1785                             dest->ebData[lEdge].tEn = 1.0;
1786                         }
1787                     }
1788                 }
1789             }
1791         } else {
1792             {
1793                 // !invert && !back && !weighted
1794                 for (int i = 0;i < int(pts.size()); i++) {
1795                     dest->AddPoint(pts[i].p);
1796                 }
1798                 int lastM = 0;
1799                 int curP = 1;
1800                 int pathEnd = 0;
1801                 bool closed = false;
1802                 int lEdge = -1;
1803                 while ( curP < int(pts.size()) ) {
1804                     int sbp = curP;
1805                     int lm = lastM;
1806                     int prp = pathEnd;
1807                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1808                         if ( closeIfNeeded ) {
1809                             if ( closed && lEdge >= 0 ) {
1810                                 dest->DisconnectEnd(lEdge);
1811                                 dest->ConnectEnd(first + lastM, lEdge);
1812                             } else {
1813                                 dest->AddEdge(first + pathEnd, first + lastM);
1814                             }
1815                         }
1816                         lastM = curP;
1817                         pathEnd = curP;
1818                         closed = false;
1819                         lEdge = -1;
1820                     } else {
1821                         if ( Geom::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1822                             lEdge = dest->AddEdge(first+pathEnd, first+curP);
1823                             pathEnd = curP;
1824                             if ( Geom::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1825                                 closed = true;
1826                             } else {
1827                                 closed = false;
1828                             }
1829                         }
1830                     }
1831                     curP++;
1832                 }
1834                 if ( closeIfNeeded ) {
1835                     if ( closed && lEdge >= 0 ) {
1836                         dest->DisconnectEnd(lEdge);
1837                         dest->ConnectEnd(first + lastM, lEdge);
1838                     } else {
1839                         dest->AddEdge(first + pathEnd, first + lastM);
1840                     }
1841                 }
1843             }
1844         }
1845     }
1848 /*
1849   Local Variables:
1850   mode:c++
1851   c-file-style:"stroustrup"
1852   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1853   indent-tabs-mode:nil
1854   fill-column:99
1855   End:
1856 */
1857 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :