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