Code

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