Code

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