Code

Added example file for feTurbulence effect
[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);
526 int
527 Shape::MakeTweak (int mode, Shape *a, double dec, JoinType join, double miter, bool do_profile, NR::Point c, NR::Point vector, double radius, NR::Matrix *i2doc)
529   Reset (0, 0);
530   MakeBackData(a->_has_back_data);
532         bool done_something = false;
534   double power;
535   if (mode == tweak_mode_push) {
536                 power = NR::L2(vector);
537         } else {
538                 power = dec;
539         }
540   
541   if (power == 0)
542   {
543     _pts = a->_pts;
544     if (numberOfPoints() > maxPt)
545     {
546       maxPt = numberOfPoints();
547       if (_has_points_data) {
548         pData.resize(maxPt);
549         _point_data_initialised = false;
550         _bbox_up_to_date = false;
551         }
552     }
553     
554     _aretes = a->_aretes;
555     if (numberOfEdges() > maxAr)
556     {
557       maxAr = numberOfEdges();
558       if (_has_edges_data)
559               eData.resize(maxAr);
560       if (_has_sweep_src_data)
561         swsData.resize(maxAr);
562       if (_has_sweep_dest_data)
563         swdData.resize(maxAr);
564       if (_has_raster_data)
565         swrData.resize(maxAr);
566       if (_has_back_data)
567         ebData.resize(maxAr);
568     }
569     return 0;
570   }
571   if (a->numberOfPoints() <= 1 || a->numberOfEdges() <= 1 || a->type != shape_polygon)
572     return shape_input_err;
573   
574   a->SortEdges ();
575   
576   a->MakeSweepDestData (true);
577   a->MakeSweepSrcData (true);
578   
579   for (int i = 0; i < a->numberOfEdges(); i++)
580   {
581     int stB = -1, enB = -1;
582     if (power <= 0 || mode == tweak_mode_push || mode == tweak_mode_repel || mode == tweak_mode_roughen)  {
583       stB = a->CyclePrevAt (a->getEdge(i).st, i);
584       enB = a->CycleNextAt (a->getEdge(i).en, i);
585     } else {
586       stB = a->CycleNextAt (a->getEdge(i).st, i);
587       enB = a->CyclePrevAt (a->getEdge(i).en, i);
588     }
589     
590     NR::Point stD, seD, enD;
591     double stL, seL, enL;
592     stD = a->getEdge(stB).dx;
593     seD = a->getEdge(i).dx;
594     enD = a->getEdge(enB).dx;
596     stL = sqrt (dot(stD,stD));
597     seL = sqrt (dot(seD,seD));
598     enL = sqrt (dot(enD,enD));
599     MiscNormalize (stD);
600     MiscNormalize (enD);
601     MiscNormalize (seD);
602     
603     NR::Point ptP;
604     int stNo, enNo;
605     ptP = a->getPoint(a->getEdge(i).st).x;
607     if (mode == tweak_mode_push) {
608                         power = 1;
609                 }
611         NR::Point to_center = ptP * (*i2doc) - c;
612         NR::Point to_center_normalized = (1/NR::L2(to_center)) * to_center;
614                 double this_power;
615                 if (do_profile && i2doc) {
616                         double alpha = 1;
617                         double x;
618                 if (mode == tweak_mode_repel) {
619                                 x = (NR::L2(to_center)/radius);
620                         } else {
621                                 x = (NR::L2(ptP * (*i2doc) - c)/radius);
622                         }
623                         if (x > 1) {
624                                 this_power = 0;
625                         } else if (x <= 0) {
626                 if (mode == tweak_mode_repel) {
627                                         this_power = 0;
628                                 } else {
629                                         this_power = power;
630                                 }
631                         } else {
632                                 this_power = power * (0.5 * cos (M_PI * (pow(x, alpha))) + 0.5);
633                         }
634                 } else {
635                 if (mode == tweak_mode_repel) {
636                                 this_power = 0;
637                         } else {
638                                 this_power = power;
639                         }
640                 }
642                 if (this_power != 0)
643                         done_something = true;
645                 NR::Point this_vec(0,0);
646     if (mode == tweak_mode_push) {
647                         this_vec = this_power * vector;
648                 } else if (mode == tweak_mode_repel) {
649                         this_vec = this_power * to_center_normalized;
650                 } else if (mode == tweak_mode_roughen) {
651                 double angle = g_random_double_range(0, 2*M_PI);
652                 this_vec = g_random_double_range(0, 1) * this_power * NR::Point(sin(angle), cos(angle));
653                 }
655     int   usePathID=-1;
656     int   usePieceID=0;
657     double useT=0.0;
658     if ( a->_has_back_data ) {
659       if ( a->ebData[i].pathID >= 0 && a->ebData[stB].pathID == a->ebData[i].pathID && a->ebData[stB].pieceID == a->ebData[i].pieceID
660            && a->ebData[stB].tEn == a->ebData[i].tSt ) {
661         usePathID=a->ebData[i].pathID;
662         usePieceID=a->ebData[i].pieceID;
663         useT=a->ebData[i].tSt;
664       } else {
665         usePathID=a->ebData[i].pathID;
666         usePieceID=0;
667         useT=0;
668       }
669     }
671                 if (mode == tweak_mode_push || mode == tweak_mode_repel || mode == tweak_mode_roughen) {
672                         Path::DoLeftJoin (this, 0, join, ptP+this_vec, stD+this_vec, seD+this_vec, miter, stL, seL,
673                                                                                                 stNo, enNo,usePathID,usePieceID,useT);
674                         a->swsData[i].stPt = enNo;
675                         a->swsData[stB].enPt = stNo;
676                 } else {
677                         if (power > 0) {
678                                 Path::DoRightJoin (this, this_power, join, ptP, stD, seD, miter, stL, seL,
679                                                                                                          stNo, enNo,usePathID,usePieceID,useT);
680                                 a->swsData[i].stPt = enNo;
681                                 a->swsData[stB].enPt = stNo;
682                         } else {
683                                 Path::DoLeftJoin (this, -this_power, join, ptP, stD, seD, miter, stL, seL,
684                                                                                                         stNo, enNo,usePathID,usePieceID,useT);
685                                 a->swsData[i].stPt = enNo;
686                                 a->swsData[stB].enPt = stNo;
687                         }
688                 }
689   }
691   if (power < 0 || mode == tweak_mode_push || mode == tweak_mode_repel || mode == tweak_mode_roughen)
692   {
693     for (int i = 0; i < numberOfEdges(); i++)
694       Inverse (i);
695   }
697   if ( _has_back_data ) {
698     for (int i = 0; i < a->numberOfEdges(); i++)
699     {
700       int nEd=AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
701       ebData[nEd]=a->ebData[i];
702     }
703   } else {
704     for (int i = 0; i < a->numberOfEdges(); i++)
705     {
706       AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
707     }
708   }
710   a->MakeSweepSrcData (false);
711   a->MakeSweepDestData (false);
712   
713   return (done_something? 0 : shape_nothing_to_do);
717 // offsets
718 // take each edge, offset it, and make joins with previous at edge start and next at edge end (previous and
719 // next being with respect to the clockwise order)
720 // you gotta be very careful with the join, as anything but the right one will fuck everything up
721 // see PathStroke.cpp for the "right" joins
722 int
723 Shape::MakeOffset (Shape * a, double dec, JoinType join, double miter, bool do_profile, double cx, double cy, double radius, NR::Matrix *i2doc)
725   Reset (0, 0);
726   MakeBackData(a->_has_back_data);
728         bool done_something = false;
729   
730   if (dec == 0)
731   {
732     _pts = a->_pts;
733     if (numberOfPoints() > maxPt)
734     {
735       maxPt = numberOfPoints();
736       if (_has_points_data) {
737         pData.resize(maxPt);
738         _point_data_initialised = false;
739         _bbox_up_to_date = false;
740         }
741     }
742     
743     _aretes = a->_aretes;
744     if (numberOfEdges() > maxAr)
745     {
746       maxAr = numberOfEdges();
747       if (_has_edges_data)
748         eData.resize(maxAr);
749       if (_has_sweep_src_data)
750         swsData.resize(maxAr);
751       if (_has_sweep_dest_data)
752         swdData.resize(maxAr);
753       if (_has_raster_data)
754         swrData.resize(maxAr);
755       if (_has_back_data)
756         ebData.resize(maxAr);
757     }
758     return 0;
759   }
760   if (a->numberOfPoints() <= 1 || a->numberOfEdges() <= 1 || a->type != shape_polygon)
761     return shape_input_err;
762   
763   a->SortEdges ();
764   
765   a->MakeSweepDestData (true);
766   a->MakeSweepSrcData (true);
767   
768   for (int i = 0; i < a->numberOfEdges(); i++)
769   {
770     //              int    stP=a->swsData[i].stPt/*,enP=a->swsData[i].enPt*/;
771     int stB = -1, enB = -1;
772     if (dec > 0)
773     {
774       stB = a->CycleNextAt (a->getEdge(i).st, i);
775       enB = a->CyclePrevAt (a->getEdge(i).en, i);
776     }
777     else
778     {
779       stB = a->CyclePrevAt (a->getEdge(i).st, i);
780       enB = a->CycleNextAt (a->getEdge(i).en, i);
781     }
782     
783     NR::Point stD, seD, enD;
784     double stL, seL, enL;
785     stD = a->getEdge(stB).dx;
786     seD = a->getEdge(i).dx;
787     enD = a->getEdge(enB).dx;
789     stL = sqrt (dot(stD,stD));
790     seL = sqrt (dot(seD,seD));
791     enL = sqrt (dot(enD,enD));
792     MiscNormalize (stD);
793     MiscNormalize (enD);
794     MiscNormalize (seD);
795     
796     NR::Point ptP;
797     int stNo, enNo;
798     ptP = a->getPoint(a->getEdge(i).st).x;
800                 double this_dec;
801                 if (do_profile && i2doc) {
802                         double alpha = 1;
803                         double x = (NR::L2(ptP * (*i2doc) - NR::Point(cx,cy))/radius);
804                         if (x > 1) {
805                                 this_dec = 0;
806                         } else if (x <= 0) {
807                                 this_dec = dec;
808                         } else {
809                                 this_dec = dec * (0.5 * cos (M_PI * (pow(x, alpha))) + 0.5);
810                         }
811                 } else {
812                         this_dec = dec;
813                 }
815                 if (this_dec != 0)
816                         done_something = true;
818     int   usePathID=-1;
819     int   usePieceID=0;
820     double useT=0.0;
821     if ( a->_has_back_data ) {
822       if ( a->ebData[i].pathID >= 0 && a->ebData[stB].pathID == a->ebData[i].pathID && a->ebData[stB].pieceID == a->ebData[i].pieceID
823            && a->ebData[stB].tEn == a->ebData[i].tSt ) {
824         usePathID=a->ebData[i].pathID;
825         usePieceID=a->ebData[i].pieceID;
826         useT=a->ebData[i].tSt;
827       } else {
828         usePathID=a->ebData[i].pathID;
829         usePieceID=0;
830         useT=0;
831       }
832     }
833     if (dec > 0)
834     {
835       Path::DoRightJoin (this, this_dec, join, ptP, stD, seD, miter, stL, seL,
836                          stNo, enNo,usePathID,usePieceID,useT);
837       a->swsData[i].stPt = enNo;
838       a->swsData[stB].enPt = stNo;
839     }
840     else
841     {
842       Path::DoLeftJoin (this, -this_dec, join, ptP, stD, seD, miter, stL, seL,
843                         stNo, enNo,usePathID,usePieceID,useT);
844       a->swsData[i].stPt = enNo;
845       a->swsData[stB].enPt = stNo;
846     }
847   }
849   if (dec < 0)
850   {
851     for (int i = 0; i < numberOfEdges(); i++)
852       Inverse (i);
853   }
855   if ( _has_back_data ) {
856     for (int i = 0; i < a->numberOfEdges(); i++)
857     {
858       int nEd=AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
859       ebData[nEd]=a->ebData[i];
860     }
861   } else {
862     for (int i = 0; i < a->numberOfEdges(); i++)
863     {
864       AddEdge (a->swsData[i].stPt, a->swsData[i].enPt);
865     }
866   }
868   a->MakeSweepSrcData (false);
869   a->MakeSweepDestData (false);
870   
871   return (done_something? 0 : shape_nothing_to_do);
876 // we found a contour, now reassemble the edges on it, instead of dumping them in the Path "dest" as a
877 // polyline. since it was a DFS, the precParc and suivParc make a nice doubly-linked list of the edges in
878 // the contour. the first and last edges of the contour are startBord and curBord
879 void
880 Shape::AddContour (Path * dest, int nbP, Path * *orig, int startBord, int curBord, bool splitWhenForced)
882   int bord = startBord;
883   
884   {
885     dest->MoveTo (getPoint(getEdge(bord).st).x);
886   }
887   
888   while (bord >= 0)
889   {
890     int nPiece = ebData[bord].pieceID;
891     int nPath = ebData[bord].pathID;
892     
893     if (nPath < 0 || nPath >= nbP || orig[nPath] == NULL)
894     {
895       // segment batard
896       dest->LineTo (getPoint(getEdge(bord).en).x);
897       bord = swdData[bord].suivParc;
898     }
899     else
900     {
901       Path *from = orig[nPath];
902       if (nPiece < 0 || nPiece >= int(from->descr_cmd.size()))
903             {
904               // segment batard
905               dest->LineTo (getPoint(getEdge(bord).en).x);
906               bord = swdData[bord].suivParc;
907             }
908       else
909             {
910               int nType = from->descr_cmd[nPiece]->getType();
911               if (nType == descr_close || nType == descr_moveto
912             || nType == descr_forced)
913         {
914           // devrait pas arriver
915           dest->LineTo (getPoint(getEdge(bord).en).x);
916           bord = swdData[bord].suivParc;
917         }
918               else if (nType == descr_lineto)
919         {
920           bord = ReFormeLineTo (bord, curBord, dest, from);
921         }
922               else if (nType == descr_arcto)
923         {
924           bord = ReFormeArcTo (bord, curBord, dest, from);
925         }
926               else if (nType == descr_cubicto)
927         {
928           bord = ReFormeCubicTo (bord, curBord, dest, from);
929         }
930               else if (nType == descr_bezierto)
931         {
932           PathDescrBezierTo* nBData =
933             dynamic_cast<PathDescrBezierTo *>(from->descr_cmd[nPiece]);
934           
935           if (nBData->nb == 0)
936           {
937             bord = ReFormeLineTo (bord, curBord, dest, from);
938           }
939           else
940           {
941             bord = ReFormeBezierTo (bord, curBord, dest, from);
942           }
943         }
944               else if (nType == descr_interm_bezier)
945         {
946           bord = ReFormeBezierTo (bord, curBord, dest, from);
947         }
948               else
949         {
950           // devrait pas arriver non plus
951           dest->LineTo (getPoint(getEdge(bord).en).x);
952           bord = swdData[bord].suivParc;
953         }
954               if (bord >= 0 && getPoint(getEdge(bord).st).totalDegree() > 2 ) {
955           dest->ForcePoint ();
956         } else if ( bord >= 0 && getPoint(getEdge(bord).st).oldDegree > 2 && getPoint(getEdge(bord).st).totalDegree() == 2)  {
957           if ( splitWhenForced ) {
958             // pour les coupures
959             dest->ForcePoint ();
960          } else {
961             if ( _has_back_data ) {
962               int   prevEdge=getPoint(getEdge(bord).st).incidentEdge[FIRST];
963               int   nextEdge=getPoint(getEdge(bord).st).incidentEdge[LAST];
964               if ( getEdge(prevEdge).en != getEdge(bord).st ) {
965                 int  swai=prevEdge;prevEdge=nextEdge;nextEdge=swai;
966               }
967               if ( ebData[prevEdge].pieceID == ebData[nextEdge].pieceID  && ebData[prevEdge].pathID == ebData[nextEdge].pathID ) {
968                 if ( fabs(ebData[prevEdge].tEn-ebData[nextEdge].tSt) < 0.05 ) {
969                 } else {
970                   dest->ForcePoint ();
971                 }
972               } else {
973                 dest->ForcePoint ();
974               }
975             } else {
976               dest->ForcePoint ();
977             }    
978           }
979         }
980       }
981     }
982   }
983   dest->Close ();
986 int
987 Shape::ReFormeLineTo (int bord, int curBord, Path * dest, Path * orig)
989   int nPiece = ebData[bord].pieceID;
990   int nPath = ebData[bord].pathID;
991   double /*ts=ebData[bord].tSt, */ te = ebData[bord].tEn;
992   NR::Point nx = getPoint(getEdge(bord).en).x;
993   bord = swdData[bord].suivParc;
994   while (bord >= 0)
995   {
996     if (getPoint(getEdge(bord).st).totalDegree() > 2
997         || getPoint(getEdge(bord).st).oldDegree > 2)
998     {
999       break;
1000     }
1001     if (ebData[bord].pieceID == nPiece && ebData[bord].pathID == nPath)
1002     {
1003       if (fabs (te - ebData[bord].tSt) > 0.0001)
1004         break;
1005       nx = getPoint(getEdge(bord).en).x;
1006       te = ebData[bord].tEn;
1007     }
1008     else
1009     {
1010       break;
1011     }
1012     bord = swdData[bord].suivParc;
1013   }
1014   {
1015     dest->LineTo (nx);
1016   }
1017   return bord;
1020 int
1021 Shape::ReFormeArcTo (int bord, int curBord, Path * dest, Path * from)
1023   int nPiece = ebData[bord].pieceID;
1024   int nPath = ebData[bord].pathID;
1025   double ts = ebData[bord].tSt, te = ebData[bord].tEn;
1026   //      double  px=pts[getEdge(bord).st].x,py=pts[getEdge(bord).st].y;
1027   NR::Point nx = getPoint(getEdge(bord).en).x;
1028   bord = swdData[bord].suivParc;
1029   while (bord >= 0)
1030   {
1031     if (getPoint(getEdge(bord).st).totalDegree() > 2
1032         || getPoint(getEdge(bord).st).oldDegree > 2)
1033     {
1034       break;
1035     }
1036     if (ebData[bord].pieceID == nPiece && ebData[bord].pathID == nPath)
1037     {
1038       if (fabs (te - ebData[bord].tSt) > 0.0001)
1039             {
1040               break;
1041             }
1042       nx = getPoint(getEdge(bord).en).x;
1043       te = ebData[bord].tEn;
1044     }
1045     else
1046     {
1047       break;
1048     }
1049     bord = swdData[bord].suivParc;
1050   }
1051   double sang, eang;
1052   PathDescrArcTo* nData = dynamic_cast<PathDescrArcTo *>(from->descr_cmd[nPiece]);
1053   bool nLarge = nData->large;
1054   bool nClockwise = nData->clockwise;
1055   Path::ArcAngles (from->PrevPoint (nPiece - 1), nData->p,nData->rx,nData->ry,nData->angle, nLarge, nClockwise,  sang, eang);
1056   if (nClockwise)
1057   {
1058     if (sang < eang)
1059       sang += 2 * M_PI;
1060   }
1061   else
1062   {
1063     if (sang > eang)
1064       sang -= 2 * M_PI;
1065   }
1066   double delta = eang - sang;
1067   double ndelta = delta * (te - ts);
1068   if (ts > te)
1069     nClockwise = !nClockwise;
1070   if (ndelta < 0)
1071     ndelta = -ndelta;
1072   if (ndelta > M_PI)
1073     nLarge = true;
1074   else
1075     nLarge = false;
1076   /*    if ( delta < 0 ) delta=-delta;
1077         if ( ndelta < 0 ) ndelta=-ndelta;
1078         if ( ( delta < M_PI && ndelta < M_PI ) || ( delta >= M_PI && ndelta >= M_PI ) ) {
1079                 if ( ts < te ) {
1080                 } else {
1081                         nClockwise=!(nClockwise);
1082                 }
1083         } else {
1084     //          nLarge=!(nLarge);
1085                 nLarge=false; // c'est un sous-segment -> l'arc ne peut que etre plus petit
1086                 if ( ts < te ) {
1087                 } else {
1088                         nClockwise=!(nClockwise);
1089                 }
1090         }*/
1091   {
1092     PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(from->descr_cmd[nPiece]);
1093     dest->ArcTo (nx, nData->rx,nData->ry,nData->angle, nLarge, nClockwise);
1094   }
1095   return bord;
1098 int
1099 Shape::ReFormeCubicTo (int bord, int curBord, Path * dest, Path * from)
1101   int nPiece = ebData[bord].pieceID;
1102   int nPath = ebData[bord].pathID;
1103   double ts = ebData[bord].tSt, te = ebData[bord].tEn;
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   NR::Point prevx = from->PrevPoint (nPiece - 1);
1129   
1130   NR::Point sDx, eDx;
1131   {
1132     PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(from->descr_cmd[nPiece]);
1133     Path::CubicTangent (ts, sDx, prevx,nData->start,nData->p,nData->end);
1134     Path::CubicTangent (te, eDx, prevx,nData->start,nData->p,nData->end);
1135   }
1136   sDx *= (te - ts);
1137   eDx *= (te - ts);
1138   {
1139     dest->CubicTo (nx,sDx,eDx);
1140   }
1141   return bord;
1144 int
1145 Shape::ReFormeBezierTo (int bord, int curBord, Path * dest, Path * from)
1147   int nPiece = ebData[bord].pieceID;
1148   int nPath = ebData[bord].pathID;
1149   double ts = ebData[bord].tSt, te = ebData[bord].tEn;
1150   int ps = nPiece, pe = nPiece;
1151   NR::Point px = getPoint(getEdge(bord).st).x;
1152   NR::Point nx = getPoint(getEdge(bord).en).x;
1153   int inBezier = -1, nbInterm = -1;
1154   int typ;
1155   typ = from->descr_cmd[nPiece]->getType();
1156   PathDescrBezierTo *nBData = NULL;
1157   if (typ == descr_bezierto)
1158   {
1159     nBData = dynamic_cast<PathDescrBezierTo *>(from->descr_cmd[nPiece]);
1160     inBezier = nPiece;
1161     nbInterm = nBData->nb;
1162   }
1163   else
1164   {
1165     int n = nPiece - 1;
1166     while (n > 0)
1167     {
1168       typ = from->descr_cmd[n]->getType();
1169       if (typ == descr_bezierto)
1170       {
1171         inBezier = n;
1172         nBData = dynamic_cast<PathDescrBezierTo *>(from->descr_cmd[n]);
1173         nbInterm = nBData->nb;
1174         break;
1175       }
1176       n--;
1177     }
1178     if (inBezier < 0)
1179     {
1180       bord = swdData[bord].suivParc;
1181       dest->LineTo (nx);
1182       return bord;
1183     }
1184   }
1185   bord = swdData[bord].suivParc;
1186   while (bord >= 0)
1187   {
1188     if (getPoint(getEdge(bord).st).totalDegree() > 2
1189         || getPoint(getEdge(bord).st).oldDegree > 2)
1190     {
1191       break;
1192     }
1193     if (ebData[bord].pathID == nPath)
1194     {
1195       if (ebData[bord].pieceID < inBezier
1196           || ebData[bord].pieceID >= inBezier + nbInterm)
1197         break;
1198       if (ebData[bord].pieceID == pe
1199           && fabs (te - ebData[bord].tSt) > 0.0001)
1200         break;
1201       if (ebData[bord].pieceID != pe
1202           && (ebData[bord].tSt > 0.0001 && ebData[bord].tSt < 0.9999))
1203         break;
1204       if (ebData[bord].pieceID != pe && (te > 0.0001 && te < 0.9999))
1205         break;
1206       nx = getPoint(getEdge(bord).en).x;
1207       te = ebData[bord].tEn;
1208       pe = ebData[bord].pieceID;
1209     }
1210     else
1211     {
1212       break;
1213     }
1214     bord = swdData[bord].suivParc;
1215   }
1217   g_return_val_if_fail(nBData != NULL, 0);
1218   
1219   if (pe == ps)
1220   {
1221     ReFormeBezierChunk (px, nx, dest, inBezier, nbInterm, from, ps,
1222                         ts, te);
1223   }
1224   else if (ps < pe)
1225   {
1226     if (ts < 0.0001)
1227     {
1228       if (te > 0.9999)
1229       {
1230         dest->BezierTo (nx);
1231         for (int i = ps; i <= pe; i++)
1232         {
1233           PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1234           dest->IntermBezierTo (nData->p);
1235         }
1236         dest->EndBezierTo ();
1237       }
1238       else
1239       {
1240         NR::Point tx;
1241         {
1242           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe]);
1243           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+1]);
1244           tx = (pnData->p + psData->p) / 2;
1245         }
1246         dest->BezierTo (tx);
1247         for (int i = ps; i < pe; i++)
1248         {
1249           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1250           dest->IntermBezierTo (nData->p);
1251         }
1252         dest->EndBezierTo ();
1253         ReFormeBezierChunk (tx, nx, dest, inBezier, nbInterm,
1254                             from, pe, 0.0, te);
1255       }
1256     }
1257     else
1258     {
1259       if (te > 0.9999)
1260       {
1261         NR::Point tx;
1262         {
1263           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
1264           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+2]);
1265           tx = (psData->p +  pnData->p) / 2;
1266         }
1267         ReFormeBezierChunk (px, tx, dest, inBezier, nbInterm,
1268                             from, ps, ts, 1.0);
1269         dest->BezierTo (nx);
1270         for (int i = ps + 1; i <= pe; i++)
1271         {
1272           PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1273           dest->IntermBezierTo (nData->p);
1274         }
1275         dest->EndBezierTo ();
1276       }
1277       else
1278       {
1279         NR::Point tx;
1280         {
1281           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
1282           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+2]);
1283           tx = (pnData->p + psData->p) / 2;
1284         }
1285         ReFormeBezierChunk (px, tx, dest, inBezier, nbInterm,
1286                             from, ps, ts, 1.0);
1287         {
1288           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe]);
1289           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+1]);
1290           tx = (pnData->p + psData->p) / 2;
1291         }
1292          dest->BezierTo (tx);
1293         for (int i = ps + 1; i <= pe; i++)
1294         {
1295           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1296           dest->IntermBezierTo (nData->p);
1297         }
1298         dest->EndBezierTo ();
1299         ReFormeBezierChunk (tx, nx, dest, inBezier, nbInterm,
1300                             from, pe, 0.0, te);
1301       }
1302     }
1303   }
1304   else
1305   {
1306     if (ts > 0.9999)
1307     {
1308       if (te < 0.0001)
1309       {
1310         dest->BezierTo (nx);
1311         for (int i = ps; i >= pe; i--)
1312         {
1313           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1314           dest->IntermBezierTo (nData->p);
1315         }
1316         dest->EndBezierTo ();
1317       }
1318       else
1319       {
1320         NR::Point tx;
1321         {
1322           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+1]);
1323           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+2]);
1324           tx = (pnData->p + psData->p) / 2;
1325         }
1326         dest->BezierTo (tx);
1327         for (int i = ps; i > pe; i--)
1328         {
1329           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i+1]);
1330           dest->IntermBezierTo (nData->p);
1331         }
1332         dest->EndBezierTo ();
1333         ReFormeBezierChunk (tx, nx, dest, inBezier, nbInterm,
1334                             from, pe, 1.0, te);
1335       }
1336     }
1337     else
1338     {
1339       if (te < 0.0001)
1340       {
1341         NR::Point tx;
1342         {
1343           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps]);
1344           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
1345           tx = (pnData->p + psData->p) / 2;
1346         }
1347          ReFormeBezierChunk (px, tx, dest, inBezier, nbInterm,
1348                             from, ps, ts, 0.0);
1349         dest->BezierTo (nx);
1350         for (int i = ps + 1; i >= pe; i--)
1351         {
1352           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i]);
1353           dest->IntermBezierTo (nData->p);
1354         }
1355         dest->EndBezierTo ();
1356       }
1357       else
1358       {
1359         NR::Point tx;
1360         {
1361           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps]);
1362           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[ps+1]);
1363           tx = (pnData->p + psData->p) / 2;
1364         }
1365         ReFormeBezierChunk (px, tx, dest, inBezier, nbInterm,
1366                             from, ps, ts, 0.0);
1367         {
1368           PathDescrIntermBezierTo* psData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+1]);
1369           PathDescrIntermBezierTo* pnData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[pe+2]);
1370           tx = (pnData->p + psData->p) / 2;
1371         }
1372         dest->BezierTo (tx);
1373         for (int i = ps + 1; i > pe; i--)
1374         {
1375           PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[i]);
1376           dest->IntermBezierTo (nData->p);
1377         }
1378         dest->EndBezierTo ();
1379         ReFormeBezierChunk (tx, nx, dest, inBezier, nbInterm,
1380                             from, pe, 1.0, te);
1381       }
1382     }
1383   }
1384   return bord;
1387 void
1388 Shape::ReFormeBezierChunk (NR::Point px, NR::Point nx,
1389                            Path * dest, int inBezier, int nbInterm,
1390                            Path * from, int p, double ts, double te)
1392   PathDescrBezierTo* nBData = dynamic_cast<PathDescrBezierTo*>(from->descr_cmd[inBezier]);
1393   NR::Point bstx = from->PrevPoint (inBezier - 1);
1394   NR::Point benx = nBData->p;
1395   
1396   NR::Point mx;
1397   if (p == inBezier)
1398   {
1399     // premier bout
1400     if (nbInterm <= 1)
1401     {
1402       // seul bout de la spline
1403       PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[inBezier+1]);
1404       mx = nData->p;
1405     }
1406     else
1407     {
1408       // premier bout d'une spline qui en contient plusieurs
1409       PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[inBezier+1]);
1410       mx = nData->p;
1411       nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[inBezier+2]);
1412       benx = (nData->p + mx) / 2;
1413     }
1414   }
1415   else if (p == inBezier + nbInterm - 1)
1416   {
1417     // dernier bout
1418     // si nbInterm == 1, le cas a deja ete traite
1419     // donc dernier bout d'une spline qui en contient plusieurs
1420     PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[inBezier+nbInterm]);
1421     mx = nData->p;
1422     nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[inBezier+nbInterm-1]);
1423     bstx = (nData->p + mx) / 2;
1424   }
1425   else
1426   {
1427     // la spline contient forcĂ©ment plusieurs bouts, et ce n'est ni le premier ni le dernier
1428     PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[p+1]);
1429     mx = nData->p;
1430     nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[p]);
1431     bstx = (nData->p + mx) / 2;
1432     nData = dynamic_cast<PathDescrIntermBezierTo*>(from->descr_cmd[p+2]);
1433     benx = (nData->p + mx) / 2;
1434   }
1435   NR::Point cx;
1436   {
1437     Path::QuadraticPoint ((ts + te) / 2, cx, bstx, mx, benx);
1438   }
1439   cx = 2 * cx - (px + nx) / 2;
1440   {
1441     dest->BezierTo (nx);
1442     dest->IntermBezierTo (cx);
1443     dest->EndBezierTo ();
1444   }
1447 #undef MiscNormalize