1 /*
2 * PathCutting.cpp
3 * nlivarot
4 *
5 * Created by fred on someday in 2004.
6 * public domain
7 *
8 */
10 #include "Path.h"
11 #include "livarot/path-description.h"
12 #include "libnr/n-art-bpath.h"
13 #include "libnr/nr-point-matrix-ops.h"
15 void Path::DashPolyline(float head,float tail,float body,int nbD,float *dashs,bool stPlain,float stOffset)
16 {
17 if ( nbD <= 0 || body <= 0.0001 ) return; // pas de tirets, en fait
19 std::vector<path_lineto> orig_pts = pts;
20 pts.clear();
22 int lastMI=-1;
23 int curP = 0;
24 int lastMP = -1;
26 for (int i = 0; i < int(orig_pts.size()); i++) {
27 if ( orig_pts[curP].isMoveTo == polyline_moveto ) {
28 if ( lastMI >= 0 && lastMI < i-1 ) { // au moins 2 points
29 DashSubPath(i-lastMI,lastMP, orig_pts, head,tail,body,nbD,dashs,stPlain,stOffset);
30 }
31 lastMI=i;
32 lastMP=curP;
33 }
34 curP++;
35 }
36 if ( lastMI >= 0 && lastMI < int(orig_pts.size()) - 1 ) {
37 DashSubPath(orig_pts.size() - lastMI, lastMP, orig_pts, head, tail, body, nbD, dashs, stPlain, stOffset);
38 }
39 }
43 void Path::DashSubPath(int spL, int spP, std::vector<path_lineto> const &orig_pts, float head,float tail,float body,int nbD,float *dashs,bool stPlain,float stOffset)
44 {
45 if ( spL <= 0 || spP == -1 ) return;
47 double totLength=0;
48 NR::Point lastP;
49 lastP = orig_pts[spP].p;
50 for (int i=1;i<spL;i++) {
51 NR::Point const n = orig_pts[spP + i].p;
52 NR::Point d=n-lastP;
53 double nl=NR::L2(d);
54 if ( nl > 0.0001 ) {
55 totLength+=nl;
56 lastP=n;
57 }
58 }
60 if ( totLength <= head+tail ) return; // tout mange par la tete et la queue
62 double curLength=0;
63 double dashPos=0;
64 int dashInd=0;
65 bool dashPlain=false;
66 double lastT=0;
67 int lastPiece=-1;
68 lastP = orig_pts[spP].p;
69 for (int i=1;i<spL;i++) {
70 NR::Point n;
71 int nPiece=-1;
72 double nT=0;
73 if ( back ) {
74 n = orig_pts[spP + i].p;
75 nPiece = orig_pts[spP + i].piece;
76 nT = orig_pts[spP + i].t;
77 } else {
78 n = orig_pts[spP + i].p;
79 }
80 NR::Point d=n-lastP;
81 double nl=NR::L2(d);
82 if ( nl > 0.0001 ) {
83 double stLength=curLength;
84 double enLength=curLength+nl;
85 // couper les bouts en trop
86 if ( curLength <= head && curLength+nl > head ) {
87 nl-=head-curLength;
88 curLength=head;
89 dashInd=0;
90 dashPos=stOffset;
91 bool nPlain=stPlain;
92 while ( dashs[dashInd] < stOffset ) {
93 dashInd++;
94 nPlain=!(nPlain);
95 if ( dashInd >= nbD ) {
96 dashPos=0;
97 dashInd=0;
98 break;
99 }
100 }
101 if ( nPlain == true && dashPlain == false ) {
102 NR::Point p=(enLength-curLength)*lastP+(curLength-stLength)*n;
103 p/=(enLength-stLength);
104 if ( back ) {
105 double pT=0;
106 if ( nPiece == lastPiece ) {
107 pT=(lastT*(enLength-curLength)+nT*(curLength-stLength))/(enLength-stLength);
108 } else {
109 pT=(nPiece*(curLength-stLength))/(enLength-stLength);
110 }
111 AddPoint(p,nPiece,pT,true);
112 } else {
113 AddPoint(p,true);
114 }
115 } else if ( nPlain == false && dashPlain == true ) {
116 }
117 dashPlain=nPlain;
118 }
119 // faire les tirets
120 if ( curLength >= head /*&& curLength+nl <= totLength-tail*/ ) {
121 while ( curLength <= totLength-tail && nl > 0 ) {
122 if ( enLength <= totLength-tail ) nl=enLength-curLength; else nl=totLength-tail-curLength;
123 double leftInDash=body-dashPos;
124 if ( dashInd < nbD ) {
125 leftInDash=dashs[dashInd]-dashPos;
126 }
127 if ( leftInDash <= nl ) {
128 bool nPlain=false;
129 if ( dashInd < nbD ) {
130 dashPos=dashs[dashInd];
131 dashInd++;
132 if ( dashPlain ) nPlain=false; else nPlain=true;
133 } else {
134 dashInd=0;
135 dashPos=0;
136 //nPlain=stPlain;
137 nPlain=dashPlain;
138 }
139 if ( nPlain == true && dashPlain == false ) {
140 NR::Point p=(enLength-curLength-leftInDash)*lastP+(curLength+leftInDash-stLength)*n;
141 p/=(enLength-stLength);
142 if ( back ) {
143 double pT=0;
144 if ( nPiece == lastPiece ) {
145 pT=(lastT*(enLength-curLength-leftInDash)+nT*(curLength+leftInDash-stLength))/(enLength-stLength);
146 } else {
147 pT=(nPiece*(curLength+leftInDash-stLength))/(enLength-stLength);
148 }
149 AddPoint(p,nPiece,pT,true);
150 } else {
151 AddPoint(p,true);
152 }
153 } else if ( nPlain == false && dashPlain == true ) {
154 NR::Point p=(enLength-curLength-leftInDash)*lastP+(curLength+leftInDash-stLength)*n;
155 p/=(enLength-stLength);
156 if ( back ) {
157 double pT=0;
158 if ( nPiece == lastPiece ) {
159 pT=(lastT*(enLength-curLength-leftInDash)+nT*(curLength+leftInDash-stLength))/(enLength-stLength);
160 } else {
161 pT=(nPiece*(curLength+leftInDash-stLength))/(enLength-stLength);
162 }
163 AddPoint(p,nPiece,pT,false);
164 } else {
165 AddPoint(p,false);
166 }
167 }
168 dashPlain=nPlain;
170 curLength+=leftInDash;
171 nl-=leftInDash;
172 } else {
173 dashPos+=nl;
174 curLength+=nl;
175 nl=0;
176 }
177 }
178 if ( dashPlain ) {
179 if ( back ) {
180 AddPoint(n,nPiece,nT,false);
181 } else {
182 AddPoint(n,false);
183 }
184 }
185 nl=enLength-curLength;
186 }
187 if ( curLength <= totLength-tail && curLength+nl > totLength-tail ) {
188 nl=totLength-tail-curLength;
189 dashInd=0;
190 dashPos=0;
191 bool nPlain=false;
192 if ( nPlain == true && dashPlain == false ) {
193 } else if ( nPlain == false && dashPlain == true ) {
194 NR::Point p=(enLength-curLength)*lastP+(curLength-stLength)*n;
195 p/=(enLength-stLength);
196 if ( back ) {
197 double pT=0;
198 if ( nPiece == lastPiece ) {
199 pT=(lastT*(enLength-curLength)+nT*(curLength-stLength))/(enLength-stLength);
200 } else {
201 pT=(nPiece*(curLength-stLength))/(enLength-stLength);
202 }
203 AddPoint(p,nPiece,pT,false);
204 } else {
205 AddPoint(p,false);
206 }
207 }
208 dashPlain=nPlain;
209 }
210 // continuer
211 curLength=enLength;
212 lastP=n;
213 lastPiece=nPiece;
214 lastT=nT;
215 }
216 }
217 }
218 #include "../display/canvas-bpath.h"
220 void* Path::MakeArtBPath(void)
221 {
222 int nb_cmd=0,max_cmd=0;
223 NArtBpath* bpath=(NArtBpath*)g_malloc((max_cmd+1)*sizeof(NArtBpath));
225 NR::Point lastP,bezSt,bezEn,lastMP;
226 int lastM=-1,bezNb=0;
227 for (int i=0;i<int(descr_cmd.size());i++) {
228 int const typ = descr_cmd[i]->getType();
229 switch ( typ ) {
230 case descr_close:
231 {
232 if ( lastM >= 0 ) {
233 bpath[lastM].code=NR_MOVETO;
234 if ( nb_cmd >= max_cmd ) {
235 max_cmd=2*nb_cmd+1;
236 bpath=(NArtBpath*)g_realloc(bpath,(max_cmd+1)*sizeof(NArtBpath));
237 }
238 bpath[nb_cmd].code=NR_LINETO;
239 bpath[nb_cmd].x3=lastMP[0];
240 bpath[nb_cmd].y3=lastMP[1];
241 nb_cmd++;
242 }
243 lastM=-1;
244 }
245 break;
246 case descr_lineto:
247 {
248 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
249 if ( nb_cmd >= max_cmd ) {
250 max_cmd=2*nb_cmd+1;
251 bpath=(NArtBpath*)g_realloc(bpath,(max_cmd+1)*sizeof(NArtBpath));
252 }
253 bpath[nb_cmd].code=NR_LINETO;
254 bpath[nb_cmd].x3=nData->p[0];
255 bpath[nb_cmd].y3=nData->p[1];
256 nb_cmd++;
257 lastP=nData->p;
258 }
259 break;
260 case descr_moveto:
261 {
262 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
263 if ( nb_cmd >= max_cmd ) {
264 max_cmd=2*nb_cmd+1;
265 bpath=(NArtBpath*)g_realloc(bpath,(max_cmd+1)*sizeof(NArtBpath));
266 }
267 bpath[nb_cmd].code=NR_MOVETO_OPEN;
268 bpath[nb_cmd].x3=nData->p[0];
269 bpath[nb_cmd].y3=nData->p[1];
270 lastM=nb_cmd;
271 nb_cmd++;
272 lastP=lastMP=nData->p;
273 }
274 break;
275 case descr_arcto:
276 {
277 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
278 lastP=nData->p;
279 }
280 break;
281 case descr_cubicto:
282 {
283 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
284 if ( nb_cmd >= max_cmd ) {
285 max_cmd=2*nb_cmd+1;
286 bpath=(NArtBpath*)g_realloc(bpath,(max_cmd+1)*sizeof(NArtBpath));
287 }
288 bpath[nb_cmd].code=NR_CURVETO;
289 bpath[nb_cmd].x1=lastP[0]+0.333333*nData->start[0];
290 bpath[nb_cmd].y1=lastP[1]+0.333333*nData->start[1];
291 bpath[nb_cmd].x2=nData->p[0]-0.333333*nData->end[0];
292 bpath[nb_cmd].y2=nData->p[1]-0.333333*nData->end[1];
293 bpath[nb_cmd].x3=nData->p[0];
294 bpath[nb_cmd].y3=nData->p[1];
295 nb_cmd++;
296 lastP=nData->p;
297 }
298 break;
299 case descr_bezierto:
300 {
301 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
302 if ( nb_cmd >= max_cmd ) {
303 max_cmd=2*nb_cmd+1;
304 bpath=(NArtBpath*)g_realloc(bpath,(max_cmd+1)*sizeof(NArtBpath));
305 }
306 if ( nData->nb <= 0 ) {
307 bpath[nb_cmd].code=NR_LINETO;
308 bpath[nb_cmd].x3=nData->p[0];
309 bpath[nb_cmd].y3=nData->p[1];
310 nb_cmd++;
311 bezNb=0;
312 } else if ( nData->nb == 1 ){
313 PathDescrIntermBezierTo *iData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i+1]);
314 bpath[nb_cmd].code=NR_CURVETO;
315 bpath[nb_cmd].x1=0.333333*(lastP[0]+2*iData->p[0]);
316 bpath[nb_cmd].y1=0.333333*(lastP[1]+2*iData->p[1]);
317 bpath[nb_cmd].x2=0.333333*(nData->p[0]+2*iData->p[0]);
318 bpath[nb_cmd].y2=0.333333*(nData->p[1]+2*iData->p[1]);
319 bpath[nb_cmd].x3=nData->p[0];
320 bpath[nb_cmd].y3=nData->p[1];
321 nb_cmd++;
322 bezNb=0;
323 } else {
324 bezSt=2*lastP-nData->p;
325 bezEn=nData->p;
326 bezNb=nData->nb;
327 }
328 lastP=nData->p;
329 }
330 break;
331 case descr_interm_bezier:
332 {
333 if ( bezNb > 0 ) {
334 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
335 NR::Point p_m=nData->p,p_s=0.5*(bezSt+p_m),p_e;
336 if ( bezNb > 1 ) {
337 PathDescrIntermBezierTo *iData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i+1]);
338 p_e=0.5*(p_m+iData->p);
339 } else {
340 p_e=bezEn;
341 }
343 if ( nb_cmd >= max_cmd ) {
344 max_cmd=2*nb_cmd+1;
345 bpath=(NArtBpath*)g_realloc(bpath,(max_cmd+1)*sizeof(NArtBpath));
346 }
347 bpath[nb_cmd].code=NR_CURVETO;
348 NR::Point cp1=0.333333*(p_s+2*p_m),cp2=0.333333*(2*p_m+p_e);
349 bpath[nb_cmd].x1=cp1[0];
350 bpath[nb_cmd].y1=cp1[1];
351 bpath[nb_cmd].x2=cp2[0];
352 bpath[nb_cmd].y2=cp2[1];
353 bpath[nb_cmd].x3=p_e[0];
354 bpath[nb_cmd].y3=p_e[1];
355 nb_cmd++;
357 bezNb--;
358 }
359 }
360 break;
361 }
362 }
363 bpath[nb_cmd].code=NR_END;
364 return bpath;
365 }
367 void Path::LoadArtBPath(void *iV,NR::Matrix const &trans,bool doTransformation)
368 {
369 if ( iV == NULL ) return;
370 NArtBpath *bpath = (NArtBpath*)iV;
372 SetBackData (false);
373 Reset();
374 {
375 int i;
376 bool closed = false;
377 NR::Point lastX(0,0);
379 for (i = 0; bpath[i].code != NR_END; i++)
380 {
381 switch (bpath[i].code)
382 {
383 case NR_LINETO:
384 lastX[0] = bpath[i].x3;
385 lastX[1] = bpath[i].y3;
386 if ( doTransformation ) {
387 lastX*=trans;
388 }
389 LineTo (lastX);
390 break;
392 case NR_CURVETO:
393 {
394 NR::Point tmp,tms(0,0),tme(0,0),tm1,tm2;
395 tmp[0]=bpath[i].x3;
396 tmp[1]=bpath[i].y3;
397 tm1[0]=bpath[i].x1;
398 tm1[1]=bpath[i].y1;
399 tm2[0]=bpath[i].x2;
400 tm2[1]=bpath[i].y2;
401 if ( doTransformation ) {
402 tmp*=trans;
403 tm1*=trans;
404 tm2*=trans;
405 }
406 tms=3 * (tm1 - lastX);
407 tme=3 * (tmp - tm2);
408 CubicTo (tmp,tms,tme);
409 }
410 lastX[0] = bpath[i].x3;
411 lastX[1] = bpath[i].y3;
412 if ( doTransformation ) {
413 lastX*=trans;
414 }
415 break;
417 case NR_MOVETO_OPEN:
418 case NR_MOVETO:
419 if (closed) Close ();
420 closed = (bpath[i].code == NR_MOVETO);
421 lastX[0] = bpath[i].x3;
422 lastX[1] = bpath[i].y3;
423 if ( doTransformation ) {
424 lastX*=trans;
425 }
426 MoveTo (lastX);
427 break;
428 default:
429 break;
430 }
431 }
432 if (closed) Close ();
433 }
434 }
437 /**
438 * \return Length of the lines in the pts vector.
439 */
441 double Path::Length()
442 {
443 if ( pts.empty() ) {
444 return 0;
445 }
447 NR::Point lastP = pts[0].p;
449 double len = 0;
450 for (std::vector<path_lineto>::const_iterator i = pts.begin(); i != pts.end(); i++) {
452 if ( i->isMoveTo != polyline_moveto ) {
453 len += NR::L2(i->p - lastP);
454 }
456 lastP = i->p;
457 }
459 return len;
460 }
463 double Path::Surface()
464 {
465 if ( pts.empty() ) {
466 return 0;
467 }
469 NR::Point lastM = pts[0].p;
470 NR::Point lastP = lastM;
472 double surf = 0;
473 for (std::vector<path_lineto>::const_iterator i = pts.begin(); i != pts.end(); i++) {
475 if ( i->isMoveTo == polyline_moveto ) {
476 surf += NR::cross(lastM - lastP, lastM);
477 lastP = lastM = i->p;
478 } else {
479 surf += NR::cross(i->p - lastP, i->p);
480 lastP = i->p;
481 }
483 }
485 return surf;
486 }
489 Path** Path::SubPaths(int &outNb,bool killNoSurf)
490 {
491 int nbRes=0;
492 Path** res=NULL;
493 Path* curAdd=NULL;
495 for (int i=0;i<int(descr_cmd.size());i++) {
496 int const typ = descr_cmd[i]->getType();
497 switch ( typ ) {
498 case descr_moveto:
499 if ( curAdd ) {
500 if ( curAdd->descr_cmd.size() > 1 ) {
501 curAdd->Convert(1.0);
502 double addSurf=curAdd->Surface();
503 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
504 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
505 res[nbRes++]=curAdd;
506 } else {
507 delete curAdd;
508 }
509 } else {
510 delete curAdd;
511 }
512 curAdd=NULL;
513 }
514 curAdd=new Path;
515 curAdd->SetBackData(false);
516 {
517 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
518 curAdd->MoveTo(nData->p);
519 }
520 break;
521 case descr_close:
522 {
523 curAdd->Close();
524 }
525 break;
526 case descr_lineto:
527 {
528 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
529 curAdd->LineTo(nData->p);
530 }
531 break;
532 case descr_cubicto:
533 {
534 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
535 curAdd->CubicTo(nData->p,nData->start,nData->end);
536 }
537 break;
538 case descr_arcto:
539 {
540 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
541 curAdd->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
542 }
543 break;
544 case descr_bezierto:
545 {
546 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
547 curAdd->BezierTo(nData->p);
548 }
549 break;
550 case descr_interm_bezier:
551 {
552 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
553 curAdd->IntermBezierTo(nData->p);
554 }
555 break;
556 default:
557 break;
558 }
559 }
560 if ( curAdd ) {
561 if ( curAdd->descr_cmd.size() > 1 ) {
562 curAdd->Convert(1.0);
563 double addSurf=curAdd->Surface();
564 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
565 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
566 res[nbRes++]=curAdd;
567 } else {
568 delete curAdd;
569 }
570 } else {
571 delete curAdd;
572 }
573 }
574 curAdd=NULL;
576 outNb=nbRes;
577 return res;
578 }
579 Path** Path::SubPathsWithNesting(int &outNb,bool killNoSurf,int nbNest,int* nesting,int* conts)
580 {
581 int nbRes=0;
582 Path** res=NULL;
583 Path* curAdd=NULL;
584 bool increment=false;
586 for (int i=0;i<int(descr_cmd.size());i++) {
587 int const typ = descr_cmd[i]->getType();
588 switch ( typ ) {
589 case descr_moveto:
590 {
591 if ( curAdd && increment == false ) {
592 if ( curAdd->descr_cmd.size() > 1 ) {
593 // sauvegarder descr_cmd[0]->associated
594 int savA=curAdd->descr_cmd[0]->associated;
595 curAdd->Convert(1.0);
596 curAdd->descr_cmd[0]->associated=savA; // associated n'est pas utilise apres
597 double addSurf=curAdd->Surface();
598 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
599 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
600 res[nbRes++]=curAdd;
601 } else {
602 delete curAdd;
603 }
604 } else {
605 delete curAdd;
606 }
607 curAdd=NULL;
608 }
609 Path* hasDad=NULL;
610 for (int j=0;j<nbNest;j++) {
611 if ( conts[j] == i && nesting[j] >= 0 ) {
612 int dadMvt=conts[nesting[j]];
613 for (int k=0;k<nbRes;k++) {
614 if ( res[k] && res[k]->descr_cmd.empty() == false && res[k]->descr_cmd[0]->associated == dadMvt ) {
615 hasDad=res[k];
616 break;
617 }
618 }
619 }
620 if ( conts[j] > i ) break;
621 }
622 if ( hasDad ) {
623 curAdd=hasDad;
624 increment=true;
625 } else {
626 curAdd=new Path;
627 curAdd->SetBackData(false);
628 increment=false;
629 }
630 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
631 int mNo=curAdd->MoveTo(nData->p);
632 curAdd->descr_cmd[mNo]->associated=i;
633 }
634 break;
635 case descr_close:
636 {
637 curAdd->Close();
638 }
639 break;
640 case descr_lineto:
641 {
642 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
643 curAdd->LineTo(nData->p);
644 }
645 break;
646 case descr_cubicto:
647 {
648 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
649 curAdd->CubicTo(nData->p,nData->start,nData->end);
650 }
651 break;
652 case descr_arcto:
653 {
654 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
655 curAdd->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
656 }
657 break;
658 case descr_bezierto:
659 {
660 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
661 curAdd->BezierTo(nData->p);
662 }
663 break;
664 case descr_interm_bezier:
665 {
666 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
667 curAdd->IntermBezierTo(nData->p);
668 }
669 break;
670 default:
671 break;
672 }
673 }
674 if ( curAdd && increment == false ) {
675 if ( curAdd->descr_cmd.size() > 1 ) {
676 curAdd->Convert(1.0);
677 double addSurf=curAdd->Surface();
678 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
679 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
680 res[nbRes++]=curAdd;
681 } else {
682 delete curAdd;
683 }
684 } else {
685 delete curAdd;
686 }
687 }
688 curAdd=NULL;
690 outNb=nbRes;
691 return res;
692 }
695 void Path::ConvertForcedToVoid()
696 {
697 for (int i=0; i < int(descr_cmd.size()); i++) {
698 if ( descr_cmd[i]->getType() == descr_forced) {
699 delete descr_cmd[i];
700 descr_cmd.erase(descr_cmd.begin() + i);
701 }
702 }
703 }
706 void Path::ConvertForcedToMoveTo()
707 {
708 NR::Point lastSeen(0, 0);
709 NR::Point lastMove(0, 0);
711 {
712 NR::Point lastPos(0, 0);
713 for (int i = int(descr_cmd.size()) - 1; i >= 0; i--) {
714 int const typ = descr_cmd[i]->getType();
715 switch ( typ ) {
716 case descr_forced:
717 {
718 PathDescrForced *d = dynamic_cast<PathDescrForced *>(descr_cmd[i]);
719 d->p = lastPos;
720 break;
721 }
722 case descr_close:
723 {
724 PathDescrClose *d = dynamic_cast<PathDescrClose *>(descr_cmd[i]);
725 d->p = lastPos;
726 break;
727 }
728 case descr_moveto:
729 {
730 PathDescrMoveTo *d = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
731 lastPos = d->p;
732 break;
733 }
734 case descr_lineto:
735 {
736 PathDescrLineTo *d = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
737 lastPos = d->p;
738 break;
739 }
740 case descr_arcto:
741 {
742 PathDescrArcTo *d = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
743 lastPos = d->p;
744 break;
745 }
746 case descr_cubicto:
747 {
748 PathDescrCubicTo *d = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
749 lastPos = d->p;
750 break;
751 }
752 case descr_bezierto:
753 {
754 PathDescrBezierTo *d = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
755 lastPos = d->p;
756 break;
757 }
758 case descr_interm_bezier:
759 {
760 PathDescrIntermBezierTo *d = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
761 lastPos = d->p;
762 break;
763 }
764 default:
765 break;
766 }
767 }
768 }
770 bool hasMoved = false;
771 for (int i = 0; i < int(descr_cmd.size()); i++) {
772 int const typ = descr_cmd[i]->getType();
773 switch ( typ ) {
774 case descr_forced:
775 if ( i < int(descr_cmd.size()) - 1 && hasMoved ) { // sinon il termine le chemin
777 delete descr_cmd[i];
778 descr_cmd[i] = new PathDescrMoveTo(lastSeen);
779 lastMove = lastSeen;
780 hasMoved = true;
781 }
782 break;
784 case descr_moveto:
785 {
786 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
787 lastMove = lastSeen = nData->p;
788 hasMoved = true;
789 }
790 break;
791 case descr_close:
792 {
793 lastSeen=lastMove;
794 }
795 break;
796 case descr_lineto:
797 {
798 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
799 lastSeen=nData->p;
800 }
801 break;
802 case descr_cubicto:
803 {
804 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
805 lastSeen=nData->p;
806 }
807 break;
808 case descr_arcto:
809 {
810 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
811 lastSeen=nData->p;
812 }
813 break;
814 case descr_bezierto:
815 {
816 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
817 lastSeen=nData->p;
818 }
819 break;
820 case descr_interm_bezier:
821 {
822 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
823 lastSeen=nData->p;
824 }
825 break;
826 default:
827 break;
828 }
829 }
830 }
831 static int CmpPosition(const void * p1, const void * p2) {
832 Path::cut_position *cp1=(Path::cut_position*)p1;
833 Path::cut_position *cp2=(Path::cut_position*)p2;
834 if ( cp1->piece < cp2->piece ) return -1;
835 if ( cp1->piece > cp2->piece ) return 1;
836 if ( cp1->t < cp2->t ) return -1;
837 if ( cp1->t > cp2->t ) return 1;
838 return 0;
839 }
840 static int CmpCurv(const void * p1, const void * p2) {
841 double *cp1=(double*)p1;
842 double *cp2=(double*)p2;
843 if ( *cp1 < *cp2 ) return -1;
844 if ( *cp1 > *cp2 ) return 1;
845 return 0;
846 }
849 Path::cut_position* Path::CurvilignToPosition(int nbCv, double *cvAbs, int &nbCut)
850 {
851 if ( nbCv <= 0 || pts.empty() || back == false ) {
852 return NULL;
853 }
855 qsort(cvAbs, nbCv, sizeof(double), CmpCurv);
857 cut_position *res = NULL;
858 nbCut = 0;
859 int curCv = 0;
861 double len = 0;
862 double lastT = 0;
863 int lastPiece = -1;
865 NR::Point lastM = pts[0].p;
866 NR::Point lastP = lastM;
868 for (std::vector<path_lineto>::const_iterator i = pts.begin(); i != pts.end(); i++) {
870 if ( i->isMoveTo == polyline_moveto ) {
872 lastP = lastM = i->p;
873 lastT = i->t;
874 lastPiece = i->piece;
876 } else {
878 double const add = NR::L2(i->p - lastP);
879 double curPos = len;
880 double curAdd = add;
882 while ( curAdd > 0.0001 && curCv < nbCv && curPos + curAdd >= cvAbs[curCv] ) {
883 double const theta = (cvAbs[curCv] - len) / add;
884 res = (cut_position*) g_realloc(res, (nbCut + 1) * sizeof(cut_position));
885 res[nbCut].piece = i->piece;
886 res[nbCut].t = theta * i->t + (1 - theta) * ( (lastPiece != i->piece) ? 0 : lastT);
887 nbCut++;
888 curAdd -= cvAbs[curCv] - curPos;
889 curPos = cvAbs[curCv];
890 curCv++;
891 }
893 len += add;
894 lastPiece = i->piece;
895 lastP = i->p;
896 lastT = i->t;
897 }
898 }
900 return res;
901 }
903 /*
904 Moved from Layout-TNG-OutIter.cpp
905 TODO: clean up uses of the original function and remove
907 Original Comment:
908 "this function really belongs to Path. I'll probably move it there eventually,
909 hence the Path-esque coding style"
911 */
912 template<typename T> inline static T square(T x) {return x*x;}
913 Path::cut_position Path::PointToCurvilignPosition(NR::Point const &pos) const
914 {
915 unsigned bestSeg = 0;
916 double bestRangeSquared = DBL_MAX;
917 double bestT = 0.0; // you need a sentinel, or make sure that you prime with correct values.
919 for (unsigned i = 1 ; i < pts.size() ; i++) {
920 if (pts[i].isMoveTo == polyline_moveto) continue;
921 NR::Point p1, p2, localPos;
922 double thisRangeSquared;
923 double t;
925 if (pts[i - 1].p == pts[i].p) {
926 thisRangeSquared = square(pts[i].p[NR::X] - pos[NR::X]) + square(pts[i].p[NR::Y] - pos[NR::Y]);
927 t = 0.0;
928 } else {
929 // we rotate all our coordinates so we're always looking at a mostly vertical line.
930 if (fabs(pts[i - 1].p[NR::X] - pts[i].p[NR::X]) < fabs(pts[i - 1].p[NR::Y] - pts[i].p[NR::Y])) {
931 p1 = pts[i - 1].p;
932 p2 = pts[i].p;
933 localPos = pos;
934 } else {
935 p1 = pts[i - 1].p.cw();
936 p2 = pts[i].p.cw();
937 localPos = pos.cw();
938 }
939 double gradient = (p2[NR::X] - p1[NR::X]) / (p2[NR::Y] - p1[NR::Y]);
940 double intersection = p1[NR::X] - gradient * p1[NR::Y];
941 /*
942 orthogonalGradient = -1.0 / gradient; // you are going to have numerical problems here.
943 orthogonalIntersection = localPos[NR::X] - orthogonalGradient * localPos[NR::Y];
944 nearestY = (orthogonalIntersection - intersection) / (gradient - orthogonalGradient);
946 expand out nearestY fully :
947 nearestY = (localPos[NR::X] - (-1.0 / gradient) * localPos[NR::Y] - intersection) / (gradient - (-1.0 / gradient));
949 multiply top and bottom by gradient:
950 nearestY = (localPos[NR::X] * gradient - (-1.0) * localPos[NR::Y] - intersection * gradient) / (gradient * gradient - (-1.0));
952 and simplify to get:
953 */
954 double nearestY = (localPos[NR::X] * gradient + localPos[NR::Y] - intersection * gradient)
955 / (gradient * gradient + 1.0);
956 t = (nearestY - p1[NR::Y]) / (p2[NR::Y] - p1[NR::Y]);
957 if (t <= 0.0) thisRangeSquared = square(p1[NR::X] - localPos[NR::X]) + square(p1[NR::Y] - localPos[NR::Y]);
958 else if (t >= 1.0) thisRangeSquared = square(p2[NR::X] - localPos[NR::X]) + square(p2[NR::Y] - localPos[NR::Y]);
959 else thisRangeSquared = square(nearestY * gradient + intersection - localPos[NR::X]) + square(nearestY - localPos[NR::Y]);
960 }
962 if (thisRangeSquared < bestRangeSquared) {
963 bestSeg = i;
964 bestRangeSquared = thisRangeSquared;
965 bestT = t;
966 }
967 }
968 Path::cut_position result;
969 if (bestSeg == 0) {
970 result.piece = 0;
971 result.t = 0.0;
972 } else {
973 result.piece = pts[bestSeg].piece;
974 if (result.piece == pts[bestSeg - 1].piece)
975 result.t = pts[bestSeg - 1].t * (1.0 - bestT) + pts[bestSeg].t * bestT;
976 else
977 result.t = pts[bestSeg].t * bestT;
978 }
979 return result;
980 }
981 /*
982 this one also belongs to Path
983 returns the length of the path up to the position indicated by t (0..1)
985 TODO: clean up uses of the original function and remove
987 should this take a cut_position as a parameter?
988 */
989 double Path::PositionToLength(int piece, double t)
990 {
991 double length = 0.0;
992 for (unsigned i = 1 ; i < pts.size() ; i++) {
993 if (pts[i].isMoveTo == polyline_moveto) continue;
994 if (pts[i].piece == piece && t < pts[i].t) {
995 length += NR::L2((t - pts[i - 1].t) / (pts[i].t - pts[i - 1].t) * (pts[i].p - pts[i - 1].p));
996 break;
997 }
998 length += NR::L2(pts[i].p - pts[i - 1].p);
999 }
1000 return length;
1001 }
1003 void Path::ConvertPositionsToForced(int nbPos, cut_position *poss)
1004 {
1005 if ( nbPos <= 0 ) {
1006 return;
1007 }
1009 {
1010 NR::Point lastPos(0, 0);
1011 for (int i = int(descr_cmd.size()) - 1; i >= 0; i--) {
1012 int const typ = descr_cmd[i]->getType();
1013 switch ( typ ) {
1015 case descr_forced:
1016 {
1017 PathDescrForced *d = dynamic_cast<PathDescrForced *>(descr_cmd[i]);
1018 d->p = lastPos;
1019 break;
1020 }
1022 case descr_close:
1023 {
1024 delete descr_cmd[i];
1025 descr_cmd[i] = new PathDescrLineTo(NR::Point(0, 0));
1027 int fp = i - 1;
1028 while ( fp >= 0 && (descr_cmd[fp]->getType()) != descr_moveto ) {
1029 fp--;
1030 }
1032 if ( fp >= 0 ) {
1033 PathDescrMoveTo *oData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[fp]);
1034 dynamic_cast<PathDescrLineTo*>(descr_cmd[i])->p = oData->p;
1035 }
1036 }
1037 break;
1039 case descr_bezierto:
1040 {
1041 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
1042 NR::Point theP = nData->p;
1043 if ( nData->nb == 0 ) {
1044 lastPos = theP;
1045 }
1046 }
1047 break;
1049 case descr_moveto:
1050 {
1051 PathDescrMoveTo *d = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
1052 lastPos = d->p;
1053 break;
1054 }
1055 case descr_lineto:
1056 {
1057 PathDescrLineTo *d = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
1058 lastPos = d->p;
1059 break;
1060 }
1061 case descr_arcto:
1062 {
1063 PathDescrArcTo *d = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
1064 lastPos = d->p;
1065 break;
1066 }
1067 case descr_cubicto:
1068 {
1069 PathDescrCubicTo *d = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
1070 lastPos = d->p;
1071 break;
1072 }
1073 case descr_interm_bezier:
1074 {
1075 PathDescrIntermBezierTo *d = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
1076 lastPos = d->p;
1077 break;
1078 }
1079 default:
1080 break;
1081 }
1082 }
1083 }
1085 qsort(poss, nbPos, sizeof(cut_position), CmpPosition);
1087 for (int curP=0;curP<nbPos;curP++) {
1088 int cp=poss[curP].piece;
1089 if ( cp < 0 || cp >= int(descr_cmd.size()) ) break;
1090 float ct=poss[curP].t;
1091 if ( ct < 0 ) continue;
1092 if ( ct > 1 ) continue;
1094 int const typ = descr_cmd[cp]->getType();
1095 if ( typ == descr_moveto || typ == descr_forced || typ == descr_close ) {
1096 // ponctuel= rien a faire
1097 } else if ( typ == descr_lineto || typ == descr_arcto || typ == descr_cubicto ) {
1098 // facile: creation d'un morceau et d'un forced -> 2 commandes
1099 NR::Point theP;
1100 NR::Point theT;
1101 NR::Point startP;
1102 startP=PrevPoint(cp-1);
1103 if ( typ == descr_cubicto ) {
1104 double len,rad;
1105 NR::Point stD,enD,endP;
1106 {
1107 PathDescrCubicTo *oData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[cp]);
1108 stD=oData->start;
1109 enD=oData->end;
1110 endP=oData->p;
1111 TangentOnCubAt (ct, startP, *oData,true, theP,theT,len,rad);
1112 }
1114 theT*=len;
1116 InsertCubicTo(endP,(1-ct)*theT,(1-ct)*enD,cp+1);
1117 InsertForcePoint(cp+1);
1118 {
1119 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[cp]);
1120 nData->start=ct*stD;
1121 nData->end=ct*theT;
1122 nData->p=theP;
1123 }
1124 // decalages dans le tableau des positions de coupe
1125 for (int j=curP+1;j<nbPos;j++) {
1126 if ( poss[j].piece == cp ) {
1127 poss[j].piece+=2;
1128 poss[j].t=(poss[j].t-ct)/(1-ct);
1129 } else {
1130 poss[j].piece+=2;
1131 }
1132 }
1133 } else if ( typ == descr_lineto ) {
1134 NR::Point endP;
1135 {
1136 PathDescrLineTo *oData = dynamic_cast<PathDescrLineTo *>(descr_cmd[cp]);
1137 endP=oData->p;
1138 }
1140 theP=ct*endP+(1-ct)*startP;
1142 InsertLineTo(endP,cp+1);
1143 InsertForcePoint(cp+1);
1144 {
1145 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[cp]);
1146 nData->p=theP;
1147 }
1148 // decalages dans le tableau des positions de coupe
1149 for (int j=curP+1;j<nbPos;j++) {
1150 if ( poss[j].piece == cp ) {
1151 poss[j].piece+=2;
1152 poss[j].t=(poss[j].t-ct)/(1-ct);
1153 } else {
1154 poss[j].piece+=2;
1155 }
1156 }
1157 } else if ( typ == descr_arcto ) {
1158 NR::Point endP;
1159 double rx,ry,angle;
1160 bool clockw,large;
1161 double delta=0;
1162 {
1163 PathDescrArcTo *oData = dynamic_cast<PathDescrArcTo *>(descr_cmd[cp]);
1164 endP=oData->p;
1165 rx=oData->rx;
1166 ry=oData->ry;
1167 angle=oData->angle;
1168 clockw=oData->clockwise;
1169 large=oData->large;
1170 }
1171 {
1172 double sang,eang;
1173 ArcAngles(startP,endP,rx,ry,angle,large,clockw,sang,eang);
1175 if (clockw) {
1176 if ( sang < eang ) sang += 2*M_PI;
1177 delta=eang-sang;
1178 } else {
1179 if ( sang > eang ) sang -= 2*M_PI;
1180 delta=eang-sang;
1181 }
1182 if ( delta < 0 ) delta=-delta;
1183 }
1185 PointAt (cp,ct, theP);
1187 if ( delta*(1-ct) > M_PI ) {
1188 InsertArcTo(endP,rx,ry,angle,true,clockw,cp+1);
1189 } else {
1190 InsertArcTo(endP,rx,ry,angle,false,clockw,cp+1);
1191 }
1192 InsertForcePoint(cp+1);
1193 {
1194 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[cp]);
1195 nData->p=theP;
1196 if ( delta*ct > M_PI ) {
1197 nData->clockwise=true;
1198 } else {
1199 nData->clockwise=false;
1200 }
1201 }
1202 // decalages dans le tableau des positions de coupe
1203 for (int j=curP+1;j<nbPos;j++) {
1204 if ( poss[j].piece == cp ) {
1205 poss[j].piece+=2;
1206 poss[j].t=(poss[j].t-ct)/(1-ct);
1207 } else {
1208 poss[j].piece+=2;
1209 }
1210 }
1211 }
1212 } else if ( typ == descr_bezierto || typ == descr_interm_bezier ) {
1213 // dur
1214 int theBDI=cp;
1215 while ( theBDI >= 0 && (descr_cmd[theBDI]->getType()) != descr_bezierto ) theBDI--;
1216 if ( (descr_cmd[theBDI]->getType()) == descr_bezierto ) {
1217 PathDescrBezierTo theBD=*(dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]));
1218 if ( cp >= theBDI && cp < theBDI+theBD.nb ) {
1219 if ( theBD.nb == 1 ) {
1220 NR::Point endP=theBD.p;
1221 NR::Point midP;
1222 NR::Point startP;
1223 startP=PrevPoint(theBDI-1);
1224 {
1225 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[theBDI+1]);
1226 midP=nData->p;
1227 }
1228 NR::Point aP=ct*midP+(1-ct)*startP;
1229 NR::Point bP=ct*endP+(1-ct)*midP;
1230 NR::Point knotP=ct*bP+(1-ct)*aP;
1232 InsertIntermBezierTo(bP,theBDI+2);
1233 InsertBezierTo(knotP,1,theBDI+2);
1234 InsertForcePoint(theBDI+2);
1235 {
1236 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[theBDI+1]);
1237 nData->p=aP;
1238 }
1239 {
1240 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]);
1241 nData->p=knotP;
1242 }
1243 // decalages dans le tableau des positions de coupe
1244 for (int j=curP+1;j<nbPos;j++) {
1245 if ( poss[j].piece == cp ) {
1246 poss[j].piece+=3;
1247 poss[j].t=(poss[j].t-ct)/(1-ct);
1248 } else {
1249 poss[j].piece+=3;
1250 }
1251 }
1253 } else {
1254 // decouper puis repasser
1255 if ( cp > theBDI ) {
1256 NR::Point pcP,ncP;
1257 {
1258 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp]);
1259 pcP=nData->p;
1260 }
1261 {
1262 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp+1]);
1263 ncP=nData->p;
1264 }
1265 NR::Point knotP=0.5*(pcP+ncP);
1267 InsertBezierTo(knotP,theBD.nb-(cp-theBDI),cp+1);
1268 {
1269 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]);
1270 nData->nb=cp-theBDI;
1271 }
1273 // decalages dans le tableau des positions de coupe
1274 for (int j=curP;j<nbPos;j++) {
1275 if ( poss[j].piece == cp ) {
1276 poss[j].piece+=1;
1277 } else {
1278 poss[j].piece+=1;
1279 }
1280 }
1281 curP--;
1282 } else {
1283 NR::Point pcP,ncP;
1284 {
1285 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp+1]);
1286 pcP=nData->p;
1287 }
1288 {
1289 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp+2]);
1290 ncP=nData->p;
1291 }
1292 NR::Point knotP=0.5*(pcP+ncP);
1294 InsertBezierTo(knotP,theBD.nb-1,cp+2);
1295 {
1296 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]);
1297 nData->nb=1;
1298 }
1300 // decalages dans le tableau des positions de coupe
1301 for (int j=curP;j<nbPos;j++) {
1302 if ( poss[j].piece == cp ) {
1303 // poss[j].piece+=1;
1304 } else {
1305 poss[j].piece+=1;
1306 }
1307 }
1308 curP--;
1309 }
1310 }
1311 } else {
1312 // on laisse aussi tomber
1313 }
1314 } else {
1315 // on laisse tomber
1316 }
1317 }
1318 }
1319 }
1321 void Path::ConvertPositionsToMoveTo(int nbPos,cut_position* poss)
1322 {
1323 ConvertPositionsToForced(nbPos,poss);
1324 // ConvertForcedToMoveTo();
1325 // on fait une version customizee a la place
1327 Path* res=new Path;
1329 NR::Point lastP(0,0);
1330 for (int i=0;i<int(descr_cmd.size());i++) {
1331 int const typ = descr_cmd[i]->getType();
1332 if ( typ == descr_moveto ) {
1333 NR::Point np;
1334 {
1335 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
1336 np=nData->p;
1337 }
1338 NR::Point endP;
1339 bool hasClose=false;
1340 int hasForced=-1;
1341 bool doesClose=false;
1342 int j=i+1;
1343 for (;j<int(descr_cmd.size());j++) {
1344 int const ntyp = descr_cmd[j]->getType();
1345 if ( ntyp == descr_moveto ) {
1346 j--;
1347 break;
1348 } else if ( ntyp == descr_forced ) {
1349 if ( hasForced < 0 ) hasForced=j;
1350 } else if ( ntyp == descr_close ) {
1351 hasClose=true;
1352 break;
1353 } else if ( ntyp == descr_lineto ) {
1354 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[j]);
1355 endP=nData->p;
1356 } else if ( ntyp == descr_arcto ) {
1357 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[j]);
1358 endP=nData->p;
1359 } else if ( ntyp == descr_cubicto ) {
1360 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[j]);
1361 endP=nData->p;
1362 } else if ( ntyp == descr_bezierto ) {
1363 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[j]);
1364 endP=nData->p;
1365 } else {
1366 }
1367 }
1368 if ( NR::LInfty(endP-np) < 0.00001 ) {
1369 doesClose=true;
1370 }
1371 if ( ( doesClose || hasClose ) && hasForced >= 0 ) {
1372 // printf("nasty i=%i j=%i frc=%i\n",i,j,hasForced);
1373 // aghhh.
1374 NR::Point nMvtP=PrevPoint(hasForced);
1375 res->MoveTo(nMvtP);
1376 NR::Point nLastP=nMvtP;
1377 for (int k = hasForced + 1; k < j; k++) {
1378 int ntyp=descr_cmd[k]->getType();
1379 if ( ntyp == descr_moveto ) {
1380 // ne doit pas arriver
1381 } else if ( ntyp == descr_forced ) {
1382 res->MoveTo(nLastP);
1383 } else if ( ntyp == descr_close ) {
1384 // rien a faire ici; de plus il ne peut y en avoir qu'un
1385 } else if ( ntyp == descr_lineto ) {
1386 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[k]);
1387 res->LineTo(nData->p);
1388 nLastP=nData->p;
1389 } else if ( ntyp == descr_arcto ) {
1390 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[k]);
1391 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1392 nLastP=nData->p;
1393 } else if ( ntyp == descr_cubicto ) {
1394 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[k]);
1395 res->CubicTo(nData->p,nData->start,nData->end);
1396 nLastP=nData->p;
1397 } else if ( ntyp == descr_bezierto ) {
1398 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[k]);
1399 res->BezierTo(nData->p);
1400 nLastP=nData->p;
1401 } else if ( ntyp == descr_interm_bezier ) {
1402 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[k]);
1403 res->IntermBezierTo(nData->p);
1404 } else {
1405 }
1406 }
1407 if ( doesClose == false ) res->LineTo(np);
1408 nLastP=np;
1409 for (int k=i+1;k<hasForced;k++) {
1410 int ntyp=descr_cmd[k]->getType();
1411 if ( ntyp == descr_moveto ) {
1412 // ne doit pas arriver
1413 } else if ( ntyp == descr_forced ) {
1414 res->MoveTo(nLastP);
1415 } else if ( ntyp == descr_close ) {
1416 // rien a faire ici; de plus il ne peut y en avoir qu'un
1417 } else if ( ntyp == descr_lineto ) {
1418 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[k]);
1419 res->LineTo(nData->p);
1420 nLastP=nData->p;
1421 } else if ( ntyp == descr_arcto ) {
1422 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[k]);
1423 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1424 nLastP=nData->p;
1425 } else if ( ntyp == descr_cubicto ) {
1426 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[k]);
1427 res->CubicTo(nData->p,nData->start,nData->end);
1428 nLastP=nData->p;
1429 } else if ( ntyp == descr_bezierto ) {
1430 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[k]);
1431 res->BezierTo(nData->p);
1432 nLastP=nData->p;
1433 } else if ( ntyp == descr_interm_bezier ) {
1434 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[k]);
1435 res->IntermBezierTo(nData->p);
1436 } else {
1437 }
1438 }
1439 lastP=nMvtP;
1440 i=j;
1441 } else {
1442 // regular, just move on
1443 res->MoveTo(np);
1444 lastP=np;
1445 }
1446 } else if ( typ == descr_close ) {
1447 res->Close();
1448 } else if ( typ == descr_forced ) {
1449 res->MoveTo(lastP);
1450 } else if ( typ == descr_lineto ) {
1451 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
1452 res->LineTo(nData->p);
1453 lastP=nData->p;
1454 } else if ( typ == descr_arcto ) {
1455 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
1456 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1457 lastP=nData->p;
1458 } else if ( typ == descr_cubicto ) {
1459 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
1460 res->CubicTo(nData->p,nData->start,nData->end);
1461 lastP=nData->p;
1462 } else if ( typ == descr_bezierto ) {
1463 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
1464 res->BezierTo(nData->p);
1465 lastP=nData->p;
1466 } else if ( typ == descr_interm_bezier ) {
1467 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
1468 res->IntermBezierTo(nData->p);
1469 } else {
1470 }
1471 }
1473 Copy(res);
1474 delete res;
1475 return;
1476 }
1478 /*
1479 Local Variables:
1480 mode:c++
1481 c-file-style:"stroustrup"
1482 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1483 indent-tabs-mode:nil
1484 fill-column:99
1485 End:
1486 */
1487 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :