Code

a45e7548adf213af1f5234d38fc6849c3918bab5
[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 start_elimination = false;
427     bool replace = false;
429     // le moveto
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     // et le reste, 1 par 1
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                 if (curent_point_relation > 0 && curent_point_relation == last_point_relation) {
491                     if (!start_elimination) {
492                         start_elimination = true;
493                     } else {
494                         replace = true;
495                         descr_cmd[curP]->associated = ReplacePoint(nextX);
496                     }
497                 } else {
498                     start_elimination = false;
499                 }
501                 if (!replace) {
502                     descr_cmd[curP]->associated = AddPoint(nextX, false);
503                 }
505                 if ( descr_cmd[curP]->associated < 0 ) {
506                     if ( curP == 0 ) {
507                         descr_cmd[curP]->associated = 0;
508                     } else {
509                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
510                     }
511                 }
512                 last_point_relation = curent_point_relation;
513                 curP++;
514                 break;
515             }
517             case descr_cubicto: {
518                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
519                 nextX = nData->p;
521                 curent_point_relation = POINT_RELATION_TO_AREA(nextX, area);
522                 replace = false;
523                 if (curent_point_relation > 0 && curent_point_relation == last_point_relation &&
524                     curent_point_relation == POINT_RELATION_TO_AREA(curX + (nData->start), area) &&
525                     curent_point_relation == POINT_RELATION_TO_AREA(nextX + (nData->end), area))
526                 {
527                     if (!start_elimination) {
528                         start_elimination = true;
529                     } else {
530                         replace = true;
531                         descr_cmd[curP]->associated = ReplacePoint(nextX);
532                     }
533                 } else {
534                     start_elimination = false;
535                 }
536                 
537                 if (!replace) {
538                     RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8);
539                     descr_cmd[curP]->associated = AddPoint(nextX,false);
540                 }
542                 if ( descr_cmd[curP]->associated < 0 ) {
543                     if ( curP == 0 ) {
544                         descr_cmd[curP]->associated = 0;
545                     } else {
546                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
547                     }
548                 }
549                 last_point_relation = curent_point_relation;
550                 curP++;
551                 break;
552             }
554             case descr_arcto: {
555                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
556                 nextX = nData->p;
557                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
558                 descr_cmd[curP]->associated = AddPoint(nextX, false);
559                 if ( descr_cmd[curP]->associated < 0 ) {
560                     if ( curP == 0 ) {
561                         descr_cmd[curP]->associated = 0;
562                     } else {
563                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
564                     }
565                 }
566                 last_point_relation = 0;
568                 curP++;
569                 break;
570             }
572             case descr_bezierto: {
573                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
574                 int nbInterm = nBData->nb;
575                 nextX = nBData->p;
576                 int curBD = curP;
578                 curP++;
579                 int ip = curP;
580                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
582                 if ( nbInterm == 1 ) {
583                     NR::Point const midX = nData->p;
584                     RecBezierTo(midX, curX, nextX, treshhold, 8);
585                 } else if ( nbInterm > 1 ) {
586                     NR::Point bx = curX;
587                     NR::Point cx = curX;
588                     NR::Point dx = curX;
590                     dx = nData->p;
591                     ip++;
592                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
594                     cx = 2 * bx - dx;
596                     for (int k = 0; k < nbInterm - 1; k++) {
597                         bx = cx;
598                         cx = dx;
600                         dx = nData->p;
601                         ip++;
602                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
604                         NR::Point stx = (bx + cx) / 2;
605                         if ( k > 0 ) {
606                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
607                             if ( descr_cmd[ip - 2]->associated < 0 ) {
608                                 if ( curP == 0 ) {
609                                     descr_cmd[ip - 2]->associated = 0;
610                                 } else {
611                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
612                                 }
613                             }
614                         }
616                         {
617                             NR::Point const mx = (cx + dx) / 2;
618                             RecBezierTo(cx, stx, mx, treshhold, 8);
619                         }
620                     }
622                     {
623                         bx = cx;
624                         cx = dx;
626                         dx = nextX;
627                         dx = 2 * dx - cx;
629                         NR::Point stx = (bx + cx) / 2;
631                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
632                         if ( descr_cmd[ip - 1]->associated < 0 ) {
633                             if ( curP == 0 ) {
634                                 descr_cmd[ip - 1]->associated = 0;
635                             } else {
636                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
637                             }
638                         }
640                         {
641                             NR::Point mx = (cx + dx) / 2;
642                             RecBezierTo(cx, stx, mx, treshhold, 8);
643                         }
644                     }
645                 }
647                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
648                 if ( descr_cmd[curBD]->associated < 0 ) {
649                     if ( curP == 0 ) {
650                         descr_cmd[curBD]->associated = 0;
651                     } else {
652                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
653                     }
654                 }
656                 last_point_relation = 0;
658                 curP += nbInterm;
659                 break;
660             }
661         }
663         curX = nextX;
664     }
668 void Path::ConvertEvenLines(double treshhold)
670     if ( descr_flags & descr_adding_bezier ) {
671         CancelBezier();
672     }
674     if ( descr_flags & descr_doing_subpath ) {
675         CloseSubpath();
676     }
678     SetBackData(false);
679     ResetPoints();
680     if ( descr_cmd.empty() ) {
681         return;
682     }
684     NR::Point curX;
685     int curP = 1;
686     int lastMoveTo = 0;
688     // le moveto
689     {
690         int const firstTyp = descr_cmd[0]->getType();
691         if ( firstTyp == descr_moveto ) {
692             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
693         } else {
694             curP = 0;
695             curX[0] = curX[1] = 0;
696         }
697         lastMoveTo = AddPoint(curX, true);
698     }
699     descr_cmd[0]->associated = lastMoveTo;
701     // et le reste, 1 par 1
702     while ( curP < int(descr_cmd.size()) ) {
704         int const nType = descr_cmd[curP]->getType();
705         NR::Point nextX;
707         switch (nType) {
708             case descr_forced: {
709                 descr_cmd[curP]->associated = AddForcedPoint(curX);
710                 curP++;
711                 break;
712             }
714             case descr_moveto: {
715                 PathDescrMoveTo* nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
716                 nextX = nData->p;
717                 lastMoveTo = AddPoint(nextX,true);
718                 descr_cmd[curP]->associated = lastMoveTo;
720                 // et on avance
721                 curP++;
722                 break;
723             }
725             case descr_close: {
726                 nextX = pts[lastMoveTo].p;
727                 {
728                     NR::Point nexcur;
729                     nexcur = nextX - curX;
730                     const double segL = NR::L2(nexcur);
731                     if ( segL > treshhold ) {
732                         for (double i = treshhold; i < segL; i += treshhold) {
733                             NR::Point nX;
734                             nX = (segL - i) * curX + i * nextX;
735                             nX /= segL;
736                             AddPoint(nX);
737                         }
738                     }
739                 }
741                 descr_cmd[curP]->associated = AddPoint(nextX,false);
742                 if ( descr_cmd[curP]->associated < 0 ) {
743                     if ( curP == 0 ) {
744                         descr_cmd[curP]->associated = 0;
745                     } else {
746                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
747                     }
748                 }
750                 curP++;
751                 break;
752             }
754             case descr_lineto: {
755                 PathDescrLineTo* nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
756                 nextX = nData->p;
757                 NR::Point nexcur = nextX - curX;
758                 const double segL = L2(nexcur);
759                 if ( segL > treshhold ) {
760                     for (double i = treshhold; i < segL; i += treshhold) {
761                         NR::Point nX = ((segL - i) * curX + i * nextX) / segL;
762                         AddPoint(nX);
763                     }
764                 }
766                 descr_cmd[curP]->associated = AddPoint(nextX,false);
767                 if ( descr_cmd[curP]->associated < 0 ) {
768                     if ( curP == 0 ) {
769                         descr_cmd[curP]->associated = 0;
770                     } else {
771                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
772                     }
773                 }
774                 // et on avance
775                 curP++;
776                 break;
777             }
779             case descr_cubicto: {
780                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
781                 nextX = nData->p;
782                 RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8, 4 * treshhold);
783                 descr_cmd[curP]->associated = AddPoint(nextX, false);
784                 if ( descr_cmd[curP]->associated < 0 ) {
785                     if ( curP == 0 ) {
786                         descr_cmd[curP]->associated = 0;
787                     } else {
788                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
789                     }
790                 }
791                 // et on avance
792                 curP++;
793                 break;
794             }
796             case descr_arcto: {
797                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
798                 nextX = nData->p;
799                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
800                 descr_cmd[curP]->associated =AddPoint(nextX, false);
801                 if ( descr_cmd[curP]->associated < 0 ) {
802                     if ( curP == 0 ) {
803                         descr_cmd[curP]->associated = 0;
804                     } else {
805                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
806                     }
807                 }
809                 // et on avance
810                 curP++;
811                 break;
812             }
814             case descr_bezierto: {
815                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
816                 int nbInterm = nBData->nb;
817                 nextX = nBData->p;
818                 int curBD = curP;
820                 curP++;
821                 int ip = curP;
822                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
824                 if ( nbInterm == 1 ) {
825                     NR::Point const midX = nData->p;
826                     RecBezierTo(midX, curX, nextX, treshhold, 8, 4 * treshhold);
827                 } else if ( nbInterm > 1 ) {
828                     NR::Point bx = curX;
829                     NR::Point cx = curX;
830                     NR::Point dx = curX;
832                     dx = nData->p;
833                     ip++;
834                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
836                     cx = 2 * bx - dx;
838                     for (int k = 0; k < nbInterm - 1; k++) {
839                         bx = cx;
840                         cx = dx;
841                         dx = nData->p;
843                         ip++;
844                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
846                         NR::Point stx = (bx+cx) / 2;
847                         if ( k > 0 ) {
848                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
849                             if ( descr_cmd[ip - 2]->associated < 0 ) {
850                                 if ( curP == 0 ) {
851                                     descr_cmd[ip- 2]->associated = 0;
852                                 } else {
853                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
854                                 }
855                             }
856                         }
858                         {
859                             NR::Point const mx = (cx + dx) / 2;
860                             RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
861                         }
862                     }
864                     {
865                         bx = cx;
866                         cx = dx;
868                         dx = nextX;
869                         dx = 2 * dx - cx;
871                         NR::Point const stx = (bx + cx) / 2;
873                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
874                         if ( descr_cmd[ip - 1]->associated < 0 ) {
875                             if ( curP == 0 ) {
876                                 descr_cmd[ip - 1]->associated = 0;
877                             } else {
878                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
879                             }
880                         }
882                         {
883                             NR::Point const mx = (cx + dx) / 2;
884                             RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
885                         }
886                     }
887                 }
889                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
890                 if ( descr_cmd[curBD]->associated < 0 ) {
891                     if ( curP == 0 ) {
892                         descr_cmd[curBD]->associated = 0;
893                     } else {
894                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
895                     }
896                 }
898                 // et on avance
899                 curP += nbInterm;
900                 break;
901             }
902         }
903         if ( NR::LInfty(curX - nextX) > 0.00001 ) {
904             curX = nextX;
905         }
906     }
909 const NR::Point Path::PrevPoint(int i) const
911     /* TODO: I suspect this should assert `(unsigned) i < descr_nb'.  We can probably change
912        the argument to unsigned.  descr_nb should probably be changed to unsigned too. */
913     g_assert( i >= 0 );
914     switch ( descr_cmd[i]->getType() ) {
915         case descr_moveto: {
916             PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
917             return nData->p;
918         }
919         case descr_lineto: {
920             PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
921             return nData->p;
922         }
923         case descr_arcto: {
924             PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
925             return nData->p;
926         }
927         case descr_cubicto: {
928             PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
929             return nData->p;
930         }
931         case descr_bezierto: {
932             PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
933             return nData->p;
934         }
935         case descr_interm_bezier:
936         case descr_close:
937         case descr_forced:
938             return PrevPoint(i - 1);
939         default:
940             g_assert_not_reached();
941             return NR::Point(0, 0);
942     }
945 // utilitaries: given a quadratic bezier curve (start point, control point, end point, ie that's a clamped curve),
946 // and an abcissis on it, get the point with that abcissis.
947 // 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"
948 void Path::QuadraticPoint(double t, NR::Point &oPt,
949                           const NR::Point &iS, const NR::Point &iM, const NR::Point &iE)
951     NR::Point const ax = iE - 2 * iM + iS;
952     NR::Point const bx = 2 * iM - 2 * iS;
953     NR::Point const cx = iS;
955     oPt = t * t * ax + t * bx + cx;
957 // idem for cubic bezier patch
958 void Path::CubicTangent(double t, NR::Point &oPt, const NR::Point &iS, const NR::Point &isD,
959                         const NR::Point &iE, const NR::Point &ieD)
961     NR::Point const ax = ieD - 2 * iE + 2 * iS + isD;
962     NR::Point const bx = 3 * iE - ieD - 2 * isD - 3 * iS;
963     NR::Point const cx = isD;
965     oPt = 3 * t * t * ax + 2 * t * bx + cx;
968 // extract interesting info of a SVG arc description
969 static void ArcAnglesAndCenter(NR::Point const &iS, NR::Point const &iE,
970                                double rx, double ry, double angle,
971                                bool large, bool wise,
972                                double &sang, double &eang, NR::Point &dr);
974 void Path::ArcAngles(const NR::Point &iS, const NR::Point &iE,
975                      double rx, double ry, double angle, bool large, bool wise, double &sang, double &eang)
977     NR::Point dr;
978     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
981 /* N.B. If iS == iE then sang,eang,dr each become NaN.  Probably a bug. */
982 static void ArcAnglesAndCenter(NR::Point const &iS, NR::Point const &iE,
983                                double rx, double ry, double angle,
984                                bool large, bool wise,
985                                double &sang, double &eang, NR::Point &dr)
987     NR::Point se = iE - iS;
988     NR::Point ca(cos(angle), sin(angle));
989     NR::Point cse(dot(se, ca), cross(se, ca));
990     cse[0] /= rx;
991     cse[1] /= ry;
992     double const lensq = dot(cse,cse);
993     NR::Point csd = ( ( lensq < 4
994                         ? sqrt( 1/lensq - .25 )
995                         : 0.0 )
996                       * cse.ccw() );
998     NR::Point ra = -csd - 0.5 * cse;
999     if ( ra[0] <= -1 ) {
1000         sang = M_PI;
1001     } else if ( ra[0] >= 1 ) {
1002         sang = 0;
1003     } else {
1004         sang = acos(ra[0]);
1005         if ( ra[1] < 0 ) {
1006             sang = 2 * M_PI - sang;
1007         }
1008     }
1010     ra = -csd + 0.5 * cse;
1011     if ( ra[0] <= -1 ) {
1012         eang = M_PI;
1013     } else if ( ra[0] >= 1 ) {
1014         eang = 0;
1015     } else {
1016         eang = acos(ra[0]);
1017         if ( ra[1] < 0 ) {
1018             eang = 2 * M_PI - eang;
1019         }
1020     }
1022     csd[0] *= rx;
1023     csd[1] *= ry;
1024     ca[1] = -ca[1]; // because it's the inverse rotation
1026     dr[0] = dot(csd, ca);
1027     dr[1] = cross(csd, ca);
1029     ca[1] = -ca[1];
1031     if ( wise ) {
1033         if (large) {
1034             dr = -dr;
1035             double swap = eang;
1036             eang = sang;
1037             sang = swap;
1038             eang += M_PI;
1039             sang += M_PI;
1040             if ( eang >= 2*M_PI ) {
1041                 eang -= 2*M_PI;
1042             }
1043             if ( sang >= 2*M_PI ) {
1044                 sang -= 2*M_PI;
1045             }
1046         }
1048     } else {
1049         if (!large) {
1050             dr = -dr;
1051             double swap = eang;
1052             eang = sang;
1053             sang = swap;
1054             eang += M_PI;
1055             sang += M_PI;
1056             if ( eang >= 2*M_PI ) {
1057                 eang -= 2 * M_PI;
1058             }
1059             if ( sang >= 2*M_PI ) {
1060                 sang -= 2 * M_PI;
1061             }
1062         }
1063     }
1065     dr += 0.5 * (iS + iE);
1070 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
1071                  double const rx, double const ry, double const angle,
1072                  bool const large, bool const wise, double const /*tresh*/)
1074     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1075        apart than the diameter.  Also check that we do the right thing for negative radius.
1076        (Same for the other DoArc functions in this file.) */
1077     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1078         return;
1079         // We always add a lineto afterwards, so this is fine.
1080         // [on ajoute toujours un lineto apres, donc c bon]
1081     }
1083     double sang;
1084     double eang;
1085     NR::Point dr;
1086     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
1087     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1088        the case of low curvature (i.e. very large radius). */
1090     NR::scale const ar(rx, ry);
1091     NR::rotate cb( angle + sang );
1092     if (wise) {
1094         double const incr = -0.1;
1095         if ( sang < eang ) {
1096             sang += 2*M_PI;
1097         }
1098         NR::rotate const omega(incr);
1099         for (double b = sang + incr ; b > eang ; b += incr) {
1100             cb = omega * cb;
1101             AddPoint( cb.vec * ar + dr );
1102         }
1104     } else {
1106         double const incr = 0.1;
1107         if ( sang > eang ) {
1108             sang -= 2*M_PI;
1109         }
1110         NR::rotate const omega(incr);
1111         for (double b = sang + incr ; b < eang ; b += incr) {
1112             cb = omega * cb;
1113             AddPoint( cb.vec * ar + dr);
1114         }
1115     }
1119 void Path::RecCubicTo( NR::Point const &iS, NR::Point const &isD,
1120                        NR::Point const &iE, NR::Point const &ieD,
1121                        double tresh, int lev, double maxL)
1123     NR::Point se = iE - iS;
1124     const double dC = NR::L2(se);
1125     if ( dC < 0.01 ) {
1127         const double sC = dot(isD,isD);
1128         const double eC = dot(ieD,ieD);
1129         if ( sC < tresh && eC < tresh ) {
1130             return;
1131         }
1133     } else {
1134         const double sC = fabs(cross(se, isD)) / dC;
1135         const double eC = fabs(cross(se, ieD)) / dC;
1136         if ( sC < tresh && eC < tresh ) {
1137             // presque tt droit -> attention si on nous demande de bien subdiviser les petits segments
1138             if ( maxL > 0 && dC > maxL ) {
1139                 if ( lev <= 0 ) {
1140                     return;
1141                 }
1142                 NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1143                 NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1145                 NR::Point hisD = 0.5 * isD;
1146                 NR::Point hieD = 0.5 * ieD;
1148                 RecCubicTo(iS, hisD, m, md, tresh, lev - 1, maxL);
1149                 AddPoint(m);
1150                 RecCubicTo(m, md, iE, hieD, tresh, lev - 1,maxL);
1151             }
1152             return;
1153         }
1154     }
1156     if ( lev <= 0 ) {
1157         return;
1158     }
1160     {
1161         NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1162         NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1164         NR::Point hisD = 0.5 * isD;
1165         NR::Point hieD = 0.5 * ieD;
1167         RecCubicTo(iS, hisD, m, md, tresh, lev - 1, maxL);
1168         AddPoint(m);
1169         RecCubicTo(m, md, iE, hieD, tresh, lev - 1,maxL);
1170     }
1175 void Path::RecBezierTo(const NR::Point &iP,
1176                        const NR::Point &iS,
1177                        const NR::Point &iE,
1178                        double tresh, int lev, double maxL)
1180     if ( lev <= 0 ) {
1181         return;
1182     }
1184     NR::Point ps = iS - iP;
1185     NR::Point pe = iE - iP;
1186     NR::Point se = iE - iS;
1187     double s = fabs(cross(pe, ps));
1188     if ( s < tresh ) {
1189         const double l = L2(se);
1190         if ( maxL > 0 && l > maxL ) {
1191             const NR::Point m = 0.25 * (iS + iE + 2 * iP);
1192             NR::Point md = 0.5 * (iS + iP);
1193             RecBezierTo(md, iS, m, tresh, lev - 1, maxL);
1194             AddPoint(m);
1195             md = 0.5 * (iP + iE);
1196             RecBezierTo(md, m, iE, tresh, lev - 1, maxL);
1197         }
1198         return;
1199     }
1201     {
1202         const NR::Point m = 0.25 * (iS + iE + 2 * iP);
1203         NR::Point md = 0.5 * (iS + iP);
1204         RecBezierTo(md, iS, m, tresh, lev - 1, maxL);
1205         AddPoint(m);
1206         md = 0.5 * (iP + iE);
1207         RecBezierTo(md, m, iE, tresh, lev - 1, maxL);
1208     }
1212 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
1213                  double const rx, double const ry, double const angle,
1214                  bool const large, bool const wise, double const /*tresh*/, int const piece)
1216     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1217        apart than the diameter.  Also check that we do the right thing for negative radius.
1218        (Same for the other DoArc functions in this file.) */
1219     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1220         return;
1221         // We always add a lineto afterwards, so this is fine.
1222         // [on ajoute toujours un lineto apres, donc c bon]
1223     }
1225     double sang;
1226     double eang;
1227     NR::Point dr;
1228     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
1229     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1230        the case of low curvature (i.e. very large radius). */
1232     NR::scale const ar(rx, ry);
1233     NR::rotate cb(angle + sang);
1234     if (wise) {
1236         double const incr = -0.1;
1237         if ( sang < eang ) {
1238             sang += 2*M_PI;
1239         }
1240         NR::rotate const omega(incr);
1241         for (double b = sang + incr; b > eang; b += incr) {
1242             cb = omega * cb;
1243             AddPoint(cb.vec * ar + dr, piece, (sang - b) / (sang - eang));
1244         }
1246     } else {
1248         double const incr = 0.1;
1249         if ( sang > eang ) {
1250             sang -= 2 * M_PI;
1251         }
1252         NR::rotate const omega(incr);
1253         for (double b = sang + incr ; b < eang ; b += incr) {
1254             cb = omega * cb;
1255             AddPoint(cb.vec * ar + dr, piece, (b - sang) / (eang - sang));
1256         }
1257     }
1260 void Path::RecCubicTo(NR::Point const &iS, NR::Point const &isD,
1261                       NR::Point const &iE, NR::Point const &ieD,
1262                       double tresh, int lev, double st, double et, int piece)
1264     const NR::Point se = iE - iS;
1265     const double dC = NR::L2(se);
1266     if ( dC < 0.01 ) {
1267         const double sC = dot(isD, isD);
1268         const double eC = dot(ieD, ieD);
1269         if ( sC < tresh && eC < tresh ) {
1270             return;
1271         }
1272     } else {
1273         const double sC = fabs(cross(se, isD)) / dC;
1274         const double eC = fabs(cross(se, ieD)) / dC;
1275         if ( sC < tresh && eC < tresh ) {
1276             return;
1277         }
1278     }
1280     if ( lev <= 0 ) {
1281         return;
1282     }
1284     NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1285     NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1286     double mt = (st + et) / 2;
1288     NR::Point hisD = 0.5 * isD;
1289     NR::Point hieD = 0.5 * ieD;
1291     RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece);
1292     AddPoint(m, piece, mt);
1293     RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece);
1299 void Path::RecBezierTo(NR::Point const &iP,
1300                        NR::Point const &iS,
1301                        NR::Point const &iE,
1302                        double tresh, int lev, double st, double et, int piece)
1304     if ( lev <= 0 ) {
1305         return;
1306     }
1308     NR::Point ps = iS - iP;
1309     NR::Point pe = iE - iP;
1310     const double s = fabs(cross(pe, ps));
1311     if ( s < tresh ) {
1312         return;
1313     }
1315     {
1316         const double mt = (st + et) / 2;
1317         const NR::Point m = 0.25 * (iS + iE + 2 * iP);
1318         RecBezierTo(0.5 * (iS + iP), iS, m, tresh, lev - 1, st, mt, piece);
1319         AddPoint(m, piece, mt);
1320         RecBezierTo(0.5 * (iP + iE), m, iE, tresh, lev - 1, mt, et, piece);
1321     }
1326 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
1327                  double const rx, double const ry, double const angle,
1328                  bool const large, bool const wise, double const /*tresh*/,
1329                  int const piece, offset_orig &/*orig*/)
1331     // Will never arrive here, as offsets are made of cubics.
1332     // [on n'arrivera jamais ici, puisque les offsets sont fait de cubiques]
1333     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1334        apart than the diameter.  Also check that we do the right thing for negative radius.
1335        (Same for the other DoArc functions in this file.) */
1336     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1337         return;
1338         // We always add a lineto afterwards, so this is fine.
1339         // [on ajoute toujours un lineto apres, donc c bon]
1340     }
1342     double sang;
1343     double eang;
1344     NR::Point dr;
1345     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
1346     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1347        the case of low curvature (i.e. very large radius). */
1349     NR::scale const ar(rx, ry);
1350     NR::rotate cb(angle + sang);
1351     if (wise) {
1353         double const incr = -0.1;
1354         if ( sang < eang ) {
1355             sang += 2*M_PI;
1356         }
1357         NR::rotate const omega(incr);
1358         for (double b = sang + incr; b > eang ;b += incr) {
1359             cb = omega * cb;
1360             AddPoint(cb.vec * ar + dr, piece, (sang - b) / (sang - eang));
1361         }
1363     } else {
1364         double const incr = 0.1;
1365         if ( sang > eang ) {
1366             sang -= 2*M_PI;
1367         }
1368         NR::rotate const omega(incr);
1369         for (double b = sang + incr ; b < eang ; b += incr) {
1370             cb = omega * cb;
1371             AddPoint(cb.vec * ar + dr, piece, (b - sang) / (eang - sang));
1372         }
1373     }
1377 void Path::RecCubicTo(NR::Point const &iS, NR::Point const &isD,
1378                       NR::Point const &iE, NR::Point const &ieD,
1379                       double tresh, int lev, double st, double et,
1380                       int piece, offset_orig &orig)
1382     const NR::Point se = iE - iS;
1383     const double dC = NR::L2(se);
1384     bool doneSub = false;
1385     if ( dC < 0.01 ) {
1386         const double sC = dot(isD, isD);
1387         const double eC = dot(ieD, ieD);
1388         if ( sC < tresh && eC < tresh ) {
1389             return;
1390         }
1391     } else {
1392         const double sC = fabs(cross(se, isD)) / dC;
1393         const double eC = fabs(cross(se, ieD)) / dC;
1394         if ( sC < tresh && eC < tresh ) {
1395             doneSub = true;
1396         }
1397     }
1399     if ( lev <= 0 ) {
1400         doneSub = true;
1401     }
1403     // test des inversions
1404     bool stInv = false;
1405     bool enInv = false;
1406     {
1407         NR::Point os_pos;
1408         NR::Point os_tgt;
1409         NR::Point oe_pos;
1410         NR::Point oe_tgt;
1412         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
1413         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
1416         NR::Point n_tgt = isD;
1417         double si = dot(n_tgt, os_tgt);
1418         if ( si < 0 ) {
1419             stInv = true;
1420         }
1421         n_tgt = ieD;
1422         si = dot(n_tgt, oe_tgt);
1423         if ( si < 0 ) {
1424             enInv = true;
1425         }
1426         if ( stInv && enInv ) {
1428             AddPoint(os_pos, -1, 0.0);
1429             AddPoint(iE, piece, et);
1430             AddPoint(iS, piece, st);
1431             AddPoint(oe_pos, -1, 0.0);
1432             return;
1434         } else if ( ( stInv && !enInv ) || ( !stInv && enInv ) ) {
1435             return;
1436         }
1438     }
1440     if ( ( !stInv && !enInv && doneSub ) || lev <= 0 ) {
1441         return;
1442     }
1444     {
1445         const NR::Point m = 0.5 * (iS+iE) + 0.125 * (isD - ieD);
1446         const NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1447         const double mt = (st + et) / 2;
1448         const NR::Point hisD = 0.5 * isD;
1449         const NR::Point hieD = 0.5 * ieD;
1451         RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece, orig);
1452         AddPoint(m, piece, mt);
1453         RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece, orig);
1454     }
1459 void Path::RecBezierTo(NR::Point const &iP, NR::Point const &iS,NR::Point const &iE,
1460                        double tresh, int lev, double st, double et,
1461                        int piece, offset_orig& orig)
1463     bool doneSub = false;
1464     if ( lev <= 0 ) {
1465         return;
1466     }
1468     const NR::Point ps = iS - iP;
1469     const NR::Point pe = iE - iP;
1470     const double s = fabs(cross(pe, ps));
1471     if ( s < tresh ) {
1472         doneSub = true ;
1473     }
1475     // test des inversions
1476     bool stInv = false;
1477     bool enInv = false;
1478     {
1479         NR::Point os_pos;
1480         NR::Point os_tgt;
1481         NR::Point oe_pos;
1482         NR::Point oe_tgt;
1483         NR::Point n_tgt;
1484         NR::Point n_pos;
1486         double n_len;
1487         double n_rad;
1488         PathDescrIntermBezierTo mid(iP);
1489         PathDescrBezierTo fin(iE, 1);
1491         TangentOnBezAt(0.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
1492         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
1493         double si = dot(n_tgt, os_tgt);
1494         if ( si < 0 ) {
1495             stInv = true;
1496         }
1498         TangentOnBezAt(1.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
1499         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
1500         si = dot(n_tgt, oe_tgt);
1501         if ( si < 0 ) {
1502             enInv = true;
1503         }
1505         if ( stInv && enInv ) {
1506             AddPoint(os_pos, -1, 0.0);
1507             AddPoint(iE, piece, et);
1508             AddPoint(iS, piece, st);
1509             AddPoint(oe_pos, -1, 0.0);
1510             return;
1511         }
1512     }
1514     if ( !stInv && !enInv && doneSub ) {
1515         return;
1516     }
1518     {
1519         double mt = (st + et) / 2;
1520         NR::Point m = 0.25 * (iS + iE + 2 * iP);
1521         NR::Point md = 0.5 * (iS + iP);
1522         RecBezierTo(md, iS, m, tresh, lev - 1, st, mt, piece, orig);
1523         AddPoint(m, piece, mt);
1524         md = 0.5 * (iP + iE);
1525         RecBezierTo(md, m, iE, tresh, lev - 1, mt, et, piece, orig);
1526     }
1530 /*
1531  * put a polyline in a Shape instance, for further fun
1532  * pathID is the ID you want this Path instance to be associated with, for when you're going to recompose the polyline
1533  * in a path description ( you need to have prepared the back data for that, of course)
1534  */
1536 void Path::Fill(Shape* dest, int pathID, bool justAdd, bool closeIfNeeded, bool invert)
1538     if ( dest == NULL ) {
1539         return;
1540     }
1542     if ( justAdd == false ) {
1543         dest->Reset(pts.size(), pts.size());
1544     }
1546     if ( pts.size() <= 1 ) {
1547         return;
1548     }
1550     int first = dest->numberOfPoints();
1552     if ( back ) {
1553         dest->MakeBackData(true);
1554     }
1556     if ( invert ) {
1557         if ( back ) {
1558             {
1559                 // invert && back && !weighted
1560                 for (int i = 0; i < int(pts.size()); i++) {
1561                     dest->AddPoint(pts[i].p);
1562                 }
1563                 int lastM = 0;
1564                 int curP = 1;
1565                 int pathEnd = 0;
1566                 bool closed = false;
1567                 int lEdge = -1;
1569                 while ( curP < int(pts.size()) ) {
1570                     int sbp = curP;
1571                     int lm = lastM;
1572                     int prp = pathEnd;
1574                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1576                         if ( closeIfNeeded ) {
1577                             if ( closed && lEdge >= 0 ) {
1578                                 dest->DisconnectStart(lEdge);
1579                                 dest->ConnectStart(first + lastM, lEdge);
1580                             } else {
1581                                 lEdge = dest->AddEdge(first + lastM, first+pathEnd);
1582                                 if ( lEdge >= 0 ) {
1583                                     dest->ebData[lEdge].pathID = pathID;
1584                                     dest->ebData[lEdge].pieceID = pts[lm].piece;
1585                                     dest->ebData[lEdge].tSt = 1.0;
1586                                     dest->ebData[lEdge].tEn = 0.0;
1587                                 }
1588                             }
1589                         }
1591                         lastM = curP;
1592                         pathEnd = curP;
1593                         closed = false;
1594                         lEdge = -1;
1596                     } else {
1598                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1599                             lEdge = dest->AddEdge(first + curP, first + pathEnd);
1600                             if ( lEdge >= 0 ) {
1601                                 dest->ebData[lEdge].pathID = pathID;
1602                                 dest->ebData[lEdge].pieceID = pts[sbp].piece;
1603                                 if ( pts[sbp].piece == pts[prp].piece ) {
1604                                     dest->ebData[lEdge].tSt = pts[sbp].t;
1605                                     dest->ebData[lEdge].tEn = pts[prp].t;
1606                                 } else {
1607                                     dest->ebData[lEdge].tSt = pts[sbp].t;
1608                                     dest->ebData[lEdge].tEn = 0.0;
1609                                 }
1610                             }
1611                             pathEnd = curP;
1612                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1613                                 closed = true;
1614                             } else {
1615                                 closed = false;
1616                             }
1617                         }
1618                     }
1620                     curP++;
1621                 }
1623                 if ( closeIfNeeded ) {
1624                     if ( closed && lEdge >= 0 ) {
1625                         dest->DisconnectStart(lEdge);
1626                         dest->ConnectStart(first + lastM, lEdge);
1627                     } else {
1628                         int lm = lastM;
1629                         lEdge = dest->AddEdge(first + lastM, first + pathEnd);
1630                         if ( lEdge >= 0 ) {
1631                             dest->ebData[lEdge].pathID = pathID;
1632                             dest->ebData[lEdge].pieceID = pts[lm].piece;
1633                             dest->ebData[lEdge].tSt = 1.0;
1634                             dest->ebData[lEdge].tEn = 0.0;
1635                         }
1636                     }
1637                 }
1638             }
1640         } else {
1642             {
1643                 // invert && !back && !weighted
1644                 for (int i = 0; i < int(pts.size()); i++) {
1645                     dest->AddPoint(pts[i].p);
1646                 }
1647                 int lastM = 0;
1648                 int curP = 1;
1649                 int pathEnd = 0;
1650                 bool closed = false;
1651                 int lEdge = -1;
1652                 while ( curP < int(pts.size()) ) {
1653                     int sbp = curP;
1654                     int lm = lastM;
1655                     int prp = pathEnd;
1656                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1657                         if ( closeIfNeeded ) {
1658                             if ( closed && lEdge >= 0 ) {
1659                                 dest->DisconnectStart(lEdge);
1660                                 dest->ConnectStart(first + lastM, lEdge);
1661                             } else {
1662                                 dest->AddEdge(first + lastM, first + pathEnd);
1663                             }
1664                         }
1665                         lastM = curP;
1666                         pathEnd = curP;
1667                         closed = false;
1668                         lEdge = -1;
1669                     } else {
1670                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1671                             lEdge = dest->AddEdge(first+curP, first+pathEnd);
1672                             pathEnd = curP;
1673                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1674                                 closed = true;
1675                             } else {
1676                                 closed = false;
1677                             }
1678                         }
1679                     }
1680                     curP++;
1681                 }
1683                 if ( closeIfNeeded ) {
1684                     if ( closed && lEdge >= 0 ) {
1685                         dest->DisconnectStart(lEdge);
1686                         dest->ConnectStart(first + lastM, lEdge);
1687                     } else {
1688                         dest->AddEdge(first + lastM, first + pathEnd);
1689                     }
1690                 }
1692             }
1693         }
1695     } else {
1697         if ( back ) {
1698             {
1699                 // !invert && back && !weighted
1700                 for (int i = 0; i < int(pts.size()); i++) {
1701                     dest->AddPoint(pts[i].p);
1702                 }
1704                 int lastM = 0;
1705                 int curP = 1;
1706                 int pathEnd = 0;
1707                 bool closed = false;
1708                 int lEdge = -1;
1709                 while ( curP < int(pts.size()) ) {
1710                     int sbp = curP;
1711                     int lm = lastM;
1712                     int prp = pathEnd;
1713                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1714                         if ( closeIfNeeded ) {
1715                             if ( closed && lEdge >= 0 ) {
1716                                 dest->DisconnectEnd(lEdge);
1717                                 dest->ConnectEnd(first + lastM, lEdge);
1718                             } else {
1719                                 lEdge = dest->AddEdge(first + pathEnd, first+lastM);
1720                                 if ( lEdge >= 0 ) {
1721                                     dest->ebData[lEdge].pathID = pathID;
1722                                     dest->ebData[lEdge].pieceID = pts[lm].piece;
1723                                     dest->ebData[lEdge].tSt = 0.0;
1724                                     dest->ebData[lEdge].tEn = 1.0;
1725                                 }
1726                             }
1727                         }
1728                         lastM = curP;
1729                         pathEnd = curP;
1730                         closed = false;
1731                         lEdge = -1;
1732                     } else {
1733                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1734                             lEdge = dest->AddEdge(first + pathEnd, first + curP);
1735                             dest->ebData[lEdge].pathID = pathID;
1736                             dest->ebData[lEdge].pieceID = pts[sbp].piece;
1737                             if ( pts[sbp].piece == pts[prp].piece ) {
1738                                 dest->ebData[lEdge].tSt = pts[prp].t;
1739                                 dest->ebData[lEdge].tEn = pts[sbp].t;
1740                             } else {
1741                                 dest->ebData[lEdge].tSt = 0.0;
1742                                 dest->ebData[lEdge].tEn = pts[sbp].t;
1743                             }
1744                             pathEnd = curP;
1745                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1746                                 closed = true;
1747                             } else {
1748                                 closed = false;
1749                             }
1750                         }
1751                     }
1752                     curP++;
1753                 }
1755                 if ( closeIfNeeded ) {
1756                     if ( closed && lEdge >= 0 ) {
1757                         dest->DisconnectEnd(lEdge);
1758                         dest->ConnectEnd(first + lastM, lEdge);
1759                     } else {
1760                         int lm = lastM;
1761                         lEdge = dest->AddEdge(first + pathEnd, first + lastM);
1762                         if ( lEdge >= 0 ) {
1763                             dest->ebData[lEdge].pathID = pathID;
1764                             dest->ebData[lEdge].pieceID = pts[lm].piece;
1765                             dest->ebData[lEdge].tSt = 0.0;
1766                             dest->ebData[lEdge].tEn = 1.0;
1767                         }
1768                     }
1769                 }
1770             }
1772         } else {
1773             {
1774                 // !invert && !back && !weighted
1775                 for (int i = 0;i < int(pts.size()); i++) {
1776                     dest->AddPoint(pts[i].p);
1777                 }
1779                 int lastM = 0;
1780                 int curP = 1;
1781                 int pathEnd = 0;
1782                 bool closed = false;
1783                 int lEdge = -1;
1784                 while ( curP < int(pts.size()) ) {
1785                     int sbp = curP;
1786                     int lm = lastM;
1787                     int prp = pathEnd;
1788                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1789                         if ( closeIfNeeded ) {
1790                             if ( closed && lEdge >= 0 ) {
1791                                 dest->DisconnectEnd(lEdge);
1792                                 dest->ConnectEnd(first + lastM, lEdge);
1793                             } else {
1794                                 dest->AddEdge(first + pathEnd, first + lastM);
1795                             }
1796                         }
1797                         lastM = curP;
1798                         pathEnd = curP;
1799                         closed = false;
1800                         lEdge = -1;
1801                     } else {
1802                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1803                             lEdge = dest->AddEdge(first+pathEnd, first+curP);
1804                             pathEnd = curP;
1805                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1806                                 closed = true;
1807                             } else {
1808                                 closed = false;
1809                             }
1810                         }
1811                     }
1812                     curP++;
1813                 }
1815                 if ( closeIfNeeded ) {
1816                     if ( closed && lEdge >= 0 ) {
1817                         dest->DisconnectEnd(lEdge);
1818                         dest->ConnectEnd(first + lastM, lEdge);
1819                     } else {
1820                         dest->AddEdge(first + pathEnd, first + lastM);
1821                     }
1822                 }
1824             }
1825         }
1826     }
1829 /*
1830   Local Variables:
1831   mode:c++
1832   c-file-style:"stroustrup"
1833   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1834   indent-tabs-mode:nil
1835   fill-column:99
1836   End:
1837 */
1838 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :