Code

7590500af08fbdd8c0ae4a170641b80a1df16bef
[inkscape.git] / src / livarot / ShapeMisc.cpp
1 /*
2  *  ShapeMisc.cpp
3  *  nlivarot
4  *
5  *  Created by fred on Sun Jul 20 2003.
6  *
7  */
9 #include "livarot/Shape.h"
10 #include <libnr/nr-point-fns.h>
11 #include "livarot/Path.h"
12 #include "livarot/path-description.h"
13 #include <glib.h>
15 /*
16  * polygon offset and polyline to path reassembling (when using back data)
17  */
19 // until i find something better
20 #define MiscNormalize(v) {\
21   double _l=sqrt(dot(v,v)); \
22     if ( _l < 0.0000001 ) { \
23       v[0]=v[1]=0; \
24     } else { \
25       v/=_l; \
26     }\
27 }
29 // extracting the contour of an uncrossed polygon: a mere depth first search
30 // more precisely that's extracting an eulerian path from a graph, but here we want to split
31 // the polygon into contours and avoid holes. so we take a "next counter-clockwise edge first" approach
32 // (make a checkboard and extract its contours to see the difference)
33 void
34 Shape::ConvertToForme (Path * dest)
35 {
36   if (numberOfPoints() <= 1 || numberOfEdges() <= 1)
37     return;
38   
39   // prepare
40   dest->Reset ();
41   
42   MakePointData (true);
43   MakeEdgeData (true);
44   MakeSweepDestData (true);
45   
46   for (int i = 0; i < numberOfPoints(); i++)
47   {
48     pData[i].rx[0] = Round (getPoint(i).x[0]);
49     pData[i].rx[1] = Round (getPoint(i).x[1]);
50   }
51   for (int i = 0; i < numberOfEdges(); i++)
52   {
53     eData[i].rdx = pData[getEdge(i).en].rx - pData[getEdge(i).st].rx;
54   }
55   
56   // sort edge clockwise, with the closest after midnight being first in the doubly-linked list
57   // that's vital to the algorithm...
58   SortEdges ();
59   
60   // depth-first search implies: we make a stack of edges traversed.
61   // precParc: previous in the stack
62   // suivParc: next in the stack
63   for (int i = 0; i < numberOfEdges(); i++)
64   {
65     swdData[i].misc = 0;
66     swdData[i].precParc = swdData[i].suivParc = -1;
67   }
68   
69   int searchInd = 0;
70   
71   int lastPtUsed = 0;
72   do
73   {
74     // first get a starting point, and a starting edge
75     // -> take the upper left point, and take its first edge
76     // points traversed have swdData[].misc != 0, so it's easy
77     int startBord = -1;
78     {
79       int fi = 0;
80       for (fi = lastPtUsed; fi < numberOfPoints(); fi++)
81       {
82         if (getPoint(fi).incidentEdge[FIRST] >= 0 && swdData[getPoint(fi).incidentEdge[FIRST]].misc == 0)
83           break;
84       }
85       lastPtUsed = fi + 1;
86       if (fi < numberOfPoints())
87       {
88         int bestB = getPoint(fi).incidentEdge[FIRST];
89         while (bestB >= 0 && getEdge(bestB).st != fi)
90           bestB = NextAt (fi, bestB);
91         if (bestB >= 0)
92               {
93           startBord = bestB;
94           dest->MoveTo (getPoint(getEdge(startBord).en).x);
95               }
96       }
97     }
98     // and walk the graph, doing contours when needed
99     if (startBord >= 0)
100     {
101       // parcours en profondeur pour mettre les leF et riF a leurs valeurs
102       swdData[startBord].misc = (void *) 1;
103       //                      printf("part de %d\n",startBord);
104       int curBord = startBord;
105       bool back = false;
106       swdData[curBord].precParc = -1;
107       swdData[curBord].suivParc = -1;
108       do
109             {
110               int cPt = getEdge(curBord).en;
111               int nb = curBord;
112         //                              printf("de curBord= %d au point %i  -> ",curBord,cPt);
113         // get next edge
114               do
115         {
116           int nnb = CycleNextAt (cPt, nb);
117           if (nnb == nb)
118           {
119             // cul-de-sac
120             nb = -1;
121             break;
122           }
123           nb = nnb;
124           if (nb < 0 || nb == curBord)
125             break;
126         }
127               while (swdData[nb].misc != 0 || getEdge(nb).st != cPt);
128         
129               if (nb < 0 || nb == curBord)
130         {
131           // no next edge: end of this contour, we get back
132           if (back == false)
133             dest->Close ();
134           back = true;
135           // retour en arriere
136           curBord = swdData[curBord].precParc;
137           //                                      printf("retour vers %d\n",curBord);
138           if (curBord < 0)
139             break;
140         }
141               else
142         {
143           // new edge, maybe for a new contour
144           if (back)
145           {
146             // we were backtracking, so if we have a new edge, that means we're creating a new contour
147             dest->MoveTo (getPoint(cPt).x);
148             back = false;
149           }
150           swdData[nb].misc = (void *) 1;
151           swdData[nb].ind = searchInd++;
152           swdData[nb].precParc = curBord;
153           swdData[curBord].suivParc = nb;
154           curBord = nb;
155           //                                      printf("suite %d\n",curBord);
156           {
157             // add that edge
158             dest->LineTo (getPoint(getEdge(nb).en).x);
159           }
160         }
161             }
162       while (1 /*swdData[curBord].precParc >= 0 */ );
163       // fin du cas non-oriente
164     }
165   }
166   while (lastPtUsed < numberOfPoints());
167   
168   MakePointData (false);
169   MakeEdgeData (false);
170   MakeSweepDestData (false);
173 // same as before, but each time we have a contour, try to reassemble the segments on it to make chunks of
174 // the original(s) path(s)
175 // originals are in the orig array, whose size is nbP
176 void
177 Shape::ConvertToForme (Path * dest, int nbP, Path * *orig, bool splitWhenForced)
179   if (numberOfPoints() <= 1 || numberOfEdges() <= 1)
180     return;
181 //  if (Eulerian (true) == false)
182 //    return;
183   
184   if (_has_back_data == false)
185   {
186     ConvertToForme (dest);
187     return;
188   }
189   
190   dest->Reset ();
191   
192   MakePointData (true);
193   MakeEdgeData (true);
194   MakeSweepDestData (true);
195   
196   for (int i = 0; i < numberOfPoints(); i++)
197   {
198     pData[i].rx[0] = Round (getPoint(i).x[0]);
199     pData[i].rx[1] = Round (getPoint(i).x[1]);
200   }
201   for (int i = 0; i < numberOfEdges(); i++)
202   {
203     eData[i].rdx = pData[getEdge(i).en].rx - pData[getEdge(i).st].rx;
204   }
205   
206   SortEdges ();
207   
208   for (int i = 0; i < numberOfEdges(); i++)
209   {
210     swdData[i].misc = 0;
211     swdData[i].precParc = swdData[i].suivParc = -1;
212   }
213   
214   int searchInd = 0;
215   
216   int lastPtUsed = 0;
217   do
218   {
219     int startBord = -1;
220     {
221       int fi = 0;
222       for (fi = lastPtUsed; fi < numberOfPoints(); fi++)
223       {
224         if (getPoint(fi).incidentEdge[FIRST] >= 0 && swdData[getPoint(fi).incidentEdge[FIRST]].misc == 0)
225           break;
226       }
227       lastPtUsed = fi + 1;
228       if (fi < numberOfPoints())
229       {
230         int bestB = getPoint(fi).incidentEdge[FIRST];
231         while (bestB >= 0 && getEdge(bestB).st != fi)
232           bestB = NextAt (fi, bestB);
233         if (bestB >= 0)
234               {
235           startBord = bestB;
236               }
237       }
238     }
239     if (startBord >= 0)
240     {
241       // parcours en profondeur pour mettre les leF et riF a leurs valeurs
242       swdData[startBord].misc = (void *) 1;
243       //printf("part de %d\n",startBord);
244       int curBord = startBord;
245       bool back = false;
246       swdData[curBord].precParc = -1;
247       swdData[curBord].suivParc = -1;
248       int curStartPt=getEdge(curBord).st;
249       do
250             {
251               int cPt = getEdge(curBord).en;
252               int nb = curBord;
253         //printf("de curBord= %d au point %i  -> ",curBord,cPt);
254               do
255         {
256           int nnb = CycleNextAt (cPt, nb);
257           if (nnb == nb)
258           {
259             // cul-de-sac
260             nb = -1;
261             break;
262           }
263           nb = nnb;
264           if (nb < 0 || nb == curBord)
265             break;
266         }
267               while (swdData[nb].misc != 0 || getEdge(nb).st != cPt);
268         
269               if (nb < 0 || nb == curBord)
270         {
271           if (back == false)
272           {
273             if (curBord == startBord || curBord < 0)
274             {
275               // probleme -> on vire le moveto
276               //                                                      dest->descr_nb--;
277             }
278             else
279             {
280               swdData[curBord].suivParc = -1;
281               AddContour (dest, nbP, orig, startBord, curBord,splitWhenForced);
282             }
283             //                                              dest->Close();
284           }
285           back = true;
286           // retour en arriere
287           curBord = swdData[curBord].precParc;
288           //printf("retour vers %d\n",curBord);
289           if (curBord < 0)
290             break;
291         }
292               else
293         {
294           if (back)
295           {
296             back = false;
297             startBord = nb;
298             curStartPt=getEdge(nb).st;
299           } else {
300             if ( getEdge(curBord).en == curStartPt ) {
301               //printf("contour %i ",curStartPt);
302               swdData[curBord].suivParc = -1;
303               AddContour (dest, nbP, orig, startBord, curBord,splitWhenForced);
304               startBord=nb;
305             }
306           }
307           swdData[nb].misc = (void *) 1;
308           swdData[nb].ind = searchInd++;
309           swdData[nb].precParc = curBord;
310           swdData[curBord].suivParc = nb;
311           curBord = nb;
312           //printf("suite %d\n",curBord);
313         }
314             }
315       while (1 /*swdData[curBord].precParc >= 0 */ );
316       // fin du cas non-oriente
317     }
318   }
319   while (lastPtUsed < numberOfPoints());
320   
321   MakePointData (false);
322   MakeEdgeData (false);
323   MakeSweepDestData (false);
325 void 
326 Shape::ConvertToFormeNested (Path * dest, int nbP, Path * *orig, int wildPath,int &nbNest,int *&nesting,int *&contStart,bool splitWhenForced)
328   nesting=NULL;
329   contStart=NULL;
330   nbNest=0;
332   if (numberOfPoints() <= 1 || numberOfEdges() <= 1)
333     return;
334   //  if (Eulerian (true) == false)
335   //    return;
336   
337   if (_has_back_data == false)
338   {
339     ConvertToForme (dest);
340     return;
341   }
342   
343   dest->Reset ();
344   
345 //  MakePointData (true);
346   MakeEdgeData (true);
347   MakeSweepDestData (true);
348   
349   for (int i = 0; i < numberOfPoints(); i++)
350   {
351     pData[i].rx[0] = Round (getPoint(i).x[0]);
352     pData[i].rx[1] = Round (getPoint(i).x[1]);
353   }
354   for (int i = 0; i < numberOfEdges(); i++)
355   {
356     eData[i].rdx = pData[getEdge(i).en].rx - pData[getEdge(i).st].rx;
357   }
358   
359   SortEdges ();
360   
361   for (int i = 0; i < numberOfEdges(); i++)
362   {
363     swdData[i].misc = 0;
364     swdData[i].precParc = swdData[i].suivParc = -1;
365   }
366   
367   int searchInd = 0;
368   
369   int lastPtUsed = 0;
370   do
371   {
372     int dadContour=-1;
373     int startBord = -1;
374     {
375       int fi = 0;
376       for (fi = lastPtUsed; fi < numberOfPoints(); fi++)
377       {
378         if (getPoint(fi).incidentEdge[FIRST] >= 0 && swdData[getPoint(fi).incidentEdge[FIRST]].misc == 0)
379           break;
380       }
381       {
382         int askTo = pData[fi].askForWindingB;
383         if (askTo < 0 || askTo >= numberOfEdges() ) {
384           dadContour=-1;
385         } else {
386           dadContour = GPOINTER_TO_INT(swdData[askTo].misc);
387           dadContour-=1; // pour compenser le decalage
388         }
389       }
390       lastPtUsed = fi + 1;
391       if (fi < numberOfPoints())
392       {
393         int bestB = getPoint(fi).incidentEdge[FIRST];
394         while (bestB >= 0 && getEdge(bestB).st != fi)
395           bestB = NextAt (fi, bestB);
396         if (bestB >= 0)
397               {
398           startBord = bestB;
399               }
400       }
401     }
402     if (startBord >= 0)
403     {
404       // parcours en profondeur pour mettre les leF et riF a leurs valeurs
405       swdData[startBord].misc = (void *) (1+nbNest);
406       //printf("part de %d\n",startBord);
407       int curBord = startBord;
408       bool back = false;
409       swdData[curBord].precParc = -1;
410       swdData[curBord].suivParc = -1;
411       int curStartPt=getEdge(curBord).st;
412       do
413             {
414               int cPt = getEdge(curBord).en;
415               int nb = curBord;
416         //printf("de curBord= %d au point %i  -> ",curBord,cPt);
417               do
418         {
419           int nnb = CycleNextAt (cPt, nb);
420           if (nnb == nb)
421           {
422             // cul-de-sac
423             nb = -1;
424             break;
425           }
426           nb = nnb;
427           if (nb < 0 || nb == curBord)
428             break;
429         }
430               while (swdData[nb].misc != 0 || getEdge(nb).st != cPt);
431         
432               if (nb < 0 || nb == curBord)
433         {
434           if (back == false)
435           {
436             if (curBord == startBord || curBord < 0)
437             {
438               // probleme -> on vire le moveto
439               //                                                      dest->descr_nb--;
440             }
441             else
442             {
443               bool escapePath=false;
444               int tb=curBord;
445               while ( tb >= 0 && tb < numberOfEdges() ) {
446                 if ( ebData[tb].pathID == wildPath ) {
447                   escapePath=true;
448                   break;
449                 }
450                 tb=swdData[tb].precParc;
451               }
452               nesting=(int*)g_realloc(nesting,(nbNest+1)*sizeof(int));
453               contStart=(int*)g_realloc(contStart,(nbNest+1)*sizeof(int));
454               contStart[nbNest]=dest->descr_cmd.size();
455               if ( escapePath ) {
456                 nesting[nbNest++]=-1; // contient des bouts de coupure -> a part
457               } else {
458                 nesting[nbNest++]=dadContour;
459               }
460               swdData[curBord].suivParc = -1;
461               AddContour (dest, nbP, orig, startBord, curBord,splitWhenForced);
462             }
463             //                                              dest->Close();
464           }
465           back = true;
466           // retour en arriere
467           curBord = swdData[curBord].precParc;
468           //printf("retour vers %d\n",curBord);
469           if (curBord < 0)
470             break;
471         }
472               else
473         {
474           if (back)
475           {
476             back = false;
477             startBord = nb;
478             curStartPt=getEdge(nb).st;
479           } else {
480             if ( getEdge(curBord).en == curStartPt ) {
481               //printf("contour %i ",curStartPt);
482               
483               bool escapePath=false;
484               int tb=curBord;
485               while ( tb >= 0 && tb < numberOfEdges() ) {
486                 if ( ebData[tb].pathID == wildPath ) {
487                   escapePath=true;
488                   break;
489                 }
490                 tb=swdData[tb].precParc;
491               }
492               nesting=(int*)g_realloc(nesting,(nbNest+1)*sizeof(int));
493               contStart=(int*)g_realloc(contStart,(nbNest+1)*sizeof(int));
494               contStart[nbNest]=dest->descr_cmd.size();
495               if ( escapePath ) {
496                 nesting[nbNest++]=-1; // contient des bouts de coupure -> a part
497               } else {
498                 nesting[nbNest++]=dadContour;
499               }
501               swdData[curBord].suivParc = -1;
502               AddContour (dest, nbP, orig, startBord, curBord,splitWhenForced);
503               startBord=nb;
504             }
505           }
506           swdData[nb].misc = (void *) (1+nbNest);
507           swdData[nb].ind = searchInd++;
508           swdData[nb].precParc = curBord;
509           swdData[curBord].suivParc = nb;
510           curBord = nb;
511           //printf("suite %d\n",curBord);
512         }
513             }
514       while (1 /*swdData[curBord].precParc >= 0 */ );
515       // fin du cas non-oriente
516     }
517   }
518   while (lastPtUsed < numberOfPoints());
519   
520   MakePointData (false);
521   MakeEdgeData (false);
522   MakeSweepDestData (false);
525 // offsets
526 // take each edge, offset it, and make joins with previous at edge start and next at edge end (previous and
527 // next being with respect to the clockwise order)
528 // you gotta be very careful with the join, as anything but the right one will fuck everything up
529 // see PathStroke.cpp for the "right" joins
530 int
531 Shape::MakeOffset (Shape * a, double dec, JoinType join, double miter, bool do_profile, double cx, double cy, double radius, NR::Matrix *i2doc)
533   Reset (0, 0);
534   MakeBackData(a->_has_back_data);
536         bool done_something = false;
537   
538   if (dec == 0)
539   {
540     _pts = a->_pts;
541     if (numberOfPoints() > maxPt)
542     {
543       maxPt = numberOfPoints();
544       if (_has_points_data) {
545         pData.resize(maxPt);
546         _point_data_initialised = false;
547         _bbox_up_to_date = false;
548         }
549     }
550     
551     _aretes = a->_aretes;
552     if (numberOfEdges() > maxAr)
553     {
554       maxAr = numberOfEdges();
555       if (_has_edges_data)
556         eData.resize(maxAr);
557       if (_has_sweep_src_data)
558         swsData.resize(maxAr);
559       if (_has_sweep_dest_data)
560         swdData.resize(maxAr);
561       if (_has_raster_data)
562         swrData.resize(maxAr);
563       if (_has_back_data)
564         ebData.resize(maxAr);
565     }
566     return 0;
567   }
568   if (a->numberOfPoints() <= 1 || a->numberOfEdges() <= 1 || a->type != shape_polygon)
569     return shape_input_err;
570   
571   a->SortEdges ();
572   
573   a->MakeSweepDestData (true);
574   a->MakeSweepSrcData (true);
575   
576   for (int i = 0; i < a->numberOfEdges(); i++)
577   {
578     //              int    stP=a->swsData[i].stPt/*,enP=a->swsData[i].enPt*/;
579     int stB = -1, enB = -1;
580     if (dec > 0)
581     {
582       stB = a->CycleNextAt (a->getEdge(i).st, i);
583       enB = a->CyclePrevAt (a->getEdge(i).en, i);
584     }
585     else
586     {
587       stB = a->CyclePrevAt (a->getEdge(i).st, i);
588       enB = a->CycleNextAt (a->getEdge(i).en, i);
589     }
590     
591     NR::Point stD, seD, enD;
592     double stL, seL, enL;
593     stD = a->getEdge(stB).dx;
594     seD = a->getEdge(i).dx;
595     enD = a->getEdge(enB).dx;
597     stL = sqrt (dot(stD,stD));
598     seL = sqrt (dot(seD,seD));
599     enL = sqrt (dot(enD,enD));
600     MiscNormalize (stD);
601     MiscNormalize (enD);
602     MiscNormalize (seD);
603     
604     NR::Point ptP;
605     int stNo, enNo;
606     ptP = a->getPoint(a->getEdge(i).st).x;
608                 double this_dec;
609                 if (do_profile && i2doc) {
610                         double alpha = 1;
611                         double x = (NR::L2(ptP * (*i2doc) - NR::Point(cx,cy))/radius);
612                         if (x > 1) {
613                                 this_dec = 0;
614                         } else if (x <= 0) {
615                                 this_dec = dec;
616                         } else {
617                                 this_dec = dec * (0.5 * cos (M_PI * (pow(x, alpha))) + 0.5);
618                         }
619                 } else {
620                         this_dec = dec;
621                 }
623                 if (this_dec != 0)
624                         done_something = true;
626     int   usePathID=-1;
627     int   usePieceID=0;
628     double useT=0.0;
629     if ( a->_has_back_data ) {
630       if ( a->ebData[i].pathID >= 0 && a->ebData[stB].pathID == a->ebData[i].pathID && a->ebData[stB].pieceID == a->ebData[i].pieceID
631            && a->ebData[stB].tEn == a->ebData[i].tSt ) {
632         usePathID=a->ebData[i].pathID;
633         usePieceID=a->ebData[i].pieceID;
634         useT=a->ebData[i].tSt;
635       } else {
636         usePathID=a->ebData[i].pathID;
637         usePieceID=0;
638         useT=0;
639       }
640     }
641     if (dec > 0)
642     {
643       Path::DoRightJoin (this, this_dec, join, ptP, stD, seD, miter, stL, seL,
644                          stNo, enNo,usePathID,usePieceID,useT);
645       a->swsData[i].stPt = enNo;
646       a->swsData[stB].enPt = stNo;
647     }
648     else
649     {
650       Path::DoLeftJoin (this, -this_dec, join, ptP, stD, seD, miter, stL, seL,
651                         stNo, enNo,usePathID,usePieceID,useT);
652       a->swsData[i].stPt = enNo;
653       a->swsData[stB].enPt = stNo;
654     }
655   }
657   if (dec < 0)
658   {
659     for (int i = 0; i < numberOfEdges(); i++)
660       Inverse (i);
661   }
663   if ( _has_back_data ) {
664     for (int i = 0; i < a->numberOfEdges(); i++)
665     {
666       int nEd=AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
667       ebData[nEd]=a->ebData[i];
668     }
669   } else {
670     for (int i = 0; i < a->numberOfEdges(); i++)
671     {
672       AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
673     }
674   }
676   a->MakeSweepSrcData (false);
677   a->MakeSweepDestData (false);
678   
679   return (done_something? 0 : shape_nothing_to_do);
682 // pushing
683 // modeled after MakeOffset black magic, the only difference being in the DoRight/LeftJoin parameters
684 int
685 Shape::MakePush (Shape * a, JoinType join, double miter, bool do_profile, NR::Point c, NR::Point vector, double radius, NR::Matrix *i2doc)
687   Reset (0, 0);
688   MakeBackData(a->_has_back_data);
690         bool done_something = false;
692   if (NR::L2(vector) == 0)
693   {
694     _pts = a->_pts;
695     if (numberOfPoints() > maxPt)
696     {
697       maxPt = numberOfPoints();
698       if (_has_points_data) {
699         pData.resize(maxPt);
700         _point_data_initialised = false;
701         _bbox_up_to_date = false;
702         }
703     }
704     
705     _aretes = a->_aretes;
706     if (numberOfEdges() > maxAr)
707     {
708       maxAr = numberOfEdges();
709       if (_has_edges_data)
710         eData.resize(maxAr);
711       if (_has_sweep_src_data)
712         swsData.resize(maxAr);
713       if (_has_sweep_dest_data)
714         swdData.resize(maxAr);
715       if (_has_raster_data)
716         swrData.resize(maxAr);
717       if (_has_back_data)
718         ebData.resize(maxAr);
719     }
720     return 0;
721   }
722   if (a->numberOfPoints() <= 1 || a->numberOfEdges() <= 1 || a->type != shape_polygon)
723     return shape_input_err;
724   
725   a->SortEdges ();
726   
727   a->MakeSweepDestData (true);
728   a->MakeSweepSrcData (true);
729   
730   for (int i = 0; i < a->numberOfEdges(); i++)
731   {
732     int stB = -1, enB = -1;
733     stB = a->CyclePrevAt (a->getEdge(i).st, i);
734     enB = a->CycleNextAt (a->getEdge(i).en, i);
735     
736     NR::Point stD, seD, enD;
737     double stL, seL, enL;
738     stD = a->getEdge(stB).dx;
739     seD = a->getEdge(i).dx;
740     enD = a->getEdge(enB).dx;
742     stL = sqrt (dot(stD,stD));
743     seL = sqrt (dot(seD,seD));
744     enL = sqrt (dot(enD,enD));
745     MiscNormalize (stD);
746     MiscNormalize (enD);
747     MiscNormalize (seD);
748     
749     NR::Point ptP;
750     int stNo, enNo;
751     ptP = a->getPoint(a->getEdge(i).st).x;
753                 NR::Point this_vec;
754                 if (do_profile && i2doc) {
755                         double alpha = 1;
756                         double x = (NR::L2(ptP * (*i2doc) - c)/radius);
757                         if (x > 1) {
758                                 this_vec = NR::Point(0,0);
759                         } else if (x <= 0) {
760                                 this_vec = vector;
761                         } else {
762                                 this_vec = (0.5 * cos (M_PI * (pow(x, alpha))) + 0.5) * vector;
763                         }
764                 } else {
765                         this_vec = vector;
766                 }
768                 if (NR::L2(this_vec) != 0)
769                         done_something = true;
771     int   usePathID=-1;
772     int   usePieceID=0;
773     double useT=0.0;
774     if ( a->_has_back_data ) {
775       if ( a->ebData[i].pathID >= 0 && a->ebData[stB].pathID == a->ebData[i].pathID && a->ebData[stB].pieceID == a->ebData[i].pieceID
776            && a->ebData[stB].tEn == a->ebData[i].tSt ) {
777         usePathID=a->ebData[i].pathID;
778         usePieceID=a->ebData[i].pieceID;
779         useT=a->ebData[i].tSt;
780       } else {
781         usePathID=a->ebData[i].pathID;
782         usePieceID=0;
783         useT=0;
784       }
785     }
786     Path::DoLeftJoin (this, 0, join, ptP+this_vec, stD+this_vec, seD+this_vec, miter, stL, seL,
787                       stNo, enNo,usePathID,usePieceID,useT);
788     a->swsData[i].stPt = enNo;
789     a->swsData[stB].enPt = stNo;
790   }
793   for (int i = 0; i < numberOfEdges(); i++)
794       Inverse (i);
796   if ( _has_back_data ) {
797     for (int i = 0; i < a->numberOfEdges(); i++)
798     {
799       int nEd=AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
800       ebData[nEd]=a->ebData[i];
801     }
802   } else {
803     for (int i = 0; i < a->numberOfEdges(); i++)
804     {
805       AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
806     }
807   }
809   a->MakeSweepSrcData (false);
810   a->MakeSweepDestData (false);
812   return (done_something? 0 : shape_nothing_to_do);
815 // pushing
816 // modeled after MakeOffset black magic, the only difference being in the DoRight/LeftJoin parameters
817 int
818 Shape::MakeJitter (Shape * a, JoinType join, double miter, bool do_profile, NR::Point c, double power, double radius, NR::Matrix *i2doc)
820   Reset (0, 0);
821   MakeBackData(a->_has_back_data);
823         bool done_something = false;
825   if (power == 0)
826   {
827     _pts = a->_pts;
828     if (numberOfPoints() > maxPt)
829     {
830       maxPt = numberOfPoints();
831       if (_has_points_data) {
832         pData.resize(maxPt);
833         _point_data_initialised = false;
834         _bbox_up_to_date = false;
835         }
836     }
837     
838     _aretes = a->_aretes;
839     if (numberOfEdges() > maxAr)
840     {
841       maxAr = numberOfEdges();
842       if (_has_edges_data)
843         eData.resize(maxAr);
844       if (_has_sweep_src_data)
845         swsData.resize(maxAr);
846       if (_has_sweep_dest_data)
847         swdData.resize(maxAr);
848       if (_has_raster_data)
849         swrData.resize(maxAr);
850       if (_has_back_data)
851         ebData.resize(maxAr);
852     }
854     return 0;
855   }
856   if (a->numberOfPoints() <= 1 || a->numberOfEdges() <= 1 || a->type != shape_polygon)
857     return shape_input_err;
858   
859   a->SortEdges ();
860   
861   a->MakeSweepDestData (true);
862   a->MakeSweepSrcData (true);
863   
864   for (int i = 0; i < a->numberOfEdges(); i++)
865   {
866     int stB = -1, enB = -1;
867     stB = a->CyclePrevAt (a->getEdge(i).st, i);
868     enB = a->CycleNextAt (a->getEdge(i).en, i);
869     
870     NR::Point stD, seD, enD;
871     double stL, seL, enL;
872     stD = a->getEdge(stB).dx;
873     seD = a->getEdge(i).dx;
874     enD = a->getEdge(enB).dx;
876     stL = sqrt (dot(stD,stD));
877     seL = sqrt (dot(seD,seD));
878     enL = sqrt (dot(enD,enD));
879     MiscNormalize (stD);
880     MiscNormalize (enD);
881     MiscNormalize (seD);
882     
883     NR::Point ptP;
884     int stNo, enNo;
885     ptP = a->getPoint(a->getEdge(i).st).x;
887                 double this_power;
888                 if (do_profile && i2doc) {
889                         double alpha = 1;
890                         double x = (NR::L2(ptP * (*i2doc) - c)/radius);
891                         if (x > 1) {
892                                 this_power = 0;
893                         } else if (x <= 0) {
894                                 this_power = power;
895                         } else {
896                                 this_power = (0.5 * cos (M_PI * (pow(x, alpha))) + 0.5) * power;
897                         }
898                 } else {
899                         this_power = power;
900                 }
902                 if (this_power != 0)
903                         done_something = true;
905                 double angle = g_random_double_range(0, 2*M_PI);
906                 NR::Point this_vec = g_random_double_range(0, 1) * this_power * NR::Point(sin(angle), cos(angle));
908     int   usePathID=-1;
909     int   usePieceID=0;
910     double useT=0.0;
911     if ( a->_has_back_data ) {
912       if ( a->ebData[i].pathID >= 0 && a->ebData[stB].pathID == a->ebData[i].pathID && a->ebData[stB].pieceID == a->ebData[i].pieceID
913            && a->ebData[stB].tEn == a->ebData[i].tSt ) {
914         usePathID=a->ebData[i].pathID;
915         usePieceID=a->ebData[i].pieceID;
916         useT=a->ebData[i].tSt;
917       } else {
918         usePathID=a->ebData[i].pathID;
919         usePieceID=0;
920         useT=0;
921       }
922     }
923     Path::DoLeftJoin (this, 0, join, ptP+this_vec, stD+this_vec, seD+this_vec, miter, stL, seL,
924                       stNo, enNo,usePathID,usePieceID,useT);
925     a->swsData[i].stPt = enNo;
926     a->swsData[stB].enPt = stNo;
927   }
930   for (int i = 0; i < numberOfEdges(); i++)
931       Inverse (i);
933   if ( _has_back_data ) {
934     for (int i = 0; i < a->numberOfEdges(); i++)
935     {
936       int nEd=AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
937       ebData[nEd]=a->ebData[i];
938     }
939   } else {
940     for (int i = 0; i < a->numberOfEdges(); i++)
941     {
942       AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
943     }
944   }
946   a->MakeSweepSrcData (false);
947   a->MakeSweepDestData (false);
949   return (done_something? 0 : shape_nothing_to_do);
953 // we found a contour, now reassemble the edges on it, instead of dumping them in the Path "dest" as a
954 // polyline. since it was a DFS, the precParc and suivParc make a nice doubly-linked list of the edges in
955 // the contour. the first and last edges of the contour are startBord and curBord
956 void
957 Shape::AddContour (Path * dest, int nbP, Path * *orig, int startBord, int curBord, bool splitWhenForced)
959   int bord = startBord;
960   
961   {
962     dest->MoveTo (getPoint(getEdge(bord).st).x);
963   }
964   
965   while (bord >= 0)
966   {
967     int nPiece = ebData[bord].pieceID;
968     int nPath = ebData[bord].pathID;
969     
970     if (nPath < 0 || nPath >= nbP || orig[nPath] == NULL)
971     {
972       // segment batard
973       dest->LineTo (getPoint(getEdge(bord).en).x);
974       bord = swdData[bord].suivParc;
975     }
976     else
977     {
978       Path *from = orig[nPath];
979       if (nPiece < 0 || nPiece >= int(from->descr_cmd.size()))
980             {
981               // segment batard
982               dest->LineTo (getPoint(getEdge(bord).en).x);
983               bord = swdData[bord].suivParc;
984             }
985       else
986             {
987               int nType = from->descr_cmd[nPiece]->getType();
988               if (nType == descr_close || nType == descr_moveto
989             || nType == descr_forced)
990         {
991           // devrait pas arriver
992           dest->LineTo (getPoint(getEdge(bord).en).x);
993           bord = swdData[bord].suivParc;
994         }
995               else if (nType == descr_lineto)
996         {
997           bord = ReFormeLineTo (bord, curBord, dest, from);
998         }
999               else if (nType == descr_arcto)
1000         {
1001           bord = ReFormeArcTo (bord, curBord, dest, from);
1002         }
1003               else if (nType == descr_cubicto)
1004         {
1005           bord = ReFormeCubicTo (bord, curBord, dest, from);
1006         }
1007               else if (nType == descr_bezierto)
1008         {
1009           PathDescrBezierTo* nBData =
1010             dynamic_cast<PathDescrBezierTo *>(from->descr_cmd[nPiece]);
1011           
1012           if (nBData->nb == 0)
1013           {
1014             bord = ReFormeLineTo (bord, curBord, dest, from);
1015           }
1016           else
1017           {
1018             bord = ReFormeBezierTo (bord, curBord, dest, from);
1019           }
1020         }
1021               else if (nType == descr_interm_bezier)
1022         {
1023           bord = ReFormeBezierTo (bord, curBord, dest, from);
1024         }
1025               else
1026         {
1027           // devrait pas arriver non plus
1028           dest->LineTo (getPoint(getEdge(bord).en).x);
1029           bord = swdData[bord].suivParc;
1030         }
1031               if (bord >= 0 && getPoint(getEdge(bord).st).totalDegree() > 2 ) {
1032           dest->ForcePoint ();
1033         } else if ( bord >= 0 && getPoint(getEdge(bord).st).oldDegree > 2 && getPoint(getEdge(bord).st).totalDegree() == 2)  {
1034           if ( splitWhenForced ) {
1035             // pour les coupures
1036             dest->ForcePoint ();
1037          } else {
1038             if ( _has_back_data ) {
1039               int   prevEdge=getPoint(getEdge(bord).st).incidentEdge[FIRST];
1040               int   nextEdge=getPoint(getEdge(bord).st).incidentEdge[LAST];
1041               if ( getEdge(prevEdge).en != getEdge(bord).st ) {
1042                 int  swai=prevEdge;prevEdge=nextEdge;nextEdge=swai;
1043               }
1044               if ( ebData[prevEdge].pieceID == ebData[nextEdge].pieceID  && ebData[prevEdge].pathID == ebData[nextEdge].pathID ) {
1045                 if ( fabs(ebData[prevEdge].tEn-ebData[nextEdge].tSt) < 0.05 ) {
1046                 } else {
1047                   dest->ForcePoint ();
1048                 }
1049               } else {
1050                 dest->ForcePoint ();
1051               }
1052             } else {
1053               dest->ForcePoint ();
1054             }    
1055           }
1056         }
1057       }
1058     }
1059   }
1060   dest->Close ();
1063 int
1064 Shape::ReFormeLineTo (int bord, int curBord, Path * dest, Path * orig)
1066   int nPiece = ebData[bord].pieceID;
1067   int nPath = ebData[bord].pathID;
1068   double /*ts=ebData[bord].tSt, */ te = ebData[bord].tEn;
1069   NR::Point nx = getPoint(getEdge(bord).en).x;
1070   bord = swdData[bord].suivParc;
1071   while (bord >= 0)
1072   {
1073     if (getPoint(getEdge(bord).st).totalDegree() > 2
1074         || getPoint(getEdge(bord).st).oldDegree > 2)
1075     {
1076       break;
1077     }
1078     if (ebData[bord].pieceID == nPiece && ebData[bord].pathID == nPath)
1079     {
1080       if (fabs (te - ebData[bord].tSt) > 0.0001)
1081         break;
1082       nx = getPoint(getEdge(bord).en).x;
1083       te = ebData[bord].tEn;
1084     }
1085     else
1086     {
1087       break;
1088     }
1089     bord = swdData[bord].suivParc;
1090   }
1091   {
1092     dest->LineTo (nx);
1093   }
1094   return bord;
1097 int
1098 Shape::ReFormeArcTo (int bord, int curBord, Path * dest, Path * from)
1100   int nPiece = ebData[bord].pieceID;
1101   int nPath = ebData[bord].pathID;
1102   double ts = ebData[bord].tSt, te = ebData[bord].tEn;
1103   //      double  px=pts[getEdge(bord).st].x,py=pts[getEdge(bord).st].y;
1104   NR::Point nx = getPoint(getEdge(bord).en).x;
1105   bord = swdData[bord].suivParc;
1106   while (bord >= 0)
1107   {
1108     if (getPoint(getEdge(bord).st).totalDegree() > 2
1109         || getPoint(getEdge(bord).st).oldDegree > 2)
1110     {
1111       break;
1112     }
1113     if (ebData[bord].pieceID == nPiece && ebData[bord].pathID == nPath)
1114     {
1115       if (fabs (te - ebData[bord].tSt) > 0.0001)
1116             {
1117               break;
1118             }
1119       nx = getPoint(getEdge(bord).en).x;
1120       te = ebData[bord].tEn;
1121     }
1122     else
1123     {
1124       break;
1125     }
1126     bord = swdData[bord].suivParc;
1127   }
1128   double sang, eang;
1129   PathDescrArcTo* nData = dynamic_cast<PathDescrArcTo *>(from->descr_cmd[nPiece]);
1130   bool nLarge = nData->large;
1131   bool nClockwise = nData->clockwise;
1132   Path::ArcAngles (from->PrevPoint (nPiece - 1), nData->p,nData->rx,nData->ry,nData->angle, nLarge, nClockwise,  sang, eang);
1133   if (nClockwise)
1134   {
1135     if (sang < eang)
1136       sang += 2 * M_PI;
1137   }
1138   else
1139   {
1140     if (sang > eang)
1141       sang -= 2 * M_PI;
1142   }
1143   double delta = eang - sang;
1144   double ndelta = delta * (te - ts);
1145   if (ts > te)
1146     nClockwise = !nClockwise;
1147   if (ndelta < 0)
1148     ndelta = -ndelta;
1149   if (ndelta > M_PI)
1150     nLarge = true;
1151   else
1152     nLarge = false;
1153   /*    if ( delta < 0 ) delta=-delta;
1154         if ( ndelta < 0 ) ndelta=-ndelta;
1155         if ( ( delta < M_PI && ndelta < M_PI ) || ( delta >= M_PI && ndelta >= M_PI ) ) {
1156                 if ( ts < te ) {
1157                 } else {
1158                         nClockwise=!(nClockwise);
1159                 }
1160         } else {
1161     //          nLarge=!(nLarge);
1162                 nLarge=false; // c'est un sous-segment -> l'arc ne peut que etre plus petit
1163                 if ( ts < te ) {
1164                 } else {
1165                         nClockwise=!(nClockwise);
1166                 }
1167         }*/
1168   {
1169     PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(from->descr_cmd[nPiece]);
1170     dest->ArcTo (nx, nData->rx,nData->ry,nData->angle, nLarge, nClockwise);
1171   }
1172   return bord;
1175 int
1176 Shape::ReFormeCubicTo (int bord, int curBord, Path * dest, Path * from)
1178   int nPiece = ebData[bord].pieceID;
1179   int nPath = ebData[bord].pathID;
1180   double ts = ebData[bord].tSt, te = ebData[bord].tEn;
1181   NR::Point nx = getPoint(getEdge(bord).en).x;
1182   bord = swdData[bord].suivParc;
1183   while (bord >= 0)
1184   {
1185     if (getPoint(getEdge(bord).st).totalDegree() > 2
1186         || getPoint(getEdge(bord).st).oldDegree > 2)
1187     {
1188       break;
1189     }
1190     if (ebData[bord].pieceID == nPiece && ebData[bord].pathID == nPath)
1191     {
1192       if (fabs (te - ebData[bord].tSt) > 0.0001)
1193             {
1194               break;
1195             }
1196       nx = getPoint(getEdge(bord).en).x;
1197       te = ebData[bord].tEn;
1198     }
1199     else
1200     {
1201       break;
1202     }
1203     bord = swdData[bord].suivParc;
1204   }
1205   NR::Point prevx = from->PrevPoint (nPiece - 1);
1206   
1207   NR::Point sDx, eDx;
1208   {
1209     PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(from->descr_cmd[nPiece]);
1210     Path::CubicTangent (ts, sDx, prevx,nData->start,nData->p,nData->end);
1211     Path::CubicTangent (te, eDx, prevx,nData->start,nData->p,nData->end);
1212   }
1213   sDx *= (te - ts);
1214   eDx *= (te - ts);
1215   {
1216     dest->CubicTo (nx,sDx,eDx);
1217   }
1218   return bord;
1221 int
1222 Shape::ReFormeBezierTo (int bord, int curBord, Path * dest, Path * from)
1224   int nPiece = ebData[bord].pieceID;
1225   int nPath = ebData[bord].pathID;
1226   double ts = ebData[bord].tSt, te = ebData[bord].tEn;
1227   int ps = nPiece, pe = nPiece;
1228   NR::Point px = getPoint(getEdge(bord).st).x;
1229   NR::Point nx = getPoint(getEdge(bord).en).x;
1230   int inBezier = -1, nbInterm = -1;
1231   int typ;
1232   typ = from->descr_cmd[nPiece]->getType();
1233   PathDescrBezierTo *nBData = NULL;
1234   if (typ == descr_bezierto)
1235   {
1236     nBData = dynamic_cast<PathDescrBezierTo *>(from->descr_cmd[nPiece]);
1237     inBezier = nPiece;
1238     nbInterm = nBData->nb;
1239   }
1240   else
1241   {
1242     int n = nPiece - 1;
1243     while (n > 0)
1244     {
1245       typ = from->descr_cmd[n]->getType();
1246       if (typ == descr_bezierto)
1247       {
1248         inBezier = n;
1249         nBData = dynamic_cast<PathDescrBezierTo *>(from->descr_cmd[n]);
1250         nbInterm = nBData->nb;
1251         break;
1252       }
1253       n--;
1254     }
1255     if (inBezier < 0)
1256     {
1257       bord = swdData[bord].suivParc;
1258       dest->LineTo (nx);
1259       return bord;
1260     }
1261   }
1262   bord = swdData[bord].suivParc;
1263   while (bord >= 0)
1264   {
1265     if (getPoint(getEdge(bord).st).totalDegree() > 2
1266         || getPoint(getEdge(bord).st).oldDegree > 2)
1267     {
1268       break;
1269     }
1270     if (ebData[bord].pathID == nPath)
1271     {
1272       if (ebData[bord].pieceID < inBezier
1273           || ebData[bord].pieceID >= inBezier + nbInterm)
1274         break;
1275       if (ebData[bord].pieceID == pe
1276           && fabs (te - ebData[bord].tSt) > 0.0001)
1277         break;
1278       if (ebData[bord].pieceID != pe
1279           && (ebData[bord].tSt > 0.0001 && ebData[bord].tSt < 0.9999))
1280         break;
1281       if (ebData[bord].pieceID != pe && (te > 0.0001 && te < 0.9999))
1282         break;
1283       nx = getPoint(getEdge(bord).en).x;
1284       te = ebData[bord].tEn;
1285       pe = ebData[bord].pieceID;
1286     }
1287     else
1288     {
1289       break;
1290     }
1291     bord = swdData[bord].suivParc;
1292   }
1294   g_return_val_if_fail(nBData != NULL, 0);
1295   
1296   if (pe == ps)
1297   {
1298     ReFormeBezierChunk (px, nx, dest, inBezier, nbInterm, from, ps,
1299                         ts, te);
1300   }
1301   else if (ps < pe)
1302   {
1303     if (ts < 0.0001)
1304     {
1305       if (te > 0.9999)
1306       {
1307         dest->BezierTo (nx);
1308         for (int i = ps; i <= pe; i++)
1309         {
1310           PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1311           dest->IntermBezierTo (nData->p);
1312         }
1313         dest->EndBezierTo ();
1314       }
1315       else
1316       {
1317         NR::Point tx;
1318         {
1319           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe]);
1320           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+1]);
1321           tx = (pnData->p + psData->p) / 2;
1322         }
1323         dest->BezierTo (tx);
1324         for (int i = ps; i < pe; i++)
1325         {
1326           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1327           dest->IntermBezierTo (nData->p);
1328         }
1329         dest->EndBezierTo ();
1330         ReFormeBezierChunk (tx, nx, dest, inBezier, nbInterm,
1331                             from, pe, 0.0, te);
1332       }
1333     }
1334     else
1335     {
1336       if (te > 0.9999)
1337       {
1338         NR::Point tx;
1339         {
1340           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
1341           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+2]);
1342           tx = (psData->p +  pnData->p) / 2;
1343         }
1344         ReFormeBezierChunk (px, tx, dest, inBezier, nbInterm,
1345                             from, ps, ts, 1.0);
1346         dest->BezierTo (nx);
1347         for (int i = ps + 1; i <= pe; i++)
1348         {
1349           PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1350           dest->IntermBezierTo (nData->p);
1351         }
1352         dest->EndBezierTo ();
1353       }
1354       else
1355       {
1356         NR::Point tx;
1357         {
1358           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
1359           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+2]);
1360           tx = (pnData->p + psData->p) / 2;
1361         }
1362         ReFormeBezierChunk (px, tx, dest, inBezier, nbInterm,
1363                             from, ps, ts, 1.0);
1364         {
1365           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe]);
1366           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+1]);
1367           tx = (pnData->p + psData->p) / 2;
1368         }
1369          dest->BezierTo (tx);
1370         for (int i = ps + 1; i <= pe; i++)
1371         {
1372           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1373           dest->IntermBezierTo (nData->p);
1374         }
1375         dest->EndBezierTo ();
1376         ReFormeBezierChunk (tx, nx, dest, inBezier, nbInterm,
1377                             from, pe, 0.0, te);
1378       }
1379     }
1380   }
1381   else
1382   {
1383     if (ts > 0.9999)
1384     {
1385       if (te < 0.0001)
1386       {
1387         dest->BezierTo (nx);
1388         for (int i = ps; i >= pe; i--)
1389         {
1390           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1391           dest->IntermBezierTo (nData->p);
1392         }
1393         dest->EndBezierTo ();
1394       }
1395       else
1396       {
1397         NR::Point tx;
1398         {
1399           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+1]);
1400           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+2]);
1401           tx = (pnData->p + psData->p) / 2;
1402         }
1403         dest->BezierTo (tx);
1404         for (int i = ps; i > pe; i--)
1405         {
1406           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1407           dest->IntermBezierTo (nData->p);
1408         }
1409         dest->EndBezierTo ();
1410         ReFormeBezierChunk (tx, nx, dest, inBezier, nbInterm,
1411                             from, pe, 1.0, te);
1412       }
1413     }
1414     else
1415     {
1416       if (te < 0.0001)
1417       {
1418         NR::Point tx;
1419         {
1420           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps]);
1421           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
1422           tx = (pnData->p + psData->p) / 2;
1423         }
1424          ReFormeBezierChunk (px, tx, dest, inBezier, nbInterm,
1425                             from, ps, ts, 0.0);
1426         dest->BezierTo (nx);
1427         for (int i = ps + 1; i >= pe; i--)
1428         {
1429           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i]);
1430           dest->IntermBezierTo (nData->p);
1431         }
1432         dest->EndBezierTo ();
1433       }
1434       else
1435       {
1436         NR::Point tx;
1437         {
1438           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps]);
1439           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
1440           tx = (pnData->p + psData->p) / 2;
1441         }
1442         ReFormeBezierChunk (px, tx, dest, inBezier, nbInterm,
1443                             from, ps, ts, 0.0);
1444         {
1445           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+1]);
1446           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+2]);
1447           tx = (pnData->p + psData->p) / 2;
1448         }
1449         dest->BezierTo (tx);
1450         for (int i = ps + 1; i > pe; i--)
1451         {
1452           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i]);
1453           dest->IntermBezierTo (nData->p);
1454         }
1455         dest->EndBezierTo ();
1456         ReFormeBezierChunk (tx, nx, dest, inBezier, nbInterm,
1457                             from, pe, 1.0, te);
1458       }
1459     }
1460   }
1461   return bord;
1464 void
1465 Shape::ReFormeBezierChunk (NR::Point px, NR::Point nx,
1466                            Path * dest, int inBezier, int nbInterm,
1467                            Path * from, int p, double ts, double te)
1469   PathDescrBezierTo* nBData = dynamic_cast<PathDescrBezierTo*>(from->descr_cmd[inBezier]);
1470   NR::Point bstx = from->PrevPoint (inBezier - 1);
1471   NR::Point benx = nBData->p;
1472   
1473   NR::Point mx;
1474   if (p == inBezier)
1475   {
1476     // premier bout
1477     if (nbInterm <= 1)
1478     {
1479       // seul bout de la spline
1480       PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[inBezier+1]);
1481       mx = nData->p;
1482     }
1483     else
1484     {
1485       // premier bout d'une spline qui en contient plusieurs
1486       PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[inBezier+1]);
1487       mx = nData->p;
1488       nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[inBezier+2]);
1489       benx = (nData->p + mx) / 2;
1490     }
1491   }
1492   else if (p == inBezier + nbInterm - 1)
1493   {
1494     // dernier bout
1495     // si nbInterm == 1, le cas a deja ete traite
1496     // donc dernier bout d'une spline qui en contient plusieurs
1497     PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[inBezier+nbInterm]);
1498     mx = nData->p;
1499     nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[inBezier+nbInterm-1]);
1500     bstx = (nData->p + mx) / 2;
1501   }
1502   else
1503   {
1504     // la spline contient forcĂ©ment plusieurs bouts, et ce n'est ni le premier ni le dernier
1505     PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[p+1]);
1506     mx = nData->p;
1507     nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[p]);
1508     bstx = (nData->p + mx) / 2;
1509     nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[p+2]);
1510     benx = (nData->p + mx) / 2;
1511   }
1512   NR::Point cx;
1513   {
1514     Path::QuadraticPoint ((ts + te) / 2, cx, bstx, mx, benx);
1515   }
1516   cx = 2 * cx - (px + nx) / 2;
1517   {
1518     dest->BezierTo (nx);
1519     dest->IntermBezierTo (cx);
1520     dest->EndBezierTo ();
1521   }
1524 #undef MiscNormalize