Code

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