Code

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