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