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