Code

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