Code

4ae4afe8610a29ae82bd04c31127a6fefb308a1c
[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     NR::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[NR::X] = curX[NR::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         NR::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                 AddPoint(nextX, curP, 1.0, false);
79                 curP++;
80                 break;
81             }
83             case descr_lineto: {
84                 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
85                 nextX = nData->p;
86                 AddPoint(nextX,curP,1.0,false);
87                 // et on avance
88                 curP++;
89                 break;
90             }
92             case descr_cubicto: {
93                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
94                 nextX = nData->p;
95                 RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8, 0.0, 1.0, curP);
96                 AddPoint(nextX, curP, 1.0, false);
97                 // et on avance
98                 curP++;
99                 break;
100             }
102             case descr_arcto: {
103                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
104                 nextX = nData->p;
105                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold, curP);
106                 AddPoint(nextX, curP, 1.0, false);
107                 // et on avance
108                 curP++;
109                 break;
110             }
112             case descr_bezierto: {
113                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
114                 int nbInterm = nBData->nb;
115                 nextX = nBData->p;
117                 int ip = curP + 1;
118                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
120                 if ( nbInterm >= 1 ) {
121                     NR::Point bx = curX;
122                     NR::Point cx = curX;
123                     NR::Point dx = curX;
125                     dx = nData->p;
126                     ip++;
127                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
129                     cx = 2 * bx - dx;
131                     for (int k = 0; k < nbInterm - 1; k++) {
132                         bx = cx;
133                         cx = dx;
135                         dx = nData->p;
136                         ip++;
137                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
139                         NR::Point stx;
140                         stx = (bx + cx) / 2;
141                         if ( k > 0 ) {
142                             AddPoint(stx,curP - 1+k,1.0,false);
143                         }
145                         {
146                             NR::Point mx;
147                             mx = (cx + dx) / 2;
148                             RecBezierTo(cx, stx, mx, treshhold, 8, 0.0, 1.0, curP + k);
149                         }
150                     }
151                     {
152                         bx = cx;
153                         cx = dx;
155                         dx = nextX;
156                         dx = 2 * dx - cx;
158                         NR::Point stx;
159                         stx = (bx + cx) / 2;
161                         if ( nbInterm > 1 ) {
162                             AddPoint(stx, curP + nbInterm - 2, 1.0, false);
163                         }
165                         {
166                             NR::Point mx;
167                             mx = (cx + dx) / 2;
168                             RecBezierTo(cx, stx, mx, treshhold, 8, 0.0, 1.0, curP + nbInterm - 1);
169                         }
170                     }
172                 }
175                 AddPoint(nextX, curP - 1 + nbInterm, 1.0, false);
177                 // et on avance
178                 curP += 1 + nbInterm;
179                 break;
180             }
181         }
182         curX = nextX;
183     }
187 void Path::Convert(double treshhold)
189     if ( descr_flags & descr_adding_bezier ) {
190         CancelBezier();
191     }
193     if ( descr_flags & descr_doing_subpath ) {
194         CloseSubpath();
195     }
197     SetBackData(false);
198     ResetPoints();
199     if ( descr_cmd.empty() ) {
200         return;
201     }
203     NR::Point curX;
204     int curP = 1;
205     int lastMoveTo = 0;
207     // le moveto
208     {
209         int const firstTyp = descr_cmd[0]->getType();
210         if ( firstTyp == descr_moveto ) {
211             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
212         } else {
213             curP = 0;
214             curX[0] = curX[1] = 0;
215         }
216         lastMoveTo = AddPoint(curX, true);
217     }
218     descr_cmd[0]->associated = lastMoveTo;
220     // et le reste, 1 par 1
221     while ( curP < int(descr_cmd.size()) ) {
223         int const nType = descr_cmd[curP]->getType();
224         NR::Point nextX;
226         switch (nType) {
227             case descr_forced: {
228                 descr_cmd[curP]->associated = AddForcedPoint(curX);
229                 curP++;
230                 break;
231             }
233             case descr_moveto: {
234                 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
235                 nextX = nData->p;
236                 lastMoveTo = AddPoint(nextX, true);
237                 descr_cmd[curP]->associated = lastMoveTo;
239                 // et on avance
240                 curP++;
241                 break;
242             }
244             case descr_close: {
245                 nextX = pts[lastMoveTo].p;
246                 descr_cmd[curP]->associated = AddPoint(nextX, false);
247                 if ( descr_cmd[curP]->associated < 0 ) {
248                     if ( curP == 0 ) {
249                         descr_cmd[curP]->associated = 0;
250                     } else {
251                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
252                     }
253                 }
254                 curP++;
255                 break;
256             }
258             case descr_lineto: {
259                 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
260                 nextX = nData->p;
261                 descr_cmd[curP]->associated = AddPoint(nextX, false);
262                 if ( descr_cmd[curP]->associated < 0 ) {
263                     if ( curP == 0 ) {
264                         descr_cmd[curP]->associated = 0;
265                     } else {
266                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
267                     }
268                 }
269                 // et on avance
270                 curP++;
271                 break;
272             }
274             case descr_cubicto: {
275                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
276                 nextX = nData->p;
277                 RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8);
278                 descr_cmd[curP]->associated = AddPoint(nextX,false);
279                 if ( descr_cmd[curP]->associated < 0 ) {
280                     if ( curP == 0 ) {
281                         descr_cmd[curP]->associated = 0;
282                     } else {
283                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
284                     }
285                 }
286                 // et on avance
287                 curP++;
288                 break;
289             }
291             case descr_arcto: {
292                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
293                 nextX = nData->p;
294                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
295                 descr_cmd[curP]->associated = AddPoint(nextX, false);
296                 if ( descr_cmd[curP]->associated < 0 ) {
297                     if ( curP == 0 ) {
298                         descr_cmd[curP]->associated = 0;
299                     } else {
300                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
301                     }
302                 }
303                 // et on avance
304                 curP++;
305                 break;
306             }
308             case descr_bezierto: {
309                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
310                 int nbInterm = nBData->nb;
311                 nextX = nBData->p;
312                 int curBD = curP;
314                 curP++;
315                 int ip = curP;
316                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
318                 if ( nbInterm == 1 ) {
319                     NR::Point const midX = nData->p;
320                     RecBezierTo(midX, curX, nextX, treshhold, 8);
321                 } else if ( nbInterm > 1 ) {
322                     NR::Point bx = curX;
323                     NR::Point cx = curX;
324                     NR::Point dx = curX;
326                     dx = nData->p;
327                     ip++;
328                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
330                     cx = 2 * bx - dx;
332                     for (int k = 0; k < nbInterm - 1; k++) {
333                         bx = cx;
334                         cx = dx;
336                         dx = nData->p;
337                         ip++;
338                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
340                         NR::Point stx = (bx + cx) / 2;
341                         if ( k > 0 ) {
342                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
343                             if ( descr_cmd[ip - 2]->associated < 0 ) {
344                                 if ( curP == 0 ) {
345                                     descr_cmd[ip - 2]->associated = 0;
346                                 } else {
347                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
348                                 }
349                             }
350                         }
352                         {
353                             NR::Point const mx = (cx + dx) / 2;
354                             RecBezierTo(cx, stx, mx, treshhold, 8);
355                         }
356                     }
358                     {
359                         bx = cx;
360                         cx = dx;
362                         dx = nextX;
363                         dx = 2 * dx - cx;
365                         NR::Point stx = (bx + cx) / 2;
367                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
368                         if ( descr_cmd[ip - 1]->associated < 0 ) {
369                             if ( curP == 0 ) {
370                                 descr_cmd[ip - 1]->associated = 0;
371                             } else {
372                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
373                             }
374                         }
376                         {
377                             NR::Point mx = (cx + dx) / 2;
378                             RecBezierTo(cx, stx, mx, treshhold, 8);
379                         }
380                     }
381                 }
383                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
384                 if ( descr_cmd[curBD]->associated < 0 ) {
385                     if ( curP == 0 ) {
386                         descr_cmd[curBD]->associated = 0;
387                     } else {
388                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
389                     }
390                 }
392                 // et on avance
393                 curP += nbInterm;
394                 break;
395             }
396         }
398         curX = nextX;
399     }
402 #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))))
404 void Path::Convert(NRRectL *area, double treshhold)
406     if ( descr_flags & descr_adding_bezier ) {
407         CancelBezier();
408     }
410     if ( descr_flags & descr_doing_subpath ) {
411         CloseSubpath();
412     }
414     SetBackData(false);
415     ResetPoints();
416     if ( descr_cmd.empty() ) {
417         return;
418     }
420     NR::Point curX;
421     int curP = 1;
422     int lastMoveTo = 0;
423     short last_point_relation = 0;
424     short curent_point_relation = 0;
425     bool last_start_elimination = false;
426     bool start_elimination = false;
427     bool replace = false;
429     // first point
430     {
431         int const firstTyp = descr_cmd[0]->getType();
432         if ( firstTyp == descr_moveto ) {
433             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
434         } else {
435             curP = 0;
436             curX[0] = curX[1] = 0;
437         }
438         
439         last_point_relation = POINT_RELATION_TO_AREA(curX, area);
440         lastMoveTo = AddPoint(curX, true);
441     }
442     descr_cmd[0]->associated = lastMoveTo;
444     // process nodes one by one
445     while ( curP < int(descr_cmd.size()) ) {
447         int const nType = descr_cmd[curP]->getType();
448         NR::Point nextX;
450         switch (nType) {
451             case descr_forced: {
452                 descr_cmd[curP]->associated = AddForcedPoint(curX);
453                 last_point_relation = 0;
454                 curP++;
455                 break;
456             }
458             case descr_moveto: {
459                 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
460                 nextX = nData->p;
461                 lastMoveTo = AddPoint(nextX, true);
462                 descr_cmd[curP]->associated = lastMoveTo;
463                 last_point_relation = POINT_RELATION_TO_AREA(nextX, area);
464                 start_elimination = false;
466                 curP++;
467                 break;
468             }
470             case descr_close: {
471                 nextX = pts[lastMoveTo].p;
472                 descr_cmd[curP]->associated = AddPoint(nextX, false);
473                 if ( descr_cmd[curP]->associated < 0 ) {
474                     if ( curP == 0 ) {
475                         descr_cmd[curP]->associated = 0;
476                     } else {
477                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
478                     }
479                 }
480                 last_point_relation = 0;
481                 curP++;
482                 break;
483             }
485             case descr_lineto: {
486                 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
487                 nextX = nData->p;
488                 curent_point_relation = POINT_RELATION_TO_AREA(nextX, area);
489                 replace = false;
490                 last_start_elimination = start_elimination;
491                 if (curent_point_relation > 0 && curent_point_relation == last_point_relation) {
492                     if (!start_elimination) {
493                         start_elimination = true;
494                     } else {
495                         replace = true;
496                         descr_cmd[curP]->associated = ReplacePoint(nextX);
497                     }
498                 } else {
499                     start_elimination = false;
500                 }
502                 if (!replace) {
503                     descr_cmd[curP]->associated = AddPoint(nextX, false);
504                 }
506                 if ( descr_cmd[curP]->associated < 0 ) {
507                     // point is not added as position is equal to the last added
508                     start_elimination = last_start_elimination;
509                     if ( curP == 0 ) {
510                         descr_cmd[curP]->associated = 0;
511                     } else {
512                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
513                     }
514                 }
515                 last_point_relation = curent_point_relation;
516                 curP++;
517                 break;
518             }
520             case descr_cubicto: {
521                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
522                 nextX = nData->p;
524                 curent_point_relation = POINT_RELATION_TO_AREA(nextX, area);
525                 replace = false;
526                 last_start_elimination = start_elimination;
527                 if (curent_point_relation > 0 && curent_point_relation == last_point_relation &&
528                     curent_point_relation == POINT_RELATION_TO_AREA(curX + (nData->start), area) &&
529                     curent_point_relation == POINT_RELATION_TO_AREA(nextX + (nData->end), area))
530                 {
531                     if (!start_elimination) {
532                         start_elimination = true;
533                     } else {
534                         replace = true;
535                         descr_cmd[curP]->associated = ReplacePoint(nextX);
536                     }
537                 } else {
538                     start_elimination = false;
539                 }
540                 
541                 if (!replace) {
542                     RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8);
543                     descr_cmd[curP]->associated = AddPoint(nextX,false);
544                 }
546                 if ( descr_cmd[curP]->associated < 0 ) {
547                     // point is not added as position is equal to the last added
548                     start_elimination = last_start_elimination;
549                     if ( curP == 0 ) {
550                         descr_cmd[curP]->associated = 0;
551                     } else {
552                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
553                     }
554                 }
555                 last_point_relation = curent_point_relation;
556                 curP++;
557                 break;
558             }
560             case descr_arcto: {
561                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
562                 nextX = nData->p;
563                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
564                 descr_cmd[curP]->associated = AddPoint(nextX, false);
565                 if ( descr_cmd[curP]->associated < 0 ) {
566                     if ( curP == 0 ) {
567                         descr_cmd[curP]->associated = 0;
568                     } else {
569                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
570                     }
571                 }
572                 last_point_relation = 0;
574                 curP++;
575                 break;
576             }
578             case descr_bezierto: {
579                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
580                 int nbInterm = nBData->nb;
581                 nextX = nBData->p;
582                 int curBD = curP;
584                 curP++;
585                 int ip = curP;
586                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
588                 if ( nbInterm == 1 ) {
589                     NR::Point const midX = nData->p;
590                     RecBezierTo(midX, curX, nextX, treshhold, 8);
591                 } else if ( nbInterm > 1 ) {
592                     NR::Point bx = curX;
593                     NR::Point cx = curX;
594                     NR::Point dx = curX;
596                     dx = nData->p;
597                     ip++;
598                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
600                     cx = 2 * bx - dx;
602                     for (int k = 0; k < nbInterm - 1; k++) {
603                         bx = cx;
604                         cx = dx;
606                         dx = nData->p;
607                         ip++;
608                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
610                         NR::Point stx = (bx + cx) / 2;
611                         if ( k > 0 ) {
612                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
613                             if ( descr_cmd[ip - 2]->associated < 0 ) {
614                                 if ( curP == 0 ) {
615                                     descr_cmd[ip - 2]->associated = 0;
616                                 } else {
617                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
618                                 }
619                             }
620                         }
622                         {
623                             NR::Point const mx = (cx + dx) / 2;
624                             RecBezierTo(cx, stx, mx, treshhold, 8);
625                         }
626                     }
628                     {
629                         bx = cx;
630                         cx = dx;
632                         dx = nextX;
633                         dx = 2 * dx - cx;
635                         NR::Point stx = (bx + cx) / 2;
637                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
638                         if ( descr_cmd[ip - 1]->associated < 0 ) {
639                             if ( curP == 0 ) {
640                                 descr_cmd[ip - 1]->associated = 0;
641                             } else {
642                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
643                             }
644                         }
646                         {
647                             NR::Point mx = (cx + dx) / 2;
648                             RecBezierTo(cx, stx, mx, treshhold, 8);
649                         }
650                     }
651                 }
653                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
654                 if ( descr_cmd[curBD]->associated < 0 ) {
655                     if ( curP == 0 ) {
656                         descr_cmd[curBD]->associated = 0;
657                     } else {
658                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
659                     }
660                 }
662                 last_point_relation = 0;
664                 curP += nbInterm;
665                 break;
666             }
667         }
669         curX = nextX;
670     }
674 void Path::ConvertEvenLines(double treshhold)
676     if ( descr_flags & descr_adding_bezier ) {
677         CancelBezier();
678     }
680     if ( descr_flags & descr_doing_subpath ) {
681         CloseSubpath();
682     }
684     SetBackData(false);
685     ResetPoints();
686     if ( descr_cmd.empty() ) {
687         return;
688     }
690     NR::Point curX;
691     int curP = 1;
692     int lastMoveTo = 0;
694     // le moveto
695     {
696         int const firstTyp = descr_cmd[0]->getType();
697         if ( firstTyp == descr_moveto ) {
698             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
699         } else {
700             curP = 0;
701             curX[0] = curX[1] = 0;
702         }
703         lastMoveTo = AddPoint(curX, true);
704     }
705     descr_cmd[0]->associated = lastMoveTo;
707     // et le reste, 1 par 1
708     while ( curP < int(descr_cmd.size()) ) {
710         int const nType = descr_cmd[curP]->getType();
711         NR::Point nextX;
713         switch (nType) {
714             case descr_forced: {
715                 descr_cmd[curP]->associated = AddForcedPoint(curX);
716                 curP++;
717                 break;
718             }
720             case descr_moveto: {
721                 PathDescrMoveTo* nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
722                 nextX = nData->p;
723                 lastMoveTo = AddPoint(nextX,true);
724                 descr_cmd[curP]->associated = lastMoveTo;
726                 // et on avance
727                 curP++;
728                 break;
729             }
731             case descr_close: {
732                 nextX = pts[lastMoveTo].p;
733                 {
734                     NR::Point nexcur;
735                     nexcur = nextX - curX;
736                     const double segL = NR::L2(nexcur);
737                     if ( segL > treshhold ) {
738                         for (double i = treshhold; i < segL; i += treshhold) {
739                             NR::Point nX;
740                             nX = (segL - i) * curX + i * nextX;
741                             nX /= segL;
742                             AddPoint(nX);
743                         }
744                     }
745                 }
747                 descr_cmd[curP]->associated = AddPoint(nextX,false);
748                 if ( descr_cmd[curP]->associated < 0 ) {
749                     if ( curP == 0 ) {
750                         descr_cmd[curP]->associated = 0;
751                     } else {
752                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
753                     }
754                 }
756                 curP++;
757                 break;
758             }
760             case descr_lineto: {
761                 PathDescrLineTo* nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
762                 nextX = nData->p;
763                 NR::Point nexcur = nextX - curX;
764                 const double segL = L2(nexcur);
765                 if ( segL > treshhold ) {
766                     for (double i = treshhold; i < segL; i += treshhold) {
767                         NR::Point nX = ((segL - i) * curX + i * nextX) / segL;
768                         AddPoint(nX);
769                     }
770                 }
772                 descr_cmd[curP]->associated = AddPoint(nextX,false);
773                 if ( descr_cmd[curP]->associated < 0 ) {
774                     if ( curP == 0 ) {
775                         descr_cmd[curP]->associated = 0;
776                     } else {
777                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
778                     }
779                 }
780                 // et on avance
781                 curP++;
782                 break;
783             }
785             case descr_cubicto: {
786                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
787                 nextX = nData->p;
788                 RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8, 4 * treshhold);
789                 descr_cmd[curP]->associated = AddPoint(nextX, false);
790                 if ( descr_cmd[curP]->associated < 0 ) {
791                     if ( curP == 0 ) {
792                         descr_cmd[curP]->associated = 0;
793                     } else {
794                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
795                     }
796                 }
797                 // et on avance
798                 curP++;
799                 break;
800             }
802             case descr_arcto: {
803                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
804                 nextX = nData->p;
805                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
806                 descr_cmd[curP]->associated =AddPoint(nextX, false);
807                 if ( descr_cmd[curP]->associated < 0 ) {
808                     if ( curP == 0 ) {
809                         descr_cmd[curP]->associated = 0;
810                     } else {
811                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
812                     }
813                 }
815                 // et on avance
816                 curP++;
817                 break;
818             }
820             case descr_bezierto: {
821                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
822                 int nbInterm = nBData->nb;
823                 nextX = nBData->p;
824                 int curBD = curP;
826                 curP++;
827                 int ip = curP;
828                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
830                 if ( nbInterm == 1 ) {
831                     NR::Point const midX = nData->p;
832                     RecBezierTo(midX, curX, nextX, treshhold, 8, 4 * treshhold);
833                 } else if ( nbInterm > 1 ) {
834                     NR::Point bx = curX;
835                     NR::Point cx = curX;
836                     NR::Point dx = curX;
838                     dx = nData->p;
839                     ip++;
840                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
842                     cx = 2 * bx - dx;
844                     for (int k = 0; k < nbInterm - 1; k++) {
845                         bx = cx;
846                         cx = dx;
847                         dx = nData->p;
849                         ip++;
850                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
852                         NR::Point stx = (bx+cx) / 2;
853                         if ( k > 0 ) {
854                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
855                             if ( descr_cmd[ip - 2]->associated < 0 ) {
856                                 if ( curP == 0 ) {
857                                     descr_cmd[ip- 2]->associated = 0;
858                                 } else {
859                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
860                                 }
861                             }
862                         }
864                         {
865                             NR::Point const mx = (cx + dx) / 2;
866                             RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
867                         }
868                     }
870                     {
871                         bx = cx;
872                         cx = dx;
874                         dx = nextX;
875                         dx = 2 * dx - cx;
877                         NR::Point const stx = (bx + cx) / 2;
879                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
880                         if ( descr_cmd[ip - 1]->associated < 0 ) {
881                             if ( curP == 0 ) {
882                                 descr_cmd[ip - 1]->associated = 0;
883                             } else {
884                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
885                             }
886                         }
888                         {
889                             NR::Point const mx = (cx + dx) / 2;
890                             RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
891                         }
892                     }
893                 }
895                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
896                 if ( descr_cmd[curBD]->associated < 0 ) {
897                     if ( curP == 0 ) {
898                         descr_cmd[curBD]->associated = 0;
899                     } else {
900                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
901                     }
902                 }
904                 // et on avance
905                 curP += nbInterm;
906                 break;
907             }
908         }
909         if ( Geom::LInfty(curX - nextX) > 0.00001 ) {
910             curX = nextX;
911         }
912     }
915 const NR::Point Path::PrevPoint(int i) const
917     /* TODO: I suspect this should assert `(unsigned) i < descr_nb'.  We can probably change
918        the argument to unsigned.  descr_nb should probably be changed to unsigned too. */
919     g_assert( i >= 0 );
920     switch ( descr_cmd[i]->getType() ) {
921         case descr_moveto: {
922             PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
923             return nData->p;
924         }
925         case descr_lineto: {
926             PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
927             return nData->p;
928         }
929         case descr_arcto: {
930             PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
931             return nData->p;
932         }
933         case descr_cubicto: {
934             PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
935             return nData->p;
936         }
937         case descr_bezierto: {
938             PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
939             return nData->p;
940         }
941         case descr_interm_bezier:
942         case descr_close:
943         case descr_forced:
944             return PrevPoint(i - 1);
945         default:
946             g_assert_not_reached();
947             return NR::Point(0, 0);
948     }
951 // utilitaries: given a quadratic bezier curve (start point, control point, end point, ie that's a clamped curve),
952 // and an abcissis on it, get the point with that abcissis.
953 // 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"
954 void Path::QuadraticPoint(double t, NR::Point &oPt,
955                           const NR::Point &iS, const NR::Point &iM, const NR::Point &iE)
957     NR::Point const ax = iE - 2 * iM + iS;
958     NR::Point const bx = 2 * iM - 2 * iS;
959     NR::Point const cx = iS;
961     oPt = t * t * ax + t * bx + cx;
963 // idem for cubic bezier patch
964 void Path::CubicTangent(double t, NR::Point &oPt, const NR::Point &iS, const NR::Point &isD,
965                         const NR::Point &iE, const NR::Point &ieD)
967     NR::Point const ax = ieD - 2 * iE + 2 * iS + isD;
968     NR::Point const bx = 3 * iE - ieD - 2 * isD - 3 * iS;
969     NR::Point const cx = isD;
971     oPt = 3 * t * t * ax + 2 * t * bx + cx;
974 // extract interesting info of a SVG arc description
975 static void ArcAnglesAndCenter(NR::Point const &iS, NR::Point const &iE,
976                                double rx, double ry, double angle,
977                                bool large, bool wise,
978                                double &sang, double &eang, NR::Point &dr);
980 void Path::ArcAngles(const NR::Point &iS, const NR::Point &iE,
981                      double rx, double ry, double angle, bool large, bool wise, double &sang, double &eang)
983     NR::Point dr;
984     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
987 /* N.B. If iS == iE then sang,eang,dr each become NaN.  Probably a bug. */
988 static void ArcAnglesAndCenter(NR::Point const &iS, NR::Point const &iE,
989                                double rx, double ry, double angle,
990                                bool large, bool wise,
991                                double &sang, double &eang, NR::Point &dr)
993     NR::Point se = iE - iS;
994     NR::Point ca(cos(angle), sin(angle));
995     NR::Point cse(dot(se, ca), cross(se, ca));
996     cse[0] /= rx;
997     cse[1] /= ry;
998     double const lensq = dot(cse,cse);
999     NR::Point csd = ( ( lensq < 4
1000                         ? sqrt( 1/lensq - .25 )
1001                         : 0.0 )
1002                       * cse.ccw() );
1004     NR::Point ra = -csd - 0.5 * cse;
1005     if ( ra[0] <= -1 ) {
1006         sang = M_PI;
1007     } else if ( ra[0] >= 1 ) {
1008         sang = 0;
1009     } else {
1010         sang = acos(ra[0]);
1011         if ( ra[1] < 0 ) {
1012             sang = 2 * M_PI - sang;
1013         }
1014     }
1016     ra = -csd + 0.5 * cse;
1017     if ( ra[0] <= -1 ) {
1018         eang = M_PI;
1019     } else if ( ra[0] >= 1 ) {
1020         eang = 0;
1021     } else {
1022         eang = acos(ra[0]);
1023         if ( ra[1] < 0 ) {
1024             eang = 2 * M_PI - eang;
1025         }
1026     }
1028     csd[0] *= rx;
1029     csd[1] *= ry;
1030     ca[1] = -ca[1]; // because it's the inverse rotation
1032     dr[0] = dot(csd, ca);
1033     dr[1] = cross(csd, ca);
1035     ca[1] = -ca[1];
1037     if ( wise ) {
1039         if (large) {
1040             dr = -dr;
1041             double swap = eang;
1042             eang = sang;
1043             sang = swap;
1044             eang += M_PI;
1045             sang += M_PI;
1046             if ( eang >= 2*M_PI ) {
1047                 eang -= 2*M_PI;
1048             }
1049             if ( sang >= 2*M_PI ) {
1050                 sang -= 2*M_PI;
1051             }
1052         }
1054     } else {
1055         if (!large) {
1056             dr = -dr;
1057             double swap = eang;
1058             eang = sang;
1059             sang = swap;
1060             eang += M_PI;
1061             sang += M_PI;
1062             if ( eang >= 2*M_PI ) {
1063                 eang -= 2 * M_PI;
1064             }
1065             if ( sang >= 2*M_PI ) {
1066                 sang -= 2 * M_PI;
1067             }
1068         }
1069     }
1071     dr += 0.5 * (iS + iE);
1076 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
1077                  double const rx, double const ry, double const angle,
1078                  bool const large, bool const wise, double const /*tresh*/)
1080     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1081        apart than the diameter.  Also check that we do the right thing for negative radius.
1082        (Same for the other DoArc functions in this file.) */
1083     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1084         return;
1085         // We always add a lineto afterwards, so this is fine.
1086         // [on ajoute toujours un lineto apres, donc c bon]
1087     }
1089     double sang;
1090     double eang;
1091     NR::Point dr_temp;
1092     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr_temp);
1093     Geom::Point dr = dr_temp;
1094     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1095        the case of low curvature (i.e. very large radius). */
1097     Geom::Scale const ar(rx, ry);
1098     Geom::Rotate cb( angle + sang );
1099     if (wise) {
1101         double const incr = -0.1;
1102         if ( sang < eang ) {
1103             sang += 2*M_PI;
1104         }
1105         Geom::Rotate const omega(incr);
1106         for (double b = sang + incr ; b > eang ; b += incr) {
1107             cb = omega * cb;
1108             AddPoint( cb.vector() * ar + dr );
1109         }
1111     } else {
1113         double const incr = 0.1;
1114         if ( sang > eang ) {
1115             sang -= 2*M_PI;
1116         }
1117         Geom::Rotate const omega(incr);
1118         for (double b = sang + incr ; b < eang ; b += incr) {
1119             cb = omega * cb;
1120             AddPoint( cb.vector() * ar + dr);
1121         }
1122     }
1126 void Path::RecCubicTo( NR::Point const &iS, NR::Point const &isD,
1127                        NR::Point const &iE, NR::Point const &ieD,
1128                        double tresh, int lev, double maxL)
1130     NR::Point se = iE - iS;
1131     const double dC = NR::L2(se);
1132     if ( dC < 0.01 ) {
1134         const double sC = dot(isD,isD);
1135         const double eC = dot(ieD,ieD);
1136         if ( sC < tresh && eC < tresh ) {
1137             return;
1138         }
1140     } else {
1141         const double sC = fabs(cross(se, isD)) / dC;
1142         const double eC = fabs(cross(se, ieD)) / dC;
1143         if ( sC < tresh && eC < tresh ) {
1144             // presque tt droit -> attention si on nous demande de bien subdiviser les petits segments
1145             if ( maxL > 0 && dC > maxL ) {
1146                 if ( lev <= 0 ) {
1147                     return;
1148                 }
1149                 NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1150                 NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1152                 NR::Point hisD = 0.5 * isD;
1153                 NR::Point hieD = 0.5 * ieD;
1155                 RecCubicTo(iS, hisD, m, md, tresh, lev - 1, maxL);
1156                 AddPoint(m);
1157                 RecCubicTo(m, md, iE, hieD, tresh, lev - 1,maxL);
1158             }
1159             return;
1160         }
1161     }
1163     if ( lev <= 0 ) {
1164         return;
1165     }
1167     {
1168         NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1169         NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1171         NR::Point hisD = 0.5 * isD;
1172         NR::Point hieD = 0.5 * ieD;
1174         RecCubicTo(iS, hisD, m, md, tresh, lev - 1, maxL);
1175         AddPoint(m);
1176         RecCubicTo(m, md, iE, hieD, tresh, lev - 1,maxL);
1177     }
1182 void Path::RecBezierTo(const NR::Point &iP,
1183                        const NR::Point &iS,
1184                        const NR::Point &iE,
1185                        double tresh, int lev, double maxL)
1187     if ( lev <= 0 ) {
1188         return;
1189     }
1191     NR::Point ps = iS - iP;
1192     NR::Point pe = iE - iP;
1193     NR::Point se = iE - iS;
1194     double s = fabs(cross(pe, ps));
1195     if ( s < tresh ) {
1196         const double l = L2(se);
1197         if ( maxL > 0 && l > maxL ) {
1198             const NR::Point m = 0.25 * (iS + iE + 2 * iP);
1199             NR::Point md = 0.5 * (iS + iP);
1200             RecBezierTo(md, iS, m, tresh, lev - 1, maxL);
1201             AddPoint(m);
1202             md = 0.5 * (iP + iE);
1203             RecBezierTo(md, m, iE, tresh, lev - 1, maxL);
1204         }
1205         return;
1206     }
1208     {
1209         const NR::Point m = 0.25 * (iS + iE + 2 * iP);
1210         NR::Point md = 0.5 * (iS + iP);
1211         RecBezierTo(md, iS, m, tresh, lev - 1, maxL);
1212         AddPoint(m);
1213         md = 0.5 * (iP + iE);
1214         RecBezierTo(md, m, iE, tresh, lev - 1, maxL);
1215     }
1219 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
1220                  double const rx, double const ry, double const angle,
1221                  bool const large, bool const wise, double const /*tresh*/, int const piece)
1223     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1224        apart than the diameter.  Also check that we do the right thing for negative radius.
1225        (Same for the other DoArc functions in this file.) */
1226     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1227         return;
1228         // We always add a lineto afterwards, so this is fine.
1229         // [on ajoute toujours un lineto apres, donc c bon]
1230     }
1232     double sang;
1233     double eang;
1234     NR::Point dr_temp;
1235     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr_temp);
1236     Geom::Point dr = dr_temp;
1237     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1238        the case of low curvature (i.e. very large radius). */
1240     Geom::Scale const ar(rx, ry);
1241     Geom::Rotate cb(angle + sang);
1242     if (wise) {
1244         double const incr = -0.1;
1245         if ( sang < eang ) {
1246             sang += 2*M_PI;
1247         }
1248         Geom::Rotate const omega(incr);
1249         for (double b = sang + incr; b > eang; b += incr) {
1250             cb = omega * cb;
1251             AddPoint(cb.vector() * ar + dr, piece, (sang - b) / (sang - eang));
1252         }
1254     } else {
1256         double const incr = 0.1;
1257         if ( sang > eang ) {
1258             sang -= 2 * M_PI;
1259         }
1260         Geom::Rotate const omega(incr);
1261         for (double b = sang + incr ; b < eang ; b += incr) {
1262             cb = omega * cb;
1263             AddPoint(cb.vector() * ar + dr, piece, (b - sang) / (eang - sang));
1264         }
1265     }
1268 void Path::RecCubicTo(NR::Point const &iS, NR::Point const &isD,
1269                       NR::Point const &iE, NR::Point const &ieD,
1270                       double tresh, int lev, double st, double et, int piece)
1272     const NR::Point se = iE - iS;
1273     const double dC = NR::L2(se);
1274     if ( dC < 0.01 ) {
1275         const double sC = dot(isD, isD);
1276         const double eC = dot(ieD, ieD);
1277         if ( sC < tresh && eC < tresh ) {
1278             return;
1279         }
1280     } else {
1281         const double sC = fabs(cross(se, isD)) / dC;
1282         const double eC = fabs(cross(se, ieD)) / dC;
1283         if ( sC < tresh && eC < tresh ) {
1284             return;
1285         }
1286     }
1288     if ( lev <= 0 ) {
1289         return;
1290     }
1292     NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1293     NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1294     double mt = (st + et) / 2;
1296     NR::Point hisD = 0.5 * isD;
1297     NR::Point hieD = 0.5 * ieD;
1299     RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece);
1300     AddPoint(m, piece, mt);
1301     RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece);
1307 void Path::RecBezierTo(NR::Point const &iP,
1308                        NR::Point const &iS,
1309                        NR::Point const &iE,
1310                        double tresh, int lev, double st, double et, int piece)
1312     if ( lev <= 0 ) {
1313         return;
1314     }
1316     NR::Point ps = iS - iP;
1317     NR::Point pe = iE - iP;
1318     const double s = fabs(cross(pe, ps));
1319     if ( s < tresh ) {
1320         return;
1321     }
1323     {
1324         const double mt = (st + et) / 2;
1325         const NR::Point m = 0.25 * (iS + iE + 2 * iP);
1326         RecBezierTo(0.5 * (iS + iP), iS, m, tresh, lev - 1, st, mt, piece);
1327         AddPoint(m, piece, mt);
1328         RecBezierTo(0.5 * (iP + iE), m, iE, tresh, lev - 1, mt, et, piece);
1329     }
1334 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
1335                  double const rx, double const ry, double const angle,
1336                  bool const large, bool const wise, double const /*tresh*/,
1337                  int const piece, offset_orig &/*orig*/)
1339     // Will never arrive here, as offsets are made of cubics.
1340     // [on n'arrivera jamais ici, puisque les offsets sont fait de cubiques]
1341     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1342        apart than the diameter.  Also check that we do the right thing for negative radius.
1343        (Same for the other DoArc functions in this file.) */
1344     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1345         return;
1346         // We always add a lineto afterwards, so this is fine.
1347         // [on ajoute toujours un lineto apres, donc c bon]
1348     }
1350     double sang;
1351     double eang;
1352     NR::Point dr_temp;
1353     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr_temp);
1354     Geom::Point dr = dr_temp;
1355     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1356        the case of low curvature (i.e. very large radius). */
1358     Geom::Scale const ar(rx, ry);
1359     Geom::Rotate cb(angle + sang);
1360     if (wise) {
1362         double const incr = -0.1;
1363         if ( sang < eang ) {
1364             sang += 2*M_PI;
1365         }
1366         Geom::Rotate const omega(incr);
1367         for (double b = sang + incr; b > eang ;b += incr) {
1368             cb = omega * cb;
1369             AddPoint(cb.vector() * ar + dr, piece, (sang - b) / (sang - eang));
1370         }
1372     } else {
1373         double const incr = 0.1;
1374         if ( sang > eang ) {
1375             sang -= 2*M_PI;
1376         }
1377         Geom::Rotate const omega(incr);
1378         for (double b = sang + incr ; b < eang ; b += incr) {
1379             cb = omega * cb;
1380             AddPoint(cb.vector() * ar + dr, piece, (b - sang) / (eang - sang));
1381         }
1382     }
1386 void Path::RecCubicTo(NR::Point const &iS, NR::Point const &isD,
1387                       NR::Point const &iE, NR::Point const &ieD,
1388                       double tresh, int lev, double st, double et,
1389                       int piece, offset_orig &orig)
1391     const NR::Point se = iE - iS;
1392     const double dC = NR::L2(se);
1393     bool doneSub = false;
1394     if ( dC < 0.01 ) {
1395         const double sC = dot(isD, isD);
1396         const double eC = dot(ieD, ieD);
1397         if ( sC < tresh && eC < tresh ) {
1398             return;
1399         }
1400     } else {
1401         const double sC = fabs(cross(se, isD)) / dC;
1402         const double eC = fabs(cross(se, ieD)) / dC;
1403         if ( sC < tresh && eC < tresh ) {
1404             doneSub = true;
1405         }
1406     }
1408     if ( lev <= 0 ) {
1409         doneSub = true;
1410     }
1412     // test des inversions
1413     bool stInv = false;
1414     bool enInv = false;
1415     {
1416         NR::Point os_pos;
1417         NR::Point os_tgt;
1418         NR::Point oe_pos;
1419         NR::Point oe_tgt;
1421         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
1422         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
1425         NR::Point n_tgt = isD;
1426         double si = dot(n_tgt, os_tgt);
1427         if ( si < 0 ) {
1428             stInv = true;
1429         }
1430         n_tgt = ieD;
1431         si = dot(n_tgt, oe_tgt);
1432         if ( si < 0 ) {
1433             enInv = true;
1434         }
1435         if ( stInv && enInv ) {
1437             AddPoint(os_pos, -1, 0.0);
1438             AddPoint(iE, piece, et);
1439             AddPoint(iS, piece, st);
1440             AddPoint(oe_pos, -1, 0.0);
1441             return;
1443         } else if ( ( stInv && !enInv ) || ( !stInv && enInv ) ) {
1444             return;
1445         }
1447     }
1449     if ( ( !stInv && !enInv && doneSub ) || lev <= 0 ) {
1450         return;
1451     }
1453     {
1454         const NR::Point m = 0.5 * (iS+iE) + 0.125 * (isD - ieD);
1455         const NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1456         const double mt = (st + et) / 2;
1457         const NR::Point hisD = 0.5 * isD;
1458         const NR::Point hieD = 0.5 * ieD;
1460         RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece, orig);
1461         AddPoint(m, piece, mt);
1462         RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece, orig);
1463     }
1468 void Path::RecBezierTo(NR::Point const &iP, NR::Point const &iS,NR::Point const &iE,
1469                        double tresh, int lev, double st, double et,
1470                        int piece, offset_orig& orig)
1472     bool doneSub = false;
1473     if ( lev <= 0 ) {
1474         return;
1475     }
1477     const NR::Point ps = iS - iP;
1478     const NR::Point pe = iE - iP;
1479     const double s = fabs(cross(pe, ps));
1480     if ( s < tresh ) {
1481         doneSub = true ;
1482     }
1484     // test des inversions
1485     bool stInv = false;
1486     bool enInv = false;
1487     {
1488         NR::Point os_pos;
1489         NR::Point os_tgt;
1490         NR::Point oe_pos;
1491         NR::Point oe_tgt;
1492         NR::Point n_tgt;
1493         NR::Point n_pos;
1495         double n_len;
1496         double n_rad;
1497         PathDescrIntermBezierTo mid(iP);
1498         PathDescrBezierTo fin(iE, 1);
1500         TangentOnBezAt(0.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
1501         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
1502         double si = dot(n_tgt, os_tgt);
1503         if ( si < 0 ) {
1504             stInv = true;
1505         }
1507         TangentOnBezAt(1.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
1508         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
1509         si = dot(n_tgt, oe_tgt);
1510         if ( si < 0 ) {
1511             enInv = true;
1512         }
1514         if ( stInv && enInv ) {
1515             AddPoint(os_pos, -1, 0.0);
1516             AddPoint(iE, piece, et);
1517             AddPoint(iS, piece, st);
1518             AddPoint(oe_pos, -1, 0.0);
1519             return;
1520         }
1521     }
1523     if ( !stInv && !enInv && doneSub ) {
1524         return;
1525     }
1527     {
1528         double mt = (st + et) / 2;
1529         NR::Point m = 0.25 * (iS + iE + 2 * iP);
1530         NR::Point md = 0.5 * (iS + iP);
1531         RecBezierTo(md, iS, m, tresh, lev - 1, st, mt, piece, orig);
1532         AddPoint(m, piece, mt);
1533         md = 0.5 * (iP + iE);
1534         RecBezierTo(md, m, iE, tresh, lev - 1, mt, et, piece, orig);
1535     }
1539 /*
1540  * put a polyline in a Shape instance, for further fun
1541  * pathID is the ID you want this Path instance to be associated with, for when you're going to recompose the polyline
1542  * in a path description ( you need to have prepared the back data for that, of course)
1543  */
1545 void Path::Fill(Shape* dest, int pathID, bool justAdd, bool closeIfNeeded, bool invert)
1547     if ( dest == NULL ) {
1548         return;
1549     }
1551     if ( justAdd == false ) {
1552         dest->Reset(pts.size(), pts.size());
1553     }
1555     if ( pts.size() <= 1 ) {
1556         return;
1557     }
1559     int first = dest->numberOfPoints();
1561     if ( back ) {
1562         dest->MakeBackData(true);
1563     }
1565     if ( invert ) {
1566         if ( back ) {
1567             {
1568                 // invert && back && !weighted
1569                 for (int i = 0; i < int(pts.size()); i++) {
1570                     dest->AddPoint(pts[i].p);
1571                 }
1572                 int lastM = 0;
1573                 int curP = 1;
1574                 int pathEnd = 0;
1575                 bool closed = false;
1576                 int lEdge = -1;
1578                 while ( curP < int(pts.size()) ) {
1579                     int sbp = curP;
1580                     int lm = lastM;
1581                     int prp = pathEnd;
1583                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1585                         if ( closeIfNeeded ) {
1586                             if ( closed && lEdge >= 0 ) {
1587                                 dest->DisconnectStart(lEdge);
1588                                 dest->ConnectStart(first + lastM, lEdge);
1589                             } else {
1590                                 lEdge = dest->AddEdge(first + lastM, first+pathEnd);
1591                                 if ( lEdge >= 0 ) {
1592                                     dest->ebData[lEdge].pathID = pathID;
1593                                     dest->ebData[lEdge].pieceID = pts[lm].piece;
1594                                     dest->ebData[lEdge].tSt = 1.0;
1595                                     dest->ebData[lEdge].tEn = 0.0;
1596                                 }
1597                             }
1598                         }
1600                         lastM = curP;
1601                         pathEnd = curP;
1602                         closed = false;
1603                         lEdge = -1;
1605                     } else {
1607                         if ( Geom::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1608                             lEdge = dest->AddEdge(first + curP, first + pathEnd);
1609                             if ( lEdge >= 0 ) {
1610                                 dest->ebData[lEdge].pathID = pathID;
1611                                 dest->ebData[lEdge].pieceID = pts[sbp].piece;
1612                                 if ( pts[sbp].piece == pts[prp].piece ) {
1613                                     dest->ebData[lEdge].tSt = pts[sbp].t;
1614                                     dest->ebData[lEdge].tEn = pts[prp].t;
1615                                 } else {
1616                                     dest->ebData[lEdge].tSt = pts[sbp].t;
1617                                     dest->ebData[lEdge].tEn = 0.0;
1618                                 }
1619                             }
1620                             pathEnd = curP;
1621                             if ( Geom::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1622                                 closed = true;
1623                             } else {
1624                                 closed = false;
1625                             }
1626                         }
1627                     }
1629                     curP++;
1630                 }
1632                 if ( closeIfNeeded ) {
1633                     if ( closed && lEdge >= 0 ) {
1634                         dest->DisconnectStart(lEdge);
1635                         dest->ConnectStart(first + lastM, lEdge);
1636                     } else {
1637                         int lm = lastM;
1638                         lEdge = dest->AddEdge(first + lastM, first + pathEnd);
1639                         if ( lEdge >= 0 ) {
1640                             dest->ebData[lEdge].pathID = pathID;
1641                             dest->ebData[lEdge].pieceID = pts[lm].piece;
1642                             dest->ebData[lEdge].tSt = 1.0;
1643                             dest->ebData[lEdge].tEn = 0.0;
1644                         }
1645                     }
1646                 }
1647             }
1649         } else {
1651             {
1652                 // invert && !back && !weighted
1653                 for (int i = 0; i < int(pts.size()); i++) {
1654                     dest->AddPoint(pts[i].p);
1655                 }
1656                 int lastM = 0;
1657                 int curP = 1;
1658                 int pathEnd = 0;
1659                 bool closed = false;
1660                 int lEdge = -1;
1661                 while ( curP < int(pts.size()) ) {
1662                     int sbp = curP;
1663                     int lm = lastM;
1664                     int prp = pathEnd;
1665                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1666                         if ( closeIfNeeded ) {
1667                             if ( closed && lEdge >= 0 ) {
1668                                 dest->DisconnectStart(lEdge);
1669                                 dest->ConnectStart(first + lastM, lEdge);
1670                             } else {
1671                                 dest->AddEdge(first + lastM, first + pathEnd);
1672                             }
1673                         }
1674                         lastM = curP;
1675                         pathEnd = curP;
1676                         closed = false;
1677                         lEdge = -1;
1678                     } else {
1679                         if ( Geom::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1680                             lEdge = dest->AddEdge(first+curP, first+pathEnd);
1681                             pathEnd = curP;
1682                             if ( Geom::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1683                                 closed = true;
1684                             } else {
1685                                 closed = false;
1686                             }
1687                         }
1688                     }
1689                     curP++;
1690                 }
1692                 if ( closeIfNeeded ) {
1693                     if ( closed && lEdge >= 0 ) {
1694                         dest->DisconnectStart(lEdge);
1695                         dest->ConnectStart(first + lastM, lEdge);
1696                     } else {
1697                         dest->AddEdge(first + lastM, first + pathEnd);
1698                     }
1699                 }
1701             }
1702         }
1704     } else {
1706         if ( back ) {
1707             {
1708                 // !invert && back && !weighted
1709                 for (int i = 0; i < int(pts.size()); i++) {
1710                     dest->AddPoint(pts[i].p);
1711                 }
1713                 int lastM = 0;
1714                 int curP = 1;
1715                 int pathEnd = 0;
1716                 bool closed = false;
1717                 int lEdge = -1;
1718                 while ( curP < int(pts.size()) ) {
1719                     int sbp = curP;
1720                     int lm = lastM;
1721                     int prp = pathEnd;
1722                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1723                         if ( closeIfNeeded ) {
1724                             if ( closed && lEdge >= 0 ) {
1725                                 dest->DisconnectEnd(lEdge);
1726                                 dest->ConnectEnd(first + lastM, lEdge);
1727                             } else {
1728                                 lEdge = dest->AddEdge(first + pathEnd, first+lastM);
1729                                 if ( lEdge >= 0 ) {
1730                                     dest->ebData[lEdge].pathID = pathID;
1731                                     dest->ebData[lEdge].pieceID = pts[lm].piece;
1732                                     dest->ebData[lEdge].tSt = 0.0;
1733                                     dest->ebData[lEdge].tEn = 1.0;
1734                                 }
1735                             }
1736                         }
1737                         lastM = curP;
1738                         pathEnd = curP;
1739                         closed = false;
1740                         lEdge = -1;
1741                     } else {
1742                         if ( Geom::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1743                             lEdge = dest->AddEdge(first + pathEnd, first + curP);
1744                             dest->ebData[lEdge].pathID = pathID;
1745                             dest->ebData[lEdge].pieceID = pts[sbp].piece;
1746                             if ( pts[sbp].piece == pts[prp].piece ) {
1747                                 dest->ebData[lEdge].tSt = pts[prp].t;
1748                                 dest->ebData[lEdge].tEn = pts[sbp].t;
1749                             } else {
1750                                 dest->ebData[lEdge].tSt = 0.0;
1751                                 dest->ebData[lEdge].tEn = pts[sbp].t;
1752                             }
1753                             pathEnd = curP;
1754                             if ( Geom::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1755                                 closed = true;
1756                             } else {
1757                                 closed = false;
1758                             }
1759                         }
1760                     }
1761                     curP++;
1762                 }
1764                 if ( closeIfNeeded ) {
1765                     if ( closed && lEdge >= 0 ) {
1766                         dest->DisconnectEnd(lEdge);
1767                         dest->ConnectEnd(first + lastM, lEdge);
1768                     } else {
1769                         int lm = lastM;
1770                         lEdge = dest->AddEdge(first + pathEnd, first + lastM);
1771                         if ( lEdge >= 0 ) {
1772                             dest->ebData[lEdge].pathID = pathID;
1773                             dest->ebData[lEdge].pieceID = pts[lm].piece;
1774                             dest->ebData[lEdge].tSt = 0.0;
1775                             dest->ebData[lEdge].tEn = 1.0;
1776                         }
1777                     }
1778                 }
1779             }
1781         } else {
1782             {
1783                 // !invert && !back && !weighted
1784                 for (int i = 0;i < int(pts.size()); i++) {
1785                     dest->AddPoint(pts[i].p);
1786                 }
1788                 int lastM = 0;
1789                 int curP = 1;
1790                 int pathEnd = 0;
1791                 bool closed = false;
1792                 int lEdge = -1;
1793                 while ( curP < int(pts.size()) ) {
1794                     int sbp = curP;
1795                     int lm = lastM;
1796                     int prp = pathEnd;
1797                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1798                         if ( closeIfNeeded ) {
1799                             if ( closed && lEdge >= 0 ) {
1800                                 dest->DisconnectEnd(lEdge);
1801                                 dest->ConnectEnd(first + lastM, lEdge);
1802                             } else {
1803                                 dest->AddEdge(first + pathEnd, first + lastM);
1804                             }
1805                         }
1806                         lastM = curP;
1807                         pathEnd = curP;
1808                         closed = false;
1809                         lEdge = -1;
1810                     } else {
1811                         if ( Geom::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1812                             lEdge = dest->AddEdge(first+pathEnd, first+curP);
1813                             pathEnd = curP;
1814                             if ( Geom::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1815                                 closed = true;
1816                             } else {
1817                                 closed = false;
1818                             }
1819                         }
1820                     }
1821                     curP++;
1822                 }
1824                 if ( closeIfNeeded ) {
1825                     if ( closed && lEdge >= 0 ) {
1826                         dest->DisconnectEnd(lEdge);
1827                         dest->ConnectEnd(first + lastM, lEdge);
1828                     } else {
1829                         dest->AddEdge(first + pathEnd, first + lastM);
1830                     }
1831                 }
1833             }
1834         }
1835     }
1838 /*
1839   Local Variables:
1840   mode:c++
1841   c-file-style:"stroustrup"
1842   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1843   indent-tabs-mode:nil
1844   fill-column:99
1845   End:
1846 */
1847 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :