Code

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