Code

e6f7acb0c17319f396099b5d529e724ea43651b6
[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     }
405 void Path::ConvertEvenLines(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;
425     // le moveto
426     {
427         int const firstTyp = descr_cmd[0]->getType();
428         if ( firstTyp == descr_moveto ) {
429             curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
430         } else {
431             curP = 0;
432             curX[0] = curX[1] = 0;
433         }
434         lastMoveTo = AddPoint(curX, true);
435     }
436     descr_cmd[0]->associated = lastMoveTo;
438     // et le reste, 1 par 1
439     while ( curP < int(descr_cmd.size()) ) {
441         int const nType = descr_cmd[curP]->getType();
442         NR::Point nextX;
444         switch (nType) {
445             case descr_forced: {
446                 descr_cmd[curP]->associated = AddForcedPoint(curX);
447                 curP++;
448                 break;
449             }
451             case descr_moveto: {
452                 PathDescrMoveTo* nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
453                 nextX = nData->p;
454                 lastMoveTo = AddPoint(nextX,true);
455                 descr_cmd[curP]->associated = lastMoveTo;
457                 // et on avance
458                 curP++;
459                 break;
460             }
462             case descr_close: {
463                 nextX = pts[lastMoveTo].p;
464                 {
465                     NR::Point nexcur;
466                     nexcur = nextX - curX;
467                     const double segL = NR::L2(nexcur);
468                     if ( segL > treshhold ) {
469                         for (double i = treshhold; i < segL; i += treshhold) {
470                             NR::Point nX;
471                             nX = (segL - i) * curX + i * nextX;
472                             nX /= segL;
473                             AddPoint(nX);
474                         }
475                     }
476                 }
478                 descr_cmd[curP]->associated = AddPoint(nextX,false);
479                 if ( descr_cmd[curP]->associated < 0 ) {
480                     if ( curP == 0 ) {
481                         descr_cmd[curP]->associated = 0;
482                     } else {
483                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
484                     }
485                 }
487                 curP++;
488                 break;
489             }
491             case descr_lineto: {
492                 PathDescrLineTo* nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
493                 nextX = nData->p;
494                 NR::Point nexcur = nextX - curX;
495                 const double segL = L2(nexcur);
496                 if ( segL > treshhold ) {
497                     for (double i = treshhold; i < segL; i += treshhold) {
498                         NR::Point nX = ((segL - i) * curX + i * nextX) / segL;
499                         AddPoint(nX);
500                     }
501                 }
503                 descr_cmd[curP]->associated = AddPoint(nextX,false);
504                 if ( descr_cmd[curP]->associated < 0 ) {
505                     if ( curP == 0 ) {
506                         descr_cmd[curP]->associated = 0;
507                     } else {
508                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
509                     }
510                 }
511                 // et on avance
512                 curP++;
513                 break;
514             }
516             case descr_cubicto: {
517                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
518                 nextX = nData->p;
519                 RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8, 4 * treshhold);
520                 descr_cmd[curP]->associated = AddPoint(nextX, false);
521                 if ( descr_cmd[curP]->associated < 0 ) {
522                     if ( curP == 0 ) {
523                         descr_cmd[curP]->associated = 0;
524                     } else {
525                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
526                     }
527                 }
528                 // et on avance
529                 curP++;
530                 break;
531             }
533             case descr_arcto: {
534                 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
535                 nextX = nData->p;
536                 DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
537                 descr_cmd[curP]->associated =AddPoint(nextX, false);
538                 if ( descr_cmd[curP]->associated < 0 ) {
539                     if ( curP == 0 ) {
540                         descr_cmd[curP]->associated = 0;
541                     } else {
542                         descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
543                     }
544                 }
546                 // et on avance
547                 curP++;
548                 break;
549             }
551             case descr_bezierto: {
552                 PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
553                 int nbInterm = nBData->nb;
554                 nextX = nBData->p;
555                 int curBD = curP;
557                 curP++;
558                 int ip = curP;
559                 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
561                 if ( nbInterm == 1 ) {
562                     NR::Point const midX = nData->p;
563                     RecBezierTo(midX, curX, nextX, treshhold, 8, 4 * treshhold);
564                 } else if ( nbInterm > 1 ) {
565                     NR::Point bx = curX;
566                     NR::Point cx = curX;
567                     NR::Point dx = curX;
569                     dx = nData->p;
570                     ip++;
571                     nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
573                     cx = 2 * bx - dx;
575                     for (int k = 0; k < nbInterm - 1; k++) {
576                         bx = cx;
577                         cx = dx;
578                         dx = nData->p;
580                         ip++;
581                         nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
583                         NR::Point stx = (bx+cx) / 2;
584                         if ( k > 0 ) {
585                             descr_cmd[ip - 2]->associated = AddPoint(stx, false);
586                             if ( descr_cmd[ip - 2]->associated < 0 ) {
587                                 if ( curP == 0 ) {
588                                     descr_cmd[ip- 2]->associated = 0;
589                                 } else {
590                                     descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
591                                 }
592                             }
593                         }
595                         {
596                             NR::Point const mx = (cx + dx) / 2;
597                             RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
598                         }
599                     }
601                     {
602                         bx = cx;
603                         cx = dx;
605                         dx = nextX;
606                         dx = 2 * dx - cx;
608                         NR::Point const stx = (bx + cx) / 2;
610                         descr_cmd[ip - 1]->associated = AddPoint(stx, false);
611                         if ( descr_cmd[ip - 1]->associated < 0 ) {
612                             if ( curP == 0 ) {
613                                 descr_cmd[ip - 1]->associated = 0;
614                             } else {
615                                 descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
616                             }
617                         }
619                         {
620                             NR::Point const mx = (cx + dx) / 2;
621                             RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
622                         }
623                     }
624                 }
626                 descr_cmd[curBD]->associated = AddPoint(nextX, false);
627                 if ( descr_cmd[curBD]->associated < 0 ) {
628                     if ( curP == 0 ) {
629                         descr_cmd[curBD]->associated = 0;
630                     } else {
631                         descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
632                     }
633                 }
635                 // et on avance
636                 curP += nbInterm;
637                 break;
638             }
639         }
640         if ( NR::LInfty(curX - nextX) > 0.00001 ) {
641             curX = nextX;
642         }
643     }
646 const NR::Point Path::PrevPoint(int i) const
648     /* TODO: I suspect this should assert `(unsigned) i < descr_nb'.  We can probably change
649        the argument to unsigned.  descr_nb should probably be changed to unsigned too. */
650     g_assert( i >= 0 );
651     switch ( descr_cmd[i]->getType() ) {
652         case descr_moveto: {
653             PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
654             return nData->p;
655         }
656         case descr_lineto: {
657             PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
658             return nData->p;
659         }
660         case descr_arcto: {
661             PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
662             return nData->p;
663         }
664         case descr_cubicto: {
665             PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
666             return nData->p;
667         }
668         case descr_bezierto: {
669             PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
670             return nData->p;
671         }
672         case descr_interm_bezier:
673         case descr_close:
674         case descr_forced:
675             return PrevPoint(i - 1);
676         default:
677             g_assert_not_reached();
678             return NR::Point(0, 0);
679     }
682 // utilitaries: given a quadratic bezier curve (start point, control point, end point, ie that's a clamped curve),
683 // and an abcissis on it, get the point with that abcissis.
684 // 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"
685 void Path::QuadraticPoint(double t, NR::Point &oPt,
686                           const NR::Point &iS, const NR::Point &iM, const NR::Point &iE)
688     NR::Point const ax = iE - 2 * iM + iS;
689     NR::Point const bx = 2 * iM - 2 * iS;
690     NR::Point const cx = iS;
692     oPt = t * t * ax + t * bx + cx;
694 // idem for cubic bezier patch
695 void Path::CubicTangent(double t, NR::Point &oPt, const NR::Point &iS, const NR::Point &isD,
696                         const NR::Point &iE, const NR::Point &ieD)
698     NR::Point const ax = ieD - 2 * iE + 2 * iS + isD;
699     NR::Point const bx = 3 * iE - ieD - 2 * isD - 3 * iS;
700     NR::Point const cx = isD;
702     oPt = 3 * t * t * ax + 2 * t * bx + cx;
705 // extract interesting info of a SVG arc description
706 static void ArcAnglesAndCenter(NR::Point const &iS, NR::Point const &iE,
707                                double rx, double ry, double angle,
708                                bool large, bool wise,
709                                double &sang, double &eang, NR::Point &dr);
711 void Path::ArcAngles(const NR::Point &iS, const NR::Point &iE,
712                      double rx, double ry, double angle, bool large, bool wise, double &sang, double &eang)
714     NR::Point dr;
715     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
718 /* N.B. If iS == iE then sang,eang,dr each become NaN.  Probably a bug. */
719 static void ArcAnglesAndCenter(NR::Point const &iS, NR::Point const &iE,
720                                double rx, double ry, double angle,
721                                bool large, bool wise,
722                                double &sang, double &eang, NR::Point &dr)
724     NR::Point se = iE - iS;
725     NR::Point ca(cos(angle), sin(angle));
726     NR::Point cse(dot(se, ca), cross(se, ca));
727     cse[0] /= rx;
728     cse[1] /= ry;
729     double const lensq = dot(cse,cse);
730     NR::Point csd = ( ( lensq < 4
731                         ? sqrt( 1/lensq - .25 )
732                         : 0.0 )
733                       * cse.ccw() );
735     NR::Point ra = -csd - 0.5 * cse;
736     if ( ra[0] <= -1 ) {
737         sang = M_PI;
738     } else if ( ra[0] >= 1 ) {
739         sang = 0;
740     } else {
741         sang = acos(ra[0]);
742         if ( ra[1] < 0 ) {
743             sang = 2 * M_PI - sang;
744         }
745     }
747     ra = -csd + 0.5 * cse;
748     if ( ra[0] <= -1 ) {
749         eang = M_PI;
750     } else if ( ra[0] >= 1 ) {
751         eang = 0;
752     } else {
753         eang = acos(ra[0]);
754         if ( ra[1] < 0 ) {
755             eang = 2 * M_PI - eang;
756         }
757     }
759     csd[0] *= rx;
760     csd[1] *= ry;
761     ca[1] = -ca[1]; // because it's the inverse rotation
763     dr[0] = dot(csd, ca);
764     dr[1] = cross(csd, ca);
766     ca[1] = -ca[1];
768     if ( wise ) {
770         if (large) {
771             dr = -dr;
772             double swap = eang;
773             eang = sang;
774             sang = swap;
775             eang += M_PI;
776             sang += M_PI;
777             if ( eang >= 2*M_PI ) {
778                 eang -= 2*M_PI;
779             }
780             if ( sang >= 2*M_PI ) {
781                 sang -= 2*M_PI;
782             }
783         }
785     } else {
786         if (!large) {
787             dr = -dr;
788             double swap = eang;
789             eang = sang;
790             sang = swap;
791             eang += M_PI;
792             sang += M_PI;
793             if ( eang >= 2*M_PI ) {
794                 eang -= 2 * M_PI;
795             }
796             if ( sang >= 2*M_PI ) {
797                 sang -= 2 * M_PI;
798             }
799         }
800     }
802     dr += 0.5 * (iS + iE);
807 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
808                  double const rx, double const ry, double const angle,
809                  bool const large, bool const wise, double const /*tresh*/)
811     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
812        apart than the diameter.  Also check that we do the right thing for negative radius.
813        (Same for the other DoArc functions in this file.) */
814     if ( rx <= 0.0001 || ry <= 0.0001 ) {
815         return;
816         // We always add a lineto afterwards, so this is fine.
817         // [on ajoute toujours un lineto apres, donc c bon]
818     }
820     double sang;
821     double eang;
822     NR::Point dr;
823     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
824     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
825        the case of low curvature (i.e. very large radius). */
827     NR::scale const ar(rx, ry);
828     NR::rotate cb( angle + sang );
829     if (wise) {
831         double const incr = -0.1;
832         if ( sang < eang ) {
833             sang += 2*M_PI;
834         }
835         NR::rotate const omega(incr);
836         for (double b = sang + incr ; b > eang ; b += incr) {
837             cb = omega * cb;
838             AddPoint( cb.vec * ar + dr );
839         }
841     } else {
843         double const incr = 0.1;
844         if ( sang > eang ) {
845             sang -= 2*M_PI;
846         }
847         NR::rotate const omega(incr);
848         for (double b = sang + incr ; b < eang ; b += incr) {
849             cb = omega * cb;
850             AddPoint( cb.vec * ar + dr);
851         }
852     }
856 void Path::RecCubicTo( NR::Point const &iS, NR::Point const &isD,
857                        NR::Point const &iE, NR::Point const &ieD,
858                        double tresh, int lev, double maxL)
860     NR::Point se = iE - iS;
861     const double dC = NR::L2(se);
862     if ( dC < 0.01 ) {
864         const double sC = dot(isD,isD);
865         const double eC = dot(ieD,ieD);
866         if ( sC < tresh && eC < tresh ) {
867             return;
868         }
870     } else {
871         const double sC = fabs(cross(se, isD)) / dC;
872         const double eC = fabs(cross(se, ieD)) / dC;
873         if ( sC < tresh && eC < tresh ) {
874             // presque tt droit -> attention si on nous demande de bien subdiviser les petits segments
875             if ( maxL > 0 && dC > maxL ) {
876                 if ( lev <= 0 ) {
877                     return;
878                 }
879                 NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
880                 NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
882                 NR::Point hisD = 0.5 * isD;
883                 NR::Point hieD = 0.5 * ieD;
885                 RecCubicTo(iS, hisD, m, md, tresh, lev - 1, maxL);
886                 AddPoint(m);
887                 RecCubicTo(m, md, iE, hieD, tresh, lev - 1,maxL);
888             }
889             return;
890         }
891     }
893     if ( lev <= 0 ) {
894         return;
895     }
897     {
898         NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
899         NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
901         NR::Point hisD = 0.5 * isD;
902         NR::Point hieD = 0.5 * ieD;
904         RecCubicTo(iS, hisD, m, md, tresh, lev - 1, maxL);
905         AddPoint(m);
906         RecCubicTo(m, md, iE, hieD, tresh, lev - 1,maxL);
907     }
912 void Path::RecBezierTo(const NR::Point &iP,
913                        const NR::Point &iS,
914                        const NR::Point &iE,
915                        double tresh, int lev, double maxL)
917     if ( lev <= 0 ) {
918         return;
919     }
921     NR::Point ps = iS - iP;
922     NR::Point pe = iE - iP;
923     NR::Point se = iE - iS;
924     double s = fabs(cross(pe, ps));
925     if ( s < tresh ) {
926         const double l = L2(se);
927         if ( maxL > 0 && l > maxL ) {
928             const NR::Point m = 0.25 * (iS + iE + 2 * iP);
929             NR::Point md = 0.5 * (iS + iP);
930             RecBezierTo(md, iS, m, tresh, lev - 1, maxL);
931             AddPoint(m);
932             md = 0.5 * (iP + iE);
933             RecBezierTo(md, m, iE, tresh, lev - 1, maxL);
934         }
935         return;
936     }
938     {
939         const NR::Point m = 0.25 * (iS + iE + 2 * iP);
940         NR::Point md = 0.5 * (iS + iP);
941         RecBezierTo(md, iS, m, tresh, lev - 1, maxL);
942         AddPoint(m);
943         md = 0.5 * (iP + iE);
944         RecBezierTo(md, m, iE, tresh, lev - 1, maxL);
945     }
949 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
950                  double const rx, double const ry, double const angle,
951                  bool const large, bool const wise, double const /*tresh*/, int const piece)
953     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
954        apart than the diameter.  Also check that we do the right thing for negative radius.
955        (Same for the other DoArc functions in this file.) */
956     if ( rx <= 0.0001 || ry <= 0.0001 ) {
957         return;
958         // We always add a lineto afterwards, so this is fine.
959         // [on ajoute toujours un lineto apres, donc c bon]
960     }
962     double sang;
963     double eang;
964     NR::Point dr;
965     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
966     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
967        the case of low curvature (i.e. very large radius). */
969     NR::scale const ar(rx, ry);
970     NR::rotate cb(angle + sang);
971     if (wise) {
973         double const incr = -0.1;
974         if ( sang < eang ) {
975             sang += 2*M_PI;
976         }
977         NR::rotate const omega(incr);
978         for (double b = sang + incr; b > eang; b += incr) {
979             cb = omega * cb;
980             AddPoint(cb.vec * ar + dr, piece, (sang - b) / (sang - eang));
981         }
983     } else {
985         double const incr = 0.1;
986         if ( sang > eang ) {
987             sang -= 2 * M_PI;
988         }
989         NR::rotate const omega(incr);
990         for (double b = sang + incr ; b < eang ; b += incr) {
991             cb = omega * cb;
992             AddPoint(cb.vec * ar + dr, piece, (b - sang) / (eang - sang));
993         }
994     }
997 void Path::RecCubicTo(NR::Point const &iS, NR::Point const &isD,
998                       NR::Point const &iE, NR::Point const &ieD,
999                       double tresh, int lev, double st, double et, int piece)
1001     const NR::Point se = iE - iS;
1002     const double dC = NR::L2(se);
1003     if ( dC < 0.01 ) {
1004         const double sC = dot(isD, isD);
1005         const double eC = dot(ieD, ieD);
1006         if ( sC < tresh && eC < tresh ) {
1007             return;
1008         }
1009     } else {
1010         const double sC = fabs(cross(se, isD)) / dC;
1011         const double eC = fabs(cross(se, ieD)) / dC;
1012         if ( sC < tresh && eC < tresh ) {
1013             return;
1014         }
1015     }
1017     if ( lev <= 0 ) {
1018         return;
1019     }
1021     NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
1022     NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1023     double mt = (st + et) / 2;
1025     NR::Point hisD = 0.5 * isD;
1026     NR::Point hieD = 0.5 * ieD;
1028     RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece);
1029     AddPoint(m, piece, mt);
1030     RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece);
1036 void Path::RecBezierTo(NR::Point const &iP,
1037                        NR::Point const &iS,
1038                        NR::Point const &iE,
1039                        double tresh, int lev, double st, double et, int piece)
1041     if ( lev <= 0 ) {
1042         return;
1043     }
1045     NR::Point ps = iS - iP;
1046     NR::Point pe = iE - iP;
1047     const double s = fabs(cross(pe, ps));
1048     if ( s < tresh ) {
1049         return;
1050     }
1052     {
1053         const double mt = (st + et) / 2;
1054         const NR::Point m = 0.25 * (iS + iE + 2 * iP);
1055         RecBezierTo(0.5 * (iS + iP), iS, m, tresh, lev - 1, st, mt, piece);
1056         AddPoint(m, piece, mt);
1057         RecBezierTo(0.5 * (iP + iE), m, iE, tresh, lev - 1, mt, et, piece);
1058     }
1063 void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
1064                  double const rx, double const ry, double const angle,
1065                  bool const large, bool const wise, double const /*tresh*/,
1066                  int const piece, offset_orig &/*orig*/)
1068     // Will never arrive here, as offsets are made of cubics.
1069     // [on n'arrivera jamais ici, puisque les offsets sont fait de cubiques]
1070     /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
1071        apart than the diameter.  Also check that we do the right thing for negative radius.
1072        (Same for the other DoArc functions in this file.) */
1073     if ( rx <= 0.0001 || ry <= 0.0001 ) {
1074         return;
1075         // We always add a lineto afterwards, so this is fine.
1076         // [on ajoute toujours un lineto apres, donc c bon]
1077     }
1079     double sang;
1080     double eang;
1081     NR::Point dr;
1082     ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
1083     /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
1084        the case of low curvature (i.e. very large radius). */
1086     NR::scale const ar(rx, ry);
1087     NR::rotate cb(angle + sang);
1088     if (wise) {
1090         double const incr = -0.1;
1091         if ( sang < eang ) {
1092             sang += 2*M_PI;
1093         }
1094         NR::rotate const omega(incr);
1095         for (double b = sang + incr; b > eang ;b += incr) {
1096             cb = omega * cb;
1097             AddPoint(cb.vec * ar + dr, piece, (sang - b) / (sang - eang));
1098         }
1100     } else {
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, piece, (b - sang) / (eang - sang));
1109         }
1110     }
1114 void Path::RecCubicTo(NR::Point const &iS, NR::Point const &isD,
1115                       NR::Point const &iE, NR::Point const &ieD,
1116                       double tresh, int lev, double st, double et,
1117                       int piece, offset_orig &orig)
1119     const NR::Point se = iE - iS;
1120     const double dC = NR::L2(se);
1121     bool doneSub = false;
1122     if ( dC < 0.01 ) {
1123         const double sC = dot(isD, isD);
1124         const double eC = dot(ieD, ieD);
1125         if ( sC < tresh && eC < tresh ) {
1126             return;
1127         }
1128     } else {
1129         const double sC = fabs(cross(se, isD)) / dC;
1130         const double eC = fabs(cross(se, ieD)) / dC;
1131         if ( sC < tresh && eC < tresh ) {
1132             doneSub = true;
1133         }
1134     }
1136     if ( lev <= 0 ) {
1137         doneSub = true;
1138     }
1140     // test des inversions
1141     bool stInv = false;
1142     bool enInv = false;
1143     {
1144         NR::Point os_pos;
1145         NR::Point os_tgt;
1146         NR::Point oe_pos;
1147         NR::Point oe_tgt;
1149         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
1150         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
1153         NR::Point n_tgt = isD;
1154         double si = dot(n_tgt, os_tgt);
1155         if ( si < 0 ) {
1156             stInv = true;
1157         }
1158         n_tgt = ieD;
1159         si = dot(n_tgt, oe_tgt);
1160         if ( si < 0 ) {
1161             enInv = true;
1162         }
1163         if ( stInv && enInv ) {
1165             AddPoint(os_pos, -1, 0.0);
1166             AddPoint(iE, piece, et);
1167             AddPoint(iS, piece, st);
1168             AddPoint(oe_pos, -1, 0.0);
1169             return;
1171         } else if ( ( stInv && !enInv ) || ( !stInv && enInv ) ) {
1172             return;
1173         }
1175     }
1177     if ( ( !stInv && !enInv && doneSub ) || lev <= 0 ) {
1178         return;
1179     }
1181     {
1182         const NR::Point m = 0.5 * (iS+iE) + 0.125 * (isD - ieD);
1183         const NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
1184         const double mt = (st + et) / 2;
1185         const NR::Point hisD = 0.5 * isD;
1186         const NR::Point hieD = 0.5 * ieD;
1188         RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece, orig);
1189         AddPoint(m, piece, mt);
1190         RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece, orig);
1191     }
1196 void Path::RecBezierTo(NR::Point const &iP, NR::Point const &iS,NR::Point const &iE,
1197                        double tresh, int lev, double st, double et,
1198                        int piece, offset_orig& orig)
1200     bool doneSub = false;
1201     if ( lev <= 0 ) {
1202         return;
1203     }
1205     const NR::Point ps = iS - iP;
1206     const NR::Point pe = iE - iP;
1207     const double s = fabs(cross(pe, ps));
1208     if ( s < tresh ) {
1209         doneSub = true ;
1210     }
1212     // test des inversions
1213     bool stInv = false;
1214     bool enInv = false;
1215     {
1216         NR::Point os_pos;
1217         NR::Point os_tgt;
1218         NR::Point oe_pos;
1219         NR::Point oe_tgt;
1220         NR::Point n_tgt;
1221         NR::Point n_pos;
1223         double n_len;
1224         double n_rad;
1225         PathDescrIntermBezierTo mid(iP);
1226         PathDescrBezierTo fin(iE, 1);
1228         TangentOnBezAt(0.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
1229         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
1230         double si = dot(n_tgt, os_tgt);
1231         if ( si < 0 ) {
1232             stInv = true;
1233         }
1235         TangentOnBezAt(1.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
1236         orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
1237         si = dot(n_tgt, oe_tgt);
1238         if ( si < 0 ) {
1239             enInv = true;
1240         }
1242         if ( stInv && enInv ) {
1243             AddPoint(os_pos, -1, 0.0);
1244             AddPoint(iE, piece, et);
1245             AddPoint(iS, piece, st);
1246             AddPoint(oe_pos, -1, 0.0);
1247             return;
1248         }
1249     }
1251     if ( !stInv && !enInv && doneSub ) {
1252         return;
1253     }
1255     {
1256         double mt = (st + et) / 2;
1257         NR::Point m = 0.25 * (iS + iE + 2 * iP);
1258         NR::Point md = 0.5 * (iS + iP);
1259         RecBezierTo(md, iS, m, tresh, lev - 1, st, mt, piece, orig);
1260         AddPoint(m, piece, mt);
1261         md = 0.5 * (iP + iE);
1262         RecBezierTo(md, m, iE, tresh, lev - 1, mt, et, piece, orig);
1263     }
1267 /*
1268  * put a polyline in a Shape instance, for further fun
1269  * pathID is the ID you want this Path instance to be associated with, for when you're going to recompose the polyline
1270  * in a path description ( you need to have prepared the back data for that, of course)
1271  */
1273 void Path::Fill(Shape* dest, int pathID, bool justAdd, bool closeIfNeeded, bool invert)
1275     if ( dest == NULL ) {
1276         return;
1277     }
1279     if ( justAdd == false ) {
1280         dest->Reset(pts.size(), pts.size());
1281     }
1283     if ( pts.size() <= 1 ) {
1284         return;
1285     }
1287     int first = dest->numberOfPoints();
1289     if ( back ) {
1290         dest->MakeBackData(true);
1291     }
1293     if ( invert ) {
1294         if ( back ) {
1295             {
1296                 // invert && back && !weighted
1297                 for (int i = 0; i < int(pts.size()); i++) {
1298                     dest->AddPoint(pts[i].p);
1299                 }
1300                 int lastM = 0;
1301                 int curP = 1;
1302                 int pathEnd = 0;
1303                 bool closed = false;
1304                 int lEdge = -1;
1306                 while ( curP < int(pts.size()) ) {
1307                     int sbp = curP;
1308                     int lm = lastM;
1309                     int prp = pathEnd;
1311                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1313                         if ( closeIfNeeded ) {
1314                             if ( closed && lEdge >= 0 ) {
1315                                 dest->DisconnectStart(lEdge);
1316                                 dest->ConnectStart(first + lastM, lEdge);
1317                             } else {
1318                                 lEdge = dest->AddEdge(first + lastM, first+pathEnd);
1319                                 if ( lEdge >= 0 ) {
1320                                     dest->ebData[lEdge].pathID = pathID;
1321                                     dest->ebData[lEdge].pieceID = pts[lm].piece;
1322                                     dest->ebData[lEdge].tSt = 1.0;
1323                                     dest->ebData[lEdge].tEn = 0.0;
1324                                 }
1325                             }
1326                         }
1328                         lastM = curP;
1329                         pathEnd = curP;
1330                         closed = false;
1331                         lEdge = -1;
1333                     } else {
1335                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1336                             lEdge = dest->AddEdge(first + curP, first + pathEnd);
1337                             if ( lEdge >= 0 ) {
1338                                 dest->ebData[lEdge].pathID = pathID;
1339                                 dest->ebData[lEdge].pieceID = pts[sbp].piece;
1340                                 if ( pts[sbp].piece == pts[prp].piece ) {
1341                                     dest->ebData[lEdge].tSt = pts[sbp].t;
1342                                     dest->ebData[lEdge].tEn = pts[prp].t;
1343                                 } else {
1344                                     dest->ebData[lEdge].tSt = pts[sbp].t;
1345                                     dest->ebData[lEdge].tEn = 0.0;
1346                                 }
1347                             }
1348                             pathEnd = curP;
1349                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1350                                 closed = true;
1351                             } else {
1352                                 closed = false;
1353                             }
1354                         }
1355                     }
1357                     curP++;
1358                 }
1360                 if ( closeIfNeeded ) {
1361                     if ( closed && lEdge >= 0 ) {
1362                         dest->DisconnectStart(lEdge);
1363                         dest->ConnectStart(first + lastM, lEdge);
1364                     } else {
1365                         int lm = lastM;
1366                         lEdge = dest->AddEdge(first + lastM, first + pathEnd);
1367                         if ( lEdge >= 0 ) {
1368                             dest->ebData[lEdge].pathID = pathID;
1369                             dest->ebData[lEdge].pieceID = pts[lm].piece;
1370                             dest->ebData[lEdge].tSt = 1.0;
1371                             dest->ebData[lEdge].tEn = 0.0;
1372                         }
1373                     }
1374                 }
1375             }
1377         } else {
1379             {
1380                 // invert && !back && !weighted
1381                 for (int i = 0; i < int(pts.size()); i++) {
1382                     dest->AddPoint(pts[i].p);
1383                 }
1384                 int lastM = 0;
1385                 int curP = 1;
1386                 int pathEnd = 0;
1387                 bool closed = false;
1388                 int lEdge = -1;
1389                 while ( curP < int(pts.size()) ) {
1390                     int sbp = curP;
1391                     int lm = lastM;
1392                     int prp = pathEnd;
1393                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1394                         if ( closeIfNeeded ) {
1395                             if ( closed && lEdge >= 0 ) {
1396                                 dest->DisconnectStart(lEdge);
1397                                 dest->ConnectStart(first + lastM, lEdge);
1398                             } else {
1399                                 dest->AddEdge(first + lastM, first + pathEnd);
1400                             }
1401                         }
1402                         lastM = curP;
1403                         pathEnd = curP;
1404                         closed = false;
1405                         lEdge = -1;
1406                     } else {
1407                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1408                             lEdge = dest->AddEdge(first+curP, first+pathEnd);
1409                             pathEnd = curP;
1410                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1411                                 closed = true;
1412                             } else {
1413                                 closed = false;
1414                             }
1415                         }
1416                     }
1417                     curP++;
1418                 }
1420                 if ( closeIfNeeded ) {
1421                     if ( closed && lEdge >= 0 ) {
1422                         dest->DisconnectStart(lEdge);
1423                         dest->ConnectStart(first + lastM, lEdge);
1424                     } else {
1425                         dest->AddEdge(first + lastM, first + pathEnd);
1426                     }
1427                 }
1429             }
1430         }
1432     } else {
1434         if ( back ) {
1435             {
1436                 // !invert && back && !weighted
1437                 for (int i = 0; i < int(pts.size()); i++) {
1438                     dest->AddPoint(pts[i].p);
1439                 }
1441                 int lastM = 0;
1442                 int curP = 1;
1443                 int pathEnd = 0;
1444                 bool closed = false;
1445                 int lEdge = -1;
1446                 while ( curP < int(pts.size()) ) {
1447                     int sbp = curP;
1448                     int lm = lastM;
1449                     int prp = pathEnd;
1450                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1451                         if ( closeIfNeeded ) {
1452                             if ( closed && lEdge >= 0 ) {
1453                                 dest->DisconnectEnd(lEdge);
1454                                 dest->ConnectEnd(first + lastM, lEdge);
1455                             } else {
1456                                 lEdge = dest->AddEdge(first + pathEnd, first+lastM);
1457                                 if ( lEdge >= 0 ) {
1458                                     dest->ebData[lEdge].pathID = pathID;
1459                                     dest->ebData[lEdge].pieceID = pts[lm].piece;
1460                                     dest->ebData[lEdge].tSt = 0.0;
1461                                     dest->ebData[lEdge].tEn = 1.0;
1462                                 }
1463                             }
1464                         }
1465                         lastM = curP;
1466                         pathEnd = curP;
1467                         closed = false;
1468                         lEdge = -1;
1469                     } else {
1470                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1471                             lEdge = dest->AddEdge(first + pathEnd, first + curP);
1472                             dest->ebData[lEdge].pathID = pathID;
1473                             dest->ebData[lEdge].pieceID = pts[sbp].piece;
1474                             if ( pts[sbp].piece == pts[prp].piece ) {
1475                                 dest->ebData[lEdge].tSt = pts[prp].t;
1476                                 dest->ebData[lEdge].tEn = pts[sbp].t;
1477                             } else {
1478                                 dest->ebData[lEdge].tSt = 0.0;
1479                                 dest->ebData[lEdge].tEn = pts[sbp].t;
1480                             }
1481                             pathEnd = curP;
1482                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1483                                 closed = true;
1484                             } else {
1485                                 closed = false;
1486                             }
1487                         }
1488                     }
1489                     curP++;
1490                 }
1492                 if ( closeIfNeeded ) {
1493                     if ( closed && lEdge >= 0 ) {
1494                         dest->DisconnectEnd(lEdge);
1495                         dest->ConnectEnd(first + lastM, lEdge);
1496                     } else {
1497                         int lm = lastM;
1498                         lEdge = dest->AddEdge(first + pathEnd, first + lastM);
1499                         if ( lEdge >= 0 ) {
1500                             dest->ebData[lEdge].pathID = pathID;
1501                             dest->ebData[lEdge].pieceID = pts[lm].piece;
1502                             dest->ebData[lEdge].tSt = 0.0;
1503                             dest->ebData[lEdge].tEn = 1.0;
1504                         }
1505                     }
1506                 }
1507             }
1509         } else {
1510             {
1511                 // !invert && !back && !weighted
1512                 for (int i = 0;i < int(pts.size()); i++) {
1513                     dest->AddPoint(pts[i].p);
1514                 }
1516                 int lastM = 0;
1517                 int curP = 1;
1518                 int pathEnd = 0;
1519                 bool closed = false;
1520                 int lEdge = -1;
1521                 while ( curP < int(pts.size()) ) {
1522                     int sbp = curP;
1523                     int lm = lastM;
1524                     int prp = pathEnd;
1525                     if ( pts[sbp].isMoveTo == polyline_moveto ) {
1526                         if ( closeIfNeeded ) {
1527                             if ( closed && lEdge >= 0 ) {
1528                                 dest->DisconnectEnd(lEdge);
1529                                 dest->ConnectEnd(first + lastM, lEdge);
1530                             } else {
1531                                 dest->AddEdge(first + pathEnd, first + lastM);
1532                             }
1533                         }
1534                         lastM = curP;
1535                         pathEnd = curP;
1536                         closed = false;
1537                         lEdge = -1;
1538                     } else {
1539                         if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
1540                             lEdge = dest->AddEdge(first+pathEnd, first+curP);
1541                             pathEnd = curP;
1542                             if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
1543                                 closed = true;
1544                             } else {
1545                                 closed = false;
1546                             }
1547                         }
1548                     }
1549                     curP++;
1550                 }
1552                 if ( closeIfNeeded ) {
1553                     if ( closed && lEdge >= 0 ) {
1554                         dest->DisconnectEnd(lEdge);
1555                         dest->ConnectEnd(first + lastM, lEdge);
1556                     } else {
1557                         dest->AddEdge(first + pathEnd, first + lastM);
1558                     }
1559                 }
1561             }
1562         }
1563     }
1566 /*
1567   Local Variables:
1568   mode:c++
1569   c-file-style:"stroustrup"
1570   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1571   indent-tabs-mode:nil
1572   fill-column:99
1573   End:
1574 */
1575 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :