Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
Shape.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
/*
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 <cstdio>
14#include <cstdlib>
15#include <glib.h>
16#include "Shape.h"
19
20/*
21 * Shape instances handling.
22 * never (i repeat: never) modify edges and points links; use Connect() and Disconnect() instead
23 * the graph is stored as a set of points and edges, with edges in a doubly-linked list for each point.
24 */
25
27 : nbInc(0),
28 maxInc(0),
29 iData(nullptr),
30 sTree(nullptr),
31 sEvts(nullptr),
32 _need_points_sorting(false),
33 _need_edges_sorting(false),
34 _has_points_data(false),
35 _point_data_initialised(false),
36 _has_edges_data(false),
37 _has_sweep_src_data(false),
38 _has_sweep_dest_data(false),
39 _has_raster_data(false),
40 _has_back_data(false),
41 _bbox_up_to_date(false)
42{
43 leftX = topY = rightX = bottomY = 0;
44 maxPt = 0;
45 maxAr = 0;
46
48}
50{
51 maxPt = 0;
52 maxAr = 0;
53}
54
56{
57 printf("sh=%p nbPt=%i nbAr=%i\n", this, static_cast<int>(_pts.size()), static_cast<int>(_aretes.size())); // localizing ok
58 for (unsigned int i=0; i<_pts.size(); i++) {
59 printf("pt %u : x=(%f %f) dI=%i dO=%i\n",i, _pts[i].x[0], _pts[i].x[1], _pts[i].dI, _pts[i].dO); // localizing ok
60 }
61 for (unsigned int i=0; i<_aretes.size(); i++) {
62 printf("ar %u : dx=(%f %f) st=%i en=%i\n",i, _aretes[i].dx[0], _aretes[i].dx[1], _aretes[i].st, _aretes[i].en); // localizing ok
63 }
64}
65
70void
72{
73 if (nVal)
74 {
75 if (_has_points_data == false)
76 {
77 _has_points_data = true;
79 _bbox_up_to_date = false;
80 pData.resize(maxPt);
81 }
82 }
83 /* no need to clean point data - keep it cached*/
84}
85
86void
88{
89 if (nVal)
90 {
91 if (_has_edges_data == false)
92 {
93 _has_edges_data = true;
94 eData.resize(maxAr);
95 }
96 }
97 else
98 {
100 {
101 _has_edges_data = false;
102 eData.clear();
103 }
104 }
105}
106
107void
109{
110 if (nVal)
111 {
112 if (_has_raster_data == false)
113 {
114 _has_raster_data = true;
115 swrData.resize(maxAr);
116 }
117 }
118 else
119 {
121 {
122 _has_raster_data = false;
123 swrData.clear();
124 }
125 }
126}
127
128void
130{
131 if (nVal)
132 {
133 if (_has_sweep_src_data == false)
134 {
135 _has_sweep_src_data = true;
136 swsData.resize(maxAr);
137 }
138 }
139 else
140 {
142 {
143 _has_sweep_src_data = false;
144 swsData.clear();
145 }
146 }
147}
148void
150{
151 if (nVal)
152 {
153 if (_has_sweep_dest_data == false)
154 {
156 swdData.resize(maxAr);
157 }
158 }
159 else
160 {
162 {
163 _has_sweep_dest_data = false;
164 swdData.clear();
165 }
166 }
167}
168void
170{
171 if (nVal)
172 {
173 if (_has_back_data == false)
174 {
175 _has_back_data = true;
176 ebData.resize(maxAr);
177 }
178 }
179 else
180 {
181 if (_has_back_data)
182 {
183 _has_back_data = false;
184 ebData.clear();
185 }
186 }
187}
188
189
194void
196{
197 if (who == nullptr)
198 {
199 Reset (0, 0);
200 return;
201 }
202 MakePointData (false);
203 MakeEdgeData (false);
204 MakeSweepSrcData (false);
205 MakeSweepDestData (false);
206 MakeRasterData (false);
207 MakeBackData (false);
208
209 delete sTree;
210 sTree = nullptr;
211 delete sEvts;
212 sEvts = nullptr;
213
214 Reset (who->numberOfPoints(), who->numberOfEdges());
215 type = who->type;
218 _has_points_data = false;
220 _has_edges_data = false;
221 _has_sweep_src_data = false;
222 _has_sweep_dest_data = false;
223 _has_raster_data = false;
224 _has_back_data = false;
225 _bbox_up_to_date = false;
226
227 _pts = who->_pts;
228 _aretes = who->_aretes;
229}
230
234void
235Shape::Reset (int pointCount, int edgeCount)
236{
237 _pts.clear();
238 _aretes.clear();
239
241 if (pointCount > maxPt)
242 {
243 maxPt = pointCount;
245 pData.resize(maxPt);
246 }
247 if (edgeCount > maxAr)
248 {
249 maxAr = edgeCount;
250 if (_has_edges_data)
251 eData.resize(maxAr);
253 swdData.resize(maxAr);
255 swsData.resize(maxAr);
256 if (_has_back_data)
257 ebData.resize(maxAr);
258 }
259 _need_points_sorting = false;
260 _need_edges_sorting = false;
262 _bbox_up_to_date = false;
263}
264
265int
267{
268 if (numberOfPoints() >= maxPt)
269 {
270 maxPt = 2 * numberOfPoints() + 1;
272 pData.resize(maxPt);
273 }
274
275 dg_point p;
276 p.x = x;
277 p.dI = p.dO = 0;
278 p.incidentEdge[FIRST] = p.incidentEdge[LAST] = -1;
279 p.oldDegree = -1;
280 _pts.push_back(p);
281 int const n = _pts.size() - 1;
282
284 {
285 pData[n].pending = 0;
286 pData[n].nextLinkedPoint = -1;
287 pData[n].askForWindingS = nullptr;
288 pData[n].askForWindingB = -1;
289 pData[n].rx[0] = Round(p.x[0]);
290 pData[n].rx[1] = Round(p.x[1]);
291 }
293
294 return n;
295}
296
297void
299{
300 if (p < 0 || p >= numberOfPoints())
301 return;
303 int cb;
304 cb = getPoint(p).incidentEdge[FIRST];
305 while (cb >= 0 && cb < numberOfEdges())
306 {
307 if (getEdge(cb).st == p)
308 {
309 int ncb = getEdge(cb).nextS;
310 _aretes[cb].nextS = _aretes[cb].prevS = -1;
311 _aretes[cb].st = -1;
312 cb = ncb;
313 }
314 else if (getEdge(cb).en == p)
315 {
316 int ncb = getEdge(cb).nextE;
317 _aretes[cb].nextE = _aretes[cb].prevE = -1;
318 _aretes[cb].en = -1;
319 cb = ncb;
320 }
321 else
322 {
323 break;
324 }
325 }
326 _pts[p].incidentEdge[FIRST] = _pts[p].incidentEdge[LAST] = -1;
327 if (p < numberOfPoints() - 1)
328 SwapPoints (p, numberOfPoints() - 1);
329 _pts.pop_back();
330}
331
332void
333Shape::SwapPoints (int a, int b)
334{
335 if (a == b)
336 return;
337 if (getPoint(a).totalDegree() == 2 && getPoint(b).totalDegree() == 2)
338 {
339 int cb = getPoint(a).incidentEdge[FIRST];
340 if (getEdge(cb).st == a)
341 {
342 _aretes[cb].st = numberOfPoints();
343 }
344 else if (getEdge(cb).en == a)
345 {
346 _aretes[cb].en = numberOfPoints();
347 }
348 cb = getPoint(a).incidentEdge[LAST];
349 if (getEdge(cb).st == a)
350 {
351 _aretes[cb].st = numberOfPoints();
352 }
353 else if (getEdge(cb).en == a)
354 {
355 _aretes[cb].en = numberOfPoints();
356 }
357
358 cb = getPoint(b).incidentEdge[FIRST];
359 if (getEdge(cb).st == b)
360 {
361 _aretes[cb].st = a;
362 }
363 else if (getEdge(cb).en == b)
364 {
365 _aretes[cb].en = a;
366 }
367 cb = getPoint(b).incidentEdge[LAST];
368 if (getEdge(cb).st == b)
369 {
370 _aretes[cb].st = a;
371 }
372 else if (getEdge(cb).en == b)
373 {
374 _aretes[cb].en = a;
375 }
376
377 cb = getPoint(a).incidentEdge[FIRST];
378 if (getEdge(cb).st == numberOfPoints())
379 {
380 _aretes[cb].st = b;
381 }
382 else if (getEdge(cb).en == numberOfPoints())
383 {
384 _aretes[cb].en = b;
385 }
386 cb = getPoint(a).incidentEdge[LAST];
387 if (getEdge(cb).st == numberOfPoints())
388 {
389 _aretes[cb].st = b;
390 }
391 else if (getEdge(cb).en == numberOfPoints())
392 {
393 _aretes[cb].en = b;
394 }
395
396 }
397 else
398 {
399 int cb;
400 cb = getPoint(a).incidentEdge[FIRST];
401 while (cb >= 0)
402 {
403 int ncb = NextAt (a, cb);
404 if (getEdge(cb).st == a)
405 {
406 _aretes[cb].st = numberOfPoints();
407 }
408 else if (getEdge(cb).en == a)
409 {
410 _aretes[cb].en = numberOfPoints();
411 }
412 cb = ncb;
413 }
414 cb = getPoint(b).incidentEdge[FIRST];
415 while (cb >= 0)
416 {
417 int ncb = NextAt (b, cb);
418 if (getEdge(cb).st == b)
419 {
420 _aretes[cb].st = a;
421 }
422 else if (getEdge(cb).en == b)
423 {
424 _aretes[cb].en = a;
425 }
426 cb = ncb;
427 }
428 cb = getPoint(a).incidentEdge[FIRST];
429 while (cb >= 0)
430 {
431 int ncb = NextAt (numberOfPoints(), cb);
432 if (getEdge(cb).st == numberOfPoints())
433 {
434 _aretes[cb].st = b;
435 }
436 else if (getEdge(cb).en == numberOfPoints())
437 {
438 _aretes[cb].en = b;
439 }
440 cb = ncb;
441 }
442 }
443 {
444 dg_point swap = getPoint(a);
445 _pts[a] = getPoint(b);
446 _pts[b] = swap;
447 }
449 {
450 point_data swad = pData[a];
451 pData[a] = pData[b];
452 pData[b] = swad;
453 // pData[pData[a].oldInd].newInd=a;
454 // pData[pData[b].oldInd].newInd=b;
455 }
456}
457void
458Shape::SwapPoints (int a, int b, int c)
459{
460 if (a == b || b == c || a == c)
461 return;
462 SwapPoints (a, b);
463 SwapPoints (b, c);
464}
465
466void
473
474void
480
481void
482Shape::SortPoints (int s, int e)
483{
484 if (s >= e)
485 return;
486 if (e == s + 1)
487 {
488 if (getPoint(s).x[1] > getPoint(e).x[1]
489 || (getPoint(s).x[1] == getPoint(e).x[1] && getPoint(s).x[0] > getPoint(e).x[0]))
490 SwapPoints (s, e);
491 return;
492 }
493
494 int ppos = (s + e) / 2;
495 int plast = ppos;
496 double pvalx = getPoint(ppos).x[0];
497 double pvaly = getPoint(ppos).x[1];
498
499 int le = s, ri = e;
500 while (le < ppos || ri > plast)
501 {
502 if (le < ppos)
503 {
504 do
505 {
506 int test = 0;
507 if (getPoint(le).x[1] > pvaly)
508 {
509 test = 1;
510 }
511 else if (getPoint(le).x[1] == pvaly)
512 {
513 if (getPoint(le).x[0] > pvalx)
514 {
515 test = 1;
516 }
517 else if (getPoint(le).x[0] == pvalx)
518 {
519 test = 0;
520 }
521 else
522 {
523 test = -1;
524 }
525 }
526 else
527 {
528 test = -1;
529 }
530 if (test == 0)
531 {
532 // on colle les valeurs egales au pivot ensemble
533 if (le < ppos - 1)
534 {
535 SwapPoints (le, ppos - 1, ppos);
536 ppos--;
537 continue; // sans changer le
538 }
539 else if (le == ppos - 1)
540 {
541 ppos--;
542 break;
543 }
544 else
545 {
546 // oupsie
547 break;
548 }
549 }
550 if (test > 0)
551 {
552 break;
553 }
554 le++;
555 }
556 while (le < ppos);
557 }
558 if (ri > plast)
559 {
560 do
561 {
562 int test = 0;
563 if (getPoint(ri).x[1] > pvaly)
564 {
565 test = 1;
566 }
567 else if (getPoint(ri).x[1] == pvaly)
568 {
569 if (getPoint(ri).x[0] > pvalx)
570 {
571 test = 1;
572 }
573 else if (getPoint(ri).x[0] == pvalx)
574 {
575 test = 0;
576 }
577 else
578 {
579 test = -1;
580 }
581 }
582 else
583 {
584 test = -1;
585 }
586 if (test == 0)
587 {
588 // on colle les valeurs egales au pivot ensemble
589 if (ri > plast + 1)
590 {
591 SwapPoints (ri, plast + 1, plast);
592 plast++;
593 continue; // sans changer ri
594 }
595 else if (ri == plast + 1)
596 {
597 plast++;
598 break;
599 }
600 else
601 {
602 // oupsie
603 break;
604 }
605 }
606 if (test < 0)
607 {
608 break;
609 }
610 ri--;
611 }
612 while (ri > plast);
613 }
614 if (le < ppos)
615 {
616 if (ri > plast)
617 {
618 SwapPoints (le, ri);
619 le++;
620 ri--;
621 }
622 else
623 {
624 if (le < ppos - 1)
625 {
626 SwapPoints (ppos - 1, plast, le);
627 ppos--;
628 plast--;
629 }
630 else if (le == ppos - 1)
631 {
632 SwapPoints (plast, le);
633 ppos--;
634 plast--;
635 }
636 }
637 }
638 else
639 {
640 if (ri > plast + 1)
641 {
642 SwapPoints (plast + 1, ppos, ri);
643 ppos++;
644 plast++;
645 }
646 else if (ri == plast + 1)
647 {
648 SwapPoints (ppos, ri);
649 ppos++;
650 plast++;
651 }
652 else
653 {
654 break;
655 }
656 }
657 }
658 SortPoints (s, ppos - 1);
659 SortPoints (plast + 1, e);
660}
661
662void
664{
665 if (s >= e)
666 return;
667 if (e == s + 1)
668 {
669 if (getPoint(s).x[1] > getPoint(e).x[1] || (getPoint(s).x[1] == getPoint(e).x[1] && getPoint(s).x[0] > getPoint(e).x[0])
670 || (getPoint(s).x[1] == getPoint(e).x[1] && getPoint(s).x[0] == getPoint(e).x[0]
671 && pData[s].oldInd > pData[e].oldInd))
672 SwapPoints (s, e);
673 return;
674 }
675
676 int ppos = (s + e) / 2;
677 int plast = ppos;
678 double pvalx = getPoint(ppos).x[0];
679 double pvaly = getPoint(ppos).x[1];
680 int pvali = pData[ppos].oldInd;
681
682 int le = s, ri = e;
683 while (le < ppos || ri > plast)
684 {
685 if (le < ppos)
686 {
687 do
688 {
689 int test = 0;
690 if (getPoint(le).x[1] > pvaly)
691 {
692 test = 1;
693 }
694 else if (getPoint(le).x[1] == pvaly)
695 {
696 if (getPoint(le).x[0] > pvalx)
697 {
698 test = 1;
699 }
700 else if (getPoint(le).x[0] == pvalx)
701 {
702 if (pData[le].oldInd > pvali)
703 {
704 test = 1;
705 }
706 else if (pData[le].oldInd == pvali)
707 {
708 test = 0;
709 }
710 else
711 {
712 test = -1;
713 }
714 }
715 else
716 {
717 test = -1;
718 }
719 }
720 else
721 {
722 test = -1;
723 }
724 if (test == 0)
725 {
726 // on colle les valeurs egales au pivot ensemble
727 if (le < ppos - 1)
728 {
729 SwapPoints (le, ppos - 1, ppos);
730 ppos--;
731 continue; // sans changer le
732 }
733 else if (le == ppos - 1)
734 {
735 ppos--;
736 break;
737 }
738 else
739 {
740 // oupsie
741 break;
742 }
743 }
744 if (test > 0)
745 {
746 break;
747 }
748 le++;
749 }
750 while (le < ppos);
751 }
752 if (ri > plast)
753 {
754 do
755 {
756 int test = 0;
757 if (getPoint(ri).x[1] > pvaly)
758 {
759 test = 1;
760 }
761 else if (getPoint(ri).x[1] == pvaly)
762 {
763 if (getPoint(ri).x[0] > pvalx)
764 {
765 test = 1;
766 }
767 else if (getPoint(ri).x[0] == pvalx)
768 {
769 if (pData[ri].oldInd > pvali)
770 {
771 test = 1;
772 }
773 else if (pData[ri].oldInd == pvali)
774 {
775 test = 0;
776 }
777 else
778 {
779 test = -1;
780 }
781 }
782 else
783 {
784 test = -1;
785 }
786 }
787 else
788 {
789 test = -1;
790 }
791 if (test == 0)
792 {
793 // on colle les valeurs egales au pivot ensemble
794 if (ri > plast + 1)
795 {
796 SwapPoints (ri, plast + 1, plast);
797 plast++;
798 continue; // sans changer ri
799 }
800 else if (ri == plast + 1)
801 {
802 plast++;
803 break;
804 }
805 else
806 {
807 // oupsie
808 break;
809 }
810 }
811 if (test < 0)
812 {
813 break;
814 }
815 ri--;
816 }
817 while (ri > plast);
818 }
819 if (le < ppos)
820 {
821 if (ri > plast)
822 {
823 SwapPoints (le, ri);
824 le++;
825 ri--;
826 }
827 else
828 {
829 if (le < ppos - 1)
830 {
831 SwapPoints (ppos - 1, plast, le);
832 ppos--;
833 plast--;
834 }
835 else if (le == ppos - 1)
836 {
837 SwapPoints (plast, le);
838 ppos--;
839 plast--;
840 }
841 }
842 }
843 else
844 {
845 if (ri > plast + 1)
846 {
847 SwapPoints (plast + 1, ppos, ri);
848 ppos++;
849 plast++;
850 }
851 else if (ri == plast + 1)
852 {
853 SwapPoints (ppos, ri);
854 ppos++;
855 plast++;
856 }
857 else
858 {
859 break;
860 }
861 }
862 }
863 SortPointsByOldInd (s, ppos - 1);
864 SortPointsByOldInd (plast + 1, e);
865}
866
867void
869{
870 if (s >= e)
871 return;
872 if (e == s + 1)
873 {
874 if (pData[s].rx[1] > pData[e].rx[1]
875 || (pData[s].rx[1] == pData[e].rx[1] && pData[s].rx[0] > pData[e].rx[0]))
876 SwapPoints (s, e);
877 return;
878 }
879
880 int ppos = (s + e) / 2;
881 int plast = ppos;
882 double pvalx = pData[ppos].rx[0];
883 double pvaly = pData[ppos].rx[1];
884
885 int le = s, ri = e;
886 while (le < ppos || ri > plast)
887 {
888 if (le < ppos)
889 {
890 do
891 {
892 int test = 0;
893 if (pData[le].rx[1] > pvaly)
894 {
895 test = 1;
896 }
897 else if (pData[le].rx[1] == pvaly)
898 {
899 if (pData[le].rx[0] > pvalx)
900 {
901 test = 1;
902 }
903 else if (pData[le].rx[0] == pvalx)
904 {
905 test = 0;
906 }
907 else
908 {
909 test = -1;
910 }
911 }
912 else
913 {
914 test = -1;
915 }
916 if (test == 0)
917 {
918 // on colle les valeurs egales au pivot ensemble
919 if (le < ppos - 1)
920 {
921 SwapPoints (le, ppos - 1, ppos);
922 ppos--;
923 continue; // sans changer le
924 }
925 else if (le == ppos - 1)
926 {
927 ppos--;
928 break;
929 }
930 else
931 {
932 // oupsie
933 break;
934 }
935 }
936 if (test > 0)
937 {
938 break;
939 }
940 le++;
941 }
942 while (le < ppos);
943 }
944 if (ri > plast)
945 {
946 do
947 {
948 int test = 0;
949 if (pData[ri].rx[1] > pvaly)
950 {
951 test = 1;
952 }
953 else if (pData[ri].rx[1] == pvaly)
954 {
955 if (pData[ri].rx[0] > pvalx)
956 {
957 test = 1;
958 }
959 else if (pData[ri].rx[0] == pvalx)
960 {
961 test = 0;
962 }
963 else
964 {
965 test = -1;
966 }
967 }
968 else
969 {
970 test = -1;
971 }
972 if (test == 0)
973 {
974 // on colle les valeurs egales au pivot ensemble
975 if (ri > plast + 1)
976 {
977 SwapPoints (ri, plast + 1, plast);
978 plast++;
979 continue; // sans changer ri
980 }
981 else if (ri == plast + 1)
982 {
983 plast++;
984 break;
985 }
986 else
987 {
988 // oupsie
989 break;
990 }
991 }
992 if (test < 0)
993 {
994 break;
995 }
996 ri--;
997 }
998 while (ri > plast);
999 }
1000 if (le < ppos)
1001 {
1002 if (ri > plast)
1003 {
1004 SwapPoints (le, ri);
1005 le++;
1006 ri--;
1007 }
1008 else
1009 {
1010 if (le < ppos - 1)
1011 {
1012 SwapPoints (ppos - 1, plast, le);
1013 ppos--;
1014 plast--;
1015 }
1016 else if (le == ppos - 1)
1017 {
1018 SwapPoints (plast, le);
1019 ppos--;
1020 plast--;
1021 }
1022 }
1023 }
1024 else
1025 {
1026 if (ri > plast + 1)
1027 {
1028 SwapPoints (plast + 1, ppos, ri);
1029 ppos++;
1030 plast++;
1031 }
1032 else if (ri == plast + 1)
1033 {
1034 SwapPoints (ppos, ri);
1035 ppos++;
1036 plast++;
1037 }
1038 else
1039 {
1040 break;
1041 }
1042 }
1043 }
1044 SortPointsRounded (s, ppos - 1);
1045 SortPointsRounded (plast + 1, e);
1046}
1047
1048/*
1049 *
1050 */
1051int
1052Shape::AddEdge (int st, int en)
1053{
1054 if (st == en)
1055 return -1;
1056 if (st < 0 || en < 0)
1057 return -1;
1058 type = shape_graph;
1059 if (numberOfEdges() >= maxAr)
1060 {
1061 maxAr = 2 * numberOfEdges() + 1;
1062 if (_has_edges_data)
1063 eData.resize(maxAr);
1065 swsData.resize(maxAr);
1067 swdData.resize(maxAr);
1068 if (_has_raster_data)
1069 swrData.resize(maxAr);
1070 if (_has_back_data)
1071 ebData.resize(maxAr);
1072 }
1073
1074 dg_arete a;
1075 a.dx = Geom::Point(0, 0);
1076 a.st = a.en = -1;
1077 a.prevS = a.nextS = -1;
1078 a.prevE = a.nextE = -1;
1079 if (st >= 0 && en >= 0) {
1080 a.dx = getPoint(en).x - getPoint(st).x;
1081 }
1082
1083 _aretes.push_back(a);
1084 int const n = numberOfEdges() - 1;
1085
1086 ConnectStart (st, n);
1087 ConnectEnd (en, n);
1088 if (_has_edges_data)
1089 {
1090 eData[n].weight = 1;
1091 eData[n].rdx = getEdge(n).dx;
1092 }
1094 {
1095 swsData[n].misc = nullptr;
1096 swsData[n].firstLinkedPoint = -1;
1097 }
1098 if (_has_back_data)
1099 {
1100 ebData[n].pathID = -1;
1101 ebData[n].pieceID = -1;
1102 ebData[n].tSt = ebData[n].tEn = 0;
1103 }
1104 _need_edges_sorting = true;
1105 return n;
1106}
1107
1108int
1109Shape::AddEdge (int st, int en, int leF, int riF)
1110{
1111 if (st == en)
1112 return -1;
1113 if (st < 0 || en < 0)
1114 return -1;
1115 {
1116 int cb = getPoint(st).incidentEdge[FIRST];
1117 while (cb >= 0)
1118 {
1119 if (getEdge(cb).st == st && getEdge(cb).en == en)
1120 return -1; // doublon
1121 if (getEdge(cb).st == en && getEdge(cb).en == st)
1122 return -1; // doublon
1123 cb = NextAt (st, cb);
1124 }
1125 }
1126 type = shape_graph;
1127 if (numberOfEdges() >= maxAr)
1128 {
1129 maxAr = 2 * numberOfEdges() + 1;
1130 if (_has_edges_data)
1131 eData.resize(maxAr);
1133 swsData.resize(maxAr);
1135 swdData.resize(maxAr);
1136 if (_has_raster_data)
1137 swrData.resize(maxAr);
1138 if (_has_back_data)
1139 ebData.resize(maxAr);
1140 }
1141
1142 dg_arete a;
1143 a.dx = Geom::Point(0, 0);
1144 a.st = a.en = -1;
1145 a.prevS = a.nextS = -1;
1146 a.prevE = a.nextE = -1;
1147 if (st >= 0 && en >= 0) {
1148 a.dx = getPoint(en).x - getPoint(st).x;
1149 }
1150
1151 _aretes.push_back(a);
1152 int const n = numberOfEdges() - 1;
1153
1154 ConnectStart (st, n);
1155 ConnectEnd (en, n);
1156 if (_has_edges_data)
1157 {
1158 eData[n].weight = 1;
1159 eData[n].rdx = getEdge(n).dx;
1160 }
1162 {
1163 swsData[n].misc = nullptr;
1164 swsData[n].firstLinkedPoint = -1;
1165 }
1166 if (_has_back_data)
1167 {
1168 ebData[n].pathID = -1;
1169 ebData[n].pieceID = -1;
1170 ebData[n].tSt = ebData[n].tEn = 0;
1171 }
1172 _need_edges_sorting = true;
1173 return n;
1174}
1175
1176void
1178{
1179 if (e < 0 || e >= numberOfEdges())
1180 return;
1181 type = shape_graph;
1182 DisconnectStart (e);
1183 DisconnectEnd (e);
1184 if (e < numberOfEdges() - 1)
1185 SwapEdges (e, numberOfEdges() - 1);
1186 _aretes.pop_back();
1187 _need_edges_sorting = true;
1188}
1189
1190void
1191Shape::SwapEdges (int a, int b)
1192{
1193 if (a == b)
1194 return;
1195 if (getEdge(a).prevS >= 0 && getEdge(a).prevS != b)
1196 {
1197 if (getEdge(getEdge(a).prevS).st == getEdge(a).st)
1198 {
1199 _aretes[getEdge(a).prevS].nextS = b;
1200 }
1201 else if (getEdge(getEdge(a).prevS).en == getEdge(a).st)
1202 {
1203 _aretes[getEdge(a).prevS].nextE = b;
1204 }
1205 }
1206 if (getEdge(a).nextS >= 0 && getEdge(a).nextS != b)
1207 {
1208 if (getEdge(getEdge(a).nextS).st == getEdge(a).st)
1209 {
1210 _aretes[getEdge(a).nextS].prevS = b;
1211 }
1212 else if (getEdge(getEdge(a).nextS).en == getEdge(a).st)
1213 {
1214 _aretes[getEdge(a).nextS].prevE = b;
1215 }
1216 }
1217 if (getEdge(a).prevE >= 0 && getEdge(a).prevE != b)
1218 {
1219 if (getEdge(getEdge(a).prevE).st == getEdge(a).en)
1220 {
1221 _aretes[getEdge(a).prevE].nextS = b;
1222 }
1223 else if (getEdge(getEdge(a).prevE).en == getEdge(a).en)
1224 {
1225 _aretes[getEdge(a).prevE].nextE = b;
1226 }
1227 }
1228 if (getEdge(a).nextE >= 0 && getEdge(a).nextE != b)
1229 {
1230 if (getEdge(getEdge(a).nextE).st == getEdge(a).en)
1231 {
1232 _aretes[getEdge(a).nextE].prevS = b;
1233 }
1234 else if (getEdge(getEdge(a).nextE).en == getEdge(a).en)
1235 {
1236 _aretes[getEdge(a).nextE].prevE = b;
1237 }
1238 }
1239 if (getEdge(a).st >= 0)
1240 {
1241 if (getPoint(getEdge(a).st).incidentEdge[FIRST] == a)
1242 _pts[getEdge(a).st].incidentEdge[FIRST] = numberOfEdges();
1243 if (getPoint(getEdge(a).st).incidentEdge[LAST] == a)
1244 _pts[getEdge(a).st].incidentEdge[LAST] = numberOfEdges();
1245 }
1246 if (getEdge(a).en >= 0)
1247 {
1248 if (getPoint(getEdge(a).en).incidentEdge[FIRST] == a)
1249 _pts[getEdge(a).en].incidentEdge[FIRST] = numberOfEdges();
1250 if (getPoint(getEdge(a).en).incidentEdge[LAST] == a)
1251 _pts[getEdge(a).en].incidentEdge[LAST] = numberOfEdges();
1252 }
1253
1254
1255 if (getEdge(b).prevS >= 0 && getEdge(b).prevS != a)
1256 {
1257 if (getEdge(getEdge(b).prevS).st == getEdge(b).st)
1258 {
1259 _aretes[getEdge(b).prevS].nextS = a;
1260 }
1261 else if (getEdge(getEdge(b).prevS).en == getEdge(b).st)
1262 {
1263 _aretes[getEdge(b).prevS].nextE = a;
1264 }
1265 }
1266 if (getEdge(b).nextS >= 0 && getEdge(b).nextS != a)
1267 {
1268 if (getEdge(getEdge(b).nextS).st == getEdge(b).st)
1269 {
1270 _aretes[getEdge(b).nextS].prevS = a;
1271 }
1272 else if (getEdge(getEdge(b).nextS).en == getEdge(b).st)
1273 {
1274 _aretes[getEdge(b).nextS].prevE = a;
1275 }
1276 }
1277 if (getEdge(b).prevE >= 0 && getEdge(b).prevE != a)
1278 {
1279 if (getEdge(getEdge(b).prevE).st == getEdge(b).en)
1280 {
1281 _aretes[getEdge(b).prevE].nextS = a;
1282 }
1283 else if (getEdge(getEdge(b).prevE).en == getEdge(b).en)
1284 {
1285 _aretes[getEdge(b).prevE].nextE = a;
1286 }
1287 }
1288 if (getEdge(b).nextE >= 0 && getEdge(b).nextE != a)
1289 {
1290 if (getEdge(getEdge(b).nextE).st == getEdge(b).en)
1291 {
1292 _aretes[getEdge(b).nextE].prevS = a;
1293 }
1294 else if (getEdge(getEdge(b).nextE).en == getEdge(b).en)
1295 {
1296 _aretes[getEdge(b).nextE].prevE = a;
1297 }
1298 }
1299
1300
1301 for (int i = 0; i < 2; i++) {
1302 int p = getEdge(b).st;
1303 if (p >= 0) {
1304 if (getPoint(p).incidentEdge[i] == b) {
1305 _pts[p].incidentEdge[i] = a;
1306 }
1307 }
1308
1309 p = getEdge(b).en;
1310 if (p >= 0) {
1311 if (getPoint(p).incidentEdge[i] == b) {
1312 _pts[p].incidentEdge[i] = a;
1313 }
1314 }
1315
1316 p = getEdge(a).st;
1317 if (p >= 0) {
1318 if (getPoint(p).incidentEdge[i] == numberOfEdges()) {
1319 _pts[p].incidentEdge[i] = b;
1320 }
1321 }
1322
1323 p = getEdge(a).en;
1324 if (p >= 0) {
1325 if (getPoint(p).incidentEdge[i] == numberOfEdges()) {
1326 _pts[p].incidentEdge[i] = b;
1327 }
1328 }
1329
1330 }
1331
1332 if (getEdge(a).prevS == b)
1333 _aretes[a].prevS = a;
1334 if (getEdge(a).prevE == b)
1335 _aretes[a].prevE = a;
1336 if (getEdge(a).nextS == b)
1337 _aretes[a].nextS = a;
1338 if (getEdge(a).nextE == b)
1339 _aretes[a].nextE = a;
1340 if (getEdge(b).prevS == a)
1341 _aretes[a].prevS = b;
1342 if (getEdge(b).prevE == a)
1343 _aretes[a].prevE = b;
1344 if (getEdge(b).nextS == a)
1345 _aretes[a].nextS = b;
1346 if (getEdge(b).nextE == a)
1347 _aretes[a].nextE = b;
1348
1349 dg_arete swap = getEdge(a);
1350 _aretes[a] = getEdge(b);
1351 _aretes[b] = swap;
1352 if (_has_edges_data)
1353 {
1354 edge_data swae = eData[a];
1355 eData[a] = eData[b];
1356 eData[b] = swae;
1357 }
1359 {
1360 sweep_src_data swae = swsData[a];
1361 swsData[a] = swsData[b];
1362 swsData[b] = swae;
1363 }
1365 {
1366 sweep_dest_data swae = swdData[a];
1367 swdData[a] = swdData[b];
1368 swdData[b] = swae;
1369 }
1370 if (_has_raster_data)
1371 {
1372 raster_data swae = swrData[a];
1373 swrData[a] = swrData[b];
1374 swrData[b] = swae;
1375 }
1376 if (_has_back_data)
1377 {
1378 back_data swae = ebData[a];
1379 ebData[a] = ebData[b];
1380 ebData[b] = swae;
1381 }
1382}
1383void
1384Shape::SwapEdges (int a, int b, int c)
1385{
1386 if (a == b || b == c || a == c)
1387 return;
1388 SwapEdges (a, b);
1389 SwapEdges (b, c);
1390}
1391
1392void
1394{
1395 if (_need_edges_sorting == false) {
1396 return;
1397 }
1398 _need_edges_sorting = false;
1399
1400 // allocate the edge_list array as it's needed by SortEdgesList
1401 edge_list *list = (edge_list *) g_malloc(numberOfEdges() * sizeof (edge_list));
1402 // for each point
1403 for (int p = 0; p < numberOfPoints(); p++)
1404 {
1405 int const d = getPoint(p).totalDegree();
1406 // if degree is greater than 1
1407 if (d > 1)
1408 {
1409 int cb;
1410 // get the first edge
1411 cb = getPoint(p).incidentEdge[FIRST];
1412 int nb = 0;
1413 // for all the edges connected at this point, form the list
1414 while (cb >= 0)
1415 {
1416 int n = nb++;
1417 list[n].no = cb;
1418 if (getEdge(cb).st == p)
1419 {
1420 list[n].x = getEdge(cb).dx;
1421 list[n].starting = true;
1422 }
1423 else
1424 {
1425 list[n].x = -getEdge(cb).dx;
1426 list[n].starting = false;
1427 }
1428 cb = NextAt (p, cb);
1429 }
1430 // sort the list
1431 SortEdgesList (list, 0, nb - 1);
1432 // recreate the linked list with the sorted edges
1433 _pts[p].incidentEdge[FIRST] = list[0].no;
1434 _pts[p].incidentEdge[LAST] = list[nb - 1].no;
1435 for (int i = 0; i < nb; i++)
1436 {
1437 if (list[i].starting)
1438 {
1439 if (i > 0)
1440 {
1441 _aretes[list[i].no].prevS = list[i - 1].no;
1442 }
1443 else
1444 {
1445 _aretes[list[i].no].prevS = -1;
1446 }
1447 if (i < nb - 1)
1448 {
1449 _aretes[list[i].no].nextS = list[i + 1].no;
1450 }
1451 else
1452 {
1453 _aretes[list[i].no].nextS = -1;
1454 }
1455 }
1456 else
1457 {
1458 if (i > 0)
1459 {
1460 _aretes[list[i].no].prevE = list[i - 1].no;
1461 }
1462 else
1463 {
1464 _aretes[list[i].no].prevE = -1;
1465 }
1466 if (i < nb - 1)
1467 {
1468 _aretes[list[i].no].nextE = list[i + 1].no;
1469 }
1470 else
1471 {
1472 _aretes[list[i].no].nextE = -1;
1473 }
1474 }
1475 }
1476 }
1477 }
1478 g_free(list);
1479}
1480
1481int
1483{
1484 // these tst variables store the sign of the x and y coordinates of each of the vectors
1485 // + is +1, - is -1 and 0 is 0
1486 int tstAX = 0;
1487 int tstAY = 0;
1488 int tstBX = 0;
1489 int tstBY = 0;
1490 if (ax[0] > 0)
1491 tstAX = 1;
1492 if (ax[0] < 0)
1493 tstAX = -1;
1494 if (ax[1] > 0)
1495 tstAY = 1;
1496 if (ax[1] < 0)
1497 tstAY = -1;
1498 if (bx[0] > 0)
1499 tstBX = 1;
1500 if (bx[0] < 0)
1501 tstBX = -1;
1502 if (bx[1] > 0)
1503 tstBY = 1;
1504 if (bx[1] < 0)
1505 tstBY = -1;
1506
1507 // calcuate quadrant for both a and b edge vectors
1508 // for quadrant numbers, see the figure in header file documentation of this
1509 // function
1510 int quadA = 0, quadB = 0;
1511 if (tstAX < 0)
1512 {
1513 if (tstAY < 0)
1514 {
1515 quadA = 7;
1516 }
1517 else if (tstAY == 0)
1518 {
1519 quadA = 6;
1520 }
1521 else if (tstAY > 0)
1522 {
1523 quadA = 5;
1524 }
1525 }
1526 else if (tstAX == 0)
1527 {
1528 if (tstAY < 0)
1529 {
1530 quadA = 0;
1531 }
1532 else if (tstAY == 0)
1533 {
1534 quadA = -1;
1535 }
1536 else if (tstAY > 0)
1537 {
1538 quadA = 4;
1539 }
1540 }
1541 else if (tstAX > 0)
1542 {
1543 if (tstAY < 0)
1544 {
1545 quadA = 1;
1546 }
1547 else if (tstAY == 0)
1548 {
1549 quadA = 2;
1550 }
1551 else if (tstAY > 0)
1552 {
1553 quadA = 3;
1554 }
1555 }
1556 if (tstBX < 0)
1557 {
1558 if (tstBY < 0)
1559 {
1560 quadB = 7;
1561 }
1562 else if (tstBY == 0)
1563 {
1564 quadB = 6;
1565 }
1566 else if (tstBY > 0)
1567 {
1568 quadB = 5;
1569 }
1570 }
1571 else if (tstBX == 0)
1572 {
1573 if (tstBY < 0)
1574 {
1575 quadB = 0;
1576 }
1577 else if (tstBY == 0)
1578 {
1579 quadB = -1;
1580 }
1581 else if (tstBY > 0)
1582 {
1583 quadB = 4;
1584 }
1585 }
1586 else if (tstBX > 0)
1587 {
1588 if (tstBY < 0)
1589 {
1590 quadB = 1;
1591 }
1592 else if (tstBY == 0)
1593 {
1594 quadB = 2;
1595 }
1596 else if (tstBY > 0)
1597 {
1598 quadB = 3;
1599 }
1600 }
1601
1602
1603 // B should have a smaller quadrant number, if the opposite is true, we need to swap
1604 if (quadA < quadB)
1605 return 1;
1606 if (quadA > quadB)
1607 return -1;
1608
1609 // if the quadrants are same, we need to do more maths to figure out their relative orientation
1610
1611 Geom::Point av, bv;
1612 av = ax;
1613 bv = bx;
1614
1615 // take cross from av to bv
1616 // cross product in SVG coordinates is different visually. With your right hand, let index finger point to vector
1617 // av, and let middle finger point to vector bv, if thumb is out of page, cross is negative, if into the page, it's
1618 // positive
1619 double si = cross(av, bv);
1620 // if the angle that bv makes from -y axis is smaller than the one av makes, our arrangement is good and needs no swap
1621 // this ideal orientation will give a negative cross product (thumb out of page)
1622 int tstSi = 0;
1623 if (si > 0.000001) tstSi = 1; // if positive cross product, swap needed
1624 if (si < -0.000001) tstSi = -1; // if negative cross product, we are good
1625
1626 // if the edges are kinda on top of each other
1627 // I have no idea if there is a reason behind these two rules below
1628 if ( tstSi == 0 ) {
1629 if ( as && !bs ) return -1; // if b ends at point and a starts, we are good
1630 if ( !as && bs ) return 1; // if b starts at point and a ends, swap
1631 }
1632
1633 // if we stil can't decide whether a swap is needed or not (both edges on top of each other and both starting
1634 // from the point) or ending at the point, we return 0
1635 return tstSi;
1636}
1637
1638void
1639Shape::SortEdgesList (edge_list * list, int s, int e)
1640{
1641 if (s >= e)
1642 return;
1643 if (e == s + 1) {
1644 int cmpval=CmpToVert (list[e].x, list[s].x,list[e].starting,list[s].starting);
1645 if ( cmpval > 0 ) { // priorite aux sortants
1646 edge_list swap = list[s];
1647 list[s] = list[e];
1648 list[e] = swap;
1649 }
1650 return;
1651 }
1652
1653 int ppos = (s + e) / 2;
1654 int plast = ppos;
1655 Geom::Point pvalx = list[ppos].x;
1656 bool pvals = list[ppos].starting;
1657
1658 int le = s, ri = e;
1659 while (le < ppos || ri > plast)
1660 {
1661 if (le < ppos)
1662 {
1663 do
1664 {
1665 int test = CmpToVert (pvalx, list[le].x,pvals,list[le].starting);
1666 if (test == 0)
1667 {
1668 // on colle les valeurs egales au pivot ensemble
1669 if (le < ppos - 1)
1670 {
1671 edge_list swap = list[le];
1672 list[le] = list[ppos - 1];
1673 list[ppos - 1] = list[ppos];
1674 list[ppos] = swap;
1675 ppos--;
1676 continue; // sans changer le
1677 }
1678 else if (le == ppos - 1)
1679 {
1680 ppos--;
1681 break;
1682 }
1683 else
1684 {
1685 // oupsie
1686 break;
1687 }
1688 }
1689 if (test > 0)
1690 {
1691 break;
1692 }
1693 le++;
1694 }
1695 while (le < ppos);
1696 }
1697 if (ri > plast)
1698 {
1699 do
1700 {
1701 int test = CmpToVert (pvalx, list[ri].x,pvals,list[ri].starting);
1702 if (test == 0)
1703 {
1704 // on colle les valeurs egales au pivot ensemble
1705 if (ri > plast + 1)
1706 {
1707 edge_list swap = list[ri];
1708 list[ri] = list[plast + 1];
1709 list[plast + 1] = list[plast];
1710 list[plast] = swap;
1711 plast++;
1712 continue; // sans changer ri
1713 }
1714 else if (ri == plast + 1)
1715 {
1716 plast++;
1717 break;
1718 }
1719 else
1720 {
1721 // oupsie
1722 break;
1723 }
1724 }
1725 if (test < 0)
1726 {
1727 break;
1728 }
1729 ri--;
1730 }
1731 while (ri > plast);
1732 }
1733
1734 if (le < ppos)
1735 {
1736 if (ri > plast)
1737 {
1738 edge_list swap = list[le];
1739 list[le] = list[ri];
1740 list[ri] = swap;
1741 le++;
1742 ri--;
1743 }
1744 else if (le < ppos - 1)
1745 {
1746 edge_list swap = list[ppos - 1];
1747 list[ppos - 1] = list[plast];
1748 list[plast] = list[le];
1749 list[le] = swap;
1750 ppos--;
1751 plast--;
1752 }
1753 else if (le == ppos - 1)
1754 {
1755 edge_list swap = list[plast];
1756 list[plast] = list[le];
1757 list[le] = swap;
1758 ppos--;
1759 plast--;
1760 }
1761 else
1762 {
1763 break;
1764 }
1765 }
1766 else
1767 {
1768 if (ri > plast + 1)
1769 {
1770 edge_list swap = list[plast + 1];
1771 list[plast + 1] = list[ppos];
1772 list[ppos] = list[ri];
1773 list[ri] = swap;
1774 ppos++;
1775 plast++;
1776 }
1777 else if (ri == plast + 1)
1778 {
1779 edge_list swap = list[ppos];
1780 list[ppos] = list[ri];
1781 list[ri] = swap;
1782 ppos++;
1783 plast++;
1784 }
1785 else
1786 {
1787 break;
1788 }
1789 }
1790 }
1791 SortEdgesList (list, s, ppos - 1);
1792 SortEdgesList (list, plast + 1, e);
1793
1794}
1795
1796
1797
1798/*
1799 *
1800 */
1801void
1803{
1804 if (getEdge(b).st >= 0)
1805 DisconnectStart (b);
1806
1807 _aretes[b].st = p;
1808 _pts[p].dO++;
1809 _aretes[b].nextS = -1;
1810 _aretes[b].prevS = getPoint(p).incidentEdge[LAST];
1811 if (getPoint(p).incidentEdge[LAST] >= 0)
1812 {
1813 if (getEdge(getPoint(p).incidentEdge[LAST]).st == p)
1814 {
1815 _aretes[getPoint(p).incidentEdge[LAST]].nextS = b;
1816 }
1817 else if (getEdge(getPoint(p).incidentEdge[LAST]).en == p)
1818 {
1819 _aretes[getPoint(p).incidentEdge[LAST]].nextE = b;
1820 }
1821 }
1822 _pts[p].incidentEdge[LAST] = b;
1823 if (getPoint(p).incidentEdge[FIRST] < 0)
1824 _pts[p].incidentEdge[FIRST] = b;
1825}
1826
1827void
1828Shape::ConnectEnd (int p, int b)
1829{
1830 if (getEdge(b).en >= 0)
1831 DisconnectEnd (b);
1832 _aretes[b].en = p;
1833 _pts[p].dI++;
1834 _aretes[b].nextE = -1;
1835 _aretes[b].prevE = getPoint(p).incidentEdge[LAST];
1836 if (getPoint(p).incidentEdge[LAST] >= 0)
1837 {
1838 if (getEdge(getPoint(p).incidentEdge[LAST]).st == p)
1839 {
1840 _aretes[getPoint(p).incidentEdge[LAST]].nextS = b;
1841 }
1842 else if (getEdge(getPoint(p).incidentEdge[LAST]).en == p)
1843 {
1844 _aretes[getPoint(p).incidentEdge[LAST]].nextE = b;
1845 }
1846 }
1847 _pts[p].incidentEdge[LAST] = b;
1848 if (getPoint(p).incidentEdge[FIRST] < 0)
1849 _pts[p].incidentEdge[FIRST] = b;
1850}
1851
1852void
1854{
1855 if (getEdge(b).st < 0)
1856 return;
1857 _pts[getEdge(b).st].dO--;
1858 if (getEdge(b).prevS >= 0)
1859 {
1860 if (getEdge(getEdge(b).prevS).st == getEdge(b).st)
1861 {
1862 _aretes[getEdge(b).prevS].nextS = getEdge(b).nextS;
1863 }
1864 else if (getEdge(getEdge(b).prevS).en == getEdge(b).st)
1865 {
1866 _aretes[getEdge(b).prevS].nextE = getEdge(b).nextS;
1867 }
1868 }
1869 if (getEdge(b).nextS >= 0)
1870 {
1871 if (getEdge(getEdge(b).nextS).st == getEdge(b).st)
1872 {
1873 _aretes[getEdge(b).nextS].prevS = getEdge(b).prevS;
1874 }
1875 else if (getEdge(getEdge(b).nextS).en == getEdge(b).st)
1876 {
1877 _aretes[getEdge(b).nextS].prevE = getEdge(b).prevS;
1878 }
1879 }
1880 if (getPoint(getEdge(b).st).incidentEdge[FIRST] == b)
1881 _pts[getEdge(b).st].incidentEdge[FIRST] = getEdge(b).nextS;
1882 if (getPoint(getEdge(b).st).incidentEdge[LAST] == b)
1883 _pts[getEdge(b).st].incidentEdge[LAST] = getEdge(b).prevS;
1884 _aretes[b].st = -1;
1885}
1886
1887void
1889{
1890 if (getEdge(b).en < 0)
1891 return;
1892 _pts[getEdge(b).en].dI--;
1893 if (getEdge(b).prevE >= 0)
1894 {
1895 if (getEdge(getEdge(b).prevE).st == getEdge(b).en)
1896 {
1897 _aretes[getEdge(b).prevE].nextS = getEdge(b).nextE;
1898 }
1899 else if (getEdge(getEdge(b).prevE).en == getEdge(b).en)
1900 {
1901 _aretes[getEdge(b).prevE].nextE = getEdge(b).nextE;
1902 }
1903 }
1904 if (getEdge(b).nextE >= 0)
1905 {
1906 if (getEdge(getEdge(b).nextE).st == getEdge(b).en)
1907 {
1908 _aretes[getEdge(b).nextE].prevS = getEdge(b).prevE;
1909 }
1910 else if (getEdge(getEdge(b).nextE).en == getEdge(b).en)
1911 {
1912 _aretes[getEdge(b).nextE].prevE = getEdge(b).prevE;
1913 }
1914 }
1915 if (getPoint(getEdge(b).en).incidentEdge[FIRST] == b)
1916 _pts[getEdge(b).en].incidentEdge[FIRST] = getEdge(b).nextE;
1917 if (getPoint(getEdge(b).en).incidentEdge[LAST] == b)
1918 _pts[getEdge(b).en].incidentEdge[LAST] = getEdge(b).prevE;
1919 _aretes[b].en = -1;
1920}
1921
1922
1923void
1925{
1926 int swap;
1927 swap = getEdge(b).st;
1928 _aretes[b].st = getEdge(b).en;
1929 _aretes[b].en = swap;
1930 swap = getEdge(b).prevE;
1931 _aretes[b].prevE = getEdge(b).prevS;
1932 _aretes[b].prevS = swap;
1933 swap = getEdge(b).nextE;
1934 _aretes[b].nextE = getEdge(b).nextS;
1935 _aretes[b].nextS = swap;
1936 _aretes[b].dx = -getEdge(b).dx;
1937 if (getEdge(b).st >= 0)
1938 {
1939 _pts[getEdge(b).st].dO++;
1940 _pts[getEdge(b).st].dI--;
1941 }
1942 if (getEdge(b).en >= 0)
1943 {
1944 _pts[getEdge(b).en].dO--;
1945 _pts[getEdge(b).en].dI++;
1946 }
1947 if (_has_edges_data)
1948 eData[b].weight = -eData[b].weight;
1950 {
1951 int swap = swdData[b].leW;
1952 swdData[b].leW = swdData[b].riW;
1953 swdData[b].riW = swap;
1954 }
1955 if (_has_back_data)
1956 {
1957 double swat = ebData[b].tSt;
1958 ebData[b].tSt = ebData[b].tEn;
1959 ebData[b].tEn = swat;
1960 }
1961}
1962void
1963Shape::CalcBBox (bool strict_degree)
1964{
1965 if (_bbox_up_to_date)
1966 return;
1967 if (hasPoints() == false)
1968 {
1969 leftX = rightX = topY = bottomY = 0;
1970 _bbox_up_to_date = true;
1971 return;
1972 }
1973 leftX = rightX = getPoint(0).x[0];
1974 topY = bottomY = getPoint(0).x[1];
1975 bool not_set=true;
1976 for (int i = 0; i < numberOfPoints(); i++)
1977 {
1978 if ( strict_degree == false || getPoint(i).dI > 0 || getPoint(i).dO > 0 ) {
1979 if ( not_set ) {
1980 leftX = rightX = getPoint(i).x[0];
1981 topY = bottomY = getPoint(i).x[1];
1982 not_set=false;
1983 } else {
1984 if ( getPoint(i).x[0] < leftX) leftX = getPoint(i).x[0];
1985 if ( getPoint(i).x[0] > rightX) rightX = getPoint(i).x[0];
1986 if ( getPoint(i).x[1] < topY) topY = getPoint(i).x[1];
1987 if ( getPoint(i).x[1] > bottomY) bottomY = getPoint(i).x[1];
1988 }
1989 }
1990 }
1991
1992 _bbox_up_to_date = true;
1993}
1994
1995// winding of a point with respect to the Shape
1996// 0= outside
1997// 1= inside (or -1, that usually the same)
1998// other=depends on your fill rule
1999// if the polygon is uncrossed, it's all the same, usually
2000int
2002{
2003 int lr = 0, ll = 0, rr = 0;
2004
2005 for (int i = 0; i < numberOfEdges(); i++)
2006 {
2007 Geom::Point const adir = getEdge(i).dx;
2008
2009 Geom::Point const ast = getPoint(getEdge(i).st).x;
2010 Geom::Point const aen = getPoint(getEdge(i).en).x;
2011
2012 //int const nWeight = eData[i].weight;
2013 int const nWeight = 1;
2014
2015 if (ast[0] < aen[0]) {
2016 if (ast[0] > px[0]) continue;
2017 if (aen[0] < px[0]) continue;
2018 } else {
2019 if (ast[0] < px[0]) continue;
2020 if (aen[0] > px[0]) continue;
2021 }
2022 if (ast[0] == px[0]) {
2023 if (ast[1] >= px[1]) continue;
2024 if (aen[0] == px[0]) continue;
2025 if (aen[0] < px[0]) ll += nWeight; else rr -= nWeight;
2026 continue;
2027 }
2028 if (aen[0] == px[0]) {
2029 if (aen[1] >= px[1]) continue;
2030 if (ast[0] == px[0]) continue;
2031 if (ast[0] < px[0]) ll -= nWeight; else rr += nWeight;
2032 continue;
2033 }
2034
2035 if (ast[1] < aen[1]) {
2036 if (ast[1] >= px[1]) continue;
2037 } else {
2038 if (aen[1] >= px[1]) continue;
2039 }
2040
2041 Geom::Point const diff = px - ast;
2042 double const cote = cross(adir, diff);
2043 if (cote == 0) continue;
2044 if (cote < 0) {
2045 if (ast[0] > px[0]) lr += nWeight;
2046 } else {
2047 if (ast[0] < px[0]) lr -= nWeight;
2048 }
2049 }
2050 return lr + (ll + rr) / 2;
2051}
2052
2053
2055{
2057 return;
2058 int const N = numberOfPoints();
2059
2060 for (int i = 0; i < N; i++) {
2061 pData[i].pending = 0;
2062 pData[i].nextLinkedPoint = -1;
2063 pData[i].rx[0] = Round(getPoint(i).x[0]);
2064 pData[i].rx[1] = Round(getPoint(i).x[1]);
2065 }
2066
2068}
2069
2071{
2072 int const N = numberOfEdges();
2073
2074 for (int i = 0; i < N; i++) {
2075 eData[i].rdx = pData[getEdge(i).en].rx - pData[getEdge(i).st].rx;
2076 eData[i].length = dot(eData[i].rdx, eData[i].rdx);
2077 eData[i].ilength = 1 / eData[i].length;
2078 eData[i].sqlength = sqrt(eData[i].length);
2079 eData[i].isqlength = 1 / eData[i].sqlength;
2080 eData[i].siEd = eData[i].rdx[1] * eData[i].isqlength;
2081 eData[i].coEd = eData[i].rdx[0] * eData[i].isqlength;
2082
2083 if (eData[i].siEd < 0) {
2084 eData[i].siEd = -eData[i].siEd;
2085 eData[i].coEd = -eData[i].coEd;
2086 }
2087
2088 swsData[i].misc = nullptr;
2089 swsData[i].firstLinkedPoint = -1;
2090 swsData[i].stPt = swsData[i].enPt = -1;
2091 swsData[i].leftRnd = swsData[i].rightRnd = -1;
2092 swsData[i].nextSh = nullptr;
2093 swsData[i].nextBo = -1;
2094 swsData[i].curPoint = -1;
2095 swsData[i].doneTo = -1;
2096 }
2097}
2098
2099
2101{
2102 g_free(iData);
2103 iData = nullptr;
2104 nbInc = maxInc = 0;
2105}
2106
2107
2108
2118{
2119 for (int i = 0; i < s->numberOfPoints(); i++) {
2120 if (s->getPoint(i).dI != s->getPoint(i).dO) {
2121 return false;
2122 }
2123 }
2124
2125 return true;
2126}
2127
2128
2129
2136double distance(Shape const *s, Geom::Point const &p)
2137{
2138 if ( s->hasPoints() == false) {
2139 return 0.0;
2140 }
2141
2142 /* Find the minimum distance from p to one of the points on s.
2143 ** Computing the dot product of the difference vector gives
2144 ** us the distance squared; we can leave the square root
2145 ** until the end.
2146 */
2147 double bdot = Geom::dot(p - s->getPoint(0).x, p - s->getPoint(0).x);
2148
2149 for (int i = 0; i < s->numberOfPoints(); i++) {
2150 Geom::Point const offset( p - s->getPoint(i).x );
2151 double ndot = Geom::dot(offset, offset);
2152 if ( ndot < bdot ) {
2153 bdot = ndot;
2154 }
2155 }
2156
2157 for (int i = 0; i < s->numberOfEdges(); i++) {
2158 if ( s->getEdge(i).st >= 0 && s->getEdge(i).en >= 0 ) {
2159 /* The edge has start and end points */
2160 Geom::Point const st(s->getPoint(s->getEdge(i).st).x); // edge start
2161 Geom::Point const en(s->getPoint(s->getEdge(i).en).x); // edge end
2162
2163 Geom::Point const d(p - st); // vector between p and edge start
2164 Geom::Point const e(en - st); // vector of the edge
2165 double const el = Geom::dot(e, e); // edge length
2166
2167 /* Update bdot if appropriate */
2168 if ( el > 0.001 ) {
2169 double const npr = Geom::dot(d, e);
2170 if ( npr > 0 && npr < el ) {
2171 double const nl = fabs( Geom::cross(d, e) );
2172 double ndot = nl * nl / el;
2173 if ( ndot < bdot ) {
2174 bdot = ndot;
2175 }
2176 }
2177 }
2178 }
2179 }
2180
2181 return sqrt(bdot);
2182}
2183
2184
2185
2198bool distanceLessThanOrEqual(Shape const *s, Geom::Point const &p, double const max_l2)
2199{
2200 if ( s->hasPoints() == false ) {
2201 return false;
2202 }
2203
2204 /* TODO: Consider using bbox to return early, perhaps conditional on nbPt or nbAr. */
2205
2206 /* TODO: Efficiency: In one test case (scribbling with the freehand tool to create a small number of long
2207 ** path elements), changing from a Distance method to a DistanceLE method reduced this
2208 ** function's CPU time from about 21% of total inkscape CPU time to 14-15% of total inkscape
2209 ** CPU time, due to allowing early termination. I don't know how much the L1 test helps, it
2210 ** may well be a case of premature optimization. Consider testing dot(offset, offset)
2211 ** instead.
2212 */
2213
2214 double const max_l1 = max_l2 * M_SQRT2;
2215 for (int i = 0; i < s->numberOfPoints(); i++) {
2216 Geom::Point const offset( p - s->getPoint(i).x );
2217 double const l1 = Geom::L1(offset);
2218 if ( (l1 <= max_l2) || ((l1 <= max_l1) && (Geom::L2(offset) <= max_l2)) ) {
2219 return true;
2220 }
2221 }
2222
2223 for (int i = 0; i < s->numberOfEdges(); i++) {
2224 if ( s->getEdge(i).st >= 0 && s->getEdge(i).en >= 0 ) {
2225 Geom::Point const st(s->getPoint(s->getEdge(i).st).x);
2226 Geom::Point const en(s->getPoint(s->getEdge(i).en).x);
2227 Geom::Point const d(p - st);
2228 Geom::Point const e(en - st);
2229 double const el = Geom::L2(e);
2230 if ( el > 0.001 ) {
2231 Geom::Point const e_unit(e / el);
2232 double const npr = Geom::dot(d, e_unit);
2233 if ( npr > 0 && npr < el ) {
2234 double const nl = fabs(Geom::cross(d, e_unit));
2235 if ( nl <= max_l2 ) {
2236 return true;
2237 }
2238 }
2239 }
2240 }
2241 }
2242
2243 return false;
2244}
2245
2246//};
2247
int test()
Definition 2junctions.cpp:5
@ FIRST
Definition LivarotDefs.h:92
@ LAST
Definition LivarotDefs.h:93
bool distanceLessThanOrEqual(Shape const *s, Geom::Point const &p, double const max_l2)
Returns true iff the L2 distance from thePt to this shape is <= max_l2.
Definition Shape.cpp:2198
double distance(Shape const *s, Geom::Point const &p)
Definition Shape.cpp:2136
bool directedEulerian(Shape const *s)
A directed graph is Eulerian iff every vertex has equal indegree and outdegree.
Definition Shape.cpp:2117
TODO: insert short description here.
@ shape_graph
Definition Shape.h:48
@ shape_polygon
Definition Shape.h:49
Two-dimensional point that doubles as a vector.
Definition point.h:66
A class to store/manipulate directed graphs.
Definition Shape.h:65
bool _has_edges_data
the eData array is allocated
Definition Shape.h:1069
void MakeSweepDestData(bool nVal)
Initialize the sweep destination data cache.
Definition Shape.cpp:149
void Affiche()
Definition Shape.cpp:55
std::vector< sweep_src_data > swsData
Definition Shape.h:1082
int maxInc
Definition Shape.h:426
double leftX
Definition Shape.h:434
void MakeBackData(bool nVal)
Definition Shape.cpp:169
bool _point_data_initialised
the pData array is up to date
Definition Shape.h:1068
int nbInc
Definition Shape.h:425
void SubPoint(int p)
Definition Shape.cpp:298
void MakeSweepSrcData(bool nVal)
Initialize the sweep source data cache.
Definition Shape.cpp:129
void DisconnectStart(int b)
Definition Shape.cpp:1853
incidenceData * iData
Definition Shape.h:428
void SwapEdges(int a, int b)
Definition Shape.cpp:1191
int AddEdge(int st, int en)
Definition Shape.cpp:1052
int PtWinding(const Geom::Point px) const
Definition Shape.cpp:2001
bool _has_back_data
Definition Shape.h:1073
bool _has_sweep_src_data
the swsData array is allocated
Definition Shape.h:1070
bool hasPoints() const
Do we have points?
Definition Shape.h:491
std::vector< raster_data > swrData
Definition Shape.h:1084
void SortPoints()
Sort the points (all points) only if needed.
Definition Shape.cpp:467
void SortEdgesList(edge_list *edges, int s, int e)
Sort edges given in a list.
Definition Shape.cpp:1639
bool _bbox_up_to_date
the leftX/rightX/topY/bottomY are up to date
Definition Shape.h:1074
double topY
Definition Shape.h:434
double rightX
Definition Shape.h:434
bool _need_points_sorting
points have been added or removed: we need to sort the points again
Definition Shape.h:1064
std::vector< back_data > ebData
Definition Shape.h:422
static int CmpToVert(const Geom::Point ax, const Geom::Point bx, bool as, bool bs)
Edge comparison function.
Definition Shape.cpp:1482
void MakePointData(bool nVal)
Initialize the point data cache.
Definition Shape.cpp:71
bool _need_edges_sorting
edges have been added: maybe they are not ordered clockwise
Definition Shape.h:1065
int maxAr
Definition Shape.h:474
void Copy(Shape *a)
Copy point and edge data from ‘who’ into this object, discarding any cached data that we have.
Definition Shape.cpp:195
void CalcBBox(bool strict_degree=false)
Definition Shape.cpp:1963
int numberOfEdges() const
Returns number of edges.
Definition Shape.h:498
void ConnectEnd(int p, int b)
Definition Shape.cpp:1828
static double Round(double x)
Definition Shape.h:350
~Shape()
Definition Shape.cpp:49
std::vector< edge_data > eData
Definition Shape.h:1081
int NextAt(int p, int b) const
Definition Shape.h:190
int numberOfPoints() const
Returns number of points.
Definition Shape.h:484
bool _has_points_data
the pData array is allocated
Definition Shape.h:1067
void SwapPoints(int a, int b)
Definition Shape.cpp:333
dg_arete const & getEdge(int n) const
Get an edge.
Definition Shape.h:548
void SortEdges()
Sort all edges (clockwise) around each point.
Definition Shape.cpp:1393
void SortPointsByOldInd(int s, int e)
Sort the points (take oldInd into account)
Definition Shape.cpp:663
void MakeRasterData(bool nVal)
Definition Shape.cpp:108
int maxPt
Definition Shape.h:473
Shape()
Definition Shape.cpp:26
SweepTreeList * sTree
Definition Shape.h:430
void Inverse(int b)
Definition Shape.cpp:1924
void Reset(int n=0, int m=0)
Clear all data.
Definition Shape.cpp:235
void initialiseEdgeData()
Definition Shape.cpp:2070
void SortPointsRounded()
Sort all points by their rounded coordinates.
Definition Shape.cpp:475
std::vector< dg_point > _pts
Definition Shape.h:1076
bool _has_raster_data
the swrData array is allocated
Definition Shape.h:1072
void ConnectStart(int p, int b)
Definition Shape.cpp:1802
int type
Definition Shape.h:477
std::vector< dg_arete > _aretes
Definition Shape.h:1077
int AddPoint(const Geom::Point x)
Definition Shape.cpp:266
void MakeEdgeData(bool nVal)
Initialize the edge data cache.
Definition Shape.cpp:87
void clearIncidenceData()
Definition Shape.cpp:2100
bool _has_sweep_dest_data
the swdData array is allocated
Definition Shape.h:1071
SweepEventQueue * sEvts
Definition Shape.h:431
dg_point const & getPoint(int n) const
Get a point.
Definition Shape.h:537
std::vector< sweep_dest_data > swdData
Definition Shape.h:1083
void initialisePointData()
Definition Shape.cpp:2054
double bottomY
Definition Shape.h:434
void SubEdge(int e)
Definition Shape.cpp:1177
void DisconnectEnd(int b)
Definition Shape.cpp:1888
std::vector< point_data > pData
Definition Shape.h:1085
double c[8][4]
double offset
Coord L1(Point const &p)
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
SBasis L2(D2< SBasis > const &a, unsigned k)
Definition d2-sbasis.cpp:42
T dot(D2< T > const &a, D2< T > const &b)
Definition d2.h:355
unsigned long bs
Definition quantize.cpp:38
size_t N
A structure to store back data for an edge.
Definition Shape.h:71
An edge in the directed graph.
Definition Shape.h:462
Geom::Point dx
Definition Shape.h:463
A point or vertex in the directed graph.
Definition Shape.h:448
int incidentEdge[2]
Definition Shape.h:452
Geom::Point x
Definition Shape.h:449
int totalDegree() const
Definition Shape.h:455
Extra data that some algorithms use.
Definition Shape.h:560
A structure to help with sorting edges around a point.
Definition Shape.h:627
Geom::Point x
Definition Shape.h:630
Extra data for points used at various occasions.
Definition Shape.h:612
A container of intersection events.
TODO: insert short description here.
void dot(Cairo::RefPtr< Cairo::Context > &cr, double x, double y)