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 }
185 }
188 void Path::Convert(double treshhold)
189 {
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 }
401 }
405 void Path::ConvertEvenLines(double treshhold)
406 {
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 }
644 }
646 const NR::Point Path::PrevPoint(int i) const
647 {
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 }
680 }
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)
687 {
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;
693 }
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)
697 {
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;
703 }
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)
713 {
714 NR::Point dr;
715 ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
716 }
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)
723 {
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);
803 }
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*/)
810 {
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 }
853 }
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)
859 {
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 }
908 }
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)
916 {
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 }
946 }
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)
952 {
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 }
995 }
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)
1000 {
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);
1032 }
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)
1040 {
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 }
1059 }
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*/)
1067 {
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 }
1111 }
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)
1118 {
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 }
1192 }
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)
1199 {
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 }
1264 }
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)
1274 {
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 }
1564 }
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 :