Code

added fix from Dale Harvey to expand incomplete JIDs specified in user
[inkscape.git] / src / livarot / PathCutting.cpp
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();
21   
22   int       lastMI=-1;
23   int curP = 0;
24   int lastMP = -1;
25   
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;
46   
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   }
59   
60   if ( totLength <= head+tail ) return; // tout mange par la tete et la queue
61   
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;
169             
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   }
218 #include "../display/canvas-bpath.h"
220 void* Path::MakeArtBPath(void)
222         int                              nb_cmd=0,max_cmd=0;
223         NArtBpath* bpath=(NArtBpath*)g_malloc((max_cmd+1)*sizeof(NArtBpath));
224         
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                                         }
342                                         
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++;
356                                         
357                                         bezNb--;
358                                 }
359                         }
360         break;
361     }
362   }
363         bpath[nb_cmd].code=NR_END;
364         return bpath;
367 void  Path::LoadArtBPath(void *iV,NR::Matrix const &trans,bool doTransformation)
369   if ( iV == NULL ) return;
370   NArtBpath *bpath = (NArtBpath*)iV;
371   
372   SetBackData (false);
373   Reset();
374   {
375     int   i;
376     bool  closed = false;
377     NR::Point lastX(0,0);
378     
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;
391           
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;
416           
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   }
437 /**
438  *    \return Length of the lines in the pts vector.
439  */
441 double Path::Length()
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     }
458     
459     return len;
463 double Path::Surface()
465     if ( pts.empty() ) {
466         return 0;
467     }
468     
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         }
482         
483     }
484     
485   return surf;
489 Path**      Path::SubPaths(int &outNb,bool killNoSurf)
491   int      nbRes=0;
492   Path**   res=NULL;
493   Path*    curAdd=NULL;
494   
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;
575   
576   outNb=nbRes;
577   return res;
579 Path**      Path::SubPathsWithNesting(int &outNb,bool killNoSurf,int nbNest,int* nesting,int* conts)
581   int      nbRes=0;
582   Path**   res=NULL;
583   Path*    curAdd=NULL;
584   bool     increment=false;
585   
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;
689   
690   outNb=nbRes;
691   return res;
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     }
706 void Path::ConvertForcedToMoveTo()
707 {  
708     NR::Point lastSeen(0, 0);
709     NR::Point lastMove(0, 0);
710     
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;
783             
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   }
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;
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;
849 Path::cut_position* Path::CurvilignToPosition(int nbCv, double *cvAbs, int &nbCut)
851     if ( nbCv <= 0 || pts.empty() || back == false ) {
852         return NULL;
853     }
854   
855     qsort(cvAbs, nbCv, sizeof(double), CmpCurv);
856   
857     cut_position *res = NULL;
858     nbCut = 0;
859     int curCv = 0;
860   
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 {
877             
878             double const add = NR::L2(i->p - lastP);
879             double curPos = len;
880             double curAdd = add;
881             
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             }
892             
893             len += add;
894             lastPiece = i->piece;
895             lastP = i->p;
896             lastT = i->t;
897         }
898     }
899     
900     return res;
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
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;
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)
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;
1003 void Path::ConvertPositionsToForced(int nbPos, cut_position *poss)
1005     if ( nbPos <= 0 ) {
1006         return;
1007     }
1008     
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 ) {
1014                 
1015             case descr_forced:
1016             {
1017                 PathDescrForced *d = dynamic_cast<PathDescrForced *>(descr_cmd[i]);
1018                 d->p = lastPos;
1019                 break;
1020             }
1021                 
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                 }
1031                 
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;
1038             
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;
1048             
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;
1093         
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         }
1113         
1114         theT*=len;
1115         
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;
1141         
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);
1174           
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         }
1184         
1185         PointAt (cp,ct, theP);
1186         
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;
1231                         
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             }
1252             
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);
1266               
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               }
1272               
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);
1293               
1294               InsertBezierTo(knotP,theBD.nb-1,cp+2);
1295               {
1296                 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]);
1297                 nData->nb=1;
1298               }
1299               
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   }
1321 void        Path::ConvertPositionsToMoveTo(int nbPos,cut_position* poss)
1323   ConvertPositionsToForced(nbPos,poss);
1324 //  ConvertForcedToMoveTo();
1325   // on fait une version customizee a la place
1327   Path*  res=new Path;
1328   
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;
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 :