Code

Refactoring SPColor to C++ and removing legacy CMYK implementation
[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 <libnr/nr-rotate-ops.h>
15 #include <libnr/nr-scale-ops.h>
17 /*
18  * path description -> polyline
19  * and Path -> Shape (the Fill() function at the bottom)
20  * nathing fancy here: take each command and append an approximation of it to the polyline
21  */
23 void Path::ConvertWithBackData(double treshhold)
24 {
25     if ( descr_flags & descr_adding_bezier ) {
26         CancelBezier();
27     }
29     if ( descr_flags & descr_doing_subpath ) {
30         CloseSubpath();
31     }
33     SetBackData(true);
34     ResetPoints();
35     if ( descr_cmd.empty() ) {
36         return;
37     }
39     NR::Point curX;
40     int curP = 1;
41     int lastMoveTo = -1;
43     // The initial moveto.
44     {
45         int const firstTyp = descr_cmd[0]->getType();
46         if ( firstTyp == descr_moveto ) {
47             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
48         } else {
49             curP = 0;
50             curX[NR::X] = curX[NR::Y] = 0;
51         }
52         lastMoveTo = AddPoint(curX, 0, 0.0, true);
53     }
55     // And the rest, one by one.
56     while ( curP < int(descr_cmd.size()) ) {
58         int const nType = descr_cmd[curP]->getType();
59         NR::Point nextX;
61         switch (nType) {
62             case descr_forced: {
63                 AddForcedPoint(curX, curP, 1.0);
64                 curP++;
65                 break;
66             }
68             case descr_moveto: {
69                 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo*>(descr_cmd[curP]);
70                 nextX = nData->p;
71                 lastMoveTo = AddPoint(nextX, curP, 0.0, true);
72                 // et on avance
73                 curP++;
74                 break;
75             }
77             case descr_close: {
78                 nextX = pts[lastMoveTo].p;
79                 AddPoint(nextX, curP, 1.0, false);
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                     NR::Point bx = curX;
123                     NR::Point cx = curX;
124                     NR::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                         NR::Point stx;
141                         stx = (bx + cx) / 2;
142                         if ( k > 0 ) {
143                             AddPoint(stx,curP - 1+k,1.0,false);
144                         }
146                         {
147                             NR::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                         NR::Point stx;
160                         stx = (bx + cx) / 2;
162                         if ( nbInterm > 1 ) {
163                             AddPoint(stx, curP + nbInterm - 2, 1.0, false);
164                         }
166                         {
167                             NR::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     NR::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         NR::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                 curP++;
256                 break;
257             }
259             case descr_lineto: {
260                 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
261                 nextX = nData->p;
262                 descr_cmd[curP]->associated = AddPoint(nextX, false);
263                 if ( descr_cmd[curP]->associated < 0 ) {
264                     if ( curP == 0 ) {
265                         descr_cmd[curP]->associated = 0;
266                     } else {
267                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
268                     }
269                 }
270                 // et on avance
271                 curP++;
272                 break;
273             }
275             case descr_cubicto: {
276                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
277                 nextX = nData->p;
278                 RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8);
279                 descr_cmd[curP]->associated = AddPoint(nextX,false);
280                 if ( descr_cmd[curP]->associated < 0 ) {
281                     if ( curP == 0 ) {
282                         descr_cmd[curP]->associated = 0;
283                     } else {
284                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
285                     }
286                 }
287                 // et on avance
288                 curP++;
289                 break;
290             }
292             case descr_arcto: {
293                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
294                 nextX = nData->p;
295                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
296                 descr_cmd[curP]->associated = AddPoint(nextX, false);
297                 if ( descr_cmd[curP]->associated < 0 ) {
298                     if ( curP == 0 ) {
299                         descr_cmd[curP]->associated = 0;
300                     } else {
301                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
302                     }
303                 }
304                 // et on avance
305                 curP++;
306                 break;
307             }
309             case descr_bezierto: {
310                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
311                 int nbInterm = nBData->nb;
312                 nextX = nBData->p;
313                 int curBD = curP;
315                 curP++;
316                 int ip = curP;
317                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
319                 if ( nbInterm == 1 ) {
320                     NR::Point const midX = nData->p;
321                     RecBezierTo(midX, curX, nextX, treshhold, 8);
322                 } else if ( nbInterm > 1 ) {
323                     NR::Point bx = curX;
324                     NR::Point cx = curX;
325                     NR::Point dx = curX;
327                     dx = nData->p;
328                     ip++;
329                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
331                     cx = 2 * bx - dx;
333                     for (int k = 0; k < nbInterm - 1; k++) {
334                         bx = cx;
335                         cx = dx;
337                         dx = nData->p;
338                         ip++;
339                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
341                         NR::Point stx = (bx + cx) / 2;
342                         if ( k > 0 ) {
343                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
344                             if ( descr_cmd[ip - 2]->associated < 0 ) {
345                                 if ( curP == 0 ) {
346                                     descr_cmd[ip - 2]->associated = 0;
347                                 } else {
348                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
349                                 }
350                             }
351                         }
353                         {
354                             NR::Point const mx = (cx + dx) / 2;
355                             RecBezierTo(cx, stx, mx, treshhold, 8);
356                         }
357                     }
359                     {
360                         bx = cx;
361                         cx = dx;
363                         dx = nextX;
364                         dx = 2 * dx - cx;
366                         NR::Point stx = (bx + cx) / 2;
368                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
369                         if ( descr_cmd[ip - 1]->associated < 0 ) {
370                             if ( curP == 0 ) {
371                                 descr_cmd[ip - 1]->associated = 0;
372                             } else {
373                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
374                             }
375                         }
377                         {
378                             NR::Point mx = (cx + dx) / 2;
379                             RecBezierTo(cx, stx, mx, treshhold, 8);
380                         }
381                     }
382                 }
384                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
385                 if ( descr_cmd[curBD]->associated < 0 ) {
386                     if ( curP == 0 ) {
387                         descr_cmd[curBD]->associated = 0;
388                     } else {
389                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
390                     }
391                 }
393                 // et on avance
394                 curP += nbInterm;
395                 break;
396             }
397         }
399         curX = nextX;
400     }
403 #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))))
405 void Path::Convert(NRRectL *area, double treshhold)
407     if ( descr_flags & descr_adding_bezier ) {
408         CancelBezier();
409     }
411     if ( descr_flags & descr_doing_subpath ) {
412         CloseSubpath();
413     }
415     SetBackData(false);
416     ResetPoints();
417     if ( descr_cmd.empty() ) {
418         return;
419     }
421     NR::Point curX;
422     int curP = 1;
423     int lastMoveTo = 0;
424     short last_point_relation = 0;
425     short curent_point_relation = 0;
426     bool last_start_elimination = false;
427     bool start_elimination = false;
428     bool replace = false;
430     // first point
431     {
432         int const firstTyp = descr_cmd[0]->getType();
433         if ( firstTyp == descr_moveto ) {
434             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
435         } else {
436             curP = 0;
437             curX[0] = curX[1] = 0;
438         }
439         
440         last_point_relation = POINT_RELATION_TO_AREA(curX, area);
441         lastMoveTo = AddPoint(curX, true);
442     }
443     descr_cmd[0]->associated = lastMoveTo;
445     // process nodes one by one
446     while ( curP < int(descr_cmd.size()) ) {
448         int const nType = descr_cmd[curP]->getType();
449         NR::Point nextX;
451         switch (nType) {
452             case descr_forced: {
453                 descr_cmd[curP]->associated = AddForcedPoint(curX);
454                 last_point_relation = 0;
455                 curP++;
456                 break;
457             }
459             case descr_moveto: {
460                 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
461                 nextX = nData->p;
462                 lastMoveTo = AddPoint(nextX, true);
463                 descr_cmd[curP]->associated = lastMoveTo;
464                 last_point_relation = POINT_RELATION_TO_AREA(nextX, area);
465                 start_elimination = false;
467                 curP++;
468                 break;
469             }
471             case descr_close: {
472                 nextX = pts[lastMoveTo].p;
473                 descr_cmd[curP]->associated = AddPoint(nextX, false);
474                 if ( descr_cmd[curP]->associated < 0 ) {
475                     if ( curP == 0 ) {
476                         descr_cmd[curP]->associated = 0;
477                     } else {
478                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
479                     }
480                 }
481                 last_point_relation = 0;
482                 curP++;
483                 break;
484             }
486             case descr_lineto: {
487                 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
488                 nextX = nData->p;
489                 curent_point_relation = POINT_RELATION_TO_AREA(nextX, area);
490                 replace = false;
491                 last_start_elimination = start_elimination;
492                 if (curent_point_relation > 0 && curent_point_relation == last_point_relation) {
493                     if (!start_elimination) {
494                         start_elimination = true;
495                     } else {
496                         replace = true;
497                         descr_cmd[curP]->associated = ReplacePoint(nextX);
498                     }
499                 } else {
500                     start_elimination = false;
501                 }
503                 if (!replace) {
504                     descr_cmd[curP]->associated = AddPoint(nextX, false);
505                 }
507                 if ( descr_cmd[curP]->associated < 0 ) {
508                     // point is not added as position is equal to the last added
509                     start_elimination = last_start_elimination;
510                     if ( curP == 0 ) {
511                         descr_cmd[curP]->associated = 0;
512                     } else {
513                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
514                     }
515                 }
516                 last_point_relation = curent_point_relation;
517                 curP++;
518                 break;
519             }
521             case descr_cubicto: {
522                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
523                 nextX = nData->p;
525                 curent_point_relation = POINT_RELATION_TO_AREA(nextX, area);
526                 replace = false;
527                 last_start_elimination = start_elimination;
528                 if (curent_point_relation > 0 && curent_point_relation == last_point_relation &&
529                     curent_point_relation == POINT_RELATION_TO_AREA(curX + (nData->start), area) &&
530                     curent_point_relation == POINT_RELATION_TO_AREA(nextX + (nData->end), area))
531                 {
532                     if (!start_elimination) {
533                         start_elimination = true;
534                     } else {
535                         replace = true;
536                         descr_cmd[curP]->associated = ReplacePoint(nextX);
537                     }
538                 } else {
539                     start_elimination = false;
540                 }
541                 
542                 if (!replace) {
543                     RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8);
544                     descr_cmd[curP]->associated = AddPoint(nextX,false);
545                 }
547                 if ( descr_cmd[curP]->associated < 0 ) {
548                     // point is not added as position is equal to the last added
549                     start_elimination = last_start_elimination;
550                     if ( curP == 0 ) {
551                         descr_cmd[curP]->associated = 0;
552                     } else {
553                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
554                     }
555                 }
556                 last_point_relation = curent_point_relation;
557                 curP++;
558                 break;
559             }
561             case descr_arcto: {
562                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
563                 nextX = nData->p;
564                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
565                 descr_cmd[curP]->associated = AddPoint(nextX, false);
566                 if ( descr_cmd[curP]->associated < 0 ) {
567                     if ( curP == 0 ) {
568                         descr_cmd[curP]->associated = 0;
569                     } else {
570                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
571                     }
572                 }
573                 last_point_relation = 0;
575                 curP++;
576                 break;
577             }
579             case descr_bezierto: {
580                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
581                 int nbInterm = nBData->nb;
582                 nextX = nBData->p;
583                 int curBD = curP;
585                 curP++;
586                 int ip = curP;
587                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
589                 if ( nbInterm == 1 ) {
590                     NR::Point const midX = nData->p;
591                     RecBezierTo(midX, curX, nextX, treshhold, 8);
592                 } else if ( nbInterm > 1 ) {
593                     NR::Point bx = curX;
594                     NR::Point cx = curX;
595                     NR::Point dx = curX;
597                     dx = nData->p;
598                     ip++;
599                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
601                     cx = 2 * bx - dx;
603                     for (int k = 0; k < nbInterm - 1; k++) {
604                         bx = cx;
605                         cx = dx;
607                         dx = nData->p;
608                         ip++;
609                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
611                         NR::Point stx = (bx + cx) / 2;
612                         if ( k > 0 ) {
613                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
614                             if ( descr_cmd[ip - 2]->associated < 0 ) {
615                                 if ( curP == 0 ) {
616                                     descr_cmd[ip - 2]->associated = 0;
617                                 } else {
618                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
619                                 }
620                             }
621                         }
623                         {
624                             NR::Point const mx = (cx + dx) / 2;
625                             RecBezierTo(cx, stx, mx, treshhold, 8);
626                         }
627                     }
629                     {
630                         bx = cx;
631                         cx = dx;
633                         dx = nextX;
634                         dx = 2 * dx - cx;
636                         NR::Point stx = (bx + cx) / 2;
638                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
639                         if ( descr_cmd[ip - 1]->associated < 0 ) {
640                             if ( curP == 0 ) {
641                                 descr_cmd[ip - 1]->associated = 0;
642                             } else {
643                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
644                             }
645                         }
647                         {
648                             NR::Point mx = (cx + dx) / 2;
649                             RecBezierTo(cx, stx, mx, treshhold, 8);
650                         }
651                     }
652                 }
654                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
655                 if ( descr_cmd[curBD]->associated < 0 ) {
656                     if ( curP == 0 ) {
657                         descr_cmd[curBD]->associated = 0;
658                     } else {
659                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
660                     }
661                 }
663                 last_point_relation = 0;
665                 curP += nbInterm;
666                 break;
667             }
668         }
670         curX = nextX;
671     }
675 void Path::ConvertEvenLines(double treshhold)
677     if ( descr_flags & descr_adding_bezier ) {
678         CancelBezier();
679     }
681     if ( descr_flags & descr_doing_subpath ) {
682         CloseSubpath();
683     }
685     SetBackData(false);
686     ResetPoints();
687     if ( descr_cmd.empty() ) {
688         return;
689     }
691     NR::Point curX;
692     int curP = 1;
693     int lastMoveTo = 0;
695     // le moveto
696     {
697         int const firstTyp = descr_cmd[0]->getType();
698         if ( firstTyp == descr_moveto ) {
699             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
700         } else {
701             curP = 0;
702             curX[0] = curX[1] = 0;
703         }
704         lastMoveTo = AddPoint(curX, true);
705     }
706     descr_cmd[0]->associated = lastMoveTo;
708     // et le reste, 1 par 1
709     while ( curP < int(descr_cmd.size()) ) {
711         int const nType = descr_cmd[curP]->getType();
712         NR::Point nextX;
714         switch (nType) {
715             case descr_forced: {
716                 descr_cmd[curP]->associated = AddForcedPoint(curX);
717                 curP++;
718                 break;
719             }
721             case descr_moveto: {
722                 PathDescrMoveTo* nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
723                 nextX = nData->p;
724                 lastMoveTo = AddPoint(nextX,true);
725                 descr_cmd[curP]->associated = lastMoveTo;
727                 // et on avance
728                 curP++;
729                 break;
730             }
732             case descr_close: {
733                 nextX = pts[lastMoveTo].p;
734                 {
735                     NR::Point nexcur;
736                     nexcur = nextX - curX;
737                     const double segL = NR::L2(nexcur);
738                     if ( segL > treshhold ) {
739                         for (double i = treshhold; i < segL; i += treshhold) {
740                             NR::Point nX;
741                             nX = (segL - i) * curX + i * nextX;
742                             nX /= segL;
743                             AddPoint(nX);
744                         }
745                     }
746                 }
748                 descr_cmd[curP]->associated = AddPoint(nextX,false);
749                 if ( descr_cmd[curP]->associated < 0 ) {
750                     if ( curP == 0 ) {
751                         descr_cmd[curP]->associated = 0;
752                     } else {
753                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
754                     }
755                 }
757                 curP++;
758                 break;
759             }
761             case descr_lineto: {
762                 PathDescrLineTo* nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
763                 nextX = nData->p;
764                 NR::Point nexcur = nextX - curX;
765                 const double segL = L2(nexcur);
766                 if ( segL > treshhold ) {
767                     for (double i = treshhold; i < segL; i += treshhold) {
768                         NR::Point nX = ((segL - i) * curX + i * nextX) / segL;
769                         AddPoint(nX);
770                     }
771                 }
773                 descr_cmd[curP]->associated = AddPoint(nextX,false);
774                 if ( descr_cmd[curP]->associated < 0 ) {
775                     if ( curP == 0 ) {
776                         descr_cmd[curP]->associated = 0;
777                     } else {
778                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
779                     }
780                 }
781                 // et on avance
782                 curP++;
783                 break;
784             }
786             case descr_cubicto: {
787                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
788                 nextX = nData->p;
789                 RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8, 4 * treshhold);
790                 descr_cmd[curP]->associated = AddPoint(nextX, false);
791                 if ( descr_cmd[curP]->associated < 0 ) {
792                     if ( curP == 0 ) {
793                         descr_cmd[curP]->associated = 0;
794                     } else {
795                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
796                     }
797                 }
798                 // et on avance
799                 curP++;
800                 break;
801             }
803             case descr_arcto: {
804                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
805                 nextX = nData->p;
806                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
807                 descr_cmd[curP]->associated =AddPoint(nextX, false);
808                 if ( descr_cmd[curP]->associated < 0 ) {
809                     if ( curP == 0 ) {
810                         descr_cmd[curP]->associated = 0;
811                     } else {
812                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
813                     }
814                 }
816                 // et on avance
817                 curP++;
818                 break;
819             }
821             case descr_bezierto: {
822                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
823                 int nbInterm = nBData->nb;
824                 nextX = nBData->p;
825                 int curBD = curP;
827                 curP++;
828                 int ip = curP;
829                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
831                 if ( nbInterm == 1 ) {
832                     NR::Point const midX = nData->p;
833                     RecBezierTo(midX, curX, nextX, treshhold, 8, 4 * treshhold);
834                 } else if ( nbInterm > 1 ) {
835                     NR::Point bx = curX;
836                     NR::Point cx = curX;
837                     NR::Point dx = curX;
839                     dx = nData->p;
840                     ip++;
841                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
843                     cx = 2 * bx - dx;
845                     for (int k = 0; k < nbInterm - 1; k++) {
846                         bx = cx;
847                         cx = dx;
848                         dx = nData->p;
850                         ip++;
851                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
853                         NR::Point stx = (bx+cx) / 2;
854                         if ( k > 0 ) {
855                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
856                             if ( descr_cmd[ip - 2]->associated < 0 ) {
857                                 if ( curP == 0 ) {
858                                     descr_cmd[ip- 2]->associated = 0;
859                                 } else {
860                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
861                                 }
862                             }
863                         }
865                         {
866                             NR::Point const mx = (cx + dx) / 2;
867                             RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
868                         }
869                     }
871                     {
872                         bx = cx;
873                         cx = dx;
875                         dx = nextX;
876                         dx = 2 * dx - cx;
878                         NR::Point const stx = (bx + cx) / 2;
880                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
881                         if ( descr_cmd[ip - 1]->associated < 0 ) {
882                             if ( curP == 0 ) {
883                                 descr_cmd[ip - 1]->associated = 0;
884                             } else {
885                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
886                             }
887                         }
889                         {
890                             NR::Point const mx = (cx + dx) / 2;
891                             RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
892                         }
893                     }
894                 }
896                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
897                 if ( descr_cmd[curBD]->associated < 0 ) {
898                     if ( curP == 0 ) {
899                         descr_cmd[curBD]->associated = 0;
900                     } else {
901                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
902                     }
903                 }
905                 // et on avance
906                 curP += nbInterm;
907                 break;
908             }
909         }
910         if ( NR::LInfty(curX - nextX) > 0.00001 ) {
911             curX = nextX;
912         }
913     }
916 const NR::Point Path::PrevPoint(int i) const
918     /* TODO: I suspect this should assert `(unsigned) i < descr_nb'.  We can probably change
919        the argument to unsigned.  descr_nb should probably be changed to unsigned too. */
920     g_assert( i >= 0 );
921     switch ( descr_cmd[i]->getType() ) {
922         case descr_moveto: {
923             PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
924             return nData->p;
925         }
926         case descr_lineto: {
927             PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
928             return nData->p;
929         }
930         case descr_arcto: {
931             PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
932             return nData->p;
933         }
934         case descr_cubicto: {
935             PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
936             return nData->p;
937         }
938         case descr_bezierto: {
939             PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
940             return nData->p;
941         }
942         case descr_interm_bezier:
943         case descr_close:
944         case descr_forced:
945             return PrevPoint(i - 1);
946         default:
947             g_assert_not_reached();
948             return NR::Point(0, 0);
949     }
952 // utilitaries: given a quadratic bezier curve (start point, control point, end point, ie that's a clamped curve),
953 // and an abcissis on it, get the point with that abcissis.
954 // 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"
955 void Path::QuadraticPoint(double t, NR::Point &oPt,
956                           const NR::Point &iS, const NR::Point &iM, const NR::Point &iE)
958     NR::Point const ax = iE - 2 * iM + iS;
959     NR::Point const bx = 2 * iM - 2 * iS;
960     NR::Point const cx = iS;
962     oPt = t * t * ax + t * bx + cx;
964 // idem for cubic bezier patch
965 void Path::CubicTangent(double t, NR::Point &oPt, const NR::Point &iS, const NR::Point &isD,
966                         const NR::Point &iE, const NR::Point &ieD)
968     NR::Point const ax = ieD - 2 * iE + 2 * iS + isD;
969     NR::Point const bx = 3 * iE - ieD - 2 * isD - 3 * iS;
970     NR::Point const cx = isD;
972     oPt = 3 * t * t * ax + 2 * t * bx + cx;
975 // extract interesting info of a SVG arc description
976 static void ArcAnglesAndCenter(NR::Point const &iS, NR::Point const &iE,
977                                double rx, double ry, double angle,
978                                bool large, bool wise,
979                                double &sang, double &eang, NR::Point &dr);
981 void Path::ArcAngles(const NR::Point &iS, const NR::Point &iE,
982                      double rx, double ry, double angle, bool large, bool wise, double &sang, double &eang)
984     NR::Point dr;
985     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
988 /* N.B. If iS == iE then sang,eang,dr each become NaN.  Probably a bug. */
989 static void ArcAnglesAndCenter(NR::Point const &iS, NR::Point const &iE,
990                                double rx, double ry, double angle,
991                                bool large, bool wise,
992                                double &sang, double &eang, NR::Point &dr)
994     NR::Point se = iE - iS;
995     NR::Point ca(cos(angle), sin(angle));
996     NR::Point cse(dot(se, ca), cross(se, ca));
997     cse[0] /= rx;
998     cse[1] /= ry;
999     double const lensq = dot(cse,cse);
1000     NR::Point csd = ( ( lensq < 4
1001                         ? sqrt( 1/lensq - .25 )
1002                         : 0.0 )
1003                       * cse.ccw() );
1005     NR::Point ra = -csd - 0.5 * cse;
1006     if ( ra[0] <= -1 ) {
1007         sang = M_PI;
1008     } else if ( ra[0] >= 1 ) {
1009         sang = 0;
1010     } else {
1011         sang = acos(ra[0]);
1012         if ( ra[1] < 0 ) {
1013             sang = 2 * M_PI - sang;
1014         }
1015     }
1017     ra = -csd + 0.5 * cse;
1018     if ( ra[0] <= -1 ) {
1019         eang = M_PI;
1020     } else if ( ra[0] >= 1 ) {
1021         eang = 0;
1022     } else {
1023         eang = acos(ra[0]);
1024         if ( ra[1] < 0 ) {
1025             eang = 2 * M_PI - eang;
1026         }
1027     }
1029     csd[0] *= rx;
1030     csd[1] *= ry;
1031     ca[1] = -ca[1]; // because it's the inverse rotation
1033     dr[0] = dot(csd, ca);
1034     dr[1] = cross(csd, ca);
1036     ca[1] = -ca[1];
1038     if ( wise ) {
1040         if (large) {
1041             dr = -dr;
1042             double swap = eang;
1043             eang = sang;
1044             sang = swap;
1045             eang += M_PI;
1046             sang += M_PI;
1047             if ( eang >= 2*M_PI ) {
1048                 eang -= 2*M_PI;
1049             }
1050             if ( sang >= 2*M_PI ) {
1051                 sang -= 2*M_PI;
1052             }
1053         }
1055     } else {
1056         if (!large) {
1057             dr = -dr;
1058             double swap = eang;
1059             eang = sang;
1060             sang = swap;
1061             eang += M_PI;
1062             sang += M_PI;
1063             if ( eang >= 2*M_PI ) {
1064                 eang -= 2 * M_PI;
1065             }
1066             if ( sang >= 2*M_PI ) {
1067                 sang -= 2 * M_PI;
1068             }
1069         }
1070     }
1072     dr += 0.5 * (iS + iE);
1077 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
1078                  double const rx, double const ry, double const angle,
1079                  bool const large, bool const wise, double const /*tresh*/)
1081     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1082        apart than the diameter.  Also check that we do the right thing for negative radius.
1083        (Same for the other DoArc functions in this file.) */
1084     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1085         return;
1086         // We always add a lineto afterwards, so this is fine.
1087         // [on ajoute toujours un lineto apres, donc c bon]
1088     }
1090     double sang;
1091     double eang;
1092     NR::Point dr;
1093     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
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     NR::scale const ar(rx, ry);
1098     NR::rotate cb( angle + sang );
1099     if (wise) {
1101         double const incr = -0.1;
1102         if ( sang < eang ) {
1103             sang += 2*M_PI;
1104         }
1105         NR::rotate const omega(incr);
1106         for (double b = sang + incr ; b > eang ; b += incr) {
1107             cb = omega * cb;
1108             AddPoint( cb.vec * ar + dr );
1109         }
1111     } else {
1113         double const incr = 0.1;
1114         if ( sang > eang ) {
1115             sang -= 2*M_PI;
1116         }
1117         NR::rotate const omega(incr);
1118         for (double b = sang + incr ; b < eang ; b += incr) {
1119             cb = omega * cb;
1120             AddPoint( cb.vec * 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;
1235     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
1236     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1237        the case of low curvature (i.e. very large radius). */
1239     NR::scale const ar(rx, ry);
1240     NR::rotate cb(angle + sang);
1241     if (wise) {
1243         double const incr = -0.1;
1244         if ( sang < eang ) {
1245             sang += 2*M_PI;
1246         }
1247         NR::rotate const omega(incr);
1248         for (double b = sang + incr; b > eang; b += incr) {
1249             cb = omega * cb;
1250             AddPoint(cb.vec * ar + dr, piece, (sang - b) / (sang - eang));
1251         }
1253     } else {
1255         double const incr = 0.1;
1256         if ( sang > eang ) {
1257             sang -= 2 * M_PI;
1258         }
1259         NR::rotate const omega(incr);
1260         for (double b = sang + incr ; b < eang ; b += incr) {
1261             cb = omega * cb;
1262             AddPoint(cb.vec * ar + dr, piece, (b - sang) / (eang - sang));
1263         }
1264     }
1267 void Path::RecCubicTo(NR::Point const &iS, NR::Point const &isD,
1268                       NR::Point const &iE, NR::Point const &ieD,
1269                       double tresh, int lev, double st, double et, int piece)
1271     const NR::Point se = iE - iS;
1272     const double dC = NR::L2(se);
1273     if ( dC < 0.01 ) {
1274         const double sC = dot(isD, isD);
1275         const double eC = dot(ieD, ieD);
1276         if ( sC < tresh && eC < tresh ) {
1277             return;
1278         }
1279     } else {
1280         const double sC = fabs(cross(se, isD)) / dC;
1281         const double eC = fabs(cross(se, ieD)) / dC;
1282         if ( sC < tresh && eC < tresh ) {
1283             return;
1284         }
1285     }
1287     if ( lev <= 0 ) {
1288         return;
1289     }
1291     NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1292     NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1293     double mt = (st + et) / 2;
1295     NR::Point hisD = 0.5 * isD;
1296     NR::Point hieD = 0.5 * ieD;
1298     RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece);
1299     AddPoint(m, piece, mt);
1300     RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece);
1306 void Path::RecBezierTo(NR::Point const &iP,
1307                        NR::Point const &iS,
1308                        NR::Point const &iE,
1309                        double tresh, int lev, double st, double et, int piece)
1311     if ( lev <= 0 ) {
1312         return;
1313     }
1315     NR::Point ps = iS - iP;
1316     NR::Point pe = iE - iP;
1317     const double s = fabs(cross(pe, ps));
1318     if ( s < tresh ) {
1319         return;
1320     }
1322     {
1323         const double mt = (st + et) / 2;
1324         const NR::Point m = 0.25 * (iS + iE + 2 * iP);
1325         RecBezierTo(0.5 * (iS + iP), iS, m, tresh, lev - 1, st, mt, piece);
1326         AddPoint(m, piece, mt);
1327         RecBezierTo(0.5 * (iP + iE), m, iE, tresh, lev - 1, mt, et, piece);
1328     }
1333 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
1334                  double const rx, double const ry, double const angle,
1335                  bool const large, bool const wise, double const /*tresh*/,
1336                  int const piece, offset_orig &/*orig*/)
1338     // Will never arrive here, as offsets are made of cubics.
1339     // [on n'arrivera jamais ici, puisque les offsets sont fait de cubiques]
1340     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1341        apart than the diameter.  Also check that we do the right thing for negative radius.
1342        (Same for the other DoArc functions in this file.) */
1343     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1344         return;
1345         // We always add a lineto afterwards, so this is fine.
1346         // [on ajoute toujours un lineto apres, donc c bon]
1347     }
1349     double sang;
1350     double eang;
1351     NR::Point dr;
1352     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
1353     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1354        the case of low curvature (i.e. very large radius). */
1356     NR::scale const ar(rx, ry);
1357     NR::rotate cb(angle + sang);
1358     if (wise) {
1360         double const incr = -0.1;
1361         if ( sang < eang ) {
1362             sang += 2*M_PI;
1363         }
1364         NR::rotate const omega(incr);
1365         for (double b = sang + incr; b > eang ;b += incr) {
1366             cb = omega * cb;
1367             AddPoint(cb.vec * ar + dr, piece, (sang - b) / (sang - eang));
1368         }
1370     } else {
1371         double const incr = 0.1;
1372         if ( sang > eang ) {
1373             sang -= 2*M_PI;
1374         }
1375         NR::rotate const omega(incr);
1376         for (double b = sang + incr ; b < eang ; b += incr) {
1377             cb = omega * cb;
1378             AddPoint(cb.vec * ar + dr, piece, (b - sang) / (eang - sang));
1379         }
1380     }
1384 void Path::RecCubicTo(NR::Point const &iS, NR::Point const &isD,
1385                       NR::Point const &iE, NR::Point const &ieD,
1386                       double tresh, int lev, double st, double et,
1387                       int piece, offset_orig &orig)
1389     const NR::Point se = iE - iS;
1390     const double dC = NR::L2(se);
1391     bool doneSub = false;
1392     if ( dC < 0.01 ) {
1393         const double sC = dot(isD, isD);
1394         const double eC = dot(ieD, ieD);
1395         if ( sC < tresh && eC < tresh ) {
1396             return;
1397         }
1398     } else {
1399         const double sC = fabs(cross(se, isD)) / dC;
1400         const double eC = fabs(cross(se, ieD)) / dC;
1401         if ( sC < tresh && eC < tresh ) {
1402             doneSub = true;
1403         }
1404     }
1406     if ( lev <= 0 ) {
1407         doneSub = true;
1408     }
1410     // test des inversions
1411     bool stInv = false;
1412     bool enInv = false;
1413     {
1414         NR::Point os_pos;
1415         NR::Point os_tgt;
1416         NR::Point oe_pos;
1417         NR::Point oe_tgt;
1419         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
1420         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
1423         NR::Point n_tgt = isD;
1424         double si = dot(n_tgt, os_tgt);
1425         if ( si < 0 ) {
1426             stInv = true;
1427         }
1428         n_tgt = ieD;
1429         si = dot(n_tgt, oe_tgt);
1430         if ( si < 0 ) {
1431             enInv = true;
1432         }
1433         if ( stInv && enInv ) {
1435             AddPoint(os_pos, -1, 0.0);
1436             AddPoint(iE, piece, et);
1437             AddPoint(iS, piece, st);
1438             AddPoint(oe_pos, -1, 0.0);
1439             return;
1441         } else if ( ( stInv && !enInv ) || ( !stInv && enInv ) ) {
1442             return;
1443         }
1445     }
1447     if ( ( !stInv && !enInv && doneSub ) || lev <= 0 ) {
1448         return;
1449     }
1451     {
1452         const NR::Point m = 0.5 * (iS+iE) + 0.125 * (isD - ieD);
1453         const NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1454         const double mt = (st + et) / 2;
1455         const NR::Point hisD = 0.5 * isD;
1456         const NR::Point hieD = 0.5 * ieD;
1458         RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece, orig);
1459         AddPoint(m, piece, mt);
1460         RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece, orig);
1461     }
1466 void Path::RecBezierTo(NR::Point const &iP, NR::Point const &iS,NR::Point const &iE,
1467                        double tresh, int lev, double st, double et,
1468                        int piece, offset_orig& orig)
1470     bool doneSub = false;
1471     if ( lev <= 0 ) {
1472         return;
1473     }
1475     const NR::Point ps = iS - iP;
1476     const NR::Point pe = iE - iP;
1477     const double s = fabs(cross(pe, ps));
1478     if ( s < tresh ) {
1479         doneSub = true ;
1480     }
1482     // test des inversions
1483     bool stInv = false;
1484     bool enInv = false;
1485     {
1486         NR::Point os_pos;
1487         NR::Point os_tgt;
1488         NR::Point oe_pos;
1489         NR::Point oe_tgt;
1490         NR::Point n_tgt;
1491         NR::Point n_pos;
1493         double n_len;
1494         double n_rad;
1495         PathDescrIntermBezierTo mid(iP);
1496         PathDescrBezierTo fin(iE, 1);
1498         TangentOnBezAt(0.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
1499         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
1500         double si = dot(n_tgt, os_tgt);
1501         if ( si < 0 ) {
1502             stInv = true;
1503         }
1505         TangentOnBezAt(1.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
1506         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
1507         si = dot(n_tgt, oe_tgt);
1508         if ( si < 0 ) {
1509             enInv = true;
1510         }
1512         if ( stInv && enInv ) {
1513             AddPoint(os_pos, -1, 0.0);
1514             AddPoint(iE, piece, et);
1515             AddPoint(iS, piece, st);
1516             AddPoint(oe_pos, -1, 0.0);
1517             return;
1518         }
1519     }
1521     if ( !stInv && !enInv && doneSub ) {
1522         return;
1523     }
1525     {
1526         double mt = (st + et) / 2;
1527         NR::Point m = 0.25 * (iS + iE + 2 * iP);
1528         NR::Point md = 0.5 * (iS + iP);
1529         RecBezierTo(md, iS, m, tresh, lev - 1, st, mt, piece, orig);
1530         AddPoint(m, piece, mt);
1531         md = 0.5 * (iP + iE);
1532         RecBezierTo(md, m, iE, tresh, lev - 1, mt, et, piece, orig);
1533     }
1537 /*
1538  * put a polyline in a Shape instance, for further fun
1539  * pathID is the ID you want this Path instance to be associated with, for when you're going to recompose the polyline
1540  * in a path description ( you need to have prepared the back data for that, of course)
1541  */
1543 void Path::Fill(Shape* dest, int pathID, bool justAdd, bool closeIfNeeded, bool invert)
1545     if ( dest == NULL ) {
1546         return;
1547     }
1549     if ( justAdd == false ) {
1550         dest->Reset(pts.size(), pts.size());
1551     }
1553     if ( pts.size() <= 1 ) {
1554         return;
1555     }
1557     int first = dest->numberOfPoints();
1559     if ( back ) {
1560         dest->MakeBackData(true);
1561     }
1563     if ( invert ) {
1564         if ( back ) {
1565             {
1566                 // invert && back && !weighted
1567                 for (int i = 0; i < int(pts.size()); i++) {
1568                     dest->AddPoint(pts[i].p);
1569                 }
1570                 int lastM = 0;
1571                 int curP = 1;
1572                 int pathEnd = 0;
1573                 bool closed = false;
1574                 int lEdge = -1;
1576                 while ( curP < int(pts.size()) ) {
1577                     int sbp = curP;
1578                     int lm = lastM;
1579                     int prp = pathEnd;
1581                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1583                         if ( closeIfNeeded ) {
1584                             if ( closed && lEdge >= 0 ) {
1585                                 dest->DisconnectStart(lEdge);
1586                                 dest->ConnectStart(first + lastM, lEdge);
1587                             } else {
1588                                 lEdge = dest->AddEdge(first + lastM, first+pathEnd);
1589                                 if ( lEdge >= 0 ) {
1590                                     dest->ebData[lEdge].pathID = pathID;
1591                                     dest->ebData[lEdge].pieceID = pts[lm].piece;
1592                                     dest->ebData[lEdge].tSt = 1.0;
1593                                     dest->ebData[lEdge].tEn = 0.0;
1594                                 }
1595                             }
1596                         }
1598                         lastM = curP;
1599                         pathEnd = curP;
1600                         closed = false;
1601                         lEdge = -1;
1603                     } else {
1605                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1606                             lEdge = dest->AddEdge(first + curP, first + pathEnd);
1607                             if ( lEdge >= 0 ) {
1608                                 dest->ebData[lEdge].pathID = pathID;
1609                                 dest->ebData[lEdge].pieceID = pts[sbp].piece;
1610                                 if ( pts[sbp].piece == pts[prp].piece ) {
1611                                     dest->ebData[lEdge].tSt = pts[sbp].t;
1612                                     dest->ebData[lEdge].tEn = pts[prp].t;
1613                                 } else {
1614                                     dest->ebData[lEdge].tSt = pts[sbp].t;
1615                                     dest->ebData[lEdge].tEn = 0.0;
1616                                 }
1617                             }
1618                             pathEnd = curP;
1619                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1620                                 closed = true;
1621                             } else {
1622                                 closed = false;
1623                             }
1624                         }
1625                     }
1627                     curP++;
1628                 }
1630                 if ( closeIfNeeded ) {
1631                     if ( closed && lEdge >= 0 ) {
1632                         dest->DisconnectStart(lEdge);
1633                         dest->ConnectStart(first + lastM, lEdge);
1634                     } else {
1635                         int lm = lastM;
1636                         lEdge = dest->AddEdge(first + lastM, first + pathEnd);
1637                         if ( lEdge >= 0 ) {
1638                             dest->ebData[lEdge].pathID = pathID;
1639                             dest->ebData[lEdge].pieceID = pts[lm].piece;
1640                             dest->ebData[lEdge].tSt = 1.0;
1641                             dest->ebData[lEdge].tEn = 0.0;
1642                         }
1643                     }
1644                 }
1645             }
1647         } else {
1649             {
1650                 // invert && !back && !weighted
1651                 for (int i = 0; i < int(pts.size()); i++) {
1652                     dest->AddPoint(pts[i].p);
1653                 }
1654                 int lastM = 0;
1655                 int curP = 1;
1656                 int pathEnd = 0;
1657                 bool closed = false;
1658                 int lEdge = -1;
1659                 while ( curP < int(pts.size()) ) {
1660                     int sbp = curP;
1661                     int lm = lastM;
1662                     int prp = pathEnd;
1663                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1664                         if ( closeIfNeeded ) {
1665                             if ( closed && lEdge >= 0 ) {
1666                                 dest->DisconnectStart(lEdge);
1667                                 dest->ConnectStart(first + lastM, lEdge);
1668                             } else {
1669                                 dest->AddEdge(first + lastM, first + pathEnd);
1670                             }
1671                         }
1672                         lastM = curP;
1673                         pathEnd = curP;
1674                         closed = false;
1675                         lEdge = -1;
1676                     } else {
1677                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1678                             lEdge = dest->AddEdge(first+curP, first+pathEnd);
1679                             pathEnd = curP;
1680                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1681                                 closed = true;
1682                             } else {
1683                                 closed = false;
1684                             }
1685                         }
1686                     }
1687                     curP++;
1688                 }
1690                 if ( closeIfNeeded ) {
1691                     if ( closed && lEdge >= 0 ) {
1692                         dest->DisconnectStart(lEdge);
1693                         dest->ConnectStart(first + lastM, lEdge);
1694                     } else {
1695                         dest->AddEdge(first + lastM, first + pathEnd);
1696                     }
1697                 }
1699             }
1700         }
1702     } else {
1704         if ( back ) {
1705             {
1706                 // !invert && back && !weighted
1707                 for (int i = 0; i < int(pts.size()); i++) {
1708                     dest->AddPoint(pts[i].p);
1709                 }
1711                 int lastM = 0;
1712                 int curP = 1;
1713                 int pathEnd = 0;
1714                 bool closed = false;
1715                 int lEdge = -1;
1716                 while ( curP < int(pts.size()) ) {
1717                     int sbp = curP;
1718                     int lm = lastM;
1719                     int prp = pathEnd;
1720                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1721                         if ( closeIfNeeded ) {
1722                             if ( closed && lEdge >= 0 ) {
1723                                 dest->DisconnectEnd(lEdge);
1724                                 dest->ConnectEnd(first + lastM, lEdge);
1725                             } else {
1726                                 lEdge = dest->AddEdge(first + pathEnd, first+lastM);
1727                                 if ( lEdge >= 0 ) {
1728                                     dest->ebData[lEdge].pathID = pathID;
1729                                     dest->ebData[lEdge].pieceID = pts[lm].piece;
1730                                     dest->ebData[lEdge].tSt = 0.0;
1731                                     dest->ebData[lEdge].tEn = 1.0;
1732                                 }
1733                             }
1734                         }
1735                         lastM = curP;
1736                         pathEnd = curP;
1737                         closed = false;
1738                         lEdge = -1;
1739                     } else {
1740                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1741                             lEdge = dest->AddEdge(first + pathEnd, first + curP);
1742                             dest->ebData[lEdge].pathID = pathID;
1743                             dest->ebData[lEdge].pieceID = pts[sbp].piece;
1744                             if ( pts[sbp].piece == pts[prp].piece ) {
1745                                 dest->ebData[lEdge].tSt = pts[prp].t;
1746                                 dest->ebData[lEdge].tEn = pts[sbp].t;
1747                             } else {
1748                                 dest->ebData[lEdge].tSt = 0.0;
1749                                 dest->ebData[lEdge].tEn = pts[sbp].t;
1750                             }
1751                             pathEnd = curP;
1752                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1753                                 closed = true;
1754                             } else {
1755                                 closed = false;
1756                             }
1757                         }
1758                     }
1759                     curP++;
1760                 }
1762                 if ( closeIfNeeded ) {
1763                     if ( closed && lEdge >= 0 ) {
1764                         dest->DisconnectEnd(lEdge);
1765                         dest->ConnectEnd(first + lastM, lEdge);
1766                     } else {
1767                         int lm = lastM;
1768                         lEdge = dest->AddEdge(first + pathEnd, first + lastM);
1769                         if ( lEdge >= 0 ) {
1770                             dest->ebData[lEdge].pathID = pathID;
1771                             dest->ebData[lEdge].pieceID = pts[lm].piece;
1772                             dest->ebData[lEdge].tSt = 0.0;
1773                             dest->ebData[lEdge].tEn = 1.0;
1774                         }
1775                     }
1776                 }
1777             }
1779         } else {
1780             {
1781                 // !invert && !back && !weighted
1782                 for (int i = 0;i < int(pts.size()); i++) {
1783                     dest->AddPoint(pts[i].p);
1784                 }
1786                 int lastM = 0;
1787                 int curP = 1;
1788                 int pathEnd = 0;
1789                 bool closed = false;
1790                 int lEdge = -1;
1791                 while ( curP < int(pts.size()) ) {
1792                     int sbp = curP;
1793                     int lm = lastM;
1794                     int prp = pathEnd;
1795                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1796                         if ( closeIfNeeded ) {
1797                             if ( closed && lEdge >= 0 ) {
1798                                 dest->DisconnectEnd(lEdge);
1799                                 dest->ConnectEnd(first + lastM, lEdge);
1800                             } else {
1801                                 dest->AddEdge(first + pathEnd, first + lastM);
1802                             }
1803                         }
1804                         lastM = curP;
1805                         pathEnd = curP;
1806                         closed = false;
1807                         lEdge = -1;
1808                     } else {
1809                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1810                             lEdge = dest->AddEdge(first+pathEnd, first+curP);
1811                             pathEnd = curP;
1812                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1813                                 closed = true;
1814                             } else {
1815                                 closed = false;
1816                             }
1817                         }
1818                     }
1819                     curP++;
1820                 }
1822                 if ( closeIfNeeded ) {
1823                     if ( closed && lEdge >= 0 ) {
1824                         dest->DisconnectEnd(lEdge);
1825                         dest->ConnectEnd(first + lastM, lEdge);
1826                     } else {
1827                         dest->AddEdge(first + pathEnd, first + lastM);
1828                     }
1829                 }
1831             }
1832         }
1833     }
1836 /*
1837   Local Variables:
1838   mode:c++
1839   c-file-style:"stroustrup"
1840   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1841   indent-tabs-mode:nil
1842   fill-column:99
1843   End:
1844 */
1845 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :