Code

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