From 98ae089d10cc8ccdf5ea65292ec5f66f695d191d Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 17 May 2023 21:57:51 +0100 Subject: [PATCH 001/182] Add package 2D Polygon Repair --- Documentation/doc/Documentation/packages.txt | 1 + .../include/CGAL/license/Polygon_repair_2.h | 54 ++++++++++++++++++ .../doc/Polygon_repair_2/Doxyfile.in | 4 ++ .../Polygon_repair_2/PackageDescription.txt | 40 +++++++++++++ .../doc/Polygon_repair_2/Polygon_repair_2.txt | 29 ++++++++++ .../doc/Polygon_repair_2/dependencies | 7 +++ .../doc/Polygon_repair_2/examples.txt | 3 + .../fig/Polygon_repair_2-small.png | Bin 0 -> 9467 bytes .../examples/Polygon_repair_2/CMakeLists.txt | 16 ++++++ .../Polygon_repair_2/repair_polygon_2.cpp | 19 ++++++ .../include/CGAL/Polygon_repair_2/repair.h | 25 ++++++++ .../package_info/Polygon_repair_2/copyright | 1 + .../Polygon_repair_2/description.txt | 1 + .../package_info/Polygon_repair_2/license.txt | 1 + .../Polygon_repair_2/long_description.txt | 0 .../package_info/Polygon_repair_2/maintainer | 1 + .../test/Polygon_repair_2/CMakeLists.txt | 16 ++++++ .../repair_polygon_2_test.cpp | 19 ++++++ 18 files changed, 237 insertions(+) create mode 100644 Installation/include/CGAL/license/Polygon_repair_2.h create mode 100644 Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in create mode 100644 Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt create mode 100644 Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt create mode 100644 Polygon_repair_2/doc/Polygon_repair_2/dependencies create mode 100644 Polygon_repair_2/doc/Polygon_repair_2/examples.txt create mode 100644 Polygon_repair_2/doc/Polygon_repair_2/fig/Polygon_repair_2-small.png create mode 100644 Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt create mode 100644 Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp create mode 100644 Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h create mode 100644 Polygon_repair_2/package_info/Polygon_repair_2/copyright create mode 100644 Polygon_repair_2/package_info/Polygon_repair_2/description.txt create mode 100644 Polygon_repair_2/package_info/Polygon_repair_2/license.txt create mode 100644 Polygon_repair_2/package_info/Polygon_repair_2/long_description.txt create mode 100644 Polygon_repair_2/package_info/Polygon_repair_2/maintainer create mode 100644 Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp diff --git a/Documentation/doc/Documentation/packages.txt b/Documentation/doc/Documentation/packages.txt index aa061c842d8d..d89ade951422 100644 --- a/Documentation/doc/Documentation/packages.txt +++ b/Documentation/doc/Documentation/packages.txt @@ -31,6 +31,7 @@ \cgalPackageSection{PartPolygons,Polygons} \package_listing{Polygon} +\package_listing{Polygon_repair_2} \package_listing{Boolean_set_operations_2} \package_listing{Nef_2} \package_listing{Nef_S2} diff --git a/Installation/include/CGAL/license/Polygon_repair_2.h b/Installation/include/CGAL/license/Polygon_repair_2.h new file mode 100644 index 000000000000..11c0f94e3c5a --- /dev/null +++ b/Installation/include/CGAL/license/Polygon_repair_2.h @@ -0,0 +1,54 @@ +// Copyright (c) 2016 GeometryFactory SARL (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Andreas Fabri +// +// Warning: this file is generated, see include/CGAL/license/README.md + +#ifndef CGAL_LICENSE_POLYGON_REPAIR_2_H +#define CGAL_LICENSE_POLYGON_REPAIR_2_H + +#include +#include + +#ifdef CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE + +# if CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE + +# if defined(CGAL_LICENSE_WARNING) + + CGAL_pragma_warning("Your commercial license for CGAL does not cover " + "this release of the 2D Polygon Repair package.") +# endif + +# ifdef CGAL_LICENSE_ERROR +# error "Your commercial license for CGAL does not cover this release \ + of the 2D Polygon Repair package. \ + You get this error, as you defined CGAL_LICENSE_ERROR." +# endif // CGAL_LICENSE_ERROR + +# endif // CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE + +#else // no CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE + +# if defined(CGAL_LICENSE_WARNING) + CGAL_pragma_warning("\nThe macro CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE is not defined." + "\nYou use the CGAL 2D Polygon Repair package under " + "the terms of the GPLv3+.") +# endif // CGAL_LICENSE_WARNING + +# ifdef CGAL_LICENSE_ERROR +# error "The macro CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE is not defined.\ + You use the CGAL 2D Polygon Repair package under the terms of \ + the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." +# endif // CGAL_LICENSE_ERROR + +#endif // no CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE + +#endif // CGAL_LICENSE_POLYGON_REPAIR_2_H diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in b/Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in new file mode 100644 index 000000000000..eac877a4f2bc --- /dev/null +++ b/Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in @@ -0,0 +1,4 @@ +@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} +PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Polygon Repair" +INPUT = ${CMAKE_SOURCE_DIR}/Polygon_repair_2/doc/Polygon_repair_2/ \ + ${CMAKE_SOURCE_DIR}/Polygon_repair_2/include diff --git a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt b/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt new file mode 100644 index 000000000000..2d02aeae88a7 --- /dev/null +++ b/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt @@ -0,0 +1,40 @@ +// PRETTY PACKAGE NAME should equal the project title in Doxyfile.in + +/// \defgroup PkgPolygonRepair2 2D Polygon Repair Reference +/// \defgroup PkgPolygonRepair2Concepts Concepts +/// \ingroup PkgPolygonRepair2 + +/// \defgroup PkgPolygonRepair2AlgorithmClasses Algorithm Classes +/// \ingroup PkgPolygonRepair2 + +/// \defgroup PkgPolygonRepair2TraitsClasses Traits Classes +/// \ingroup PkgPolygonRepair2 + +/// \defgroup PkgPolygonRepair2Miscellaneous Miscellaneous +/// \ingroup PkgPolygonRepair2 + +/*! +\addtogroup PkgPolygonRepair2 +\todo check generated documentation + +\cgalPkgDescriptionBegin{2D Polygon Repair,PkgPolygonRepair2} +\cgalPkgPicture{Polygon_repair_2-small.png} + +\cgalPkgSummaryBegin +\cgalPkgAuthors{Ken Arroyo Ohori} +\cgalPkgDesc{The package provides algorithms to repair 2D polygons. } +\cgalPkgManuals{Chapter_2D_Polygon_repair,PkgPolygonRepair2} +\cgalPkgSummaryEnd + +\cgalPkgShortInfoBegin +\cgalPkgSince{6.0} +\cgalPkgDependsOn{\ref PkgDEPENDENCY} +\cgalPkgBib{cgal:x-x} +\cgalPkgLicense{\ref licensesGPL "GPL"} +\cgalPkgDemo{DEMO 1,demo1.zip} +\cgalPkgDemo{DEMO 2,demo2.zip} +\cgalPkgShortInfoEnd + +\cgalPkgDescriptionEnd + +*/ diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt new file mode 100644 index 000000000000..723a7d05053d --- /dev/null +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -0,0 +1,29 @@ +namespace CGAL { +/*! + +\mainpage User Manual +\anchor Chapter_2D_Polygon_repair + +\cgalAutoToc +\author Ken Arroyo Ohori + +This chapter describes the ... + +\section SectionPolygonRepair2_Definitions Definitions + +Section on definitions here ... + +\section SectionPolygonRepair2_Examples Examples + +\subsection SubsectionPolygonRepair2_FirstExample First Example + +The following example shows ... + +\cgalExample{Polygon_repair_2/repair_polygon_2.cpp} + +\cgalFigureBegin{figPck,bench.png} +Left: ... +\cgalFigureEnd + +*/ +} /* namespace CGAL */ diff --git a/Polygon_repair_2/doc/Polygon_repair_2/dependencies b/Polygon_repair_2/doc/Polygon_repair_2/dependencies new file mode 100644 index 000000000000..6df3ace8d07a --- /dev/null +++ b/Polygon_repair_2/doc/Polygon_repair_2/dependencies @@ -0,0 +1,7 @@ +Manual +Kernel_23 +STL_Extension +Algebraic_foundations +Circulator +Stream_support +Polygon \ No newline at end of file diff --git a/Polygon_repair_2/doc/Polygon_repair_2/examples.txt b/Polygon_repair_2/doc/Polygon_repair_2/examples.txt new file mode 100644 index 000000000000..c3d2195f5d89 --- /dev/null +++ b/Polygon_repair_2/doc/Polygon_repair_2/examples.txt @@ -0,0 +1,3 @@ +/*! +\example Polygon_repair_2/repair_polygon_2.cpp +*/ diff --git a/Polygon_repair_2/doc/Polygon_repair_2/fig/Polygon_repair_2-small.png b/Polygon_repair_2/doc/Polygon_repair_2/fig/Polygon_repair_2-small.png new file mode 100644 index 0000000000000000000000000000000000000000..5609b037587a48c46b483d2c0768c7ae88b40c72 GIT binary patch literal 9467 zcmZ`QsjDeqppv3OAP@}2H?o@G)$`?vj0nC9ne$JA7erHK1zGS4zV2k21HcQ4 z zCJl=cDv8?+kDJMb7&3R*r#9Iwrub+2I7!eriC^t2XLk3%^j*@x3U5uey|6ovm})lf z&^Np>>jQqLNi~D}ZZdw@T2ypcdP!s$*r4&YrJMVZH%Onc|0Fp5-Ocg|?%HmtpEd-On~O*pAO8iP^87-XI%SYLZHOjC2|PNsojDhu^5nYAv&DP} zF(b_6d;@1}^;|7JW-|J7Vc!lf%A3v)lU#BE3YfXGRU3@_ch4=&M@Jl{MedF~P!QE_oPp-z~06lE>Y`l8(x0P}}hJe+oczo-?$g zO>tIq=g(d8IdONsJvA|{UySNnZ-6~DI3*<|MV8aJc#@FQ*xH*Y+!__BPx|?j-g!)H zU@L}Ga_P7`q-mN@5ZQSR5^J}TB|SMgztu}Nmni0QZ2&XRsj8~l4dsG=@&l_n&%B?J zrB!6CYU!kBoEn64s~IxQFr4%f<*>H0qSmWOowxg?JURACJ|=Z&+v?M&hz@A`X1oM) zVGY`t_(Ave5q?q<2j@siAKYvO+^sJqJ}QC=Bc7g~Ui-RZLUuMr;v0BjvDbuuqhaQ4 z>NaL{a%Fsc#Eg7KqU;xut$q&88BAGO^^dT(hoKRvYib5>Y?!L3sI)`5^6Kk}XcLiz zgoNIxsy^<(wFEp@ot_Uphu{hxsK{Ud9e`bkrV&$IHuClvkG$KB`9M*c4H;)+=506kqRfqX%elFRzJVD5kTEOJYt=TvLKd>db%X2IAogsv9SnUHbnL~(fa23d6e#^~`(#;F87;@;i?egYF`RFf2k6DJRgYUP7|%P9s1l;0qS99u zj@*;;^JymM=ijJh3(N76VmJws!|;qa)Z@j<%lJRvuO=f=`34&J*c0F&Cq=#KW)yL! zPv-ocRTsnQuhS@+(sHxngZ8J8Ir{SYI%%rpEmGa1DkGkd$1%CJgG1ZHPpg=o;1mBF z{ZnuK@%cSj!H_T5Yn%Zv*Tq}9~a)^4QpvBAU4%#15@#LC(_NIG9qNojB}r{nSQ z@mo1t{KFQLq6r>>cdvKr_5b#`ZQa)odFp$gy{vmO8=Zh2I zA^o`~E)LVc?L8l*cYmPAic?4rs^9Y^?`b<6`I0*smcY^}PpMY+e5;Rur>K#sodP2d zv@BYd79A7Q)YFr=V9XE=FYT!j>I zlT1wsY-|n4FL@tmS1%lfz6xq>Z3V4ST3RZps*2Iu*EcagkDNI|c=^;v=|lehz0PJ) zny!_#qO|JB`=E}=m6f>SVn*Uvd3F3cXv}G*noXT|$H`-e)y#kI6Na|c%Vzfe{tfQi zY`j!0rFN|kQTrz;UyU2Ye*TpS7a zE&aS-=-pZxZ<04A#ya{?b!D3?OAE96nny!PwfXc zK_1s~#e7mrXKXgEymuc*0f5%oDkEpB(G?aJN-h4>tN2!1%Try|w0!JE>TYZMN~3H> zxvh3+yUEq3dceGMwqnj~jFRlvC#+UB4-Ysp0cWSpScxtoV_$^CH@pE@cYngCt$5#P zrN(xx>uTAm0uVGbq=4i#Hj+5h`>bf{>FUBZ8nmp5>^%8-c?tdf`*-ck)A4vo2%y%j zuQ(ufEp6@2ZRh;oza_Rr7{e6D`zWCCeIbhui=XWmiyco|^E-|X;eXk!Z#3>+gDbjb z8(fR*G36pgCywn6g#Z?8NA57>CPvrN(vqZ21daAOPjJ z>J^&G&iU69MMcF6iyhOXv@|5r*znm|ZGikieVgk~_f&zB)X2>hTU+J;EITY}^Q)?` z5JO;kdV2bYheJm!LV8SLBoLj&D|v3)gC4Ey#e(A{+^N3^3|qlFwDKWTwO*^~uE9cb z$08)D+t=3CevGaC{K>1LrWWq@$-#j`Nl9sZb{4U01~qLc?BU@da#01G@cZ`!q0%&< z5V(YeNx5Ekk=PAkR?8Q5T#QLXy%l$&{(>~T4*BJQq0w9kEa7a*6tr=$dC*FPF$lJ^*Ld0Qc(FT3~>y|7LuVqgH~)!^5M@YB+>?`l_l0oI zffA)ctM!qe0uIj0b2AoBqyD|RdSFHdiHfQ!`>X!DySuyztG&ZRbS3d&f|9AIU%&Xd zGE|V^VO`za!nz~?%S#q%1`U{-9{s74;yVG?{)QeG9Rs5S%0*8Jjg=1xc)szwT?-k% zckmE6-G~{uJ$ZgY9~c;zIAKBI&U|1*gOqBqg4#fk^l3E$Z$!w#gQ#n0z<{C*3JSv3 zI^_NO^(&M+L*392BSYm^>8u*~&42;~wEcR;M|)2^0!3G&BUl1Od>@(01^Mg^avB zqK%CWxMb8QSyI6N$CVZpfMAOH}!#fUR0DJkLW zS5#2C(#Y}(3L5X<^NsZ$?d>5C^S2sdwHn0-2g80zO_e8iRVbWL*VBszO|Z4IQ}F#e z3IPFu@>g?>8+01@x1whdBfpt2_3t9?BB#SVq&`~Bm`4+w;a!=Qb57#-AujjgSjbJn-wVp`C3;<;E#MY!cfOU^Zi9Vfq^#eLgM z4(Dx(p&6{5(B6NXu!9r zeLzX$Hg!&hji95$BO*4j9ACVNh)9iD-(YX3z2Xj>sva~4H8(X`(5qz7SDPO+e(=#z~?&Iex{4>c7@Fx~=51orrRTZC}on?ey zll97EBSZrr5r1~(RBqHNOpoSv#+H+wjx3SNik|p}Ub#{a2gdhuPosK)LraI#uWA5( zcvu~6IAZ(DHg6`VucoG^@r8w`&Q9rUt~?XcWbdf*b-v(fMu#ecWgvl_kG3i8w^ z5eL1$K25bO#OWUxP;HPWds}O5V}lwS8=IbyA!TpRj*5zEI(RVB-yhhu9yqiey?A5s z@nabJ2}MXQ)y35~U=^MDq6W>DW9|*Vaaa&ZaN{!OP7Z?6Nz`p1$o*_#fyb5)u-iZtR!Z zvqfS?EL@gy`b=xU6+>%ugE331VYI)iL8ppOQ;3qIVuy#zLqiVcoL!uqVbvhN?Exl5 zA0FCi>F6N+fPWau954@7Dhi%E=xK60fQ4~8OZ9|nndk8nH#S#xwY8JzYKIgzPN*x!Zv|fT3w9~hQ&20)RMO9YGlO79W!2ozsXc>w`0iN z*|GQ>7iW6)cLs1DVoZ;;ySqCzrVtK5I$WK=$B^FNni}{7B<G<`|z5u4zB(sgaFR-n^@)SYYz9e5M9hfJ2k+1rwhp(p~H@$ zv*i*Xa%?9`7swNs|3U(zrzyo)mnot z5JGTe;|9Oj%NhPyWJWazesJK(n~SHn+W|z(3(rZD%NIu(HYEDkh(woS!-NL3OQc$f{4i1?6e5TwPPIGT}#Cc2uNzf5#-$%y8 z1l7ED>6Eqx)($*?RG*xj4E~|sG0a%IfSx;6Z-tn<>=2<{CI^&^Ao*z0$$FL3%3@sK1PT%yb+s)B?~a@F9)b9&lUvhLit zp^Z9V#VcJlL(9X1cQ9Ll_U8^aiat-h?&nYV>*AO?%?j<9)rTF(^|2pZROm9_pO<$XHlN`E>e3qv(;2^?B?PiSja_k6)f^J z3V3w;@ln}EYy0Tts4zKO2=NH5anA%aj;F`A?!7_mOA##Cet;#B?ruE>Ab&UIZx{|9&i zzM^^GQLul1sss*B2siM`+i&fDhwuZM@=LnKMJyW0=+OKPo|(Pqv_#^Ortu-881n?c9WBf?qe!N9X7%|V3JHB>BxOO#ngOsW&-Cxk+ zRezZ;vis_w0JnC#_|S>g!+2{4Yu$b+@FM zX+lF)ruEp~oIKs1ASJVOCelsR`>jEUfL41DwHVlU4el{z7lwjpC-Li7(i)GUZD)k{ zf?cqJ3=9Zm+7$|Zey%uSt9O{=tE;hbadC1Ax!Pr6N=2~oeKEFdUwTYYzISk@F3J{8 zRNF7M-sV0>aoAZ}AX?cQrh8iQXQqkf0<{;49)`i_LMOY!`oUyuZE%n@OPFBU&XhYS zg38@&wT+1IV?KzIfH~ZtMB8>0Ol7nEsp~KmE8rj}BjXz4?MaLsb&Hm2TD#D)wT3~M zkAvCnl05Yo!dG6u>)cpcR@Rll;}8m6lO7!N-|3ksG=^VtBdS$DQ%blKpL_i z932hUR+bYBXuN%S*`>A12+$GD27(SX*WS>8B}R zAE$R&UK0n7DU57($I8=nn+VP_F)<~krV_gA`z!I4#^D^xfN0Tah`oMoh?7P30NJEA zNMO}_3?yIk>V@Khpfd^LFvC+VIZmpmP-ce2tVcLcd5eX?Rs}%@wi&_!} z1_qjJc9*iTKX$(o?!D(BE{z82_+jk&zXAt_+b0SqJUq1tPY;Ym9On!@x+_lI1Ocsu zfTRXEHFo3-fToV8i1B?gN=m5ch%zcX>DaJAl8_9Q@cn)3`J?MR)Ky@VK$6VG#}@{q zNnU7J-zG}dsBqdgYMm$?4x#jgW$&_6pP1*}w()u|Sz-Lq)1U%o5cQqj`GOpPhMgS)_~_@`J_*yD4u9-#nk>xG zs9(q}Y8ODZ3q&N)R9;?QF~`jygxNbfk^{N%Ifw8YC(zzo{uDUi;E4gBWeR-iHGVqB zdAd~~J8t3mhxxqCDR$d|H9g;WK?%Z2DqQXuA#%*Y!9hvnAi$@KN0{b&BXwzazT%qi z-kGh09Jz}W7ZWk#`rMPg%8#oXk&*pR!yZ-80~_06ECQ!h($qAEa9u!vILq zf?W^DVF`(Vl?$*RP^KXkrnf!6-6r;3%RkgImQL~kX*WDPoS?XW`9`FtikUe@2|3L9 zVK<;xJ28C>sqJAhJOs(O!?vn5IECI-Sge;srQ^tbY$y#i;-{6py&TB0A$ct=z7q*F zg%b_mHV9t}KOq4CHG6*YINOL(jI5)VSHpCCXrTCgzdYpmcx7Bk9B64hI)A?RS;7Z(MFkmUzW<2;7+^FsG`L+{5Rk3S{r1ONtarhV z$9=ED=(rY$_Ez+D04`wR9EG!kU^5qg*>};!KS6BN_!t8vBcSdV9e# zx2ssyV@-c`gW71(QVQnu=C_FB&GJ#hzrU=a*Yh$?>_`n+K3p{LU0q$+QL^(tt?@u7 z6bS#fY&`P|C@`P~G-_ky3)vw;jC9&;gmf${)SgwCl)Qx<%1H17Oj%271YHTSF?=rIBqwcvj zL83;XT&L?1xp}2~j9?=6IV$Sbtw9oUxVS52RtN_NheVyc4c#5}8UORgd%=1_IchbS zn4J9O;z6*(933r+!!fJ2<|t^~$6>w8tf=Dqa7LA{wG!uckmR&3?JLq&jeWZYht$-R z)jxC(*YNz-*Rj=;#pfX7x~&?f}cB(2NO!dk|E$wvz6-8a6nt!&WwrrX`RZ zItu1Z?E^O)1tuN<0N2Z^+F*e)mM;vFq>g0%%mfjRGEGM)6I++4&nqsrkcyxb_azqb zSc&bUbTPYez)HO!e^o^!=!JW``uuTyOOZoQ?=WG2KCkrd$vABYE^`E>YzCuhF5>Xe zd~0i5L-$RHfrE@<6c#Fi`Ue!*gnKb0E=g)A7{+maC&2PmvLyqJ zL3}r!vAeqg3`{3xery>FA+@?})6>%+k7d_uYy0*M zKG)wH{ke+`b7OthN?zBM<1QH`V%8B3VeKg6oDc> z^KQl2M&e`~LgbJ@>D4j!_ zT*3SiAklx*)<^&01DmEEE49SKy4%)>fH4yYgMd1f&1zRgrUBXix3;#N27}7dC-HQ) zgN|n4VwqW3q?DD>SYN%8Y3jD(B?UUv@pLVsdci+rO#B`_H{i+gVMjm#M$qx`insiO znT#q%wKrcvWvQ$v95RR6^?>-=@~Vh4j%0XR|pe3`)e0MYZqQ?7gOzlD2b&I zFmMJ02EvtaT{ffCFWSG=@e%6uFro|8!BF?+&j%EQ`7!spx;iOfa!X5@^CK)Oc%2#z zKz0ugepSuy2851ynAN#(Z2(35m-f$LjFIP1uQ!*u$ zuP*zA)k_FXP6G^$(zCJvjvCB%-zZ~pab;f5FD#${o!4lP!?nGw2}UpIP0h`qbu=_I zaCB6?dSDNC4UmwKKAJ z)6aD!;4J~|jnB;?<*TQwU)adO9-iO_@O_|+kLc{|3_W}|1asKl4goR8mh&CMV>kiA zsR0OnRH&jE%5 zL6X?SvQa-wsvzXD1{^vN>gHw2(yrG;vH`)V68ZKVw;(YB3CGLBQBZ?w&@c#fjbm>h1 literal 0 HcmV?d00001 diff --git a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt new file mode 100644 index 000000000000..7e634d7d73e5 --- /dev/null +++ b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt @@ -0,0 +1,16 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + +cmake_minimum_required(VERSION 3.1...3.23) +project(Polygon_repair_2_Examples) + +find_package(CGAL REQUIRED) + +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp new file mode 100644 index 000000000000..20b2c9694a81 --- /dev/null +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -0,0 +1,19 @@ +#include +#include + +#include +#include +#include +#include +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Polygon_2 Polygon_2; +typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; + +int main(int argc, char* argv[]) +{ + std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); + return 0; +} diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h new file mode 100644 index 000000000000..eae44162a9b7 --- /dev/null +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h @@ -0,0 +1,25 @@ +// Copyright (c) 2023 GeometryFactory. All rights reserved. +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Ken Arroyo Ohori +// +#ifndef CGAL_POLYGON_REPAIR_2_REPAIR_H +#define CGAL_POLYGON_REPAIR_2_REPAIR_H + +#include + + +namespace CGAL { + +namespace Polygon_repair_2 { + +} // namespace Polygon_repair_2 +} // namespace CGAL + +#endif diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/copyright b/Polygon_repair_2/package_info/Polygon_repair_2/copyright new file mode 100644 index 000000000000..b9a65603a2ee --- /dev/null +++ b/Polygon_repair_2/package_info/Polygon_repair_2/copyright @@ -0,0 +1 @@ +GeometryFactory (France) diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/description.txt b/Polygon_repair_2/package_info/Polygon_repair_2/description.txt new file mode 100644 index 000000000000..4fee1c792710 --- /dev/null +++ b/Polygon_repair_2/package_info/Polygon_repair_2/description.txt @@ -0,0 +1 @@ +Package Polygon_repair_2 provides functions to repair polygons. diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/license.txt b/Polygon_repair_2/package_info/Polygon_repair_2/license.txt new file mode 100644 index 000000000000..8bb8efcb72b0 --- /dev/null +++ b/Polygon_repair_2/package_info/Polygon_repair_2/license.txt @@ -0,0 +1 @@ +GPL (v3 or later) diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/long_description.txt b/Polygon_repair_2/package_info/Polygon_repair_2/long_description.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/maintainer b/Polygon_repair_2/package_info/Polygon_repair_2/maintainer new file mode 100644 index 000000000000..2427333ef578 --- /dev/null +++ b/Polygon_repair_2/package_info/Polygon_repair_2/maintainer @@ -0,0 +1 @@ +GeometryFactory diff --git a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt new file mode 100644 index 000000000000..7e634d7d73e5 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt @@ -0,0 +1,16 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + +cmake_minimum_required(VERSION 3.1...3.23) +project(Polygon_repair_2_Examples) + +find_package(CGAL REQUIRED) + +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp new file mode 100644 index 000000000000..20b2c9694a81 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp @@ -0,0 +1,19 @@ +#include +#include + +#include +#include +#include +#include +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Polygon_2 Polygon_2; +typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; + +int main(int argc, char* argv[]) +{ + std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); + return 0; +} From 3d0fc6065e213903ee556c33bdb9481ea35db354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 24 May 2023 18:35:50 +0200 Subject: [PATCH 002/182] fix minimal doc --- Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in | 3 +-- .../doc/Polygon_repair_2/PackageDescription.txt | 12 +++++++++++- .../include/CGAL/Polygon_repair_2/repair.h | 5 +++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in b/Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in index eac877a4f2bc..2ef1e12b3c0d 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in +++ b/Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in @@ -1,4 +1,3 @@ @INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Polygon Repair" -INPUT = ${CMAKE_SOURCE_DIR}/Polygon_repair_2/doc/Polygon_repair_2/ \ - ${CMAKE_SOURCE_DIR}/Polygon_repair_2/include + diff --git a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt b/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt index 2d02aeae88a7..8f02d4c00b41 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt @@ -10,6 +10,9 @@ /// \defgroup PkgPolygonRepair2TraitsClasses Traits Classes /// \ingroup PkgPolygonRepair2 +/// \defgroup PkgPolygonRepair2Functions Functions +/// \ingroup PkgPolygonRepair2 + /// \defgroup PkgPolygonRepair2Miscellaneous Miscellaneous /// \ingroup PkgPolygonRepair2 @@ -28,7 +31,7 @@ \cgalPkgShortInfoBegin \cgalPkgSince{6.0} -\cgalPkgDependsOn{\ref PkgDEPENDENCY} +\cgalPkgDependsOn{\ref PkgPolygon2} \cgalPkgBib{cgal:x-x} \cgalPkgLicense{\ref licensesGPL "GPL"} \cgalPkgDemo{DEMO 1,demo1.zip} @@ -37,4 +40,11 @@ \cgalPkgDescriptionEnd +\cgalClassifedRefPages + +\cgalCRPSection{Concepts} +- ... +\cgalCRPSection{Functions} +- `CGAL::Polygon_repair_2::repair()` + */ diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h index eae44162a9b7..bd0bb93439c7 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h @@ -19,6 +19,11 @@ namespace CGAL { namespace Polygon_repair_2 { +/// \ingroup PkgPolygonRepair2Functions +/// This is a place holder for a function +template +bool repair(Polygon& p); + } // namespace Polygon_repair_2 } // namespace CGAL From da558be865bd96467ee1b7a050d37b66d3817cb3 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 6 Jun 2023 19:08:37 -0600 Subject: [PATCH 003/182] initial api proposal --- .../Concepts/MultiPolygonWithHoles_2.h | 83 ++++++++++++++++++ .../Polygon_repair_2/PackageDescription.txt | 10 ++- .../Multipolygon_with_holes_2.h | 84 +++++++++++++++++++ .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 67 +++++++++++++++ ...riangulation_with_odd_even_constraints_2.h | 44 ++++++++++ .../include/CGAL/Polygon_repair_2/repair.h | 30 ------- 6 files changed, 286 insertions(+), 32 deletions(-) create mode 100644 Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h create mode 100644 Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h create mode 100644 Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h create mode 100644 Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h delete mode 100644 Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h b/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h new file mode 100644 index 000000000000..269a7c5c22c8 --- /dev/null +++ b/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h @@ -0,0 +1,83 @@ +/*! \ingroup PkgPolygonRepair2Concepts + * \cgalConcept + * + * \cgalRefines{CopyConstructible,Assignable,DefaultConstructible} + * + * A model of this concept represents a multipolygon with holes. + * + * \cgalHasModel `CGAL::Multipolygon_with_holes_2` + */ + +class MultiPolygonWithHoles_2 { +public: + +/// \name Types +/// @{ + +//! the polygon type used to represent each connected component of the multipolygon. +typedef unspecified_type Polygon_with_holes_2; + +/*! a bidirectional iterator over the polygons. + * Its value type is `Polygon_with_holes_2`. + */ +typedef unspecified_type Polygon_const_iterator; + +//! range type for iterating over holes. +typedef unspecified_type Polygons_container; + +/// @} + +/// \name Creation +/// @{ + +/*! constructs a multipolygon using a range of polygons. + */ +template +MultipolygonWithHoles_2(InputIterator begin, InputIterator end); + +/// @} + +/// \name Predicates +/// @{ + +/*! returns the number of polygons. + */ +Size number_of_polygons(); + +/// @} + +/// \name Access Functions +/// @{ + +/*! returns the begin iterator of the polygons. + */ +Polygon_const_iterator polygons_begin() const; + +/*! returns the past-the-end iterator of the polygons. + */ +Polygon_const_iterator polygons_end() const; + +/*! returns the range of polygons. + */ +const Polygons_container& polygons() const; + +/// @} + +/// \name Modifiers +/// @{ + +/*! adds a given polygon to the multipolygon. + */ +void add_polygon(const Polygon_with_holes_2& polygon); + +/*! erases the specified polygon. + */ +void erase_polygon(Polygon_iterator pit); + +/*! removes all the polygons. + */ +void clear(); + +/// @} + +}; /* end MultipolygonWithHoles_2 */ diff --git a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt b/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt index 8f02d4c00b41..a8d4bb5cf863 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt @@ -31,7 +31,7 @@ \cgalPkgShortInfoBegin \cgalPkgSince{6.0} -\cgalPkgDependsOn{\ref PkgPolygon2} +\cgalPkgDependsOn{\ref PkgPolygon2, \ref PkgTriangulation2} \cgalPkgBib{cgal:x-x} \cgalPkgLicense{\ref licensesGPL "GPL"} \cgalPkgDemo{DEMO 1,demo1.zip} @@ -43,7 +43,13 @@ \cgalClassifedRefPages \cgalCRPSection{Concepts} -- ... +- `MultipolygonWithHoles_2` + +\cgalCRPSection{Classes} +- `CGAL::Triangulation_with_odd_even_constraints_2` +- `CGAL::Multipolygon_with_holes_2` +- `CGAL::Polygon_repair_2` + \cgalCRPSection{Functions} - `CGAL::Polygon_repair_2::repair()` diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h new file mode 100644 index 000000000000..26dd1f796971 --- /dev/null +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h @@ -0,0 +1,84 @@ +// Copyright (c) 2023 GeometryFactory. All rights reserved. +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Ken Arroyo Ohori + +#ifndef CGAL_MULTIPOLYGON_WITH_HOLES_2_H +#define CGAL_MULTIPOLYGON_WITH_HOLES_2_H + +#include + +namespace CGAL { + +/*! \ingroup PkgPolygonRepair2Ref + * + * The class `Multipolygon_with_holes_2` models the concept + * `MultiPolygonWithHoles_2`. + * It is parameterized with a type `Polygon` used to define the exposed + * type `Polygon_with_holes_2`. This type represents each polygon. + * + * \tparam Polygon_ must have input and output operators. + * + * \cgalModels `MultipolygonWithHoles_2` + */ +template +class Multipolygon_with_holes_2 { +public: +/// \name Definition + +/// @{ + /// polygon with holes type + typedef Polygon_ Polygon_with_holes_2; +/// @} + + typedef std::deque Polygons_container; + + typedef typename Polygons_container::iterator Polygon_iterator; + typedef typename Polygons_container::const_iterator Polygon_const_iterator; + + typedef unsigned int Size; + + Multipolygon_with_holes_2() {} + + template + Multipolygon_with_holes_2(PolygonsInputIterator p_begin, + PolygonsInputIterator p_end) : + m_polygons(p_begin, p_end) + {} + + Polygons_container& polygons() { return m_polygons; } + + const Polygons_container& polygons() const { return m_polygons; } + + Polygon_iterator polygons_begin() { return m_polygons.begin(); } + + Polygon_iterator polygons_end() { return m_polygons.end(); } + + Polygon_const_iterator polygons_begin() const { return m_polygons.begin(); } + + Polygon_const_iterator polygons_end() const { return m_polygons.end(); } + + void add_polygon(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); } + + void add_polygon(Polygon_with_holes_2&& pgn) { m_polygons.emplace_back(std::move(pgn)); } + + void erase_polygon(Polygon_iterator pit) { m_polygons.erase(pit); } + + void clear() { m_polygons.clear(); } + + Size number_of_polygons() const { return static_cast(m_polygons.size()); } + +protected: + Polygons_container m_polygons; +}; + + +} //namespace CGAL + +#endif diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h new file mode 100644 index 000000000000..237ed1aa3f4a --- /dev/null +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -0,0 +1,67 @@ +// Copyright (c) 2023 GeometryFactory. All rights reserved. +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Ken Arroyo Ohori + +#ifndef CGAL_POLYGON_REPAIR_2_H +#define CGAL_POLYGON_REPAIR_2_H + +#include +#include +#include +#include + +namespace CGAL { + +namespace Polygon_repair_2 { + +/// \ingroup PkgPolygonRepair2Functions +/// Repair a polygon without holes +Multipolygon_with_holes_2 repair(const Polygon_2& p); + +/// Repair a polygon with holes +Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p); + +/// Repair a polygon with holes +Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p); + +class Polygon_repair_2 { + public: + + /// \name Modifiers + /// @{ + + // Add edges of the polygon to the triangulation + void add_to_triangulation(const Polygon_2& p); + + // Add edges of the polygon to the triangulation + void add_to_triangulation(const Polygon_with_holes_2& p); + + // Add edges of the polygon to the triangulation + void add_to_triangulation(const Multipolygon_with_holes_2& p); + + // Label triangles in triangulation as inside or outside the polygon + void label_triangulation(); + + /// @} + + // Reconstruct multipolygon based on the triangles labelled as inside the polygon + Multipolygon_with_holes_2 reconstruct_polygon(); + + // Erases the triangulation. + void clear(); + + protected: + Triangulation_with_odd_even_constraints_2 triangulation; +} + +} // namespace Polygon_repair_2 +} // namespace CGAL + +#endif // CGAL_POLYGON_REPAIR_2_H diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h new file mode 100644 index 000000000000..9ebd5aa46a22 --- /dev/null +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -0,0 +1,44 @@ +// Copyright (c) 2023 GeometryFactory. All rights reserved. +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Ken Arroyo Ohori + +#ifndef CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H +#define CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H + +namespace CGAL { + +template +class Triangulation_with_odd_even_constraints_2 { + + // the triangulation class. + typedef typename Triangulation_ Triangulation; + + // handle to a vertex. + typedef typename Triangulation_::Vertex_handle Vertex_handle; + + // iterator over interior faces. + class Interior_faces_iterator : Triangulation::All_faces_iterator { + Interior_faces_iterator operator++(); + Interior_faces_iterator operator--(); + } + + // Add constraint from va to vb using the odd-even rule + void odd_even_insert_constraint(Vertex_handle va, Vertex_handle vb); + + // Starts at an arbitrary interior face + Interior_faces_iterator interior_faces_begin(); + + // Past-the-end iterator + Interior_faces_iterator interior_faces_end(); +} + +} // namespace CGAL + +#endif // CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H \ No newline at end of file diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h deleted file mode 100644 index bd0bb93439c7..000000000000 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/repair.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2023 GeometryFactory. All rights reserved. -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Ken Arroyo Ohori -// -#ifndef CGAL_POLYGON_REPAIR_2_REPAIR_H -#define CGAL_POLYGON_REPAIR_2_REPAIR_H - -#include - - -namespace CGAL { - -namespace Polygon_repair_2 { - -/// \ingroup PkgPolygonRepair2Functions -/// This is a place holder for a function -template -bool repair(Polygon& p); - -} // namespace Polygon_repair_2 -} // namespace CGAL - -#endif From 5426708ba431dbd9f6e0c8778b3dd58ecb97f3cd Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 7 Jun 2023 17:42:02 -0600 Subject: [PATCH 004/182] defined rest of API based on meeting today --- .../Concepts/MultiPolygonWithHoles_2.h | 2 +- .../Polygon_repair_2/PackageDescription.txt | 3 +- .../Multipolygon_with_holes_2.h | 16 ++--- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 70 +++++++++++++------ ...riangulation_with_odd_even_constraints_2.h | 17 ++++- 5 files changed, 71 insertions(+), 37 deletions(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h b/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h index 269a7c5c22c8..9ffa99054673 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h @@ -8,7 +8,7 @@ * \cgalHasModel `CGAL::Multipolygon_with_holes_2` */ -class MultiPolygonWithHoles_2 { +class MultipolygonWithHoles_2 { public: /// \name Types diff --git a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt b/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt index a8d4bb5cf863..054a066091a7 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt @@ -35,7 +35,6 @@ \cgalPkgBib{cgal:x-x} \cgalPkgLicense{\ref licensesGPL "GPL"} \cgalPkgDemo{DEMO 1,demo1.zip} -\cgalPkgDemo{DEMO 2,demo2.zip} \cgalPkgShortInfoEnd \cgalPkgDescriptionEnd @@ -46,8 +45,8 @@ - `MultipolygonWithHoles_2` \cgalCRPSection{Classes} -- `CGAL::Triangulation_with_odd_even_constraints_2` - `CGAL::Multipolygon_with_holes_2` +- `CGAL::Triangulation_with_odd_even_constraints_2` - `CGAL::Polygon_repair_2` \cgalCRPSection{Functions} diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h index 26dd1f796971..832549cb729b 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h @@ -12,7 +12,7 @@ #ifndef CGAL_MULTIPOLYGON_WITH_HOLES_2_H #define CGAL_MULTIPOLYGON_WITH_HOLES_2_H -#include +#include namespace CGAL { @@ -27,22 +27,22 @@ namespace CGAL { * * \cgalModels `MultipolygonWithHoles_2` */ -template +template > class Multipolygon_with_holes_2 { public: -/// \name Definition + /// \name Definition -/// @{ /// polygon with holes type - typedef Polygon_ Polygon_with_holes_2; -/// @} - + typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; + typedef std::deque Polygons_container; typedef typename Polygons_container::iterator Polygon_iterator; typedef typename Polygons_container::const_iterator Polygon_const_iterator; typedef unsigned int Size; + Multipolygon_with_holes_2() {} @@ -81,4 +81,4 @@ class Multipolygon_with_holes_2 { } //namespace CGAL -#endif +#endif // CGAL_MULTIPOLYGON_WITH_HOLES_2_H diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 237ed1aa3f4a..a550065ec755 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -23,42 +23,66 @@ namespace Polygon_repair_2 { /// \ingroup PkgPolygonRepair2Functions /// Repair a polygon without holes -Multipolygon_with_holes_2 repair(const Polygon_2& p); - -/// Repair a polygon with holes -Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p); +template +Multipolygon_with_holes_2 repair(const Polygon_2& p); +/// \ingroup PkgPolygonRepair2Functions /// Repair a polygon with holes -Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p); +template +Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p); +/// \ingroup PkgPolygonRepair2Functions +/// Repair a multipolygon with holes +Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p); + +/*! \ingroup PkgPolygonRepair2Ref + * + * The class `Polygon_repair_2` builds on a constrained + * triangulation to remove the parts of constraints that overlap an even number of times + */ +template class Polygon_repair_2 { - public: +public: + + /// \name Creation + Polygon_repair_2(); + + /// \name Modifiers + /// @{ + + // Add edges of the polygon to the triangulation + void add_to_triangulation(const Polygon_2& p); + + // Add edges of the polygon to the triangulation + void add_to_triangulation(const Polygon_with_holes_2& p); + + // Add edges of the polygon to the triangulation + void add_to_triangulation(const Multipolygon_with_holes_2& p); - /// \name Modifiers - /// @{ + // Label triangles in triangulation as inside or outside the polygon + void label_triangulation(); - // Add edges of the polygon to the triangulation - void add_to_triangulation(const Polygon_2& p); + // Reconstruct multipolygon based on the triangles labelled as inside the polygon + void reconstruct_polygon(); - // Add edges of the polygon to the triangulation - void add_to_triangulation(const Polygon_with_holes_2& p); + // Erases the triangulation. + void clear(); - // Add edges of the polygon to the triangulation - void add_to_triangulation(const Multipolygon_with_holes_2& p); + /// @} - // Label triangles in triangulation as inside or outside the polygon - void label_triangulation(); + /// \name Access Functions + /// @{ - /// @} + Triangulation_with_odd_even_constraints_2 triangulation(); - // Reconstruct multipolygon based on the triangles labelled as inside the polygon - Multipolygon_with_holes_2 reconstruct_polygon(); + Multipolygon_with_holes_2 multipolygon(); - // Erases the triangulation. - void clear(); + /// @} + - protected: - Triangulation_with_odd_even_constraints_2 triangulation; +protected: + Triangulation_with_odd_even_constraints_2 t; + Multipolygon_with_holes_2 mp; } } // namespace Polygon_repair_2 diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index 9ebd5aa46a22..e0819226b214 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -14,17 +14,28 @@ namespace CGAL { +/*! \ingroup PkgPolygonRepair2Ref + * + * The class `Triangulation_with_odd_even_constraints_2` builds on a constrained + * triangulation to remove the parts of constraints that overlap an even number of times + * + * \tparam Triangulation_ must have support for constraints + */ template class Triangulation_with_odd_even_constraints_2 { +public: + /// \name Definition - // the triangulation class. + /// @{ + /// the triangulation class. typedef typename Triangulation_ Triangulation; - // handle to a vertex. + /// handle to a vertex. typedef typename Triangulation_::Vertex_handle Vertex_handle; + /// @} // iterator over interior faces. - class Interior_faces_iterator : Triangulation::All_faces_iterator { + class Interior_faces_iterator : public Triangulation::All_faces_iterator { Interior_faces_iterator operator++(); Interior_faces_iterator operator--(); } From bd3cf86a43cf6c305ea6b6603ef0f154c99bdf3e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 13 Jun 2023 19:41:18 -0600 Subject: [PATCH 005/182] skeleton with compiling code --- .../Polygon_repair_2/repair_polygon_2.cpp | 20 +++--- .../Multipolygon_with_holes_2.h | 6 +- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 72 ++++++++++++++----- ...riangulation_with_odd_even_constraints_2.h | 22 +++--- 4 files changed, 83 insertions(+), 37 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 20b2c9694a81..aa66fb706c3c 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -2,18 +2,18 @@ #include #include -#include -#include -#include -#include +#include +// #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Polygon_2 Polygon_2; -typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef CGAL::Multipolygon_with_holes_2 Multipolygon; +typedef CGAL::Polygon_repair_2::Polygon_repair_2 Polygon_repair; + +int main(int argc, char* argv[]) { + // std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); + + Polygon_repair pr; -int main(int argc, char* argv[]) -{ - std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); return 0; } diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h index 832549cb729b..bc279b9c279f 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h @@ -27,14 +27,14 @@ namespace CGAL { * * \cgalModels `MultipolygonWithHoles_2` */ -template > +template > class Multipolygon_with_holes_2 { public: /// \name Definition /// polygon with holes type - typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; + typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; typedef std::deque Polygons_container; diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index a550065ec755..9308ef52e002 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -14,6 +14,9 @@ #include #include +#include +#include + #include #include @@ -21,43 +24,78 @@ namespace CGAL { namespace Polygon_repair_2 { +template +class Polygon_repair_2; + /// \ingroup PkgPolygonRepair2Functions /// Repair a polygon without holes -template -Multipolygon_with_holes_2 repair(const Polygon_2& p); +template +Multipolygon_with_holes_2 repair(const CGAL::Polygon_2& p) { + CGAL::Polygon_repair_2::Polygon_repair_2 pr; +} /// \ingroup PkgPolygonRepair2Functions /// Repair a polygon with holes -template -Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p); +template +Multipolygon_with_holes_2 repair(const CGAL::Polygon_with_holes_2& p) { + CGAL::Polygon_repair_2::Polygon_repair_2 pr; +} /// \ingroup PkgPolygonRepair2Functions /// Repair a multipolygon with holes -Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p); +template +Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p) { + CGAL::Polygon_repair_2::Polygon_repair_2 pr; +} /*! \ingroup PkgPolygonRepair2Ref * * The class `Polygon_repair_2` builds on a constrained * triangulation to remove the parts of constraints that overlap an even number of times */ -template +template > class Polygon_repair_2 { public: + struct Repair_face_info { + bool processed; + bool interior; + Repair_face_info() { + processed = false; + interior = false; + } + }; + typedef CGAL::Triangulation_vertex_base_2 Vertex_base; + typedef CGAL::Constrained_triangulation_face_base_2 Face_base; + typedef CGAL::Triangulation_face_base_with_info_2 Face_base_with_repair_info; + typedef CGAL::Triangulation_data_structure_2 Triangulation_data_structure; + typedef CGAL::Exact_predicates_tag Tag; // assumed for now + typedef CGAL::Constrained_Delaunay_triangulation_2 Constrained_Delaunay_triangulation; + typedef Triangulation_with_odd_even_constraints_2 Triangulation; + /// \name Creation - Polygon_repair_2(); + Polygon_repair_2() { + + } /// \name Modifiers /// @{ // Add edges of the polygon to the triangulation - void add_to_triangulation(const Polygon_2& p); + void add_to_triangulation(const Polygon_2& p) { + + } // Add edges of the polygon to the triangulation - void add_to_triangulation(const Polygon_with_holes_2& p); + void add_to_triangulation(const Polygon_with_holes_2& p) { + + } // Add edges of the polygon to the triangulation - void add_to_triangulation(const Multipolygon_with_holes_2& p); + void add_to_triangulation(const Multipolygon_with_holes_2& p) { + + } // Label triangles in triangulation as inside or outside the polygon void label_triangulation(); @@ -66,24 +104,26 @@ class Polygon_repair_2 { void reconstruct_polygon(); // Erases the triangulation. - void clear(); + void clear() { + t.clear(); + } /// @} /// \name Access Functions /// @{ - Triangulation_with_odd_even_constraints_2 triangulation(); + Triangulation_with_odd_even_constraints_2 triangulation(); - Multipolygon_with_holes_2 multipolygon(); + Multipolygon_with_holes_2 multipolygon(); /// @} protected: - Triangulation_with_odd_even_constraints_2 t; - Multipolygon_with_holes_2 mp; -} + Triangulation_with_odd_even_constraints_2 t; + Multipolygon_with_holes_2 mp; +}; } // namespace Polygon_repair_2 } // namespace CGAL diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index e0819226b214..fc74b1730134 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -22,33 +22,39 @@ namespace CGAL { * \tparam Triangulation_ must have support for constraints */ template -class Triangulation_with_odd_even_constraints_2 { +class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { public: /// \name Definition /// @{ /// the triangulation class. - typedef typename Triangulation_ Triangulation; + typedef Triangulation_ Base_triangulation; /// handle to a vertex. typedef typename Triangulation_::Vertex_handle Vertex_handle; /// @} // iterator over interior faces. - class Interior_faces_iterator : public Triangulation::All_faces_iterator { + class Interior_faces_iterator : public Base_triangulation::All_faces_iterator { Interior_faces_iterator operator++(); Interior_faces_iterator operator--(); - } + }; // Add constraint from va to vb using the odd-even rule - void odd_even_insert_constraint(Vertex_handle va, Vertex_handle vb); + void odd_even_insert_constraint(Vertex_handle va, Vertex_handle vb) { + if (va == vb) return; + } // Starts at an arbitrary interior face - Interior_faces_iterator interior_faces_begin(); + Interior_faces_iterator interior_faces_begin() { + + } // Past-the-end iterator - Interior_faces_iterator interior_faces_end(); -} + Interior_faces_iterator interior_faces_end() { + + } +}; } // namespace CGAL From a2ed96dd34051cf79baa3679baf901fba73f6d92 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 23 Jun 2023 19:21:31 -0600 Subject: [PATCH 006/182] added insertion of odd-even constraints and creation from different polygon types --- .../Polygon_repair_2/repair_polygon_2.cpp | 44 +++++++++++++ .../Multipolygon_with_holes_2.h | 5 ++ .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 45 +++++++++++--- ...riangulation_with_odd_even_constraints_2.h | 62 ++++++++++++++++++- 4 files changed, 146 insertions(+), 10 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index aa66fb706c3c..e4828301db73 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -7,13 +7,57 @@ // #include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef Kernel::Point_2 Point; +typedef CGAL::Polygon_2 Polygon; typedef CGAL::Multipolygon_with_holes_2 Multipolygon; typedef CGAL::Polygon_repair_2::Polygon_repair_2 Polygon_repair; int main(int argc, char* argv[]) { // std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); + // Square + // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Polygon p(ps, ps+4); + + // Bowtie + // Point ps[] = {Point(0,0), Point(1,1), Point(1,0), Point(0,1)}; + // Polygon p(ps, ps+4); + + // Overlapping edge + // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Polygon p1(ps1, ps1+4); + // Point ps2[] = {Point(1,0), Point(2,0), Point(2,1), Point(1,1)}; + // Polygon p2(ps2, ps2+4); + // Multipolygon mp; + // mp.add_polygon(p1); + // mp.add_polygon(p2); + + // Edge partly overlapping (start) + // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Polygon p1(ps1, ps1+4); + // Point ps2[] = {Point(1,0), Point(2,0), Point(2,0.5), Point(1,0.5)}; + // Polygon p2(ps2, ps2+4); + // Multipolygon mp; + // mp.add_polygon(p1); + // mp.add_polygon(p2); + + // Edge partly overlapping (middle) + Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + Polygon p1(ps1, ps1+4); + Point ps2[] = {Point(1,0.25), Point(2,0.25), Point(2,0.75), Point(1,0.75)}; + Polygon p2(ps2, ps2+4); + Multipolygon mp; + mp.add_polygon(p1); + mp.add_polygon(p2); + Polygon_repair pr; + pr.add_to_triangulation(mp); + + for (auto const& ce: pr.triangulation().constrained_edges()) { + std::cout << ce.first->vertex(ce.first->cw(ce.second))->point() << " to " << ce.first->vertex(ce.first->ccw(ce.second))->point() << std::endl; + } + + // CGAL::Polygon_repair_2::repair(mp); return 0; } diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h index bc279b9c279f..ea5f737e163e 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h @@ -33,6 +33,9 @@ class Multipolygon_with_holes_2 { public: /// \name Definition + /// polygon type + typedef CGAL::Polygon_2 Polygon_2; + /// polygon with holes type typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; @@ -64,6 +67,8 @@ class Multipolygon_with_holes_2 { Polygon_const_iterator polygons_end() const { return m_polygons.end(); } + void add_polygon(const Polygon_2& pgn) { m_polygons.push_back(Polygon_with_holes_2(pgn)); } + void add_polygon(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); } void add_polygon(Polygon_with_holes_2&& pgn) { m_polygons.emplace_back(std::move(pgn)); } diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 9308ef52e002..a50fee4192e1 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -32,6 +32,10 @@ class Polygon_repair_2; template Multipolygon_with_holes_2 repair(const CGAL::Polygon_2& p) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; + pr.add_to_triangulation(p); + pr.label_triangulation(); + pr.reconstruct_polygon(); + return pr.multipolygon(); } /// \ingroup PkgPolygonRepair2Functions @@ -39,13 +43,21 @@ Multipolygon_with_holes_2 repair(const CGAL::Polygon_2 template Multipolygon_with_holes_2 repair(const CGAL::Polygon_with_holes_2& p) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; + pr.add_to_triangulation(p); + pr.label_triangulation(); + pr.reconstruct_polygon(); + return pr.multipolygon(); } /// \ingroup PkgPolygonRepair2Functions /// Repair a multipolygon with holes template -Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p) { +Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& mp) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; + pr.add_to_triangulation(mp); + pr.label_triangulation(); + pr.reconstruct_polygon(); + return pr.multipolygon(); } /*! \ingroup PkgPolygonRepair2Ref @@ -84,24 +96,35 @@ class Polygon_repair_2 { // Add edges of the polygon to the triangulation void add_to_triangulation(const Polygon_2& p) { - + for (auto const& e: p.edges()) { + t.odd_even_insert_constraint(e.source(), e.target()); + } } // Add edges of the polygon to the triangulation void add_to_triangulation(const Polygon_with_holes_2& p) { - + add_to_triangulation(p.outer_boundary()); + for (auto const& h: p.holes()) { + add_to_triangulation(h); + } } // Add edges of the polygon to the triangulation - void add_to_triangulation(const Multipolygon_with_holes_2& p) { - + void add_to_triangulation(const Multipolygon_with_holes_2& mp) { + for (auto const &p: mp.polygons()) { + add_to_triangulation(p); + } } // Label triangles in triangulation as inside or outside the polygon - void label_triangulation(); + void label_triangulation() { + + } // Reconstruct multipolygon based on the triangles labelled as inside the polygon - void reconstruct_polygon(); + void reconstruct_polygon() { + + } // Erases the triangulation. void clear() { @@ -113,9 +136,13 @@ class Polygon_repair_2 { /// \name Access Functions /// @{ - Triangulation_with_odd_even_constraints_2 triangulation(); + Triangulation_with_odd_even_constraints_2& triangulation() { + return t; + } + + Multipolygon_with_holes_2 multipolygon() { - Multipolygon_with_holes_2 multipolygon(); + } /// @} diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index fc74b1730134..84f239dad34a 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -30,8 +30,24 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { /// the triangulation class. typedef Triangulation_ Base_triangulation; - /// handle to a vertex. + /// Point type + typedef typename Triangulation_::Point Point; + + /// Edge type + typedef typename Triangulation_::Edge Edge; + + /// handle to a vertex typedef typename Triangulation_::Vertex_handle Vertex_handle; + + /// handle to a face + typedef typename Triangulation_::Face_handle Face_handle; + + /// list of edges + typedef typename Triangulation_::List_edges List_edges; + + /// list of faces + typedef typename Triangulation_::List_faces List_faces; + /// @} // iterator over interior faces. @@ -40,9 +56,53 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { Interior_faces_iterator operator--(); }; + // Inserts point p in the triangulation and returns the corresponding vertex. + Vertex_handle insert(const Point &p, Face_handle f = Face_handle()) { + return Base_triangulation::insert(p, f); + } + // Add constraint from va to vb using the odd-even rule void odd_even_insert_constraint(Vertex_handle va, Vertex_handle vb) { + + // Degenerate edge if (va == vb) return; + + // [va, vb] is an existing edge OR it is composed of shorter edges + Vertex_handle vc; // [va, vc] is the first edge along [va, vb] + Face_handle incident_face; // incident to [va, vc] + int opposite_vertex; // opposite to [va, vc] + if (Base_triangulation::includes_edge(va, vb, vc, incident_face, opposite_vertex)) { + if (Base_triangulation::is_constrained(Edge(incident_face, opposite_vertex))) { + Base_triangulation::remove_constrained_edge(incident_face, opposite_vertex); + } else Base_triangulation::mark_constraint(incident_face, opposite_vertex); + if (vc != vb) odd_even_insert_constraint(vc, vb); // process edges along [vc, vb] + return; + } + + // [va, vb] intersects a constrained edge or an existing vertex + List_faces intersected_faces; + List_edges conflict_boundary_ab, conflict_boundary_ba; + Vertex_handle intersection; + if (Base_triangulation::find_intersected_faces(va, vb, intersected_faces, conflict_boundary_ab, conflict_boundary_ba, intersection)) { + if (intersection != va && intersection != vb) { + odd_even_insert_constraint(va, intersection); + odd_even_insert_constraint(intersection, vb); + } else odd_even_insert_constraint(va, vb); + return; + } + + // Otherwise + Base_triangulation::triangulate_hole(intersected_faces, conflict_boundary_ab, conflict_boundary_ba); + if (intersection != vb) { + odd_even_insert_constraint(intersection, vb); + } + } + + // Add constraint from pa to pb using the odd-even rule + void odd_even_insert_constraint(Point pa, Point pb) { + Vertex_handle va = insert(pa); + Vertex_handle vb = insert(pb); + odd_even_insert_constraint(va, vb); } // Starts at an arbitrary interior face From 7c60fad080f466cbe45fc0f37774faa220a1d4e9 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 4 Jul 2023 20:01:28 -0600 Subject: [PATCH 007/182] < +std::ostream& operator<<(std::ostream& os, + const Multipolygon_with_holes_2& mp) { + typename Multipolygon_with_holes_2::Polygon_const_iterator i; + + switch(IO::get_mode(os)) { + case IO::ASCII : + os << mp.number_of_polygons() << ' '; + for (i = mp.polygons_begin(); i != mp.polygons_end(); ++i) { + os << *i << ' '; + } + return os; + + case IO::BINARY : + os << mp.number_of_polygons(); + for (i = mp.polygons_begin(); i != mp.polygons_end(); ++i) { + os << *i ; + } + return os; + + default: + os << "Multipolygon_with_holes_2(" << std::endl; + for (i = mp.polygons_begin(); i != mp.polygons_end(); ++i) { + os << " " << *i << std::endl; + } + + os << ")" << std::endl; + return os; + } +} + } //namespace CGAL From b46e3e8f288ba84fb7bd9b96d22ba8cfcad513e4 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 4 Jul 2023 20:02:29 -0600 Subject: [PATCH 008/182] reconstruction of multipolygon using new face base with repair info --- .../Polygon_repair_2/repair_polygon_2.cpp | 28 +- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 256 +++++++++++++++--- ...iangulation_face_base_with_repair_info_2.h | 51 ++++ ...riangulation_with_odd_even_constraints_2.h | 10 +- 4 files changed, 294 insertions(+), 51 deletions(-) create mode 100644 Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index e4828301db73..76cd3bf677c5 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -18,10 +18,14 @@ int main(int argc, char* argv[]) { // Square // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; // Polygon p(ps, ps+4); + // Multipolygon mp; + // mp.add_polygon(p); // Bowtie - // Point ps[] = {Point(0,0), Point(1,1), Point(1,0), Point(0,1)}; - // Polygon p(ps, ps+4); + Point ps[] = {Point(0,0), Point(1,1), Point(1,0), Point(0,1)}; + Polygon p(ps, ps+4); + Multipolygon mp; + mp.add_polygon(p); // Overlapping edge // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; @@ -42,20 +46,20 @@ int main(int argc, char* argv[]) { // mp.add_polygon(p2); // Edge partly overlapping (middle) - Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - Polygon p1(ps1, ps1+4); - Point ps2[] = {Point(1,0.25), Point(2,0.25), Point(2,0.75), Point(1,0.75)}; - Polygon p2(ps2, ps2+4); - Multipolygon mp; - mp.add_polygon(p1); - mp.add_polygon(p2); + // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Polygon p1(ps1, ps1+4); + // Point ps2[] = {Point(1,0.25), Point(2,0.25), Point(2,0.75), Point(1,0.75)}; + // Polygon p2(ps2, ps2+4); + // Multipolygon mp; + // mp.add_polygon(p1); + // mp.add_polygon(p2); Polygon_repair pr; pr.add_to_triangulation(mp); + pr.label_triangulation(); + pr.reconstruct_multipolygon(); + std::cout << pr.multipolygon(); - for (auto const& ce: pr.triangulation().constrained_edges()) { - std::cout << ce.first->vertex(ce.first->cw(ce.second))->point() << " to " << ce.first->vertex(ce.first->ccw(ce.second))->point() << std::endl; - } // CGAL::Polygon_repair_2::repair(mp); diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index a50fee4192e1..d2d9b8f8a19b 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -15,9 +15,9 @@ #include #include #include -#include #include +#include #include namespace CGAL { @@ -30,7 +30,7 @@ class Polygon_repair_2; /// \ingroup PkgPolygonRepair2Functions /// Repair a polygon without holes template -Multipolygon_with_holes_2 repair(const CGAL::Polygon_2& p) { +Multipolygon_with_holes_2 repair(const Polygon_2& p) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; pr.add_to_triangulation(p); pr.label_triangulation(); @@ -41,7 +41,7 @@ Multipolygon_with_holes_2 repair(const CGAL::Polygon_2 /// \ingroup PkgPolygonRepair2Functions /// Repair a polygon with holes template -Multipolygon_with_holes_2 repair(const CGAL::Polygon_with_holes_2& p) { +Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; pr.add_to_triangulation(p); pr.label_triangulation(); @@ -69,18 +69,9 @@ template > class Polygon_repair_2 { public: - - struct Repair_face_info { - bool processed; - bool interior; - Repair_face_info() { - processed = false; - interior = false; - } - }; typedef CGAL::Triangulation_vertex_base_2 Vertex_base; typedef CGAL::Constrained_triangulation_face_base_2 Face_base; - typedef CGAL::Triangulation_face_base_with_info_2 Face_base_with_repair_info; + typedef CGAL::Triangulation_face_base_with_repair_info_2 Face_base_with_repair_info; typedef CGAL::Triangulation_data_structure_2 Triangulation_data_structure; typedef CGAL::Exact_predicates_tag Tag; // assumed for now typedef CGAL::Constrained_Delaunay_triangulation_2 Constrained_Delaunay_triangulation; @@ -91,39 +82,230 @@ class Polygon_repair_2 { } - /// \name Modifiers + /// \name Modifiers /// @{ - // Add edges of the polygon to the triangulation - void add_to_triangulation(const Polygon_2& p) { - for (auto const& e: p.edges()) { - t.odd_even_insert_constraint(e.source(), e.target()); + // Add edges of the polygon to the triangulation + void add_to_triangulation(const Polygon_2& polygon) { + for (auto const& edge: polygon.edges()) { + t.odd_even_insert_constraint(edge.source(), edge.target()); } } - // Add edges of the polygon to the triangulation - void add_to_triangulation(const Polygon_with_holes_2& p) { - add_to_triangulation(p.outer_boundary()); - for (auto const& h: p.holes()) { - add_to_triangulation(h); + // Add edges of the polygon to the triangulation + void add_to_triangulation(const Polygon_with_holes_2& polygon) { + add_to_triangulation(polygon.outer_boundary()); + for (auto const& hole: polygon.holes()) { + add_to_triangulation(hole); } } - // Add edges of the polygon to the triangulation - void add_to_triangulation(const Multipolygon_with_holes_2& mp) { - for (auto const &p: mp.polygons()) { - add_to_triangulation(p); + // Add edges of the polygon to the triangulation + void add_to_triangulation(const Multipolygon_with_holes_2& multipolygon) { + for (auto const& polygon: multipolygon.polygons()) { + add_to_triangulation(polygon); } } - // Label triangles in triangulation as inside or outside the polygon - void label_triangulation() { + // Label triangles in triangulation as inside or outside the polygon + void label_triangulation() { + for (auto const face: t.all_face_handles()) { + face->processed() = false; + face->interior() = false; + } std::list to_check; + t.infinite_face()->processed() = true; + to_check.push_back(t.infinite_face()); + while (!to_check.empty()) { + for (int neighbour = 0; neighbour < 3; ++neighbour) { + if (!to_check.front()->neighbor(neighbour)->processed()) { + to_check.front()->neighbor(neighbour)->processed() = true; + if (t.is_constrained(typename Triangulation::Edge(to_check.front(), neighbour))) { + to_check.front()->neighbor(neighbour)->interior() = !to_check.front()->interior(); + to_check.push_back(to_check.front()->neighbor(neighbour)); + } else { + to_check.front()->neighbor(neighbour)->interior() = to_check.front()->interior(); + to_check.push_back(to_check.front()->neighbor(neighbour)); + } + } + } to_check.pop_front(); + } + } + void get_boundary(typename Triangulation::Face_handle face, int edge, std::list &out_vertices) { + // Check clockwise edge + if (face->neighbor(face->cw(edge))->interior() && !face->neighbor(face->cw(edge))->reconstructed()) { + face->neighbor(face->cw(edge))->reconstructed() = true; + std::list v1; + get_boundary(face->neighbor(face->cw(edge)), face->neighbor(face->cw(edge))->index(face), v1); + out_vertices.splice(out_vertices.end(), v1); + } + + // Add central vertex + out_vertices.push_back(face->vertex(edge)); + + // Check counterclockwise edge + if (face->neighbor(face->ccw(edge))->interior() && !face->neighbor(face->ccw(edge))->reconstructed()) { + face->neighbor(face->ccw(edge))->reconstructed() = true; + std::list v2; + get_boundary(face->neighbor(face->ccw(edge)), face->neighbor(face->ccw(edge))->index(face), v2); + out_vertices.splice(out_vertices.end(), v2); + } } // Reconstruct multipolygon based on the triangles labelled as inside the polygon - void reconstruct_polygon() { - + void reconstruct_multipolygon() { + mp.clear(); + for (auto const face: t.all_face_handles()) { + face->reconstructed() = false; + } + + for (auto const interior_face: t.finite_face_handles()) { + if (!interior_face->interior() || interior_face->reconstructed()) continue; + + // Get boundary + std::list vertices; + if (interior_face->neighbor(2)->interior() && !interior_face->neighbor(2)->reconstructed()) { + interior_face->neighbor(2)->reconstructed() = true; + std::list l2; + get_boundary(interior_face->neighbor(2), interior_face->neighbor(2)->index(interior_face), l2); + vertices.splice(vertices.end(), l2); + } vertices.push_back(interior_face->vertex(0)); + if (interior_face->neighbor(1)->interior() && !interior_face->neighbor(1)->reconstructed()) { + interior_face->neighbor(1)->reconstructed() = true; + std::list l1; + get_boundary(interior_face->neighbor(1), interior_face->neighbor(1)->index(interior_face), l1); + vertices.splice(vertices.end(), l1); + } vertices.push_back(interior_face->vertex(2)); + if (interior_face->neighbor(0)->interior() && !interior_face->neighbor(0)->reconstructed()) { + interior_face->neighbor(0)->reconstructed() = true; + std::list l0; + get_boundary(interior_face->neighbor(0), interior_face->neighbor(0)->index(interior_face), l0); + vertices.splice(vertices.end(), l0); + } vertices.push_back(interior_face->vertex(1)); + + // Find cutting vertices + std::set visited_vertices, repeated_vertices; + for (auto const& current_vertex: vertices) { + if (!visited_vertices.insert(current_vertex).second) repeated_vertices.insert(current_vertex); + } visited_vertices.clear(); + + // Cut and join rings in the correct order + std::list> rings; + std::stack> chains_stack; + std::set vertices_where_chains_begin; + rings.push_back(std::list()); + for (auto const& current_vertex: vertices) { + + // New chain + if (repeated_vertices.count(current_vertex) > 0) { + // Closed by itself + if (rings.back().front() == current_vertex) { + // Degenerate (insufficient vertices to be valid) + if (rings.back().size() < 3) { + rings.back().clear(); + } else { + typename std::list::iterator second_element = rings.back().begin(); + ++second_element; + // Degenerate (zero area) + if (rings.back().back() == *second_element) { + rings.back().clear(); + } + // Valid + else { + rings.push_back(std::list()); + } + } + } + // Open by itself + else { + // Closed with others in stack + if (vertices_where_chains_begin.count(current_vertex)) { + + while (rings.back().front() != current_vertex) { + rings.back().splice(rings.back().begin(), chains_stack.top()); + chains_stack.pop(); + } vertices_where_chains_begin.erase(current_vertex); + // Degenerate (insufficient vertices to be valid) + if (rings.back().size() < 3) { + rings.back().clear(); + } else { + typename std::list::iterator second_element = rings.back().begin(); + ++second_element; + // Degenerate (zero area) + if (rings.back().back() == *second_element) { + rings.back().clear(); + } + // Valid + else { + rings.push_back(std::list()); + } + } + } + // Open + else { + // Not first chain + if (repeated_vertices.count(rings.back().front()) > 0) { + vertices_where_chains_begin.insert(rings.back().front()); + } + chains_stack.push(std::list()); + chains_stack.top().splice(chains_stack.top().begin(), rings.back()); + } + } + } rings.back().push_back(current_vertex); + } + // Final ring + while (chains_stack.size() > 0) { + rings.back().splice(rings.back().begin(), chains_stack.top()); + chains_stack.pop(); + } + // Degenerate (insufficient vertices to be valid) + if (rings.back().size() < 3) { + rings.back().clear(); + } else { + typename std::list::iterator second_element = rings.back().begin(); + ++second_element; + // Degenerate (zero area) + if (rings.back().back() == *second_element) { + rings.back().clear(); + } + } + + // Remove last ring if too small (or empty) + if (rings.back().size() < 3) { + rings.pop_back(); + } + + // Start rings at the lexicographically smallest vertex + for (auto& current_ring: rings) { + typename std::list::iterator smallest_vertex = current_ring.begin(); + for (typename std::list::iterator current_vertex = current_ring.begin(); current_vertex != current_ring.end(); ++current_vertex) { + if ((*current_vertex)->point() < (*smallest_vertex)->point()) smallest_vertex = current_vertex; + } if (current_ring.back() != *smallest_vertex) { + ++smallest_vertex; + current_ring.splice(current_ring.begin(), current_ring, smallest_vertex, current_ring.end()); + } + } + + // Make rings + if (rings.size() == 0) continue; + typename std::list> rings_for_polygon; + for (auto& current_ring: rings) { + rings_for_polygon.push_back(Polygon_2()); + for (typename std::list::reverse_iterator current_vertex = current_ring.rbegin(); current_vertex != current_ring.rend(); ++current_vertex) { + rings_for_polygon.back().push_back(typename Kernel::Point_2((*current_vertex)->point().x(), (*current_vertex)->point().y())); + } + } typename std::list>::iterator outer_ring; + for (typename std::list>::iterator current_ring = rings_for_polygon.begin(); current_ring != rings_for_polygon.end(); ++current_ring) { + if (current_ring->orientation() == COUNTERCLOCKWISE) { + outer_ring = current_ring; + break; + } + } Polygon_with_holes_2 new_polygon(*outer_ring); + rings_for_polygon.erase(outer_ring); + + for (auto const& current_ring: rings_for_polygon) new_polygon.add_hole(current_ring); + mp.add_polygon(new_polygon); + } } // Erases the triangulation. @@ -131,24 +313,24 @@ class Polygon_repair_2 { t.clear(); } - /// @} + /// @} - /// \name Access Functions + /// \name Access Functions /// @{ - Triangulation_with_odd_even_constraints_2& triangulation() { + Triangulation& triangulation() { return t; } Multipolygon_with_holes_2 multipolygon() { - + return mp; } /// @} - + protected: - Triangulation_with_odd_even_constraints_2 t; + Triangulation t; Multipolygon_with_holes_2 mp; }; diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h new file mode 100644 index 000000000000..5f8ad643bdf8 --- /dev/null +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h @@ -0,0 +1,51 @@ +// Copyright (c) 2023 GeometryFactory. All rights reserved. +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Ken Arroyo Ohori + +#ifndef CGAL_TRIANGULATION_WITH_REPAIR_INFO_2_H +#define CGAL_TRIANGULATION_WITH_REPAIR_INFO_2_H + +namespace CGAL { + +template > +class Triangulation_face_base_with_repair_info_2 : public FaceBase { + bool _processed; + bool _interior; + bool _reconstructed; +public: + typedef typename FaceBase::Vertex_handle Vertex_handle; + typedef typename FaceBase::Face_handle Face_handle; + + template + struct Rebind_TDS { + typedef typename FaceBase::template Rebind_TDS::Other FaceBase2; + typedef Triangulation_face_base_with_repair_info_2 Other; + }; + + Triangulation_face_base_with_repair_info_2() : FaceBase() {} + + Triangulation_face_base_with_repair_info_2(Vertex_handle v0, Vertex_handle v1, Vertex_handle v2) + : FaceBase(v0, v1, v2) {} + + Triangulation_face_base_with_repair_info_2(Vertex_handle v0, Vertex_handle v1, Vertex_handle v2, + Face_handle n0, Face_handle n1, Face_handle n2 ) + : FaceBase(v0, v1, v2, n0, n1, n2) {} + + const bool& processed() const { return _processed; } + bool& processed() { return _processed; } + const bool& interior() const { return _interior; } + bool& interior() { return _interior; } + const bool& reconstructed() const { return _reconstructed; } + bool& reconstructed() { return _reconstructed; } +}; + +} //namespace CGAL + +#endif // CGAL_TRIANGULATION_WITH_REPAIR_INFO_2_H \ No newline at end of file diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index 84f239dad34a..5a4a83ed0f77 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -52,8 +52,14 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { // iterator over interior faces. class Interior_faces_iterator : public Base_triangulation::All_faces_iterator { - Interior_faces_iterator operator++(); - Interior_faces_iterator operator--(); + + Interior_faces_iterator operator++() { + + } + + Interior_faces_iterator operator--() { + + } }; // Inserts point p in the triangulation and returns the corresponding vertex. From 868dd5499338e73548b785e40a3109d8080f05f3 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 6 Jul 2023 17:38:58 -0600 Subject: [PATCH 009/182] sketch of new labelling method (untested) --- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 251 +++++------------- ...iangulation_face_base_with_repair_info_2.h | 15 +- 2 files changed, 68 insertions(+), 198 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index d2d9b8f8a19b..526a08387012 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -78,9 +78,7 @@ class Polygon_repair_2 { typedef Triangulation_with_odd_even_constraints_2 Triangulation; /// \name Creation - Polygon_repair_2() { - - } + Polygon_repair_2() {} /// \name Modifiers /// @{ @@ -107,205 +105,80 @@ class Polygon_repair_2 { } } - // Label triangles in triangulation as inside or outside the polygon + // Label triangles in triangulation void label_triangulation() { + std::list to_check_exterior, to_check_interior, to_check; + std::list to_check_exterior_added_by; for (auto const face: t.all_face_handles()) { - face->processed() = false; - face->interior() = false; - } std::list to_check; - t.infinite_face()->processed() = true; - to_check.push_back(t.infinite_face()); - while (!to_check.empty()) { + face->label() = 0; + face->added_to_list() = false; + } + + // Mark exterior as added to list and get interior triangles adjacent to it + to_check_exterior.push_back(t.infinite_face()); + t.infinite_face()->added_to_list() = true; + while (!to_check_exterior.empty()) { for (int neighbour = 0; neighbour < 3; ++neighbour) { - if (!to_check.front()->neighbor(neighbour)->processed()) { - to_check.front()->neighbor(neighbour)->processed() = true; - if (t.is_constrained(typename Triangulation::Edge(to_check.front(), neighbour))) { - to_check.front()->neighbor(neighbour)->interior() = !to_check.front()->interior(); - to_check.push_back(to_check.front()->neighbor(neighbour)); + if (!to_check_exterior.front()->neighbor(neighbour)->added_to_list()) { + if (!t.is_constrained(typename Triangulation::Edge(to_check_exterior.front(), neighbour))) { + to_check_exterior.push_back(to_check_exterior.front()->neighbor(neighbour)); } else { - to_check.front()->neighbor(neighbour)->interior() = to_check.front()->interior(); - to_check.push_back(to_check.front()->neighbor(neighbour)); - } + to_check_interior.push_back(to_check_exterior.front()->neighbor(neighbour)); + } to_check_exterior.front()->neighbor(neighbour)->added_to_list() = true; } - } to_check.pop_front(); + } to_check_exterior.pop_front(); } - } - void get_boundary(typename Triangulation::Face_handle face, int edge, std::list &out_vertices) { - // Check clockwise edge - if (face->neighbor(face->cw(edge))->interior() && !face->neighbor(face->cw(edge))->reconstructed()) { - face->neighbor(face->cw(edge))->reconstructed() = true; - std::list v1; - get_boundary(face->neighbor(face->cw(edge)), face->neighbor(face->cw(edge))->index(face), v1); - out_vertices.splice(out_vertices.end(), v1); - } - - // Add central vertex - out_vertices.push_back(face->vertex(edge)); - - // Check counterclockwise edge - if (face->neighbor(face->ccw(edge))->interior() && !face->neighbor(face->ccw(edge))->reconstructed()) { - face->neighbor(face->ccw(edge))->reconstructed() = true; - std::list v2; - get_boundary(face->neighbor(face->ccw(edge)), face->neighbor(face->ccw(edge))->index(face), v2); - out_vertices.splice(out_vertices.end(), v2); + // Label region of front element of interior and exterior lists + int current_polygon = 1, current_hole = -1; + std::unordered_map hole_nesting; + while (!to_check_interior.empty() || !to_check_exterior.empty()) { + + // Interior + if (!to_check_interior.empty()) { + if (to_check_interior.front()->label() == 0) { + to_check.push_back(to_check_interior.front()); + to_check_interior.front()->added_to_list() = true; + while (!to_check.empty()) { + to_check.front()->label() = current_polygon; + for (int neighbour = 0; neighbour < 3; ++neighbour) { + if (!t.is_constrained(typename Triangulation::Edge(to_check.front(), neighbour))) { + to_check.push_back(to_check.front()->neighbor(neighbour)); + } else if (!to_check.front()->neighbor(neighbour)->added_to_list()) { + to_check_exterior.push_back(to_check.front()->neighbor(neighbour)); + to_check_exterior_added_by.push_back(current_polygon); + } to_check.front()->neighbor(neighbour)->added_to_list() = true; + } to_check.pop_front(); + } ++current_polygon; + } to_check_interior.pop_front(); + } + + // Exterior + if (!to_check_exterior.empty()) { + if (to_check_exterior.front()->label() == 0) { + hole_nesting[current_hole] = to_check_exterior_added_by.front(); + to_check.push_back(to_check_exterior.front()); + to_check_exterior.front()->added_to_list() = true; + while (!to_check.empty()) { + to_check.front()->label() = current_hole; + for (int neighbour = 0; neighbour < 3; ++neighbour) { + if (!t.is_constrained(typename Triangulation::Edge(to_check.front(), neighbour))) { + to_check.push_back(to_check.front()->neighbor(neighbour)); + } else if (!to_check.front()->neighbor(neighbour)->added_to_list()) { + to_check_interior.push_back(to_check.front()->neighbor(neighbour)); + } to_check.front()->neighbor(neighbour)->added_to_list() = true; + } to_check.pop_front(); + } --current_hole; + } to_check_exterior.pop_front(); + to_check_exterior_added_by.pop_front(); + } + } } // Reconstruct multipolygon based on the triangles labelled as inside the polygon void reconstruct_multipolygon() { mp.clear(); - for (auto const face: t.all_face_handles()) { - face->reconstructed() = false; - } - - for (auto const interior_face: t.finite_face_handles()) { - if (!interior_face->interior() || interior_face->reconstructed()) continue; - - // Get boundary - std::list vertices; - if (interior_face->neighbor(2)->interior() && !interior_face->neighbor(2)->reconstructed()) { - interior_face->neighbor(2)->reconstructed() = true; - std::list l2; - get_boundary(interior_face->neighbor(2), interior_face->neighbor(2)->index(interior_face), l2); - vertices.splice(vertices.end(), l2); - } vertices.push_back(interior_face->vertex(0)); - if (interior_face->neighbor(1)->interior() && !interior_face->neighbor(1)->reconstructed()) { - interior_face->neighbor(1)->reconstructed() = true; - std::list l1; - get_boundary(interior_face->neighbor(1), interior_face->neighbor(1)->index(interior_face), l1); - vertices.splice(vertices.end(), l1); - } vertices.push_back(interior_face->vertex(2)); - if (interior_face->neighbor(0)->interior() && !interior_face->neighbor(0)->reconstructed()) { - interior_face->neighbor(0)->reconstructed() = true; - std::list l0; - get_boundary(interior_face->neighbor(0), interior_face->neighbor(0)->index(interior_face), l0); - vertices.splice(vertices.end(), l0); - } vertices.push_back(interior_face->vertex(1)); - - // Find cutting vertices - std::set visited_vertices, repeated_vertices; - for (auto const& current_vertex: vertices) { - if (!visited_vertices.insert(current_vertex).second) repeated_vertices.insert(current_vertex); - } visited_vertices.clear(); - - // Cut and join rings in the correct order - std::list> rings; - std::stack> chains_stack; - std::set vertices_where_chains_begin; - rings.push_back(std::list()); - for (auto const& current_vertex: vertices) { - - // New chain - if (repeated_vertices.count(current_vertex) > 0) { - // Closed by itself - if (rings.back().front() == current_vertex) { - // Degenerate (insufficient vertices to be valid) - if (rings.back().size() < 3) { - rings.back().clear(); - } else { - typename std::list::iterator second_element = rings.back().begin(); - ++second_element; - // Degenerate (zero area) - if (rings.back().back() == *second_element) { - rings.back().clear(); - } - // Valid - else { - rings.push_back(std::list()); - } - } - } - // Open by itself - else { - // Closed with others in stack - if (vertices_where_chains_begin.count(current_vertex)) { - - while (rings.back().front() != current_vertex) { - rings.back().splice(rings.back().begin(), chains_stack.top()); - chains_stack.pop(); - } vertices_where_chains_begin.erase(current_vertex); - // Degenerate (insufficient vertices to be valid) - if (rings.back().size() < 3) { - rings.back().clear(); - } else { - typename std::list::iterator second_element = rings.back().begin(); - ++second_element; - // Degenerate (zero area) - if (rings.back().back() == *second_element) { - rings.back().clear(); - } - // Valid - else { - rings.push_back(std::list()); - } - } - } - // Open - else { - // Not first chain - if (repeated_vertices.count(rings.back().front()) > 0) { - vertices_where_chains_begin.insert(rings.back().front()); - } - chains_stack.push(std::list()); - chains_stack.top().splice(chains_stack.top().begin(), rings.back()); - } - } - } rings.back().push_back(current_vertex); - } - // Final ring - while (chains_stack.size() > 0) { - rings.back().splice(rings.back().begin(), chains_stack.top()); - chains_stack.pop(); - } - // Degenerate (insufficient vertices to be valid) - if (rings.back().size() < 3) { - rings.back().clear(); - } else { - typename std::list::iterator second_element = rings.back().begin(); - ++second_element; - // Degenerate (zero area) - if (rings.back().back() == *second_element) { - rings.back().clear(); - } - } - - // Remove last ring if too small (or empty) - if (rings.back().size() < 3) { - rings.pop_back(); - } - - // Start rings at the lexicographically smallest vertex - for (auto& current_ring: rings) { - typename std::list::iterator smallest_vertex = current_ring.begin(); - for (typename std::list::iterator current_vertex = current_ring.begin(); current_vertex != current_ring.end(); ++current_vertex) { - if ((*current_vertex)->point() < (*smallest_vertex)->point()) smallest_vertex = current_vertex; - } if (current_ring.back() != *smallest_vertex) { - ++smallest_vertex; - current_ring.splice(current_ring.begin(), current_ring, smallest_vertex, current_ring.end()); - } - } - - // Make rings - if (rings.size() == 0) continue; - typename std::list> rings_for_polygon; - for (auto& current_ring: rings) { - rings_for_polygon.push_back(Polygon_2()); - for (typename std::list::reverse_iterator current_vertex = current_ring.rbegin(); current_vertex != current_ring.rend(); ++current_vertex) { - rings_for_polygon.back().push_back(typename Kernel::Point_2((*current_vertex)->point().x(), (*current_vertex)->point().y())); - } - } typename std::list>::iterator outer_ring; - for (typename std::list>::iterator current_ring = rings_for_polygon.begin(); current_ring != rings_for_polygon.end(); ++current_ring) { - if (current_ring->orientation() == COUNTERCLOCKWISE) { - outer_ring = current_ring; - break; - } - } Polygon_with_holes_2 new_polygon(*outer_ring); - rings_for_polygon.erase(outer_ring); - - for (auto const& current_ring: rings_for_polygon) new_polygon.add_hole(current_ring); - mp.add_polygon(new_polygon); - } } // Erases the triangulation. diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h index 5f8ad643bdf8..8e1b55455c8f 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h @@ -16,9 +16,8 @@ namespace CGAL { template > class Triangulation_face_base_with_repair_info_2 : public FaceBase { - bool _processed; - bool _interior; - bool _reconstructed; + int _label; + bool _added_to_list; public: typedef typename FaceBase::Vertex_handle Vertex_handle; typedef typename FaceBase::Face_handle Face_handle; @@ -38,12 +37,10 @@ class Triangulation_face_base_with_repair_info_2 : public FaceBase { Face_handle n0, Face_handle n1, Face_handle n2 ) : FaceBase(v0, v1, v2, n0, n1, n2) {} - const bool& processed() const { return _processed; } - bool& processed() { return _processed; } - const bool& interior() const { return _interior; } - bool& interior() { return _interior; } - const bool& reconstructed() const { return _reconstructed; } - bool& reconstructed() { return _reconstructed; } + const bool& added_to_list() const { return _added_to_list; } + bool& added_to_list() { return _added_to_list; } + const int& label() const { return _label; } + int& label() { return _label; } }; } //namespace CGAL From 173b91bba340134f0f4083bd6aa6a8e1310f4b4f Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 11 Jul 2023 19:34:22 -0600 Subject: [PATCH 010/182] polygon reconstruction + fixed labelling method --- .../Polygon_repair_2/repair_polygon_2.cpp | 14 +- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 134 ++++++++++++++---- ...iangulation_face_base_with_repair_info_2.h | 6 +- 3 files changed, 114 insertions(+), 40 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 76cd3bf677c5..e67b7ead2a70 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -16,17 +16,17 @@ int main(int argc, char* argv[]) { // std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); // Square - // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - // Polygon p(ps, ps+4); - // Multipolygon mp; - // mp.add_polygon(p); - - // Bowtie - Point ps[] = {Point(0,0), Point(1,1), Point(1,0), Point(0,1)}; + Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; Polygon p(ps, ps+4); Multipolygon mp; mp.add_polygon(p); + // Bowtie + // Point ps[] = {Point(0,0), Point(1,1), Point(1,0), Point(0,1)}; + // Polygon p(ps, ps+4); + // Multipolygon mp; + // mp.add_polygon(p); + // Overlapping edge // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; // Polygon p1(ps1, ps1+4); diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 526a08387012..a8ac77e8fd12 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -68,6 +68,8 @@ Multipolygon_with_holes_2 repair(const Multipolygon_wi template > class Polygon_repair_2 { + int number_of_polygons, number_of_holes; + std::unordered_map hole_nesting; public: typedef CGAL::Triangulation_vertex_base_2 Vertex_base; typedef CGAL::Constrained_triangulation_face_base_2 Face_base; @@ -78,7 +80,7 @@ class Polygon_repair_2 { typedef Triangulation_with_odd_even_constraints_2 Triangulation; /// \name Creation - Polygon_repair_2() {} + Polygon_repair_2(): number_of_polygons(0), number_of_holes(0) {} /// \name Modifiers /// @{ @@ -111,74 +113,146 @@ class Polygon_repair_2 { std::list to_check_exterior_added_by; for (auto const face: t.all_face_handles()) { face->label() = 0; - face->added_to_list() = false; + face->processed() = false; } - // Mark exterior as added to list and get interior triangles adjacent to it + // Mark exterior as processed and put interior triangles adjacent to it in to_check_interior + // these are used as starting points for the reconstruction + // Note: exterior triangles are already labelled with 0 to_check_exterior.push_back(t.infinite_face()); - t.infinite_face()->added_to_list() = true; + t.infinite_face()->processed() = true; // processed means added to a list (to ensure elements are only added once) while (!to_check_exterior.empty()) { for (int neighbour = 0; neighbour < 3; ++neighbour) { - if (!to_check_exterior.front()->neighbor(neighbour)->added_to_list()) { + if (!to_check_exterior.front()->neighbor(neighbour)->processed()) { if (!t.is_constrained(typename Triangulation::Edge(to_check_exterior.front(), neighbour))) { to_check_exterior.push_back(to_check_exterior.front()->neighbor(neighbour)); } else { to_check_interior.push_back(to_check_exterior.front()->neighbor(neighbour)); - } to_check_exterior.front()->neighbor(neighbour)->added_to_list() = true; + } to_check_exterior.front()->neighbor(neighbour)->processed() = true; } } to_check_exterior.pop_front(); } - // Label region of front element of interior and exterior lists - int current_polygon = 1, current_hole = -1; - std::unordered_map hole_nesting; + // Label region of front element of interior and exterior lists (alternating) while (!to_check_interior.empty() || !to_check_exterior.empty()) { - // Interior + // Interior triangle if (!to_check_interior.empty()) { - if (to_check_interior.front()->label() == 0) { + if (to_check_interior.front()->label() == 0) { // label = 0 means not labelled yet + to_check_interior.front()->label() = number_of_polygons+1; to_check.push_back(to_check_interior.front()); - to_check_interior.front()->added_to_list() = true; while (!to_check.empty()) { - to_check.front()->label() = current_polygon; for (int neighbour = 0; neighbour < 3; ++neighbour) { if (!t.is_constrained(typename Triangulation::Edge(to_check.front(), neighbour))) { - to_check.push_back(to_check.front()->neighbor(neighbour)); - } else if (!to_check.front()->neighbor(neighbour)->added_to_list()) { - to_check_exterior.push_back(to_check.front()->neighbor(neighbour)); - to_check_exterior_added_by.push_back(current_polygon); - } to_check.front()->neighbor(neighbour)->added_to_list() = true; + if (to_check.front()->neighbor(neighbour)->label() == 0) { + to_check.front()->neighbor(neighbour)->label() = number_of_polygons+1; + to_check.push_back(to_check.front()->neighbor(neighbour)); + to_check.front()->neighbor(neighbour)->processed() = true; + } + } else { // constrained -> exterior or hole + if (!to_check.front()->neighbor(neighbour)->processed()) { // only add holes (not processed) to list once + to_check_exterior.push_back(to_check.front()->neighbor(neighbour)); + to_check.front()->neighbor(neighbour)->processed() = true; + to_check_exterior_added_by.push_back(number_of_polygons+1); + } + } } to_check.pop_front(); - } ++current_polygon; + } ++number_of_polygons; } to_check_interior.pop_front(); } - // Exterior + // Exterior triangle (hole) if (!to_check_exterior.empty()) { - if (to_check_exterior.front()->label() == 0) { - hole_nesting[current_hole] = to_check_exterior_added_by.front(); + if (to_check_exterior.front()->label() == 0) { // label = 0 means not labelled yet + to_check_exterior.front()->label() = -number_of_holes+1; to_check.push_back(to_check_exterior.front()); - to_check_exterior.front()->added_to_list() = true; + hole_nesting[-number_of_holes+1] = to_check_exterior_added_by.front(); // record nesting of current hole while (!to_check.empty()) { - to_check.front()->label() = current_hole; for (int neighbour = 0; neighbour < 3; ++neighbour) { if (!t.is_constrained(typename Triangulation::Edge(to_check.front(), neighbour))) { - to_check.push_back(to_check.front()->neighbor(neighbour)); - } else if (!to_check.front()->neighbor(neighbour)->added_to_list()) { - to_check_interior.push_back(to_check.front()->neighbor(neighbour)); - } to_check.front()->neighbor(neighbour)->added_to_list() = true; + if (to_check.front()->neighbor(neighbour)->label() == 0) { + to_check.front()->neighbor(neighbour)->label() = number_of_polygons+1; + to_check.push_back(to_check.front()->neighbor(neighbour)); + to_check.front()->neighbor(neighbour)->processed() = true; + } + } else { // constrained -> interior + if (!to_check.front()->neighbor(neighbour)->processed()) { // interior triangles only added once + to_check_interior.push_back(to_check.front()->neighbor(neighbour)); + to_check.front()->neighbor(neighbour)->processed() = true; + } + } } to_check.pop_front(); - } --current_hole; + } ++number_of_holes; } to_check_exterior.pop_front(); to_check_exterior_added_by.pop_front(); } - } + } std::cout << number_of_polygons << " polygons with " << number_of_holes << " holes in triangulation" << std::endl; + } + + // Reconstruct ring boundary starting from an edge (face + opposite vertex) that is part of it + void reconstruct_ring(Polygon_2& ring, + typename Triangulation::Face_handle face_adjacent_to_boundary, int opposite_vertex) { + typename Triangulation::Face_handle current_face = face_adjacent_to_boundary; + int current_opposite_vertex = opposite_vertex; + do { + typename Triangulation::Vertex_handle pivot_vertex = current_face->vertex(current_face->cw(current_opposite_vertex)); + // std::cout << "Adding point " << pivot_vertex->point() << std::endl; + ring.push_back(pivot_vertex->point()); + typename Triangulation::Face_circulator fc = t.incident_faces(pivot_vertex, current_face); + do { + ++fc; + } while (fc->label() != current_face->label()); + current_face = fc; + current_opposite_vertex = fc->cw(fc->index(pivot_vertex)); + } while (current_face != face_adjacent_to_boundary || + current_opposite_vertex != opposite_vertex); } // Reconstruct multipolygon based on the triangles labelled as inside the polygon void reconstruct_multipolygon() { mp.clear(); + std::vector> polygons, holes; + polygons.reserve(number_of_polygons); + holes.reserve(number_of_holes); + + for (auto const face: t.all_face_handles()) { + face->processed() = false; + } for (auto const &face: t.finite_face_handles()) { + if (face->label() == 0) continue; // exterior triangle + if (face->processed()) continue; // already reconstructed + for (int opposite_vertex = 0; opposite_vertex < 3; ++opposite_vertex) { + if (face->label() != face->neighbor(opposite_vertex)->label()) { + + if (face->label() > 0) { + polygons.emplace_back(); + reconstruct_ring(polygons.back(), face, opposite_vertex); + } else { + holes.emplace_back(); + reconstruct_ring(holes.back(), face, opposite_vertex); + } + + std::list to_check; + to_check.push_back(face); + while (!to_check.empty()) { + for (int neighbour = 0; neighbour < 3; ++neighbour) { + if (to_check.front()->label() == to_check.front()->neighbor(neighbour)->label() && + !to_check.front()->neighbor(neighbour)->processed()) { + to_check.push_back(to_check.front()->neighbor(neighbour)); + } + } to_check.front()->processed() = true; + to_check.pop_front(); + } + + break; + } + } + } + + for (auto& polygon: polygons) { + // std::cout << "Adding polygon " << polygon << std::endl; + mp.add_polygon(Polygon_with_holes_2(polygon)); + } } // Erases the triangulation. diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h index 8e1b55455c8f..d755f7078cbc 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h @@ -17,7 +17,7 @@ namespace CGAL { template > class Triangulation_face_base_with_repair_info_2 : public FaceBase { int _label; - bool _added_to_list; + bool _processed; public: typedef typename FaceBase::Vertex_handle Vertex_handle; typedef typename FaceBase::Face_handle Face_handle; @@ -37,8 +37,8 @@ class Triangulation_face_base_with_repair_info_2 : public FaceBase { Face_handle n0, Face_handle n1, Face_handle n2 ) : FaceBase(v0, v1, v2, n0, n1, n2) {} - const bool& added_to_list() const { return _added_to_list; } - bool& added_to_list() { return _added_to_list; } + const bool& processed() const { return _processed; } + bool& processed() { return _processed; } const int& label() const { return _label; } int& label() { return _label; } }; From aefce52a0430a974de855ff0cd3996fc18dfe53a Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 14 Jul 2023 10:20:00 -0600 Subject: [PATCH 011/182] simplified labelling code + fixed bugs, corrected reconstruction of holes --- .../Polygon_repair_2/repair_polygon_2.cpp | 43 ++++- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 154 ++++++++---------- 2 files changed, 106 insertions(+), 91 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index e67b7ead2a70..37c02ed74587 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -3,12 +3,14 @@ #include #include +#include // #include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_2 Point; typedef CGAL::Polygon_2 Polygon; +typedef CGAL::Polygon_with_holes_2 Polygon_with_holes; typedef CGAL::Multipolygon_with_holes_2 Multipolygon; typedef CGAL::Polygon_repair_2::Polygon_repair_2 Polygon_repair; @@ -16,10 +18,10 @@ int main(int argc, char* argv[]) { // std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); // Square - Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - Polygon p(ps, ps+4); - Multipolygon mp; - mp.add_polygon(p); + // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Polygon p(ps, ps+4); + // Multipolygon mp; + // mp.add_polygon(p); // Bowtie // Point ps[] = {Point(0,0), Point(1,1), Point(1,0), Point(0,1)}; @@ -54,11 +56,42 @@ int main(int argc, char* argv[]) { // mp.add_polygon(p1); // mp.add_polygon(p2); + // Square with hole + // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Polygon_with_holes p(Polygon(ps1, ps1+4)); + // Point ps2[] = {Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0.25,0.75)}; + // Polygon h(ps2, ps2+4); + // p.add_hole(h); + // Multipolygon mp; + // mp.add_polygon(p); + + // Square with hole touching boundary + // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Polygon_with_holes p(Polygon(ps1, ps1+4)); + // Point ps2[] = {Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0,1)}; + // Polygon h(ps2, ps2+4); + // p.add_hole(h); + // Multipolygon mp; + // mp.add_polygon(p); + + // Square with hole touching boundary (self-intersecting loop) + // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1), + // Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0,1)}; + // Polygon p(ps, ps+8); + // std::cout << p << std::endl; + // Multipolygon mp; + // mp.add_polygon(p); + Polygon_repair pr; pr.add_to_triangulation(mp); pr.label_triangulation(); + + // for (auto const f: pr.triangulation().all_face_handles()) { + // std::cout << f->label() << " "; + // } std::cout << std::endl; + pr.reconstruct_multipolygon(); - std::cout << pr.multipolygon(); + std::cout << pr.multipolygon() << std::endl; // CGAL::Polygon_repair_2::repair(mp); diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index a8ac77e8fd12..ff9e8c02688c 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -69,7 +69,7 @@ template > class Polygon_repair_2 { int number_of_polygons, number_of_holes; - std::unordered_map hole_nesting; + std::vector hole_nesting; public: typedef CGAL::Triangulation_vertex_base_2 Vertex_base; typedef CGAL::Constrained_triangulation_face_base_2 Face_base; @@ -80,7 +80,7 @@ class Polygon_repair_2 { typedef Triangulation_with_odd_even_constraints_2 Triangulation; /// \name Creation - Polygon_repair_2(): number_of_polygons(0), number_of_holes(0) {} + Polygon_repair_2() : number_of_polygons(0), number_of_holes(0) {} /// \name Modifiers /// @{ @@ -107,92 +107,70 @@ class Polygon_repair_2 { } } + // Label a region of adjacent triangles without passing through constraints + // adjacent triangles that involve passing through constraints are added to to_check + void label_region(typename Triangulation::Face_handle face, int label, + std::list& to_check, + std::list& to_check_added_by) { + std::cout << "Labelling region with " << label << std::endl; + std::list to_check_in_region; + face->label() = label; + to_check_in_region.push_back(face); + face->processed() = true; // processed means added to a list (to ensure elements are only added once) + + while (!to_check_in_region.empty()) { + for (int neighbour = 0; neighbour < 3; ++neighbour) { + if (!t.is_constrained(typename Triangulation::Edge(to_check_in_region.front(), neighbour))) { + if (to_check_in_region.front()->neighbor(neighbour)->label() == 0) { + to_check_in_region.front()->neighbor(neighbour)->label() = label; + to_check_in_region.push_back(to_check_in_region.front()->neighbor(neighbour)); + to_check_in_region.front()->neighbor(neighbour)->processed() = true; + } + } else { + if (!to_check_in_region.front()->neighbor(neighbour)->processed()) { + to_check.push_back(to_check_in_region.front()->neighbor(neighbour)); + to_check_added_by.push_back(label); + to_check_in_region.front()->neighbor(neighbour)->processed() = true; + } + } + } to_check_in_region.pop_front(); + } + } + // Label triangles in triangulation void label_triangulation() { - std::list to_check_exterior, to_check_interior, to_check; - std::list to_check_exterior_added_by; for (auto const face: t.all_face_handles()) { face->label() = 0; face->processed() = false; } - // Mark exterior as processed and put interior triangles adjacent to it in to_check_interior - // these are used as starting points for the reconstruction - // Note: exterior triangles are already labelled with 0 - to_check_exterior.push_back(t.infinite_face()); - t.infinite_face()->processed() = true; // processed means added to a list (to ensure elements are only added once) - while (!to_check_exterior.empty()) { - for (int neighbour = 0; neighbour < 3; ++neighbour) { - if (!to_check_exterior.front()->neighbor(neighbour)->processed()) { - if (!t.is_constrained(typename Triangulation::Edge(to_check_exterior.front(), neighbour))) { - to_check_exterior.push_back(to_check_exterior.front()->neighbor(neighbour)); - } else { - to_check_interior.push_back(to_check_exterior.front()->neighbor(neighbour)); - } to_check_exterior.front()->neighbor(neighbour)->processed() = true; + // Mark exterior as processed and put interior triangles adjacent to it in to_check + std::list to_check; + std::list to_check_added_by; + label_region(t.infinite_face(), -1, to_check, to_check_added_by); + + // Label region of front element to_check list + while (!to_check.empty()) { + + if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check_added_by.front() < 0) { + label_region(to_check.front(), number_of_polygons+1, to_check, to_check_added_by); + ++number_of_polygons; + } else { + hole_nesting.push_back(to_check_added_by.front()); // record nesting of current hole + label_region(to_check.front(), -(number_of_holes+2), to_check, to_check_added_by); + ++number_of_holes; } - } to_check_exterior.pop_front(); - } - - // Label region of front element of interior and exterior lists (alternating) - while (!to_check_interior.empty() || !to_check_exterior.empty()) { - - // Interior triangle - if (!to_check_interior.empty()) { - if (to_check_interior.front()->label() == 0) { // label = 0 means not labelled yet - to_check_interior.front()->label() = number_of_polygons+1; - to_check.push_back(to_check_interior.front()); - while (!to_check.empty()) { - for (int neighbour = 0; neighbour < 3; ++neighbour) { - if (!t.is_constrained(typename Triangulation::Edge(to_check.front(), neighbour))) { - if (to_check.front()->neighbor(neighbour)->label() == 0) { - to_check.front()->neighbor(neighbour)->label() = number_of_polygons+1; - to_check.push_back(to_check.front()->neighbor(neighbour)); - to_check.front()->neighbor(neighbour)->processed() = true; - } - } else { // constrained -> exterior or hole - if (!to_check.front()->neighbor(neighbour)->processed()) { // only add holes (not processed) to list once - to_check_exterior.push_back(to_check.front()->neighbor(neighbour)); - to_check.front()->neighbor(neighbour)->processed() = true; - to_check_exterior_added_by.push_back(number_of_polygons+1); - } - } - } to_check.pop_front(); - } ++number_of_polygons; - } to_check_interior.pop_front(); - } - - // Exterior triangle (hole) - if (!to_check_exterior.empty()) { - if (to_check_exterior.front()->label() == 0) { // label = 0 means not labelled yet - to_check_exterior.front()->label() = -number_of_holes+1; - to_check.push_back(to_check_exterior.front()); - hole_nesting[-number_of_holes+1] = to_check_exterior_added_by.front(); // record nesting of current hole - while (!to_check.empty()) { - for (int neighbour = 0; neighbour < 3; ++neighbour) { - if (!t.is_constrained(typename Triangulation::Edge(to_check.front(), neighbour))) { - if (to_check.front()->neighbor(neighbour)->label() == 0) { - to_check.front()->neighbor(neighbour)->label() = number_of_polygons+1; - to_check.push_back(to_check.front()->neighbor(neighbour)); - to_check.front()->neighbor(neighbour)->processed() = true; - } - } else { // constrained -> interior - if (!to_check.front()->neighbor(neighbour)->processed()) { // interior triangles only added once - to_check_interior.push_back(to_check.front()->neighbor(neighbour)); - to_check.front()->neighbor(neighbour)->processed() = true; - } - } - } to_check.pop_front(); - } ++number_of_holes; - } to_check_exterior.pop_front(); - to_check_exterior_added_by.pop_front(); - } + } to_check.pop_front(); + to_check_added_by.pop_front(); } std::cout << number_of_polygons << " polygons with " << number_of_holes << " holes in triangulation" << std::endl; } // Reconstruct ring boundary starting from an edge (face + opposite vertex) that is part of it - void reconstruct_ring(Polygon_2& ring, - typename Triangulation::Face_handle face_adjacent_to_boundary, int opposite_vertex) { + void reconstruct_ring(std::list& ring, + typename Triangulation::Face_handle face_adjacent_to_boundary, + int opposite_vertex) { typename Triangulation::Face_handle current_face = face_adjacent_to_boundary; int current_opposite_vertex = opposite_vertex; do { @@ -212,24 +190,29 @@ class Polygon_repair_2 { // Reconstruct multipolygon based on the triangles labelled as inside the polygon void reconstruct_multipolygon() { mp.clear(); - std::vector> polygons, holes; - polygons.reserve(number_of_polygons); - holes.reserve(number_of_holes); + std::vector> polygons; + std::vector>> holes; + for (int i = 0; i < number_of_polygons; ++i) { + polygons.emplace_back(); + holes.emplace_back(); + } for (auto const face: t.all_face_handles()) { face->processed() = false; } for (auto const &face: t.finite_face_handles()) { - if (face->label() == 0) continue; // exterior triangle + if (face->label() == -1) continue; // exterior triangle if (face->processed()) continue; // already reconstructed for (int opposite_vertex = 0; opposite_vertex < 3; ++opposite_vertex) { if (face->label() != face->neighbor(opposite_vertex)->label()) { + std::list ring; + reconstruct_ring(ring, face, opposite_vertex); if (face->label() > 0) { - polygons.emplace_back(); - reconstruct_ring(polygons.back(), face, opposite_vertex); + polygons[face->label()-1].insert(polygons[face->label()-1].vertices_end(), + ring.begin(), ring.end()); } else { - holes.emplace_back(); - reconstruct_ring(holes.back(), face, opposite_vertex); + // std::cout << "Label: " << face->label() << " -> item " << -face->label()-2 << " -> in polygon " << hole_nesting[-face->label()-2] << std::endl; + holes[hole_nesting[-face->label()-2]-1].emplace_back(ring.begin(), ring.end()); } std::list to_check; @@ -249,9 +232,8 @@ class Polygon_repair_2 { } } - for (auto& polygon: polygons) { - // std::cout << "Adding polygon " << polygon << std::endl; - mp.add_polygon(Polygon_with_holes_2(polygon)); + for (int i = 0; i < polygons.size(); ++i) { + mp.add_polygon(Polygon_with_holes_2(polygons[i], holes[i].begin(), holes[i].end())); } } From 3517005129427caf60c178a36e39c73a1b6f6145 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 14 Jul 2023 17:36:33 -0600 Subject: [PATCH 012/182] drawing multipolygon with holes --- .../examples/Polygon_repair_2/CMakeLists.txt | 6 +- .../Polygon_repair_2/repair_polygon_2.cpp | 11 +- .../draw_multipolygon_with_holes_2.h | 203 ++++++++++++++++++ 3 files changed, 214 insertions(+), 6 deletions(-) create mode 100644 Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h diff --git a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt index 7e634d7d73e5..c4626d9d2556 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1...3.23) project(Polygon_repair_2_Examples) -find_package(CGAL REQUIRED) +find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) # create a target per cppfile file( @@ -14,3 +14,7 @@ file( foreach(cppfile ${cppfiles}) create_single_source_cgal_program("${cppfile}") endforeach() + +if(CGAL_Qt5_FOUND) + target_link_libraries(repair_polygon_2 PUBLIC CGAL::CGAL_Basic_viewer) +endif() \ No newline at end of file diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 37c02ed74587..5bbb5e59df9e 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include // #include @@ -24,10 +24,10 @@ int main(int argc, char* argv[]) { // mp.add_polygon(p); // Bowtie - // Point ps[] = {Point(0,0), Point(1,1), Point(1,0), Point(0,1)}; - // Polygon p(ps, ps+4); - // Multipolygon mp; - // mp.add_polygon(p); + Point ps[] = {Point(0,0), Point(1,1), Point(1,0), Point(0,1)}; + Polygon p(ps, ps+4); + Multipolygon mp; + mp.add_polygon(p); // Overlapping edge // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; @@ -92,6 +92,7 @@ int main(int argc, char* argv[]) { pr.reconstruct_multipolygon(); std::cout << pr.multipolygon() << std::endl; + CGAL::draw(pr.multipolygon()); // CGAL::Polygon_repair_2::repair(mp); diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h new file mode 100644 index 000000000000..8519699f0579 --- /dev/null +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h @@ -0,0 +1,203 @@ +// Copyright (c) 2023 GeometryFactory. All rights reserved. +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Ken Arroyo Ohori + +#ifndef CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H +#define CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H + +#include + +#ifdef DOXYGEN_RUNNING +namespace CGAL { + +/*! + * \ingroup PkgDrawMultipolygonWithHoles2 + * + * opens a new window and draws `aph`, an instance of the + * `CGAL::Multipolygon_with_holes_2` class. A call to this function is blocking, that + * is the program continues as soon as the user closes the window. This function + * requires `CGAL_Qt5`, and is only available if the macro + * `CGAL_USE_BASIC_VIEWER` is defined. Linking with the cmake target + * `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` and add the definition + * `CGAL_USE_BASIC_VIEWER`. + * \tparam PH an instance of the `CGAL::Multipolygon_with_holes_2` class. + * \param aph the polygon with holes to draw. + */ + +template +void draw(const PH& aph); + +} /* namespace CGAL */ + +#endif + +#ifdef CGAL_USE_BASIC_VIEWER + +#include +#include + +namespace CGAL { + +// Viewer class for Multipolygon_with_holes_2 +template +class Mpwh_2_basic_viewer_qt : public Basic_viewer_qt { + using Base = Basic_viewer_qt; + using Mpwh = Multipolygon; + using Pwh = typename Mpwh::Polygon_with_holes_2; + using Pgn = typename Mpwh::Polygon_2; + using Pnt = typename Pgn::Point_2; + +public: + /// Construct the viewer. + /// @param parent the active window to draw + /// @param mpwh the multipolygon to view + /// @param title the title of the window + Mpwh_2_basic_viewer_qt(QWidget* parent, const Mpwh& mpwh, + const char* title = "Basic Multipolygon_with_holes_2 Viewer") : + Base(parent, title, true, true, true, false, false), + m_mpwh(mpwh) { + if (mpwh.number_of_polygons() == 0) return; + + // mimic the computation of Camera::pixelGLRatio() + auto bbox = bounding_box(); + CGAL::qglviewer::Vec minv(bbox.xmin(), bbox.ymin(), 0); + CGAL::qglviewer::Vec maxv(bbox.xmax(), bbox.ymax(), 0); + auto diameter = (maxv - minv).norm(); + m_pixel_ratio = diameter / m_height; + } + + /*! Intercept the resizing of the window. + */ + virtual void resizeGL(int width, int height) { + CGAL::QGLViewer::resizeGL(width, height); + m_width = width; + m_height = height; + CGAL::qglviewer::Vec p; + auto ratio = camera()->pixelGLRatio(p); + m_pixel_ratio = ratio; + add_elements(); + } + + /*! Obtain the pixel ratio. + */ + double pixel_ratio() const { return m_pixel_ratio; } + + /*! Compute the bounding box. + */ + CGAL::Bbox_2 bounding_box() { + Bbox_2 bbox; + for (auto const& pwh: m_mpwh.polygons()) { + bbox += pwh.outer_boundary().bbox(); + } return bbox; + } + + /*! Compute the elements of a multipolygon with holes. + */ + void add_elements() { + clear(); + CGAL::IO::Color c(75,160,255); + + for (auto const& p: m_mpwh.polygons()) { + face_begin(c); + + const Pnt* point_in_face; + const auto& outer_boundary = p.outer_boundary(); + compute_loop(outer_boundary, false); + point_in_face = &(outer_boundary.vertex(outer_boundary.size()-1)); + + for (auto it = p.holes_begin(); it != p.holes_end(); ++it) { + compute_loop(*it, true); + add_point_in_face(*point_in_face); + } + + face_end(); + } + } + +protected: + /*! Compute the face + */ + void compute_loop(const Pgn& p, bool hole) { + if (hole) add_point_in_face(p.vertex(p.size()-1)); + + auto prev = p.vertices_begin(); + auto it = prev; + add_point(*it); + add_point_in_face(*it); + for (++it; it != p.vertices_end(); ++it) { + add_segment(*prev, *it); // add segment with previous point + add_point(*it); + add_point_in_face(*it); // add point in face + prev = it; + } + + // Add the last segment between the last point and the first one + add_segment(*prev, *(p.vertices_begin())); + } + + virtual void keyPressEvent(QKeyEvent* e) { + // Test key pressed: + // const ::Qt::KeyboardModifiers modifiers = e->modifiers(); + // if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::NoButton)) { ... } + + // Call: * add_elements() if the model changed, followed by + // * redraw() if some viewing parameters changed that implies some + // modifications of the buffers + // (eg. type of normal, color/mono) + // * update() just to update the drawing + + // Call the base method to process others/classicals key + Base::keyPressEvent(e); + } + +private: + //! The window width in pixels. + int m_width = CGAL_BASIC_VIEWER_INIT_SIZE_X; + + //! The window height in pixels. + int m_height = CGAL_BASIC_VIEWER_INIT_SIZE_Y; + + //! The ratio between pixel and opengl units (in world coordinate system). + double m_pixel_ratio = 1; + + //! The polygon with holes to draw. + const Mpwh& m_mpwh; +}; + +// Specialization of draw function. +template +void draw(const CGAL::Multipolygon_with_holes_2& mpwh, + const char* title = "Multipolygon_with_holes_2 Basic Viewer") +{ +#if defined(CGAL_TEST_SUITE) + bool cgal_test_suite = true; +#else + bool cgal_test_suite = qEnvironmentVariableIsSet("CGAL_TEST_SUITE"); +#endif + + if (! cgal_test_suite) { + using Mpwh = CGAL::Multipolygon_with_holes_2; + using Viewer = Mpwh_2_basic_viewer_qt; + CGAL::Qt::init_ogl_context(4,3); + int argc = 1; + const char* argv[2] = {"t2_viewer", nullptr}; + QApplication app(argc, const_cast(argv)); + Viewer mainwindow(app.activeWindow(), mpwh, title); + mainwindow.add_elements(); + mainwindow.show(); + app.exec(); + } +} + +} // End namespace CGAL + +#endif // CGAL_USE_BASIC_VIEWER + +#endif // CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H From b296459fb72efbf5ae6ca3b24d46bb92a69a48f4 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 14 Jul 2023 17:58:28 -0600 Subject: [PATCH 013/182] interior face iterators --- .../Polygon_repair_2/repair_polygon_2.cpp | 6 +-- ...riangulation_with_odd_even_constraints_2.h | 51 ++++++++++--------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 5bbb5e59df9e..ad34a77d06ff 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -86,9 +86,9 @@ int main(int argc, char* argv[]) { pr.add_to_triangulation(mp); pr.label_triangulation(); - // for (auto const f: pr.triangulation().all_face_handles()) { - // std::cout << f->label() << " "; - // } std::cout << std::endl; + for (auto f = pr.triangulation().interior_faces_begin(); f != pr.triangulation().interior_faces_end(); ++f) { + std::cout << f->label() << " "; + } std::cout << std::endl; pr.reconstruct_multipolygon(); std::cout << pr.multipolygon() << std::endl; diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index 5a4a83ed0f77..0063e6af2516 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -27,40 +27,40 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { /// \name Definition /// @{ - /// the triangulation class. typedef Triangulation_ Base_triangulation; - - /// Point type typedef typename Triangulation_::Point Point; - - /// Edge type typedef typename Triangulation_::Edge Edge; - - /// handle to a vertex typedef typename Triangulation_::Vertex_handle Vertex_handle; - - /// handle to a face typedef typename Triangulation_::Face_handle Face_handle; - - /// list of edges typedef typename Triangulation_::List_edges List_edges; - - /// list of faces typedef typename Triangulation_::List_faces List_faces; - + typedef typename Triangulation_::All_faces_iterator All_faces_iterator; /// @} - - // iterator over interior faces. - class Interior_faces_iterator : public Base_triangulation::All_faces_iterator { - - Interior_faces_iterator operator++() { - - } - Interior_faces_iterator operator--() { + class Interior_tester { + const Triangulation_with_odd_even_constraints_2 *t; + public: + Interior_tester() {} + Interior_tester(const Triangulation_with_odd_even_constraints_2 *tr) : t(tr) {} + bool operator()(const All_faces_iterator & fit) const { + return fit->label() < 1; } }; + + // iterator over interior faces. + class Interior_faces_iterator : public Filter_iterator { + typedef Filter_iterator Base; + typedef Interior_faces_iterator Self; + public: + Interior_faces_iterator() : Base() {} + Interior_faces_iterator(const Base &b) : Base(b) {} + Self& operator++() { Base::operator++(); return *this; } + Self& operator--() { Base::operator--(); return *this; } + Self operator++(int) { Self tmp(*this); ++(*this); return tmp; } + Self operator--(int) { Self tmp(*this); --(*this); return tmp; } + operator Face_handle() const { return Base::base(); } + }; // Inserts point p in the triangulation and returns the corresponding vertex. Vertex_handle insert(const Point &p, Face_handle f = Face_handle()) { @@ -113,12 +113,15 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { // Starts at an arbitrary interior face Interior_faces_iterator interior_faces_begin() { - + return CGAL::filter_iterator(Base_triangulation::all_faces_end(), + Interior_tester(this), + Base_triangulation::all_faces_begin()); } // Past-the-end iterator Interior_faces_iterator interior_faces_end() { - + return CGAL::filter_iterator(Base_triangulation::all_faces_end(), + Interior_tester(this)); } }; From 2f1f793a591b57450410fe878005231caa097718 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 14 Jul 2023 18:42:20 -0600 Subject: [PATCH 014/182] fixed simple version --- .../Polygon_repair_2/repair_polygon_2.cpp | 22 +++++++++---------- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 10 ++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index ad34a77d06ff..5cf72b0c39c7 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -82,20 +82,20 @@ int main(int argc, char* argv[]) { // Multipolygon mp; // mp.add_polygon(p); - Polygon_repair pr; - pr.add_to_triangulation(mp); - pr.label_triangulation(); + // Polygon_repair pr; + // pr.add_to_triangulation(mp); + // pr.label_triangulation(); - for (auto f = pr.triangulation().interior_faces_begin(); f != pr.triangulation().interior_faces_end(); ++f) { - std::cout << f->label() << " "; - } std::cout << std::endl; + // for (auto f = pr.triangulation().interior_faces_begin(); f != pr.triangulation().interior_faces_end(); ++f) { + // std::cout << f->label() << " "; + // } std::cout << std::endl; - pr.reconstruct_multipolygon(); - std::cout << pr.multipolygon() << std::endl; - CGAL::draw(pr.multipolygon()); + // pr.reconstruct_multipolygon(); + // std::cout << pr.multipolygon() << std::endl; + // CGAL::draw(pr.multipolygon()); - - // CGAL::Polygon_repair_2::repair(mp); + std::cout << CGAL::Polygon_repair_2::repair(p) << std::endl; + std::cout << CGAL::Polygon_repair_2::repair(mp) << std::endl; return 0; } diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index ff9e8c02688c..12a1afe837f6 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -34,7 +34,7 @@ Multipolygon_with_holes_2 repair(const Polygon_2 pr; pr.add_to_triangulation(p); pr.label_triangulation(); - pr.reconstruct_polygon(); + pr.reconstruct_multipolygon(); return pr.multipolygon(); } @@ -45,7 +45,7 @@ Multipolygon_with_holes_2 repair(const Polygon_with_ho CGAL::Polygon_repair_2::Polygon_repair_2 pr; pr.add_to_triangulation(p); pr.label_triangulation(); - pr.reconstruct_polygon(); + pr.reconstruct_multipolygon(); return pr.multipolygon(); } @@ -56,7 +56,7 @@ Multipolygon_with_holes_2 repair(const Multipolygon_wi CGAL::Polygon_repair_2::Polygon_repair_2 pr; pr.add_to_triangulation(mp); pr.label_triangulation(); - pr.reconstruct_polygon(); + pr.reconstruct_multipolygon(); return pr.multipolygon(); } @@ -112,7 +112,7 @@ class Polygon_repair_2 { void label_region(typename Triangulation::Face_handle face, int label, std::list& to_check, std::list& to_check_added_by) { - std::cout << "Labelling region with " << label << std::endl; + // std::cout << "Labelling region with " << label << std::endl; std::list to_check_in_region; face->label() = label; to_check_in_region.push_back(face); @@ -164,7 +164,7 @@ class Polygon_repair_2 { } to_check.pop_front(); to_check_added_by.pop_front(); - } std::cout << number_of_polygons << " polygons with " << number_of_holes << " holes in triangulation" << std::endl; + } // std::cout << number_of_polygons << " polygons with " << number_of_holes << " holes in triangulation" << std::endl; } // Reconstruct ring boundary starting from an edge (face + opposite vertex) that is part of it From e1319a92889b704b66ff0fe1c11f4c3c1afc5791 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 18 Jul 2023 19:25:55 -0600 Subject: [PATCH 015/182] mostly fixed documentation --- .../Concepts/MultiPolygonWithHoles_2.h | 6 ++-- .../Polygon_repair_2/PackageDescription.txt | 32 ++++++++++--------- .../Multipolygon_with_holes_2.h | 17 ++++++---- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h b/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h index 9ffa99054673..b97ef40ecae1 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h @@ -3,7 +3,9 @@ * * \cgalRefines{CopyConstructible,Assignable,DefaultConstructible} * - * A model of this concept represents a multipolygon with holes. + * A model of this concept represents a multipolygon with holes. + * The concept requires the ability to store the polygons with holes + * that the multipolygon is composed of. * * \cgalHasModel `CGAL::Multipolygon_with_holes_2` */ @@ -14,7 +16,7 @@ class MultipolygonWithHoles_2 { /// \name Types /// @{ -//! the polygon type used to represent each connected component of the multipolygon. +//! the polygon type used to represent each polygon with holes of the multipolygon. typedef unspecified_type Polygon_with_holes_2; /*! a bidirectional iterator over the polygons. diff --git a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt b/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt index 054a066091a7..e74c1ef034f8 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt @@ -1,23 +1,23 @@ // PRETTY PACKAGE NAME should equal the project title in Doxyfile.in -/// \defgroup PkgPolygonRepair2 2D Polygon Repair Reference -/// \defgroup PkgPolygonRepair2Concepts Concepts -/// \ingroup PkgPolygonRepair2 - -/// \defgroup PkgPolygonRepair2AlgorithmClasses Algorithm Classes -/// \ingroup PkgPolygonRepair2 +/// \defgroup PkgPolygonRepair2Ref 2D Polygon Repair Reference -/// \defgroup PkgPolygonRepair2TraitsClasses Traits Classes -/// \ingroup PkgPolygonRepair2 +/// \defgroup PkgPolygonRepair2Concepts Concepts +/// \ingroup PkgPolygonRepair2Ref /// \defgroup PkgPolygonRepair2Functions Functions -/// \ingroup PkgPolygonRepair2 +/// \ingroup PkgPolygonRepair2Ref -/// \defgroup PkgPolygonRepair2Miscellaneous Miscellaneous -/// \ingroup PkgPolygonRepair2 +/*! + \code + #include + \endcode +*/ +/// \defgroup PkgDrawMultipolygonWithHoles2 Draw a 2D Multipolygon with holes +/// \ingroup PkgPolygonRepair2Ref /*! -\addtogroup PkgPolygonRepair2 +\addtogroup PkgPolygonRepair2Ref \todo check generated documentation \cgalPkgDescriptionBegin{2D Polygon Repair,PkgPolygonRepair2} @@ -25,8 +25,8 @@ \cgalPkgSummaryBegin \cgalPkgAuthors{Ken Arroyo Ohori} -\cgalPkgDesc{The package provides algorithms to repair 2D polygons. } -\cgalPkgManuals{Chapter_2D_Polygon_repair,PkgPolygonRepair2} +\cgalPkgDesc{The package provides a 2D multipolygon class and algorithms to repair 2D (multi)polygons. } +\cgalPkgManuals{Chapter_2D_Polygon_repair,PkgPolygonRepair2Ref} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin @@ -46,10 +46,12 @@ \cgalCRPSection{Classes} - `CGAL::Multipolygon_with_holes_2` -- `CGAL::Triangulation_with_odd_even_constraints_2` - `CGAL::Polygon_repair_2` \cgalCRPSection{Functions} - `CGAL::Polygon_repair_2::repair()` +\cgalCRPSection{Draw a Multipolygon_with_holes_2} +- \link PkgDrawMultipolygonWithHoles2 CGAL::draw() \endlink + */ diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h index d3f92bb9d090..9432beaa16c2 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h @@ -18,12 +18,10 @@ namespace CGAL { /*! \ingroup PkgPolygonRepair2Ref * - * The class `Multipolygon_with_holes_2` models the concept - * `MultiPolygonWithHoles_2`. - * It is parameterized with a type `Polygon` used to define the exposed - * type `Polygon_with_holes_2`. This type represents each polygon. - * - * \tparam Polygon_ must have input and output operators. + * The class `Multipolygon_with_holes_2` models the concept `MultipolygonWithHoles_2`. + * It is parameterized with two types (`Kernel` and `Container`) that are used to instantiate + * the types `Polygon_2` and `Polygon_with_holes_2`. + * The latter is used to represents each polygon with holes. The former is converted to the latter. * * \cgalModels `MultipolygonWithHoles_2` */ @@ -33,12 +31,16 @@ class Multipolygon_with_holes_2 { public: /// \name Definition + /// @{ + /// polygon type typedef CGAL::Polygon_2 Polygon_2; /// polygon with holes type typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; + /// @} + typedef std::deque Polygons_container; typedef typename Polygons_container::iterator Polygon_iterator; @@ -46,9 +48,10 @@ class Multipolygon_with_holes_2 { typedef unsigned int Size; - + /*! %Default constructor. */ Multipolygon_with_holes_2() {} + /*! Constructor from polygons. */ template Multipolygon_with_holes_2(PolygonsInputIterator p_begin, PolygonsInputIterator p_end) : From 0cc9b43729b5aa7f09b0f179ae430eb8979f187b Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 18 Jul 2023 19:32:07 -0600 Subject: [PATCH 016/182] fix cmake target name --- Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt index 7e634d7d73e5..d01986d94de1 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt @@ -2,7 +2,7 @@ # This is the CMake script for compiling a CGAL application. cmake_minimum_required(VERSION 3.1...3.23) -project(Polygon_repair_2_Examples) +project(Polygon_repair_2_Tests) find_package(CGAL REQUIRED) From 31ad1cb1fb445621aafd50bd320b9585fec3626c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 18 Jul 2023 19:45:17 -0600 Subject: [PATCH 017/182] added licence line --- .../include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h | 4 +++- .../include/CGAL/Polygon_repair_2/Polygon_repair_2.h | 4 +++- .../Triangulation_face_base_with_repair_info_2.h | 4 +++- .../Triangulation_with_odd_even_constraints_2.h | 4 +++- .../CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h index 9432beaa16c2..71f2b789e24d 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 GeometryFactory. All rights reserved. +// Copyright (c) 2023 GeometryFactory. // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -12,6 +12,8 @@ #ifndef CGAL_MULTIPOLYGON_WITH_HOLES_2_H #define CGAL_MULTIPOLYGON_WITH_HOLES_2_H +#include + #include namespace CGAL { diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 12a1afe837f6..5f16c2a7c11a 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 GeometryFactory. All rights reserved. +// Copyright (c) 2023 GeometryFactory. // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -12,6 +12,8 @@ #ifndef CGAL_POLYGON_REPAIR_2_H #define CGAL_POLYGON_REPAIR_2_H +#include + #include #include #include diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h index d755f7078cbc..20a4898c240e 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 GeometryFactory. All rights reserved. +// Copyright (c) 2023 GeometryFactory. // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -12,6 +12,8 @@ #ifndef CGAL_TRIANGULATION_WITH_REPAIR_INFO_2_H #define CGAL_TRIANGULATION_WITH_REPAIR_INFO_2_H +#include + namespace CGAL { template > diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index 0063e6af2516..e5af07d57ffe 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 GeometryFactory. All rights reserved. +// Copyright (c) 2023 GeometryFactory. // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -12,6 +12,8 @@ #ifndef CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H #define CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H +#include + namespace CGAL { /*! \ingroup PkgPolygonRepair2Ref diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h index 8519699f0579..14df7088e1dc 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 GeometryFactory. All rights reserved. +// Copyright (c) 2023 GeometryFactory. // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -12,6 +12,8 @@ #ifndef CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H #define CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H +#include + #include #ifdef DOXYGEN_RUNNING From 5998fc0ea296729f9b76e5a8246a6287c2d7f358 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 18 Jul 2023 19:55:56 -0600 Subject: [PATCH 018/182] trimmed trailing whitespace --- .../Concepts/MultiPolygonWithHoles_2.h | 4 ++-- .../examples/Polygon_repair_2/repair_polygon_2.cpp | 2 +- .../Polygon_repair_2/Multipolygon_with_holes_2.h | 8 ++++---- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 14 +++++++------- .../Triangulation_with_odd_even_constraints_2.h | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h b/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h index b97ef40ecae1..1054217ddce7 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h @@ -3,8 +3,8 @@ * * \cgalRefines{CopyConstructible,Assignable,DefaultConstructible} * - * A model of this concept represents a multipolygon with holes. - * The concept requires the ability to store the polygons with holes + * A model of this concept represents a multipolygon with holes. + * The concept requires the ability to store the polygons with holes * that the multipolygon is composed of. * * \cgalHasModel `CGAL::Multipolygon_with_holes_2` diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 5cf72b0c39c7..1469b73124bb 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -75,7 +75,7 @@ int main(int argc, char* argv[]) { // mp.add_polygon(p); // Square with hole touching boundary (self-intersecting loop) - // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1), + // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1), // Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0,1)}; // Polygon p(ps, ps+8); // std::cout << p << std::endl; diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h index 71f2b789e24d..528c144378c3 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h @@ -40,16 +40,16 @@ class Multipolygon_with_holes_2 { /// polygon with holes type typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; - + /// @} - + typedef std::deque Polygons_container; typedef typename Polygons_container::iterator Polygon_iterator; typedef typename Polygons_container::const_iterator Polygon_const_iterator; typedef unsigned int Size; - + /*! %Default constructor. */ Multipolygon_with_holes_2() {} @@ -97,7 +97,7 @@ respectively. The modifier `set_pretty_mode()` can be used to allow for (a few) structuring comments in the output. Otherwise, the output would be free of comments. The default for writing is \ascii without comments. -The number of polygons is exported followed by the polygons. For each polygon, +The number of polygons is exported followed by the polygons. For each polygon, the number of points of the outer boundary is exported followed by the points themselves in counterclockwise order. Then, the number of holes is exported, and for each hole, the number of points on its outer diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 5f16c2a7c11a..176678243ca7 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -133,7 +133,7 @@ class Polygon_repair_2 { to_check.push_back(to_check_in_region.front()->neighbor(neighbour)); to_check_added_by.push_back(label); to_check_in_region.front()->neighbor(neighbour)->processed() = true; - } + } } } to_check_in_region.pop_front(); } @@ -144,7 +144,7 @@ class Polygon_repair_2 { for (auto const face: t.all_face_handles()) { face->label() = 0; face->processed() = false; - } + } // Mark exterior as processed and put interior triangles adjacent to it in to_check std::list to_check; @@ -171,7 +171,7 @@ class Polygon_repair_2 { // Reconstruct ring boundary starting from an edge (face + opposite vertex) that is part of it void reconstruct_ring(std::list& ring, - typename Triangulation::Face_handle face_adjacent_to_boundary, + typename Triangulation::Face_handle face_adjacent_to_boundary, int opposite_vertex) { typename Triangulation::Face_handle current_face = face_adjacent_to_boundary; int current_opposite_vertex = opposite_vertex; @@ -215,7 +215,7 @@ class Polygon_repair_2 { } else { // std::cout << "Label: " << face->label() << " -> item " << -face->label()-2 << " -> in polygon " << hole_nesting[-face->label()-2] << std::endl; holes[hole_nesting[-face->label()-2]-1].emplace_back(ring.begin(), ring.end()); - } + } std::list to_check; to_check.push_back(face); @@ -224,10 +224,10 @@ class Polygon_repair_2 { if (to_check.front()->label() == to_check.front()->neighbor(neighbour)->label() && !to_check.front()->neighbor(neighbour)->processed()) { to_check.push_back(to_check.front()->neighbor(neighbour)); - } + } } to_check.front()->processed() = true; to_check.pop_front(); - } + } break; } @@ -258,7 +258,7 @@ class Polygon_repair_2 { } /// @} - + protected: Triangulation t; diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index e5af07d57ffe..3118c8974928 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -49,7 +49,7 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { return fit->label() < 1; } }; - + // iterator over interior faces. class Interior_faces_iterator : public Filter_iterator { typedef Filter_iterator Base; From 6d9579a258e29201ec9e9303f3b5c8fd58c13ba4 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 20 Jul 2023 08:54:32 +0100 Subject: [PATCH 019/182] The word 'Polygon' is reserved by Microsoft --- .../Polygon_repair_2/repair_polygon_2.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 1469b73124bb..0b9b41bdb9b5 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -9,7 +9,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_2 Point; -typedef CGAL::Polygon_2 Polygon; +typedef CGAL::Polygon_2 Polygon_2; typedef CGAL::Polygon_with_holes_2 Polygon_with_holes; typedef CGAL::Multipolygon_with_holes_2 Multipolygon; typedef CGAL::Polygon_repair_2::Polygon_repair_2 Polygon_repair; @@ -19,39 +19,39 @@ int main(int argc, char* argv[]) { // Square // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - // Polygon p(ps, ps+4); + // Polygon_2 p(ps, ps+4); // Multipolygon mp; // mp.add_polygon(p); // Bowtie Point ps[] = {Point(0,0), Point(1,1), Point(1,0), Point(0,1)}; - Polygon p(ps, ps+4); + Polygon_2 p(ps, ps+4); Multipolygon mp; mp.add_polygon(p); // Overlapping edge // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - // Polygon p1(ps1, ps1+4); + // Polygon_2 p1(ps1, ps1+4); // Point ps2[] = {Point(1,0), Point(2,0), Point(2,1), Point(1,1)}; - // Polygon p2(ps2, ps2+4); + // Polygon_2 p2(ps2, ps2+4); // Multipolygon mp; // mp.add_polygon(p1); // mp.add_polygon(p2); // Edge partly overlapping (start) // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - // Polygon p1(ps1, ps1+4); + // Polygon_2 p1(ps1, ps1+4); // Point ps2[] = {Point(1,0), Point(2,0), Point(2,0.5), Point(1,0.5)}; - // Polygon p2(ps2, ps2+4); + // Polygon_2 p2(ps2, ps2+4); // Multipolygon mp; // mp.add_polygon(p1); // mp.add_polygon(p2); // Edge partly overlapping (middle) // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - // Polygon p1(ps1, ps1+4); + // Polygon_2 p1(ps1, ps1+4); // Point ps2[] = {Point(1,0.25), Point(2,0.25), Point(2,0.75), Point(1,0.75)}; - // Polygon p2(ps2, ps2+4); + // Polygon_2 p2(ps2, ps2+4); // Multipolygon mp; // mp.add_polygon(p1); // mp.add_polygon(p2); @@ -60,7 +60,7 @@ int main(int argc, char* argv[]) { // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; // Polygon_with_holes p(Polygon(ps1, ps1+4)); // Point ps2[] = {Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0.25,0.75)}; - // Polygon h(ps2, ps2+4); + // Polygon_2 h(ps2, ps2+4); // p.add_hole(h); // Multipolygon mp; // mp.add_polygon(p); @@ -69,7 +69,7 @@ int main(int argc, char* argv[]) { // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; // Polygon_with_holes p(Polygon(ps1, ps1+4)); // Point ps2[] = {Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0,1)}; - // Polygon h(ps2, ps2+4); + // Polygon_2 h(ps2, ps2+4); // p.add_hole(h); // Multipolygon mp; // mp.add_polygon(p); @@ -77,7 +77,7 @@ int main(int argc, char* argv[]) { // Square with hole touching boundary (self-intersecting loop) // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1), // Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0,1)}; - // Polygon p(ps, ps+8); + // Polygon_2 p(ps, ps+8); // std::cout << p << std::endl; // Multipolygon mp; // mp.add_polygon(p); From 46bd5dd9b52d74a68fdc02279fb8aa2a3ccf48d7 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 20 Jul 2023 09:39:25 +0100 Subject: [PATCH 020/182] Add needed #include of base class --- .../Triangulation_face_base_with_repair_info_2.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h index 20a4898c240e..b78a51323627 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h @@ -14,6 +14,8 @@ #include +#include + namespace CGAL { template > @@ -47,4 +49,4 @@ class Triangulation_face_base_with_repair_info_2 : public FaceBase { } //namespace CGAL -#endif // CGAL_TRIANGULATION_WITH_REPAIR_INFO_2_H \ No newline at end of file +#endif // CGAL_TRIANGULATION_WITH_REPAIR_INFO_2_H From 24ca8b4eb4c96f3cd061a12cb92d5b22c558f80e Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 20 Jul 2023 09:45:16 +0100 Subject: [PATCH 021/182] Add needed #includes --- .../include/CGAL/Polygon_repair_2/Polygon_repair_2.h | 1 + .../Triangulation_with_odd_even_constraints_2.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 176678243ca7..5facc1f4a90f 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -14,6 +14,7 @@ #include +#include #include #include #include diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index 3118c8974928..ac290d70cb1f 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -13,6 +13,7 @@ #define CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H #include +#include namespace CGAL { @@ -129,4 +130,4 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { } // namespace CGAL -#endif // CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H \ No newline at end of file +#endif // CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H From 879b7ea1399bd460df61f506a446726e51fc5d3f Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 20 Jul 2023 10:51:51 +0100 Subject: [PATCH 022/182] Add WKT support for Multipolygon_with_holes --- .../Polygon_repair_2/repair_polygon_2.cpp | 1 - .../examples/Stream_support/Polygon_WKT.cpp | 12 +++++++++++- Stream_support/include/CGAL/IO/WKT.h | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 0b9b41bdb9b5..74e484462831 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -4,7 +4,6 @@ #include #include #include - // #include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; diff --git a/Stream_support/examples/Stream_support/Polygon_WKT.cpp b/Stream_support/examples/Stream_support/Polygon_WKT.cpp index f417e4a48ee2..7c7acf1b95d6 100644 --- a/Stream_support/examples/Stream_support/Polygon_WKT.cpp +++ b/Stream_support/examples/Stream_support/Polygon_WKT.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -11,7 +12,7 @@ int main(int argc, char* argv[]) { typedef CGAL::Polygon_with_holes_2 Polygon; typedef std::deque MultiPolygon; - + typedef CGAL::Multipolygon_with_holes_2 Multipolygon_with_holes_2; { std::ifstream is((argc>1)?argv[1]:"data/polygons.wkt"); std::list polys; @@ -33,5 +34,14 @@ int main(int argc, char* argv[]) for(Polygon p : mp) std::cout<2)?argv[2]:"data/multipolygon.wkt"); + Multipolygon_with_holes_2 mp; + CGAL::IO::read_multi_polygon_WKT(is, mp); + std::cout << mp << std::endl; + CGAL::IO::write_multi_polygon_WKT(std::cout, mp); + std::cout << std::endl; + } return 0; } diff --git a/Stream_support/include/CGAL/IO/WKT.h b/Stream_support/include/CGAL/IO/WKT.h index 266939338fde..303f793e0ff4 100644 --- a/Stream_support/include/CGAL/IO/WKT.h +++ b/Stream_support/include/CGAL/IO/WKT.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -345,6 +346,22 @@ bool read_multi_polygon_WKT(std::istream& in, return !in.fail(); } + +template +bool read_multi_polygon_WKT(std::istream& in, + Multipolygon_with_holes_2& mp) +{ + return read_multi_polygon_WKT(in, mp.polygons()); +} + + +template +std::ostream& write_multi_polygon_WKT(std::ostream& out, + Multipolygon_with_holes_2& mp) +{ + return write_multi_polygon_WKT(out, mp.polygons()); +} + //! \ingroup PkgStreamSupportIoFuncsWKT //! //! \brief writes `point` into a WKT stream. From 12d420f827b8914ca70e01104e7c2b8c4458470d Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 20 Jul 2023 11:00:21 +0100 Subject: [PATCH 023/182] Fix Stream_support/dependencies --- Stream_support/package_info/Stream_support/dependencies | 1 + 1 file changed, 1 insertion(+) diff --git a/Stream_support/package_info/Stream_support/dependencies b/Stream_support/package_info/Stream_support/dependencies index 86fd53b13ace..33648bd70333 100644 --- a/Stream_support/package_info/Stream_support/dependencies +++ b/Stream_support/package_info/Stream_support/dependencies @@ -7,6 +7,7 @@ Kernel_23 Modular_arithmetic Number_types Polygon +Polygon_repair_2 Profiling_tools Property_map STL_Extension From 6c85e541f7d39278d6abbc796b4d54f2b642c50c Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 20 Jul 2023 11:25:25 +0100 Subject: [PATCH 024/182] Fix doc typos --- Stream_support/include/CGAL/IO/WKT.h | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Stream_support/include/CGAL/IO/WKT.h b/Stream_support/include/CGAL/IO/WKT.h index 303f793e0ff4..e91af554199e 100644 --- a/Stream_support/include/CGAL/IO/WKT.h +++ b/Stream_support/include/CGAL/IO/WKT.h @@ -68,7 +68,7 @@ void pop_back_if_equal_to_front(CGAL::Polygon_with_holes_2& pwh) //! //! \tparam Point can be a `CGAL::Point_2` or `CGAL::Point_3`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //! \see `CGAL::Point_2` //! \see `CGAL::Point_3` @@ -113,10 +113,10 @@ bool read_point_WKT(std::istream& in, //! and have: //! - a function `push_back()` that takes the same point type, //! - a function `clear()`, -//! - a function `resize()` that takes an `size_type` +//! - a function `resize()` that takes a `size_type` //! - an `operator[]()` that takes a `size_type`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //! \see `CGAL::Point_2` //! \see `CGAL::Point_3` @@ -160,10 +160,10 @@ bool read_multi_point_WKT(std::istream& in, //! and have: //! - a function `push_back()` that takes a `CGAL::Point_2`. //! - a function `clear()`, -//! - a function `resize()` that takes an `size_type` +//! - a function `resize()` that takes a `size_type` //! - an `operator[]()` that takes a `size_type`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //! \see `CGAL::Point_2` template @@ -204,10 +204,10 @@ bool read_linestring_WKT(std::istream& in, //! and have: //! - a function `push_back()` that takes a `Linestring`, //! - a function `clear()`, -//! - a function `resize()` that takes an `size_type` +//! - a function `resize()` that takes a `size_type` //! - an `operator[]()` that takes a `size_type`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //! \see `CGAL::Point_2` template @@ -259,7 +259,7 @@ bool read_multi_linestring_WKT(std::istream& in, //! //! \tparam Polygon is a `CGAL::General_polygon_with_holes_2`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //! \see `CGAL::General_polygon_with_holes_2` template @@ -303,10 +303,10 @@ bool read_polygon_WKT(std::istream& in, //! and have: //! - a function `push_back()` that takes a `CGAL::General_polygon_with_holes_2`, //! - a function `clear()`, -//! - a function `resize()` that takes an `size_type` +//! - a function `resize()` that takes a `size_type` //! - an `operator[]()` that takes a `size_type`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //! \see `CGAL::General_polygon_with_holes_2` template @@ -368,7 +368,7 @@ std::ostream& write_multi_polygon_WKT(std::ostream& out, //! //! \tparam Point is a `CGAL::Point_2` //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //! \see `CGAL::Point_2` template @@ -388,7 +388,7 @@ std::ostream& write_point_WKT(std::ostream& out, //! //! \tparam Polygon must be a `CGAL::General_polygon_with_holes_2` //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //! \see `CGAL::General_polygon_with_holes_2` template @@ -408,7 +408,7 @@ std::ostream& write_polygon_WKT(std::ostream& out, //! //! \tparam LineString must be a `RandomAccessRange` of `CGAL::Point_2`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //!\see `CGAL::Point_2` template @@ -429,7 +429,7 @@ std::ostream& write_linestring_WKT(std::ostream& out, //! //! \tparam MultiPoint must be a `RandomAccessRange` of `CGAL::Point_2`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //!\see `CGAL::Point_2` template @@ -450,7 +450,7 @@ std::ostream& write_multi_point_WKT(std::ostream& out, //! //! \tparam MultiPolygon must be a `RandomAccessRange` of `CGAL::General_polygon_with_holes_2`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //!\see `CGAL::General_polygon_with_holes_2` template @@ -471,7 +471,7 @@ std::ostream& write_multi_polygon_WKT(std::ostream& out, //! //! \tparam MultiLineString must be a `RandomAccessRange` of `LineString`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //! \see `CGAL::IO::write_linestring_WKT()` template @@ -506,7 +506,7 @@ std::ostream& write_multi_linestring_WKT(std::ostream& out, //! \tparam MultiLineString must be a `RandomAccessRange` of `Linestring`. //! \tparam MultiPolygon must be a model of `RandomAccessRange` of `CGAL::General_polygon_with_holes_2`. //! -//! \attention Only Cartesian Kernels with double or float as `FT` are supported. +//! \attention Only %Cartesian Kernels with double or float as `FT` are supported. //! //! \see `CGAL::IO::read_linestring_WKT()` template Date: Thu, 20 Jul 2023 18:32:04 -0600 Subject: [PATCH 025/182] deterministic order from lexicographically smallest vertex, hole and polygon --- .../Polygon_repair_2/repair_polygon_2.cpp | 23 +++++-- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 65 ++++++++++++++++++- 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 74e484462831..88785f6ac1a6 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -4,7 +4,7 @@ #include #include #include -// #include +#include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_2 Point; @@ -57,7 +57,7 @@ int main(int argc, char* argv[]) { // Square with hole // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - // Polygon_with_holes p(Polygon(ps1, ps1+4)); + // Polygon_with_holes p(Polygon_2(ps1, ps1+4)); // Point ps2[] = {Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0.25,0.75)}; // Polygon_2 h(ps2, ps2+4); // p.add_hole(h); @@ -66,7 +66,7 @@ int main(int argc, char* argv[]) { // Square with hole touching boundary // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - // Polygon_with_holes p(Polygon(ps1, ps1+4)); + // Polygon_with_holes p(Polygon_2(ps1, ps1+4)); // Point ps2[] = {Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0,1)}; // Polygon_2 h(ps2, ps2+4); // p.add_hole(h); @@ -93,8 +93,21 @@ int main(int argc, char* argv[]) { // std::cout << pr.multipolygon() << std::endl; // CGAL::draw(pr.multipolygon()); - std::cout << CGAL::Polygon_repair_2::repair(p) << std::endl; - std::cout << CGAL::Polygon_repair_2::repair(mp) << std::endl; + // CGAL::IO::write_polygon_WKT(std::cout, p); + // CGAL::IO::write_multi_polygon_WKT(std::cout, mp); + + Multipolygon rmp = CGAL::Polygon_repair_2::repair(p); + + CGAL::IO::write_multi_polygon_WKT(std::cout, rmp); + + // std::cout << "Orientations good?" << std::endl; + // for (auto const& polygon: rmp.polygons()) { + // std::cout << (polygon.outer_boundary().orientation() == CGAL::COUNTERCLOCKWISE) << std::endl; + // for (auto const &hole: polygon.holes()) { + // std::cout << (hole.orientation() == CGAL::CLOCKWISE) << std::endl; + // } + // } + return 0; } diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 5facc1f4a90f..84594c79027d 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -82,6 +82,47 @@ class Polygon_repair_2 { typedef CGAL::Constrained_Delaunay_triangulation_2 Constrained_Delaunay_triangulation; typedef Triangulation_with_odd_even_constraints_2 Triangulation; + struct Polygon_compare { + bool operator()(const Polygon_2& pa, const Polygon_2& pb) const { + typename Polygon_2::Vertex_iterator va = pa.vertices_begin(); + typename Polygon_2::Vertex_iterator vb = pb.vertices_begin(); + while (va != pa.vertices_end() && vb != pb.vertices_end()) { + if (*va != *vb) return *va < *vb; + ++va; + ++vb; + } if (vb == pb.vertices_end()) return false; + return true; + } + }; + + struct Polygon_with_holes_compare { + bool operator()(const Polygon_with_holes_2& pa, const Polygon_with_holes_2& pb) const { + typename Polygon_2::Vertex_iterator va = pa.outer_boundary().vertices_begin(); + typename Polygon_2::Vertex_iterator vb = pb.outer_boundary().vertices_begin(); + while (va != pa.outer_boundary().vertices_end() && vb != pb.outer_boundary().vertices_end()) { + if (*va != *vb) return *va < *vb; + ++va; + ++vb; + } if (vb != pb.outer_boundary().vertices_end()) return true; + else if (va != pa.outer_boundary().vertices_end()) return false; + typename Polygon_with_holes_2::Hole_const_iterator ha = pa.holes_begin(); + typename Polygon_with_holes_2::Hole_const_iterator hb = pb.holes_begin(); + while (ha != pa.holes_end() && hb != pb.holes_end()) { + va = ha->vertices_begin(); + vb = hb->vertices_begin(); + while (va != ha->vertices_end() && vb != hb->vertices_end()) { + if (*va != *vb) return *va < *vb; + ++va; + ++vb; + } if (vb != hb->vertices_end()) return true; + else if (va != ha->vertices_end()) return false; + ++ha; + ++hb; + } if (hb == pb.holes_end()) return false; + return true; + } + }; + /// \name Creation Polygon_repair_2() : number_of_polygons(0), number_of_holes(0) {} @@ -174,6 +215,8 @@ class Polygon_repair_2 { void reconstruct_ring(std::list& ring, typename Triangulation::Face_handle face_adjacent_to_boundary, int opposite_vertex) { + + // Create ring typename Triangulation::Face_handle current_face = face_adjacent_to_boundary; int current_opposite_vertex = opposite_vertex; do { @@ -188,13 +231,22 @@ class Polygon_repair_2 { current_opposite_vertex = fc->cw(fc->index(pivot_vertex)); } while (current_face != face_adjacent_to_boundary || current_opposite_vertex != opposite_vertex); + + // Start at lexicographically smallest vertex + typename std::list::iterator smallest_vertex = ring.begin(); + for (typename std::list::iterator current_vertex = ring.begin(); + current_vertex != ring.end(); ++current_vertex) { + if (*current_vertex < *smallest_vertex) smallest_vertex = current_vertex; + } if (ring.front() != *smallest_vertex) { + ring.splice(ring.begin(), ring, smallest_vertex, ring.end()); + } } // Reconstruct multipolygon based on the triangles labelled as inside the polygon void reconstruct_multipolygon() { mp.clear(); std::vector> polygons; - std::vector>> holes; + std::vector, Polygon_compare>> holes; // holes are ordered for (int i = 0; i < number_of_polygons; ++i) { polygons.emplace_back(); holes.emplace_back(); @@ -215,7 +267,9 @@ class Polygon_repair_2 { ring.begin(), ring.end()); } else { // std::cout << "Label: " << face->label() << " -> item " << -face->label()-2 << " -> in polygon " << hole_nesting[-face->label()-2] << std::endl; - holes[hole_nesting[-face->label()-2]-1].emplace_back(ring.begin(), ring.end()); + ring.push_back(ring.front()); + ring.pop_front(); + holes[hole_nesting[-face->label()-2]-1].insert(Polygon_2(ring.rbegin(), ring.rend())); } std::list to_check; @@ -235,8 +289,13 @@ class Polygon_repair_2 { } } + // Create polygons with holes and put in multipolygon + std::set, Polygon_with_holes_compare> ordered_polygons; for (int i = 0; i < polygons.size(); ++i) { - mp.add_polygon(Polygon_with_holes_2(polygons[i], holes[i].begin(), holes[i].end())); + ordered_polygons.insert(Polygon_with_holes_2(polygons[i], holes[i].begin(), holes[i].end())); + } for (auto const& polygon: ordered_polygons) { + std::cout << "Adding polygon " << polygon << std::endl; + mp.add_polygon(polygon); } } From 65ea5a5b32109af6f20e04590389a52c262541cd Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 20 Jul 2023 21:58:52 -0600 Subject: [PATCH 026/182] random colours for each drawn polygon --- .../examples/Polygon_repair_2/repair_polygon_2.cpp | 3 +-- .../CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 88785f6ac1a6..b0126a9625f7 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -91,14 +91,13 @@ int main(int argc, char* argv[]) { // pr.reconstruct_multipolygon(); // std::cout << pr.multipolygon() << std::endl; - // CGAL::draw(pr.multipolygon()); // CGAL::IO::write_polygon_WKT(std::cout, p); // CGAL::IO::write_multi_polygon_WKT(std::cout, mp); Multipolygon rmp = CGAL::Polygon_repair_2::repair(p); - CGAL::IO::write_multi_polygon_WKT(std::cout, rmp); + CGAL::draw(rmp); // std::cout << "Orientations good?" << std::endl; // for (auto const& polygon: rmp.polygons()) { diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h index 14df7088e1dc..2035c225c48d 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h @@ -104,9 +104,9 @@ class Mpwh_2_basic_viewer_qt : public Basic_viewer_qt { */ void add_elements() { clear(); - CGAL::IO::Color c(75,160,255); for (auto const& p: m_mpwh.polygons()) { + CGAL::IO::Color c(rand()%255,rand()%255,rand()%255); face_begin(c); const Pnt* point_in_face; From eeb441f369a2b0c6e57f344f1b22aec47a61b8b5 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 20 Jul 2023 21:59:37 -0600 Subject: [PATCH 027/182] add Guillaume since he was the author of drawing of polygons with holes --- .../include/CGAL/Polygon_repair_2/Polygon_repair_2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 84594c79027d..6088e68bcc9a 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -8,6 +8,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Ken Arroyo Ohori +// Guillaume Damiand #ifndef CGAL_POLYGON_REPAIR_2_H #define CGAL_POLYGON_REPAIR_2_H From 53614997090569835e7a4bec1144f69b40b4019e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 24 Jul 2023 15:29:14 -0600 Subject: [PATCH 028/182] using instead of typedefs --- .../Polygon_repair_2/repair_polygon_2.cpp | 64 +++++++++---------- .../Multipolygon_with_holes_2.h | 12 ++-- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 18 +++--- ...iangulation_face_base_with_repair_info_2.h | 8 +-- ...riangulation_with_odd_even_constraints_2.h | 20 +++--- 5 files changed, 61 insertions(+), 61 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index b0126a9625f7..62b94eb40375 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -6,82 +6,82 @@ #include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef Kernel::Point_2 Point; -typedef CGAL::Polygon_2 Polygon_2; -typedef CGAL::Polygon_with_holes_2 Polygon_with_holes; -typedef CGAL::Multipolygon_with_holes_2 Multipolygon; -typedef CGAL::Polygon_repair_2::Polygon_repair_2 Polygon_repair; +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_2 = Kernel::Point_2; +using Polygon_2 = CGAL::Polygon_2; +using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; +using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; int main(int argc, char* argv[]) { // std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); // Square - // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Point_2 ps[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; // Polygon_2 p(ps, ps+4); - // Multipolygon mp; + // Multipolygon_with_holes_2 mp; // mp.add_polygon(p); // Bowtie - Point ps[] = {Point(0,0), Point(1,1), Point(1,0), Point(0,1)}; + Point_2 ps[] = {Point_2(0,0), Point_2(1,1), Point_2(1,0), Point_2(0,1)}; Polygon_2 p(ps, ps+4); - Multipolygon mp; + Multipolygon_with_holes_2 mp; mp.add_polygon(p); // Overlapping edge - // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Point_2 ps1[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; // Polygon_2 p1(ps1, ps1+4); - // Point ps2[] = {Point(1,0), Point(2,0), Point(2,1), Point(1,1)}; + // Point_2 ps2[] = {Point_2(1,0), Point_2(2,0), Point_2(2,1), Point_2(1,1)}; // Polygon_2 p2(ps2, ps2+4); - // Multipolygon mp; + // Multipolygon_with_holes_2 mp; // mp.add_polygon(p1); // mp.add_polygon(p2); // Edge partly overlapping (start) - // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Point_2 ps1[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; // Polygon_2 p1(ps1, ps1+4); - // Point ps2[] = {Point(1,0), Point(2,0), Point(2,0.5), Point(1,0.5)}; + // Point_2 ps2[] = {Point_2(1,0), Point_2(2,0), Point_2(2,0.5), Point_2(1,0.5)}; // Polygon_2 p2(ps2, ps2+4); - // Multipolygon mp; + // Multipolygon_with_holes_2 mp; // mp.add_polygon(p1); // mp.add_polygon(p2); // Edge partly overlapping (middle) - // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; + // Point_2 ps1[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; // Polygon_2 p1(ps1, ps1+4); - // Point ps2[] = {Point(1,0.25), Point(2,0.25), Point(2,0.75), Point(1,0.75)}; + // Point_2 ps2[] = {Point_2(1,0.25), Point_2(2,0.25), Point_2(2,0.75), Point_2(1,0.75)}; // Polygon_2 p2(ps2, ps2+4); - // Multipolygon mp; + // Multipolygon_with_holes_2 mp; // mp.add_polygon(p1); // mp.add_polygon(p2); // Square with hole - // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - // Polygon_with_holes p(Polygon_2(ps1, ps1+4)); - // Point ps2[] = {Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0.25,0.75)}; + // Point_2 ps1[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; + // Polygon_with_holes_2 p(Polygon_2(ps1, ps1+4)); + // Point_2 ps2[] = {Point_2(0.25,0.25), Point_2(0.75,0.25), Point_2(0.75,0.75), Point_2(0.25,0.75)}; // Polygon_2 h(ps2, ps2+4); // p.add_hole(h); - // Multipolygon mp; + // Multipolygon_with_holes_2 mp; // mp.add_polygon(p); // Square with hole touching boundary - // Point ps1[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1)}; - // Polygon_with_holes p(Polygon_2(ps1, ps1+4)); - // Point ps2[] = {Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0,1)}; + // Point_2 ps1[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; + // Polygon_with_holes_2 p(Polygon_2(ps1, ps1+4)); + // Point_2 ps2[] = {Point_2(0.25,0.25), Point_2(0.75,0.25), Point_2(0.75,0.75), Point_2(0,1)}; // Polygon_2 h(ps2, ps2+4); // p.add_hole(h); - // Multipolygon mp; + // Multipolygon_with_holes_2 mp; // mp.add_polygon(p); // Square with hole touching boundary (self-intersecting loop) - // Point ps[] = {Point(0,0), Point(1,0), Point(1,1), Point(0,1), - // Point(0.25,0.25), Point(0.75,0.25), Point(0.75,0.75), Point(0,1)}; + // Point_2 ps[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1), + // Point_2(0.25,0.25), Point_2(0.75,0.25), Point_2(0.75,0.75), Point_2(0,1)}; // Polygon_2 p(ps, ps+8); // std::cout << p << std::endl; - // Multipolygon mp; + // Multipolygon_with_holes_2 mp; // mp.add_polygon(p); - // Polygon_repair pr; + // Polygon_repair_2 pr; // pr.add_to_triangulation(mp); // pr.label_triangulation(); @@ -95,7 +95,7 @@ int main(int argc, char* argv[]) { // CGAL::IO::write_polygon_WKT(std::cout, p); // CGAL::IO::write_multi_polygon_WKT(std::cout, mp); - Multipolygon rmp = CGAL::Polygon_repair_2::repair(p); + Multipolygon_with_holes_2 rmp = CGAL::Polygon_repair_2::repair(p); CGAL::IO::write_multi_polygon_WKT(std::cout, rmp); CGAL::draw(rmp); diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h index 528c144378c3..ba0e883773ba 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h @@ -36,19 +36,19 @@ class Multipolygon_with_holes_2 { /// @{ /// polygon type - typedef CGAL::Polygon_2 Polygon_2; + using Polygon_2 = CGAL::Polygon_2; /// polygon with holes type - typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; + using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; /// @} - typedef std::deque Polygons_container; + using Polygons_container = std::deque; - typedef typename Polygons_container::iterator Polygon_iterator; - typedef typename Polygons_container::const_iterator Polygon_const_iterator; + using Polygon_iterator = typename Polygons_container::iterator; + using Polygon_const_iterator = typename Polygons_container::const_iterator; - typedef unsigned int Size; + using Size = unsigned int; /*! %Default constructor. */ Multipolygon_with_holes_2() {} diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 6088e68bcc9a..4d95aedecfad 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -75,15 +75,15 @@ class Polygon_repair_2 { int number_of_polygons, number_of_holes; std::vector hole_nesting; public: - typedef CGAL::Triangulation_vertex_base_2 Vertex_base; - typedef CGAL::Constrained_triangulation_face_base_2 Face_base; - typedef CGAL::Triangulation_face_base_with_repair_info_2 Face_base_with_repair_info; - typedef CGAL::Triangulation_data_structure_2 Triangulation_data_structure; - typedef CGAL::Exact_predicates_tag Tag; // assumed for now - typedef CGAL::Constrained_Delaunay_triangulation_2 Constrained_Delaunay_triangulation; - typedef Triangulation_with_odd_even_constraints_2 Triangulation; - - struct Polygon_compare { + using Vertex_base = CGAL::Triangulation_vertex_base_2; + using Face_base = CGAL::Constrained_triangulation_face_base_2; + using Face_base_with_repair_info = CGAL::Triangulation_face_base_with_repair_info_2; + using Triangulation_data_structure = CGAL::Triangulation_data_structure_2; + using Tag = CGAL::Exact_predicates_tag; // assumed for now + using Constrained_Delaunay_triangulation = CGAL::Constrained_Delaunay_triangulation_2; + using Triangulation = Triangulation_with_odd_even_constraints_2; + + struct Polygon_less { bool operator()(const Polygon_2& pa, const Polygon_2& pb) const { typename Polygon_2::Vertex_iterator va = pa.vertices_begin(); typename Polygon_2::Vertex_iterator vb = pb.vertices_begin(); diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h index b78a51323627..770b332d86b9 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h @@ -23,13 +23,13 @@ class Triangulation_face_base_with_repair_info_2 : public FaceBase { int _label; bool _processed; public: - typedef typename FaceBase::Vertex_handle Vertex_handle; - typedef typename FaceBase::Face_handle Face_handle; + using Vertex_handle = typename FaceBase::Vertex_handle; + using Face_handle = typename FaceBase::Face_handle; template struct Rebind_TDS { - typedef typename FaceBase::template Rebind_TDS::Other FaceBase2; - typedef Triangulation_face_base_with_repair_info_2 Other; + using FaceBase2 = typename FaceBase::template Rebind_TDS::Other; + using Other = Triangulation_face_base_with_repair_info_2; }; Triangulation_face_base_with_repair_info_2() : FaceBase() {} diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index ac290d70cb1f..957faf869c88 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -30,14 +30,14 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { /// \name Definition /// @{ - typedef Triangulation_ Base_triangulation; - typedef typename Triangulation_::Point Point; - typedef typename Triangulation_::Edge Edge; - typedef typename Triangulation_::Vertex_handle Vertex_handle; - typedef typename Triangulation_::Face_handle Face_handle; - typedef typename Triangulation_::List_edges List_edges; - typedef typename Triangulation_::List_faces List_faces; - typedef typename Triangulation_::All_faces_iterator All_faces_iterator; + using Base_triangulation = Triangulation_; + using Point = typename Triangulation_::Point; + using Edge = typename Triangulation_::Edge; + using Vertex_handle = typename Triangulation_::Vertex_handle; + using Face_handle = typename Triangulation_::Face_handle; + using List_edges = typename Triangulation_::List_edges; + using List_faces = typename Triangulation_::List_faces; + using All_faces_iterator = typename Triangulation_::All_faces_iterator; /// @} class Interior_tester { @@ -53,8 +53,8 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { // iterator over interior faces. class Interior_faces_iterator : public Filter_iterator { - typedef Filter_iterator Base; - typedef Interior_faces_iterator Self; + using Base = Filter_iterator; + using Self = Interior_faces_iterator; public: Interior_faces_iterator() : Base() {} Interior_faces_iterator(const Base &b) : Base(b) {} From d79c53d05a83d90b6949cfa8241924c728e3135e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 24 Jul 2023 15:29:59 -0600 Subject: [PATCH 029/182] less instead of compare, reuse polygon less --- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 4d95aedecfad..98dc589f02c8 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -96,29 +96,16 @@ class Polygon_repair_2 { } }; - struct Polygon_with_holes_compare { + struct Polygon_with_holes_less { + Polygon_less pl; bool operator()(const Polygon_with_holes_2& pa, const Polygon_with_holes_2& pb) const { - typename Polygon_2::Vertex_iterator va = pa.outer_boundary().vertices_begin(); - typename Polygon_2::Vertex_iterator vb = pb.outer_boundary().vertices_begin(); - while (va != pa.outer_boundary().vertices_end() && vb != pb.outer_boundary().vertices_end()) { - if (*va != *vb) return *va < *vb; - ++va; - ++vb; - } if (vb != pb.outer_boundary().vertices_end()) return true; - else if (va != pa.outer_boundary().vertices_end()) return false; + if (pl(pa.outer_boundary(), pb.outer_boundary())) return true; + if (pl(pb.outer_boundary(), pa.outer_boundary())) return false; typename Polygon_with_holes_2::Hole_const_iterator ha = pa.holes_begin(); typename Polygon_with_holes_2::Hole_const_iterator hb = pb.holes_begin(); while (ha != pa.holes_end() && hb != pb.holes_end()) { - va = ha->vertices_begin(); - vb = hb->vertices_begin(); - while (va != ha->vertices_end() && vb != hb->vertices_end()) { - if (*va != *vb) return *va < *vb; - ++va; - ++vb; - } if (vb != hb->vertices_end()) return true; - else if (va != ha->vertices_end()) return false; - ++ha; - ++hb; + if (pl(*ha, *hb)) return true; + if (pl(*hb, *ha)) return false; } if (hb == pb.holes_end()) return false; return true; } @@ -247,7 +234,7 @@ class Polygon_repair_2 { void reconstruct_multipolygon() { mp.clear(); std::vector> polygons; - std::vector, Polygon_compare>> holes; // holes are ordered + std::vector, Polygon_less>> holes; // holes are ordered for (int i = 0; i < number_of_polygons; ++i) { polygons.emplace_back(); holes.emplace_back(); @@ -291,7 +278,7 @@ class Polygon_repair_2 { } // Create polygons with holes and put in multipolygon - std::set, Polygon_with_holes_compare> ordered_polygons; + std::set, Polygon_with_holes_less> ordered_polygons; for (int i = 0; i < polygons.size(); ++i) { ordered_polygons.insert(Polygon_with_holes_2(polygons[i], holes[i].begin(), holes[i].end())); } for (auto const& polygon: ordered_polygons) { From 59433d9edb9e633800d5cad08fab4e4e3c883c0d Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 24 Jul 2023 18:04:51 -0600 Subject: [PATCH 030/182] shorter definitions with using --- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 98dc589f02c8..0a3f9859371f 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -84,9 +84,10 @@ class Polygon_repair_2 { using Triangulation = Triangulation_with_odd_even_constraints_2; struct Polygon_less { - bool operator()(const Polygon_2& pa, const Polygon_2& pb) const { - typename Polygon_2::Vertex_iterator va = pa.vertices_begin(); - typename Polygon_2::Vertex_iterator vb = pb.vertices_begin(); + using Polygon_2 = Polygon_2; + bool operator()(const Polygon_2& pa, const Polygon_2& pb) const { + typename Polygon_2::Vertex_iterator va = pa.vertices_begin(); + typename Polygon_2::Vertex_iterator vb = pb.vertices_begin(); while (va != pa.vertices_end() && vb != pb.vertices_end()) { if (*va != *vb) return *va < *vb; ++va; @@ -97,12 +98,13 @@ class Polygon_repair_2 { }; struct Polygon_with_holes_less { + using Polygon_with_holes_2 = Polygon_with_holes_2; Polygon_less pl; - bool operator()(const Polygon_with_holes_2& pa, const Polygon_with_holes_2& pb) const { + bool operator()(const Polygon_with_holes_2& pa, const Polygon_with_holes_2& pb) const { if (pl(pa.outer_boundary(), pb.outer_boundary())) return true; if (pl(pb.outer_boundary(), pa.outer_boundary())) return false; - typename Polygon_with_holes_2::Hole_const_iterator ha = pa.holes_begin(); - typename Polygon_with_holes_2::Hole_const_iterator hb = pb.holes_begin(); + typename Polygon_with_holes_2::Hole_const_iterator ha = pa.holes_begin(); + typename Polygon_with_holes_2::Hole_const_iterator hb = pb.holes_begin(); while (ha != pa.holes_end() && hb != pb.holes_end()) { if (pl(*ha, *hb)) return true; if (pl(*hb, *ha)) return false; From 0461ded921ee0c0d266db74747cc4423884d3322 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 24 Jul 2023 18:41:14 -0600 Subject: [PATCH 031/182] use wkt reader instead of manually constructed examples --- .../Polygon_repair_2/repair_polygon_2.cpp | 89 ++++++------------- 1 file changed, 26 insertions(+), 63 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 62b94eb40375..9a8175614559 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -17,84 +18,46 @@ int main(int argc, char* argv[]) { // std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); // Square - // Point_2 ps[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; - // Polygon_2 p(ps, ps+4); - // Multipolygon_with_holes_2 mp; - // mp.add_polygon(p); + // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0))"); + // Polygon_2 p; + // CGAL::IO::read_polygon_WKT(iss, p); // Bowtie - Point_2 ps[] = {Point_2(0,0), Point_2(1,1), Point_2(1,0), Point_2(0,1)}; - Polygon_2 p(ps, ps+4); - Multipolygon_with_holes_2 mp; - mp.add_polygon(p); + std::istringstream iss("POLYGON((0 0,1 1,1 0,0 1,0 0))"); + Polygon_2 p; + CGAL::IO::read_polygon_WKT(iss, p); // Overlapping edge - // Point_2 ps1[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; - // Polygon_2 p1(ps1, ps1+4); - // Point_2 ps2[] = {Point_2(1,0), Point_2(2,0), Point_2(2,1), Point_2(1,1)}; - // Polygon_2 p2(ps2, ps2+4); - // Multipolygon_with_holes_2 mp; - // mp.add_polygon(p1); - // mp.add_polygon(p2); + // std::istringstream iss("MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 0,2 0,2 1,1 1,1 0)))"); + // Multipolygon_with_holes_2 p; + // CGAL::IO::read_multi_polygon_WKT(iss, p); // Edge partly overlapping (start) - // Point_2 ps1[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; - // Polygon_2 p1(ps1, ps1+4); - // Point_2 ps2[] = {Point_2(1,0), Point_2(2,0), Point_2(2,0.5), Point_2(1,0.5)}; - // Polygon_2 p2(ps2, ps2+4); - // Multipolygon_with_holes_2 mp; - // mp.add_polygon(p1); - // mp.add_polygon(p2); + // std::istringstream iss("MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 0,2 0,2 0.5,1 0.5,1 0)))"); + // Multipolygon_with_holes_2 p; + // CGAL::IO::read_multi_polygon_WKT(iss, p); // Edge partly overlapping (middle) - // Point_2 ps1[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; - // Polygon_2 p1(ps1, ps1+4); - // Point_2 ps2[] = {Point_2(1,0.25), Point_2(2,0.25), Point_2(2,0.75), Point_2(1,0.75)}; - // Polygon_2 p2(ps2, ps2+4); - // Multipolygon_with_holes_2 mp; - // mp.add_polygon(p1); - // mp.add_polygon(p2); + // std::istringstream iss("MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 0.25,2 0.25,2 0.75,1 0.75,1 0)))"); + // Multipolygon_with_holes_2 p; + // CGAL::IO::read_multi_polygon_WKT(iss, p); // Square with hole - // Point_2 ps1[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; - // Polygon_with_holes_2 p(Polygon_2(ps1, ps1+4)); - // Point_2 ps2[] = {Point_2(0.25,0.25), Point_2(0.75,0.25), Point_2(0.75,0.75), Point_2(0.25,0.75)}; - // Polygon_2 h(ps2, ps2+4); - // p.add_hole(h); - // Multipolygon_with_holes_2 mp; - // mp.add_polygon(p); + // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.75 0.25,0.75 0.75,0.25 0.75,0.25 0.25))"); + // Polygon_with_holes_2 p; + // CGAL::IO::read_polygon_WKT(iss, p); // Square with hole touching boundary - // Point_2 ps1[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; - // Polygon_with_holes_2 p(Polygon_2(ps1, ps1+4)); - // Point_2 ps2[] = {Point_2(0.25,0.25), Point_2(0.75,0.25), Point_2(0.75,0.75), Point_2(0,1)}; - // Polygon_2 h(ps2, ps2+4); - // p.add_hole(h); - // Multipolygon_with_holes_2 mp; - // mp.add_polygon(p); + // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.75 0.25,0.75 0.75,0 1,0.25 0.25))"); + // Polygon_with_holes_2 p; + // CGAL::IO::read_polygon_WKT(iss, p); // Square with hole touching boundary (self-intersecting loop) - // Point_2 ps[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1), - // Point_2(0.25,0.25), Point_2(0.75,0.25), Point_2(0.75,0.75), Point_2(0,1)}; - // Polygon_2 p(ps, ps+8); - // std::cout << p << std::endl; - // Multipolygon_with_holes_2 mp; - // mp.add_polygon(p); - - // Polygon_repair_2 pr; - // pr.add_to_triangulation(mp); - // pr.label_triangulation(); - - // for (auto f = pr.triangulation().interior_faces_begin(); f != pr.triangulation().interior_faces_end(); ++f) { - // std::cout << f->label() << " "; - // } std::cout << std::endl; - - // pr.reconstruct_multipolygon(); - // std::cout << pr.multipolygon() << std::endl; - - // CGAL::IO::write_polygon_WKT(std::cout, p); - // CGAL::IO::write_multi_polygon_WKT(std::cout, mp); + // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0.25 0.25,0.75 0.25,0.75 0.75,0 1,0 0))"); + // Polygon_2 p; + // CGAL::IO::read_polygon_WKT(iss, p); + std::cout << p << std::endl; Multipolygon_with_holes_2 rmp = CGAL::Polygon_repair_2::repair(p); CGAL::IO::write_multi_polygon_WKT(std::cout, rmp); CGAL::draw(rmp); From 8dea133a07469c6ecf3ffee43e88973c179a2d87 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 24 Jul 2023 22:05:30 -0600 Subject: [PATCH 032/182] more examples --- .../Polygon_repair_2/repair_polygon_2.cpp | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 9a8175614559..686324c4d0af 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include #include @@ -23,9 +25,9 @@ int main(int argc, char* argv[]) { // CGAL::IO::read_polygon_WKT(iss, p); // Bowtie - std::istringstream iss("POLYGON((0 0,1 1,1 0,0 1,0 0))"); - Polygon_2 p; - CGAL::IO::read_polygon_WKT(iss, p); + // std::istringstream iss("POLYGON((0 0,1 1,1 0,0 1,0 0))"); + // Polygon_2 p; + // CGAL::IO::read_polygon_WKT(iss, p); // Overlapping edge // std::istringstream iss("MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 0,2 0,2 1,1 1,1 0)))"); @@ -52,12 +54,37 @@ int main(int argc, char* argv[]) { // Polygon_with_holes_2 p; // CGAL::IO::read_polygon_WKT(iss, p); + // Square with hole touching boundary twice + std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,1 0,0.75 0.75,0 1,0.25 0.25))"); + Polygon_with_holes_2 p; + CGAL::IO::read_polygon_WKT(iss, p); + // Square with hole touching boundary (self-intersecting loop) // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0.25 0.25,0.75 0.25,0.75 0.75,0 1,0 0))"); // Polygon_2 p; // CGAL::IO::read_polygon_WKT(iss, p); - std::cout << p << std::endl; + // Square with hole using bridge edge + // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0.25 0.75,0.75 0.75,0.75 0.25,0.25 0.25,0.25 0.75,0 1,0 0))"); + // Polygon_2 p; + // CGAL::IO::read_polygon_WKT(iss, p); + + // Square with hole outside + // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(1.25 1.25,1.75 1.25,1.75 1.75,1.25 1.75,1.25 1.25))"); + // Polygon_with_holes_2 p; + // CGAL::IO::read_polygon_WKT(iss, p); + + // Square with hole overlapping outer boundary + // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.5 0.5,1 0.5,1 1,0.5 1,0.5 0.5))"); + // Polygon_with_holes_2 p; + // CGAL::IO::read_polygon_WKT(iss, p); + + // Square with hole partly outside + // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.75 0.75,1.25 0.75,1.25 1.25,0.75 1.25,0.75 0.75))"); + // Polygon_with_holes_2 p; + // CGAL::IO::read_polygon_WKT(iss, p); + + CGAL::draw(p); Multipolygon_with_holes_2 rmp = CGAL::Polygon_repair_2::repair(p); CGAL::IO::write_multi_polygon_WKT(std::cout, rmp); CGAL::draw(rmp); From 3df83bc224f810138bb66b2995d619bd53ab945c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 25 Jul 2023 15:17:50 -0600 Subject: [PATCH 033/182] new code for hole nesting --- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 0a3f9859371f..ce9f720b3819 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -38,6 +38,7 @@ Multipolygon_with_holes_2 repair(const Polygon_2 pr; pr.add_to_triangulation(p); pr.label_triangulation(); + pr.compute_hole_nesting(); pr.reconstruct_multipolygon(); return pr.multipolygon(); } @@ -49,6 +50,7 @@ Multipolygon_with_holes_2 repair(const Polygon_with_ho CGAL::Polygon_repair_2::Polygon_repair_2 pr; pr.add_to_triangulation(p); pr.label_triangulation(); + pr.compute_hole_nesting(); pr.reconstruct_multipolygon(); return pr.multipolygon(); } @@ -60,6 +62,7 @@ Multipolygon_with_holes_2 repair(const Multipolygon_wi CGAL::Polygon_repair_2::Polygon_repair_2 pr; pr.add_to_triangulation(mp); pr.label_triangulation(); + pr.compute_hole_nesting(); pr.reconstruct_multipolygon(); return pr.multipolygon(); } @@ -72,8 +75,6 @@ Multipolygon_with_holes_2 repair(const Multipolygon_wi template > class Polygon_repair_2 { - int number_of_polygons, number_of_holes; - std::vector hole_nesting; public: using Vertex_base = CGAL::Triangulation_vertex_base_2; using Face_base = CGAL::Constrained_triangulation_face_base_2; @@ -155,13 +156,13 @@ class Polygon_repair_2 { while (!to_check_in_region.empty()) { for (int neighbour = 0; neighbour < 3; ++neighbour) { if (!t.is_constrained(typename Triangulation::Edge(to_check_in_region.front(), neighbour))) { - if (to_check_in_region.front()->neighbor(neighbour)->label() == 0) { + if (to_check_in_region.front()->neighbor(neighbour)->label() == 0) { // unlabelled to_check_in_region.front()->neighbor(neighbour)->label() = label; to_check_in_region.push_back(to_check_in_region.front()->neighbor(neighbour)); to_check_in_region.front()->neighbor(neighbour)->processed() = true; } - } else { - if (!to_check_in_region.front()->neighbor(neighbour)->processed()) { + } else { // constrained + if (!to_check_in_region.front()->neighbor(neighbour)->processed()) { // not added to to_check to_check.push_back(to_check_in_region.front()->neighbor(neighbour)); to_check_added_by.push_back(label); to_check_in_region.front()->neighbor(neighbour)->processed() = true; @@ -178,7 +179,8 @@ class Polygon_repair_2 { face->processed() = false; } - // Mark exterior as processed and put interior triangles adjacent to it in to_check + // Label exterior with label -1, marking it as processed and + // putting interior triangles adjacent to it in to_check std::list to_check; std::list to_check_added_by; label_region(t.infinite_face(), -1, to_check, to_check_added_by); @@ -191,7 +193,6 @@ class Polygon_repair_2 { label_region(to_check.front(), number_of_polygons+1, to_check, to_check_added_by); ++number_of_polygons; } else { - hole_nesting.push_back(to_check_added_by.front()); // record nesting of current hole label_region(to_check.front(), -(number_of_holes+2), to_check, to_check_added_by); ++number_of_holes; } @@ -232,6 +233,24 @@ class Polygon_repair_2 { } } + void compute_hole_nesting() { + for (int i = 0; i < number_of_holes; ++i) { + nesting.emplace_back(); + } for (auto const &face: t.finite_face_handles()) { + if (face->label() >= -1) continue; // skip non-hole triangles + for (int opposite_vertex = 0; opposite_vertex < 3; ++opposite_vertex) { + if (face->label() == face->neighbor(opposite_vertex)->label()) continue; + nesting[-face->label()-2].insert(face->neighbor(opposite_vertex)->label()); + } + } int hole_label = -2; + for (auto const &hole: nesting) { + std::cout << "Hole " << hole_label-- << " contained in polygon(s): "; + for (auto const &polygon: hole) { + std::cout << polygon << " "; + } std::cout << std::endl; + } + } + // Reconstruct multipolygon based on the triangles labelled as inside the polygon void reconstruct_multipolygon() { mp.clear(); @@ -246,6 +265,7 @@ class Polygon_repair_2 { face->processed() = false; } for (auto const &face: t.finite_face_handles()) { if (face->label() == -1) continue; // exterior triangle + if (face->label() < -1 && nesting[-face->label()-2].size() > 1) continue; // exterior triangle if (face->processed()) continue; // already reconstructed for (int opposite_vertex = 0; opposite_vertex < 3; ++opposite_vertex) { if (face->label() != face->neighbor(opposite_vertex)->label()) { @@ -256,10 +276,11 @@ class Polygon_repair_2 { polygons[face->label()-1].insert(polygons[face->label()-1].vertices_end(), ring.begin(), ring.end()); } else { - // std::cout << "Label: " << face->label() << " -> item " << -face->label()-2 << " -> in polygon " << hole_nesting[-face->label()-2] << std::endl; + int hole_nesting = *(nesting[-face->label()-2].begin()); + // std::cout << "Hole: " << face->label() << " -> item " << -face->label()-2 << " -> in polygon " << hole_nesting << std::endl; ring.push_back(ring.front()); ring.pop_front(); - holes[hole_nesting[-face->label()-2]-1].insert(Polygon_2(ring.rbegin(), ring.rend())); + holes[hole_nesting-1].insert(Polygon_2(ring.rbegin(), ring.rend())); } std::list to_check; @@ -313,6 +334,8 @@ class Polygon_repair_2 { protected: Triangulation t; Multipolygon_with_holes_2 mp; + int number_of_polygons, number_of_holes; + std::vector> nesting; // note: holes are surrounded by exactly one polygon }; } // namespace Polygon_repair_2 From 842bd857cc5a3f368e936274ef0c35709de9128f Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 25 Jul 2023 17:29:55 -0600 Subject: [PATCH 034/182] Testing using reference files --- .../Polygon_repair_2/repair_polygon_2.cpp | 109 +++++------------- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 22 ++-- .../test/Polygon_repair_2/data/in/bowtie.wkt | 1 + .../Polygon_repair_2/data/in/bridge-edge.wkt | 1 + .../Polygon_repair_2/data/in/hole-as-loop.wkt | 1 + .../Polygon_repair_2/data/in/hole-carved.wkt | 1 + .../Polygon_repair_2/data/in/hole-filled.wkt | 1 + .../Polygon_repair_2/data/in/hole-outside.wkt | 1 + .../data/in/hole-partly-outside.wkt | 1 + .../data/in/hole-touching-once.wkt | 1 + .../data/in/hole-touching-twice.wkt | 1 + .../test/Polygon_repair_2/data/in/hole.wkt | 1 + .../data/in/overlapping-edge-inside.wkt | 1 + .../data/in/overlapping-edge-partial.wkt | 1 + .../data/in/overlapping-edge.wkt | 1 + .../data/in/spike-boundary.wkt | 1 + .../Polygon_repair_2/data/in/spike-in.wkt | 1 + .../Polygon_repair_2/data/in/spike-out.wkt | 1 + .../test/Polygon_repair_2/data/in/square.wkt | 1 + .../test/Polygon_repair_2/data/ref/bowtie.wkt | 1 + .../Polygon_repair_2/data/ref/bridge-edge.wkt | 1 + .../data/ref/hole-as-loop.wkt | 1 + .../Polygon_repair_2/data/ref/hole-carved.wkt | 1 + .../Polygon_repair_2/data/ref/hole-filled.wkt | 1 + .../data/ref/hole-outside.wkt | 1 + .../data/ref/hole-partly-outside.wkt | 1 + .../data/ref/hole-touching-once.wkt | 1 + .../data/ref/hole-touching-twice.wkt | 1 + .../test/Polygon_repair_2/data/ref/hole.wkt | 1 + .../data/ref/overlapping-edge-inside.wkt | 1 + .../data/ref/overlapping-edge-partial.wkt | 1 + .../data/ref/overlapping-edge.wkt | 1 + .../data/ref/spike-boundary.wkt | 1 + .../Polygon_repair_2/data/ref/spike-in.wkt | 1 + .../Polygon_repair_2/data/ref/spike-out.wkt | 1 + .../test/Polygon_repair_2/data/ref/square.wkt | 1 + .../repair_polygon_2_test.cpp | 75 ++++++++++-- 37 files changed, 142 insertions(+), 98 deletions(-) create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/bowtie.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/bridge-edge.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/hole-as-loop.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/hole-carved.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/hole-filled.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/hole-outside.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/hole-partly-outside.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-once.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-twice.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/hole.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-inside.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-partial.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/spike-boundary.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/spike-in.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/spike-out.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/square.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/bowtie.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/bridge-edge.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-as-loop.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-carved.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-filled.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-outside.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-partly-outside.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-once.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-twice.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/hole.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-inside.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-partial.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-boundary.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-in.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-out.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/square.wkt diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 686324c4d0af..b7ea6b42b1df 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -17,86 +18,36 @@ using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; int main(int argc, char* argv[]) { - // std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); - // Square - // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0))"); - // Polygon_2 p; - // CGAL::IO::read_polygon_WKT(iss, p); - - // Bowtie - // std::istringstream iss("POLYGON((0 0,1 1,1 0,0 1,0 0))"); - // Polygon_2 p; - // CGAL::IO::read_polygon_WKT(iss, p); - - // Overlapping edge - // std::istringstream iss("MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 0,2 0,2 1,1 1,1 0)))"); - // Multipolygon_with_holes_2 p; - // CGAL::IO::read_multi_polygon_WKT(iss, p); - - // Edge partly overlapping (start) - // std::istringstream iss("MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 0,2 0,2 0.5,1 0.5,1 0)))"); - // Multipolygon_with_holes_2 p; - // CGAL::IO::read_multi_polygon_WKT(iss, p); - - // Edge partly overlapping (middle) - // std::istringstream iss("MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 0.25,2 0.25,2 0.75,1 0.75,1 0)))"); - // Multipolygon_with_holes_2 p; - // CGAL::IO::read_multi_polygon_WKT(iss, p); - - // Square with hole - // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.75 0.25,0.75 0.75,0.25 0.75,0.25 0.25))"); - // Polygon_with_holes_2 p; - // CGAL::IO::read_polygon_WKT(iss, p); - - // Square with hole touching boundary - // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.75 0.25,0.75 0.75,0 1,0.25 0.25))"); - // Polygon_with_holes_2 p; - // CGAL::IO::read_polygon_WKT(iss, p); - - // Square with hole touching boundary twice - std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,1 0,0.75 0.75,0 1,0.25 0.25))"); - Polygon_with_holes_2 p; - CGAL::IO::read_polygon_WKT(iss, p); - - // Square with hole touching boundary (self-intersecting loop) - // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0.25 0.25,0.75 0.25,0.75 0.75,0 1,0 0))"); - // Polygon_2 p; - // CGAL::IO::read_polygon_WKT(iss, p); - - // Square with hole using bridge edge - // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0.25 0.75,0.75 0.75,0.75 0.25,0.25 0.25,0.25 0.75,0 1,0 0))"); - // Polygon_2 p; - // CGAL::IO::read_polygon_WKT(iss, p); - - // Square with hole outside - // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(1.25 1.25,1.75 1.25,1.75 1.75,1.25 1.75,1.25 1.25))"); - // Polygon_with_holes_2 p; - // CGAL::IO::read_polygon_WKT(iss, p); - - // Square with hole overlapping outer boundary - // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.5 0.5,1 0.5,1 1,0.5 1,0.5 0.5))"); - // Polygon_with_holes_2 p; - // CGAL::IO::read_polygon_WKT(iss, p); - - // Square with hole partly outside - // std::istringstream iss("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.75 0.75,1.25 0.75,1.25 1.25,0.75 1.25,0.75 0.75))"); - // Polygon_with_holes_2 p; - // CGAL::IO::read_polygon_WKT(iss, p); - - CGAL::draw(p); - Multipolygon_with_holes_2 rmp = CGAL::Polygon_repair_2::repair(p); - CGAL::IO::write_multi_polygon_WKT(std::cout, rmp); - CGAL::draw(rmp); - - // std::cout << "Orientations good?" << std::endl; - // for (auto const& polygon: rmp.polygons()) { - // std::cout << (polygon.outer_boundary().orientation() == CGAL::COUNTERCLOCKWISE) << std::endl; - // for (auto const &hole: polygon.holes()) { - // std::cout << (hole.orientation() == CGAL::CLOCKWISE) << std::endl; - // } - // } - + for (const auto& file: std::__fs::filesystem::directory_iterator("../../test/Polygon_repair_2/data/in")) { + std::cout << "Reading " << file.path().filename() << "..." << std::endl; + + // if (file.path().filename() != "hole-outside.wkt") continue; + + std::string in; + std::getline(std::ifstream(file.path()), in); + std::istringstream iss(in); + std::size_t is_polygon = in.find("POLYGON"); + std::size_t is_multipolygon = in.find("MULTIPOLYGON"); + Multipolygon_with_holes_2 rmp; + if (is_polygon == 0) { + Polygon_with_holes_2 p; + CGAL::IO::read_polygon_WKT(iss, p); + CGAL::draw(p); + rmp = CGAL::Polygon_repair_2::repair(p); + } else if (is_multipolygon == 0) { + Multipolygon_with_holes_2 mp; + CGAL::IO::read_multi_polygon_WKT(iss, mp); + CGAL::draw(mp); + rmp = CGAL::Polygon_repair_2::repair(mp); + } std::ostringstream oss; + CGAL::IO::write_multi_polygon_WKT(oss, rmp); + std::string out = oss.str(); + std::cout << "\tin: " << in << std::endl; + std::cout << "\tout: " << out; + CGAL::draw(rmp); + + } return 0; } diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index ce9f720b3819..cc0535d37cd2 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -179,7 +179,7 @@ class Polygon_repair_2 { face->processed() = false; } - // Label exterior with label -1, marking it as processed and + // Label exterior with label -1, marking it as processed and // putting interior triangles adjacent to it in to_check std::list to_check; std::list to_check_added_by; @@ -225,7 +225,7 @@ class Polygon_repair_2 { // Start at lexicographically smallest vertex typename std::list::iterator smallest_vertex = ring.begin(); - for (typename std::list::iterator current_vertex = ring.begin(); + for (typename std::list::iterator current_vertex = ring.begin(); current_vertex != ring.end(); ++current_vertex) { if (*current_vertex < *smallest_vertex) smallest_vertex = current_vertex; } if (ring.front() != *smallest_vertex) { @@ -242,13 +242,15 @@ class Polygon_repair_2 { if (face->label() == face->neighbor(opposite_vertex)->label()) continue; nesting[-face->label()-2].insert(face->neighbor(opposite_vertex)->label()); } - } int hole_label = -2; - for (auto const &hole: nesting) { - std::cout << "Hole " << hole_label-- << " contained in polygon(s): "; - for (auto const &polygon: hole) { - std::cout << polygon << " "; - } std::cout << std::endl; - } + } + + // int hole_label = -2; + // for (auto const &hole: nesting) { + // std::cout << "Hole " << hole_label-- << " contained in polygon(s): "; + // for (auto const &polygon: hole) { + // std::cout << polygon << " "; + // } std::cout << std::endl; + // } } // Reconstruct multipolygon based on the triangles labelled as inside the polygon @@ -305,7 +307,7 @@ class Polygon_repair_2 { for (int i = 0; i < polygons.size(); ++i) { ordered_polygons.insert(Polygon_with_holes_2(polygons[i], holes[i].begin(), holes[i].end())); } for (auto const& polygon: ordered_polygons) { - std::cout << "Adding polygon " << polygon << std::endl; + // std::cout << "Adding polygon " << polygon << std::endl; mp.add_polygon(polygon); } } diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/bowtie.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/bowtie.wkt new file mode 100644 index 000000000000..3005eb3e3f60 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/bowtie.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 1,1 0,0 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/bridge-edge.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/bridge-edge.wkt new file mode 100644 index 000000000000..1e86cf795061 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/bridge-edge.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0.25 0.75,0.75 0.75,0.75 0.25,0.25 0.25,0.25 0.75,0 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-as-loop.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-as-loop.wkt new file mode 100644 index 000000000000..8c5a4a1c74c9 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-as-loop.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0.25 0.25,0.75 0.25,0.75 0.75,0 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-carved.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-carved.wkt new file mode 100644 index 000000000000..7b20d27fcfb9 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-carved.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0),(0.5 0.5,1 0.5,1 1,0.5 1,0.5 0.5)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-filled.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-filled.wkt new file mode 100644 index 000000000000..ca7167347792 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-filled.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.75 0.25,0.75 0.75,0.25 0.75,0.25 0.25)),((0.25 0.25,0.75 0.25,0.75 0.75,0.25 0.75,0.25 0.25))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-outside.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-outside.wkt new file mode 100644 index 000000000000..9d16d9c87cae --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-outside.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0),(1.25 1.25,1.75 1.25,1.75 1.75,1.25 1.75,1.25 1.25)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-partly-outside.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-partly-outside.wkt new file mode 100644 index 000000000000..da99d6a31e50 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-partly-outside.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0),(0.75 0.75,1.25 0.75,1.25 1.25,0.75 1.25,0.75 0.75)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-once.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-once.wkt new file mode 100644 index 000000000000..587930ced4c6 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-once.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.75 0.25,0.75 0.75,0 1,0.25 0.25)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-twice.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-twice.wkt new file mode 100644 index 000000000000..54f1083af911 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-twice.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,1 0,0.75 0.75,0 1,0.25 0.25)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole.wkt new file mode 100644 index 000000000000..6c0e1bfe42b2 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.75 0.25,0.75 0.75,0.25 0.75,0.25 0.25)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-inside.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-inside.wkt new file mode 100644 index 000000000000..646ca0d5b5ad --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-inside.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 0.25,2 0.25,2 0.75,1 0.75,1 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-partial.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-partial.wkt new file mode 100644 index 000000000000..2dc63c238221 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-partial.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 0,2 0,2 0.5,1 0.5,1 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge.wkt new file mode 100644 index 000000000000..6e59f2e83e58 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 0,2 0,2 1,1 1,1 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-boundary.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-boundary.wkt new file mode 100644 index 000000000000..477315fcf87d --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-boundary.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 1,0 0,1 0,1 1,0 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-in.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-in.wkt new file mode 100644 index 000000000000..49f02f9d1e48 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-in.wkt @@ -0,0 +1 @@ +POLYGON((0 0,0.5 0.5,0 0,1 0,1 1,0 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-out.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-out.wkt new file mode 100644 index 000000000000..7a95b726a2f8 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-out.wkt @@ -0,0 +1 @@ +POLYGON((0 0,-0.5 -0.5,0 0,1 0,1 1,0 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/square.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/square.wkt new file mode 100644 index 000000000000..d97ff8d423bf --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/square.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/bowtie.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/bowtie.wkt new file mode 100644 index 000000000000..0ca7c0da217b --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/bowtie.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,0.5 0.5,0 1,0 0)),((0.5 0.5,1 0,1 1,0.5 0.5))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/bridge-edge.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/bridge-edge.wkt new file mode 100644 index 000000000000..99b3f4c1cbbf --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/bridge-edge.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.25 0.75,0.75 0.75,0.75 0.25,0.25 0.25))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-as-loop.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-as-loop.wkt new file mode 100644 index 000000000000..b5ee1d022877 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-as-loop.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0 1,0.75 0.75,0.75 0.25,0.25 0.25,0 1))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-carved.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-carved.wkt new file mode 100644 index 000000000000..d6e9a18d49e8 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-carved.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 0.5,0.5 0.5,0.5 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-filled.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-filled.wkt new file mode 100644 index 000000000000..511245f448ea --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-filled.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-outside.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-outside.wkt new file mode 100644 index 000000000000..1d003ce0e92d --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-outside.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1.25 1.25,1.75 1.25,1.75 1.75,1.25 1.75,1.25 1.25))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-partly-outside.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-partly-outside.wkt new file mode 100644 index 000000000000..503189d5d256 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-partly-outside.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 0.75,0.75 0.75,0.75 1,0 1,0 0)),((0.75 1,1 1,1 0.75,1.25 0.75,1.25 1.25,0.75 1.25,0.75 1))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-once.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-once.wkt new file mode 100644 index 000000000000..b5ee1d022877 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-once.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0 1,0.75 0.75,0.75 0.25,0.25 0.25,0 1))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-twice.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-twice.wkt new file mode 100644 index 000000000000..bc530227b8fb --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-twice.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,0.25 0.25,0 1,0 0)),((0 1,0.75 0.75,1 0,1 1,0 1))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole.wkt new file mode 100644 index 000000000000..99b3f4c1cbbf --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.25 0.75,0.75 0.75,0.75 0.25,0.25 0.25))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-inside.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-inside.wkt new file mode 100644 index 000000000000..f801b7ff6ecc --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-inside.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 0.25,2 0.25,2 0.75,1 0.75,1 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-partial.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-partial.wkt new file mode 100644 index 000000000000..f7372fef3b31 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-partial.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,2 0,2 0.5,1 0.5,1 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge.wkt new file mode 100644 index 000000000000..33b6059e3993 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,2 0,2 1,1 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-boundary.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-boundary.wkt new file mode 100644 index 000000000000..511245f448ea --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-boundary.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-in.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-in.wkt new file mode 100644 index 000000000000..511245f448ea --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-in.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-out.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-out.wkt new file mode 100644 index 000000000000..511245f448ea --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-out.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/square.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/square.wkt new file mode 100644 index 000000000000..511245f448ea --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/square.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp index 20b2c9694a81..c011815ca57d 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp @@ -1,19 +1,76 @@ #include #include +#include +#include #include -#include -#include -#include +#include #include +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_2 = Kernel::Point_2; +using Polygon_2 = CGAL::Polygon_2; +using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; +using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Polygon_2 Polygon_2; -typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; +int main(int argc, char* argv[]) { + + for (const auto& file: std::__fs::filesystem::directory_iterator("data/in")) { + std::cout << "Testing " << file.path().filename() << "... "; + + // Read test file + std::string in; + std::getline(std::ifstream(file.path()), in); + + // Load test file and repair to create output + std::istringstream iss(in); + std::size_t is_polygon = in.find("POLYGON"); + std::size_t is_multipolygon = in.find("MULTIPOLYGON"); + Multipolygon_with_holes_2 rmp; + if (is_polygon == 0) { + Polygon_with_holes_2 p; + CGAL::IO::read_polygon_WKT(iss, p); + rmp = CGAL::Polygon_repair_2::repair(p); + } else if (is_multipolygon == 0) { + Multipolygon_with_holes_2 mp; + CGAL::IO::read_multi_polygon_WKT(iss, mp); + rmp = CGAL::Polygon_repair_2::repair(mp); + } std::ostringstream oss; + CGAL::IO::write_multi_polygon_WKT(oss, rmp); + std::string out = oss.str(); + + // Read reference file + std::string ref_path = "data/ref/"; + ref_path += file.path().filename(); + std::ifstream ref_ifs(ref_path); + if (ref_ifs.fail()) { + std::cout << std::endl << "\tin: " << in << std::endl; + std::cout << "\tout: " << out; + std::cout << "\tno reference output -> skipped" << std::endl; + continue; + } std::string ref; + std::getline(ref_ifs, ref); + ref += "\n"; + + // Compare output with reference file + if (ref == out) { + std::cout << "ok" << std::endl; + } else { + std::cout << "fail" << std::endl; + std::cout << "\tin: " << in << std::endl; + std::cout << "\tout: " << out; + std::cout << "\tref: " << ref; + } CGAL_assertion(ref == out); + + // Test orientations + for (auto const& polygon: rmp.polygons()) { + CGAL_assertion(polygon.outer_boundary().orientation() == CGAL::COUNTERCLOCKWISE); + for (auto const &hole: polygon.holes()) { + CGAL_assertion(hole.orientation() == CGAL::CLOCKWISE); + } + } + } -int main(int argc, char* argv[]) -{ - std::ifstream ifs( (argc==1)?"data/polygon.wkt":argv[1]); return 0; } From c0135ea9ccd410c6350a11f76e4e4601d23417f2 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 26 Jul 2023 15:08:48 -0600 Subject: [PATCH 035/182] reorganise examples and tests --- .../examples/Polygon_repair_2/CMakeLists.txt | 8 +- .../Polygon_repair_2/nasty_polygons.cpp | 82 +++++++++++++++++++ .../test/Polygon_repair_2/CMakeLists.txt | 6 +- .../Polygon_repair_2/draw_test_polygons.cpp} | 2 +- .../repair_polygon_2_test.cpp | 4 +- 5 files changed, 92 insertions(+), 10 deletions(-) create mode 100644 Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp rename Polygon_repair_2/{examples/Polygon_repair_2/repair_polygon_2.cpp => test/Polygon_repair_2/draw_test_polygons.cpp} (97%) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt index c4626d9d2556..73263ecace7c 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1...3.23) project(Polygon_repair_2_Examples) -find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) +find_package(CGAL REQUIRED) # create a target per cppfile file( @@ -13,8 +13,4 @@ file( ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) create_single_source_cgal_program("${cppfile}") -endforeach() - -if(CGAL_Qt5_FOUND) - target_link_libraries(repair_polygon_2 PUBLIC CGAL::CGAL_Basic_viewer) -endif() \ No newline at end of file +endforeach() \ No newline at end of file diff --git a/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp b/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp new file mode 100644 index 000000000000..d9fddbba8350 --- /dev/null +++ b/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp @@ -0,0 +1,82 @@ +#include +#include +#include +#include + +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_2 = Kernel::Point_2; +using Polygon_2 = CGAL::Polygon_2; +using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; +using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; + +int main(int argc, char* argv[]) { + + // std::ifstream ifs("/Users/ken/Downloads/2018418.wkt"); + // std::ofstream ofs("/Users/ken/Downloads/1.geojson"); + + std::ifstream ifs("/Users/ken/Downloads/180927.wkt"); + std::ofstream ofs("/Users/ken/Downloads/2.geojson"); + + std::string in; + std::getline(ifs, in); + std::istringstream iss(in); + Polygon_with_holes_2 p; + CGAL::IO::read_polygon_WKT(iss, p); + Polygon_repair_2 pr; + pr.add_to_triangulation(p); + pr.label_triangulation(); + + + + pr.compute_hole_nesting(); + pr.reconstruct_multipolygon(); + Multipolygon_with_holes_2 rmp = pr.multipolygon(); + std::ostringstream oss; + CGAL::IO::write_multi_polygon_WKT(oss, rmp); + std::string out = oss.str(); + + ofs << std::fixed; + ofs << std::setprecision(15); + + ofs << "{" << std::endl; + ofs << "\t\"type\": \"MultiPolygon\"," << std::endl; + ofs << "\t\"coordinates\": [" << std::endl; + for (int i = 0; i < rmp.polygons().size(); ++i) { + ofs << "\t\t[" << std::endl; + + ofs << "\t\t\t[" << std::endl; + for (int j = 0; j < rmp.polygons()[i].outer_boundary().size(); ++j) { + ofs << "\t\t\t\t[" << rmp.polygons()[i].outer_boundary()[j].x() << + ", " << rmp.polygons()[i].outer_boundary()[j].y() << "]"; + if (j < rmp.polygons()[i].outer_boundary().size()-1) ofs << ","; + ofs << std::endl; + } ofs << "\t\t\t]"; + if (rmp.polygons()[i].number_of_holes() > 0) ofs << ","; + ofs << std::endl; + + for (int j = 0; j < rmp.polygons()[i].holes().size(); ++j) { + ofs << "\t\t\t[" << std::endl; + for (int k = 0; k < rmp.polygons()[i].holes()[j].size(); ++k) { + ofs << "\t\t\t\t[" << rmp.polygons()[i].holes()[j][k].x() << + ", " << rmp.polygons()[i].holes()[j][k].y() << "]"; + if (k < rmp.polygons()[i].holes()[j].size()-1) ofs << ","; + ofs << std::endl; + } + ofs << "\t\t\t]"; + if (j < rmp.polygons()[i].holes().size()-1) ofs << ","; + ofs << std::endl; + } + + ofs << "\t\t]"; + if (i < rmp.polygons().size()-1) ofs << ","; + ofs << std::endl; + } ofs << "\t]" << std::endl; + ofs << "}" << std::endl; + + return 0; +} diff --git a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt index d01986d94de1..365fba1a84c2 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1...3.23) project(Polygon_repair_2_Tests) -find_package(CGAL REQUIRED) +find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) # create a target per cppfile file( @@ -14,3 +14,7 @@ file( foreach(cppfile ${cppfiles}) create_single_source_cgal_program("${cppfile}") endforeach() + +if(CGAL_Qt5_FOUND) + target_link_libraries(draw_test_polygons PUBLIC CGAL::CGAL_Basic_viewer) +endif() \ No newline at end of file diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp similarity index 97% rename from Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp rename to Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp index b7ea6b42b1df..4ae03ef51a31 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp @@ -19,7 +19,7 @@ using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; int main(int argc, char* argv[]) { - for (const auto& file: std::__fs::filesystem::directory_iterator("../../test/Polygon_repair_2/data/in")) { + for (const auto& file: std::__fs::filesystem::directory_iterator("data/in")) { std::cout << "Reading " << file.path().filename() << "..." << std::endl; // if (file.path().filename() != "hole-outside.wkt") continue; diff --git a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp index c011815ca57d..73bf756b311c 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp @@ -15,7 +15,7 @@ using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; int main(int argc, char* argv[]) { - + for (const auto& file: std::__fs::filesystem::directory_iterator("data/in")) { std::cout << "Testing " << file.path().filename() << "... "; @@ -52,7 +52,7 @@ int main(int argc, char* argv[]) { } std::string ref; std::getline(ref_ifs, ref); ref += "\n"; - + // Compare output with reference file if (ref == out) { std::cout << "ok" << std::endl; From 9a28bcbdf8d2542fcc8f8ee484a2f27d376fcb23 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 26 Jul 2023 15:09:05 -0600 Subject: [PATCH 036/182] resize for vectors --- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index cc0535d37cd2..abf8ab1f29a9 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -234,15 +234,14 @@ class Polygon_repair_2 { } void compute_hole_nesting() { - for (int i = 0; i < number_of_holes; ++i) { - nesting.emplace_back(); - } for (auto const &face: t.finite_face_handles()) { + nesting.resize(number_of_holes); + for (auto const &face: t.finite_face_handles()) { if (face->label() >= -1) continue; // skip non-hole triangles for (int opposite_vertex = 0; opposite_vertex < 3; ++opposite_vertex) { if (face->label() == face->neighbor(opposite_vertex)->label()) continue; nesting[-face->label()-2].insert(face->neighbor(opposite_vertex)->label()); } - } + } // int hole_label = -2; // for (auto const &hole: nesting) { @@ -258,10 +257,8 @@ class Polygon_repair_2 { mp.clear(); std::vector> polygons; std::vector, Polygon_less>> holes; // holes are ordered - for (int i = 0; i < number_of_polygons; ++i) { - polygons.emplace_back(); - holes.emplace_back(); - } + polygons.resize(number_of_polygons); + holes.resize(number_of_polygons); for (auto const face: t.all_face_handles()) { face->processed() = false; From 6286ef8f5aafa2c6eca794651593fea185a5817b Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 26 Jul 2023 15:13:28 -0600 Subject: [PATCH 037/182] direct comparison to detect polygon/multipolygon --- .../test/Polygon_repair_2/repair_polygon_2_test.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp index 73bf756b311c..6e33bd296713 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp @@ -25,14 +25,12 @@ int main(int argc, char* argv[]) { // Load test file and repair to create output std::istringstream iss(in); - std::size_t is_polygon = in.find("POLYGON"); - std::size_t is_multipolygon = in.find("MULTIPOLYGON"); Multipolygon_with_holes_2 rmp; - if (is_polygon == 0) { + if (in.find("POLYGON") == 0) { Polygon_with_holes_2 p; CGAL::IO::read_polygon_WKT(iss, p); rmp = CGAL::Polygon_repair_2::repair(p); - } else if (is_multipolygon == 0) { + } else if (in.find("MULTIPOLYGON") == 0) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); rmp = CGAL::Polygon_repair_2::repair(mp); From 0ff6dcc66801f356375620c955e39dbfaac4704a Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 26 Jul 2023 15:19:14 -0600 Subject: [PATCH 038/182] comments in American English + fix typo --- .../include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h | 2 +- .../include/CGAL/Polygon_repair_2/Polygon_repair_2.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h index ba0e883773ba..a584d088cab8 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h @@ -23,7 +23,7 @@ namespace CGAL { * The class `Multipolygon_with_holes_2` models the concept `MultipolygonWithHoles_2`. * It is parameterized with two types (`Kernel` and `Container`) that are used to instantiate * the types `Polygon_2` and `Polygon_with_holes_2`. - * The latter is used to represents each polygon with holes. The former is converted to the latter. + * The latter is used to represent each polygon with holes. The former is converted to the latter. * * \cgalModels `MultipolygonWithHoles_2` */ diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index abf8ab1f29a9..6769a39bf1ce 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -252,7 +252,7 @@ class Polygon_repair_2 { // } } - // Reconstruct multipolygon based on the triangles labelled as inside the polygon + // Reconstruct multipolygon based on the triangles labeled as inside the polygon void reconstruct_multipolygon() { mp.clear(); std::vector> polygons; From db0cb2af4f6fb2e37cadf712e07e5c357cd2507b Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 26 Jul 2023 15:24:06 -0600 Subject: [PATCH 039/182] spread code a bit after } --- .../include/CGAL/Polygon_repair_2/Polygon_repair_2.h | 12 ++++++++---- .../draw_multipolygon_with_holes_2.h | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 6769a39bf1ce..69bbac932ad2 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -93,7 +93,8 @@ class Polygon_repair_2 { if (*va != *vb) return *va < *vb; ++va; ++vb; - } if (vb == pb.vertices_end()) return false; + } + if (vb == pb.vertices_end()) return false; return true; } }; @@ -109,7 +110,8 @@ class Polygon_repair_2 { while (ha != pa.holes_end() && hb != pb.holes_end()) { if (pl(*ha, *hb)) return true; if (pl(*hb, *ha)) return false; - } if (hb == pb.holes_end()) return false; + } + if (hb == pb.holes_end()) return false; return true; } }; @@ -228,7 +230,8 @@ class Polygon_repair_2 { for (typename std::list::iterator current_vertex = ring.begin(); current_vertex != ring.end(); ++current_vertex) { if (*current_vertex < *smallest_vertex) smallest_vertex = current_vertex; - } if (ring.front() != *smallest_vertex) { + } + if (ring.front() != *smallest_vertex) { ring.splice(ring.begin(), ring, smallest_vertex, ring.end()); } } @@ -303,7 +306,8 @@ class Polygon_repair_2 { std::set, Polygon_with_holes_less> ordered_polygons; for (int i = 0; i < polygons.size(); ++i) { ordered_polygons.insert(Polygon_with_holes_2(polygons[i], holes[i].begin(), holes[i].end())); - } for (auto const& polygon: ordered_polygons) { + } + for (auto const& polygon: ordered_polygons) { // std::cout << "Adding polygon " << polygon << std::endl; mp.add_polygon(polygon); } diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h index 2035c225c48d..3a28356873bb 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h @@ -97,7 +97,8 @@ class Mpwh_2_basic_viewer_qt : public Basic_viewer_qt { Bbox_2 bbox; for (auto const& pwh: m_mpwh.polygons()) { bbox += pwh.outer_boundary().bbox(); - } return bbox; + } + return bbox; } /*! Compute the elements of a multipolygon with holes. From 53ae5f8abd5962e36f9493f60d69e7a7d1ebf4a8 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 26 Jul 2023 19:07:41 -0600 Subject: [PATCH 040/182] bugfixes, empty output works now --- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 35 ++++++++++--------- .../draw_multipolygon_with_holes_2.h | 2 +- .../Polygon_repair_2/draw_test_polygons.cpp | 1 + .../repair_polygon_2_test.cpp | 1 + 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 69bbac932ad2..5ad3d31b15dc 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -37,10 +37,11 @@ template Multipolygon_with_holes_2 repair(const Polygon_2& p) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; pr.add_to_triangulation(p); - pr.label_triangulation(); - pr.compute_hole_nesting(); - pr.reconstruct_multipolygon(); - return pr.multipolygon(); + if (pr.triangulation().number_of_faces() > 0) { + pr.label_triangulation(); + pr.compute_hole_nesting(); + pr.reconstruct_multipolygon(); + } return pr.multipolygon(); } /// \ingroup PkgPolygonRepair2Functions @@ -49,10 +50,11 @@ template Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; pr.add_to_triangulation(p); - pr.label_triangulation(); - pr.compute_hole_nesting(); - pr.reconstruct_multipolygon(); - return pr.multipolygon(); + if (pr.triangulation().number_of_faces() > 0) { + pr.label_triangulation(); + pr.compute_hole_nesting(); + pr.reconstruct_multipolygon(); + } return pr.multipolygon(); } /// \ingroup PkgPolygonRepair2Functions @@ -61,10 +63,11 @@ template Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& mp) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; pr.add_to_triangulation(mp); - pr.label_triangulation(); - pr.compute_hole_nesting(); - pr.reconstruct_multipolygon(); - return pr.multipolygon(); + if (pr.triangulation().number_of_faces() > 0) { + pr.label_triangulation(); + pr.compute_hole_nesting(); + pr.reconstruct_multipolygon(); + } return pr.multipolygon(); } /*! \ingroup PkgPolygonRepair2Ref @@ -93,7 +96,7 @@ class Polygon_repair_2 { if (*va != *vb) return *va < *vb; ++va; ++vb; - } + } if (vb == pb.vertices_end()) return false; return true; } @@ -110,7 +113,7 @@ class Polygon_repair_2 { while (ha != pa.holes_end() && hb != pb.holes_end()) { if (pl(*ha, *hb)) return true; if (pl(*hb, *ha)) return false; - } + } if (hb == pb.holes_end()) return false; return true; } @@ -230,7 +233,7 @@ class Polygon_repair_2 { for (typename std::list::iterator current_vertex = ring.begin(); current_vertex != ring.end(); ++current_vertex) { if (*current_vertex < *smallest_vertex) smallest_vertex = current_vertex; - } + } if (ring.front() != *smallest_vertex) { ring.splice(ring.begin(), ring, smallest_vertex, ring.end()); } @@ -306,7 +309,7 @@ class Polygon_repair_2 { std::set, Polygon_with_holes_less> ordered_polygons; for (int i = 0; i < polygons.size(); ++i) { ordered_polygons.insert(Polygon_with_holes_2(polygons[i], holes[i].begin(), holes[i].end())); - } + } for (auto const& polygon: ordered_polygons) { // std::cout << "Adding polygon " << polygon << std::endl; mp.add_polygon(polygon); diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h index 3a28356873bb..d8c9d47736ad 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h @@ -97,7 +97,7 @@ class Mpwh_2_basic_viewer_qt : public Basic_viewer_qt { Bbox_2 bbox; for (auto const& pwh: m_mpwh.polygons()) { bbox += pwh.outer_boundary().bbox(); - } + } return bbox; } diff --git a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp index 4ae03ef51a31..e75a0ecdb646 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp @@ -20,6 +20,7 @@ using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; int main(int argc, char* argv[]) { for (const auto& file: std::__fs::filesystem::directory_iterator("data/in")) { + if (file.path().filename().extension() != ".wkt") continue; std::cout << "Reading " << file.path().filename() << "..." << std::endl; // if (file.path().filename() != "hole-outside.wkt") continue; diff --git a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp index 6e33bd296713..545c19943daa 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp @@ -17,6 +17,7 @@ using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; int main(int argc, char* argv[]) { for (const auto& file: std::__fs::filesystem::directory_iterator("data/in")) { + if (file.path().filename().extension() != ".wkt") continue; std::cout << "Testing " << file.path().filename() << "... "; // Read test file From 61fe1f43ac24721e47a9e7779f1341a527a553f7 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 26 Jul 2023 19:08:37 -0600 Subject: [PATCH 041/182] more unit tests --- .../test/Polygon_repair_2/data/in/back-and-forth.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/in/edge.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/in/hole-all.wkt | 1 + .../test/Polygon_repair_2/data/in/hole-touching-edge.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/in/nesting.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/in/not-closed.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/in/point-double.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/in/point.wkt | 1 + .../test/Polygon_repair_2/data/ref/back-and-forth.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/ref/edge.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-all.wkt | 1 + .../test/Polygon_repair_2/data/ref/hole-touching-edge.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/ref/not-closed.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/ref/point-double.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/ref/point.wkt | 1 + 15 files changed, 15 insertions(+) create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/back-and-forth.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/edge.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/hole-all.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-edge.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/nesting.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/not-closed.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/point-double.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/point.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/back-and-forth.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/edge.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-all.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-edge.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/not-closed.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/point-double.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/point.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/back-and-forth.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/back-and-forth.wkt new file mode 100644 index 000000000000..3911b8f5203a --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/back-and-forth.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 1,0 0,1 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/edge.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/edge.wkt new file mode 100644 index 000000000000..66839d345315 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/edge.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-all.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-all.wkt new file mode 100644 index 000000000000..34482d54ef09 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-all.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0),(0 0,1 0,1 1,0 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-edge.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-edge.wkt new file mode 100644 index 000000000000..4953794c84a0 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-edge.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.75 0.25,0.75 0.75,0.5 1,0.25 0.75,0.25 0.25)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/nesting.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/nesting.wkt new file mode 100644 index 000000000000..142ea6dc746f --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/nesting.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0.1 0.1,0.9 0.1,0.9 0.9,0.1 0.9,0.1 0.1)),((0.2 0.2,0.8 0.2,0.8 0.8,0.2 0.8,0.2 0.2),(0.3 0.3,0.7 0.3,0.7 0.7,0.3 0.7,0.3 0.3))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/not-closed.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/not-closed.wkt new file mode 100644 index 000000000000..ce5c6b3dbf05 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/not-closed.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/point-double.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/point-double.wkt new file mode 100644 index 000000000000..ddecaff4c21b --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/point-double.wkt @@ -0,0 +1 @@ +POLYGON((0 0,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/point.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/point.wkt new file mode 100644 index 000000000000..1c9d31654c2e --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/point.wkt @@ -0,0 +1 @@ +POLYGON((0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/back-and-forth.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/back-and-forth.wkt new file mode 100644 index 000000000000..21e6672095b6 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/back-and-forth.wkt @@ -0,0 +1 @@ +MULTIPOLYGON() \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/edge.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/edge.wkt new file mode 100644 index 000000000000..21e6672095b6 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/edge.wkt @@ -0,0 +1 @@ +MULTIPOLYGON() \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-all.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-all.wkt new file mode 100644 index 000000000000..21e6672095b6 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-all.wkt @@ -0,0 +1 @@ +MULTIPOLYGON() \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-edge.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-edge.wkt new file mode 100644 index 000000000000..4d3bb2343970 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-edge.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0.5 1,0 1,0 0),(0.25 0.25,0.25 0.75,0.5 1,0.75 0.75,0.75 0.25,0.25 0.25))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/not-closed.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/not-closed.wkt new file mode 100644 index 000000000000..511245f448ea --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/not-closed.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/point-double.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/point-double.wkt new file mode 100644 index 000000000000..21e6672095b6 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/point-double.wkt @@ -0,0 +1 @@ +MULTIPOLYGON() \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/point.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/point.wkt new file mode 100644 index 000000000000..21e6672095b6 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/point.wkt @@ -0,0 +1 @@ +MULTIPOLYGON() \ No newline at end of file From 4c3cbc864e08ed87b3f179b7238dd3a894c1b54e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 26 Jul 2023 20:26:26 -0600 Subject: [PATCH 042/182] unit tests with empty input (breaks wkt reader) --- .../test/Polygon_repair_2/data/in/empty-multipolygon.wkt | 1 + .../test/Polygon_repair_2/data/in/empty-polygon.wkt | 1 + .../test/Polygon_repair_2/data/in/hole-touching-once.wkt | 2 +- .../test/Polygon_repair_2/data/ref/empty-multipolygon.wkt | 1 + .../test/Polygon_repair_2/data/ref/empty-polygon.wkt | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/empty-multipolygon.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/empty-polygon.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-multipolygon.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-polygon.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/empty-multipolygon.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/empty-multipolygon.wkt new file mode 100644 index 000000000000..21e6672095b6 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/empty-multipolygon.wkt @@ -0,0 +1 @@ +MULTIPOLYGON() \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/empty-polygon.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/empty-polygon.wkt new file mode 100644 index 000000000000..aec93ace4b9b --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/empty-polygon.wkt @@ -0,0 +1 @@ +POLYGON() \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-once.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-once.wkt index 587930ced4c6..e9e070b92244 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-once.wkt +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-once.wkt @@ -1 +1 @@ -POLYGON((0 0,1 0,1 1,0 1,0 0),(0.25 0.25,0.75 0.25,0.75 0.75,0 1,0.25 0.25)) \ No newline at end of file +POLYGON((0 0,1 0,1 1,0 1,0 0),(0 1,0.75 0.75,0.75 0.25,0.25 0.25,0 1)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-multipolygon.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-multipolygon.wkt new file mode 100644 index 000000000000..21e6672095b6 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-multipolygon.wkt @@ -0,0 +1 @@ +MULTIPOLYGON() \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-polygon.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-polygon.wkt new file mode 100644 index 000000000000..21e6672095b6 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-polygon.wkt @@ -0,0 +1 @@ +MULTIPOLYGON() \ No newline at end of file From 7fd3badc4ca8110d0ae1cae8385ebeac9a784f02 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 27 Jul 2023 21:44:04 -0600 Subject: [PATCH 043/182] easy check for empty polygons --- .../test/Polygon_repair_2/draw_test_polygons.cpp | 14 +++++++------- .../Polygon_repair_2/repair_polygon_2_test.cpp | 5 +++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp index e75a0ecdb646..1c8c9366cfc1 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp @@ -23,20 +23,20 @@ int main(int argc, char* argv[]) { if (file.path().filename().extension() != ".wkt") continue; std::cout << "Reading " << file.path().filename() << "..." << std::endl; - // if (file.path().filename() != "hole-outside.wkt") continue; + // if (file.path().filename() != "nesting.wkt") continue; std::string in; std::getline(std::ifstream(file.path()), in); std::istringstream iss(in); - std::size_t is_polygon = in.find("POLYGON"); - std::size_t is_multipolygon = in.find("MULTIPOLYGON"); Multipolygon_with_holes_2 rmp; - if (is_polygon == 0) { + + if (in.find("POLYGON") == 0) { Polygon_with_holes_2 p; - CGAL::IO::read_polygon_WKT(iss, p); - CGAL::draw(p); + if (in != "POLYGON()") { // maybe should be checked in WKT reader + CGAL::IO::read_polygon_WKT(iss, p); + } CGAL::draw(p); rmp = CGAL::Polygon_repair_2::repair(p); - } else if (is_multipolygon == 0) { + } else if (in.find("MULTIPOLYGON") == 0) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); CGAL::draw(mp); diff --git a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp index 545c19943daa..a9e367b39b8c 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp @@ -29,8 +29,9 @@ int main(int argc, char* argv[]) { Multipolygon_with_holes_2 rmp; if (in.find("POLYGON") == 0) { Polygon_with_holes_2 p; - CGAL::IO::read_polygon_WKT(iss, p); - rmp = CGAL::Polygon_repair_2::repair(p); + if (in != "POLYGON()") { // maybe should be checked in WKT reader + CGAL::IO::read_polygon_WKT(iss, p); + } rmp = CGAL::Polygon_repair_2::repair(p); } else if (in.find("MULTIPOLYGON") == 0) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); From 49177f78dfd21fde270b4d690d16c65866087b80 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 27 Jul 2023 21:45:33 -0600 Subject: [PATCH 044/182] new nesting code + reconstruction fix --- .../Polygon_repair_2/nasty_polygons.cpp | 9 +- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 110 +++++++++++------- 2 files changed, 70 insertions(+), 49 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp b/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp index d9fddbba8350..9e64c21ecb56 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp @@ -16,10 +16,10 @@ using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; int main(int argc, char* argv[]) { - // std::ifstream ifs("/Users/ken/Downloads/2018418.wkt"); + // std::ifstream ifs("/Users/ken/Downloads/180927.wkt"); // std::ofstream ofs("/Users/ken/Downloads/1.geojson"); - std::ifstream ifs("/Users/ken/Downloads/180927.wkt"); + std::ifstream ifs("/Users/ken/Downloads/2018418.wkt"); std::ofstream ofs("/Users/ken/Downloads/2.geojson"); std::string in; @@ -30,10 +30,7 @@ int main(int argc, char* argv[]) { Polygon_repair_2 pr; pr.add_to_triangulation(p); pr.label_triangulation(); - - - - pr.compute_hole_nesting(); + pr.compute_nesting(); pr.reconstruct_multipolygon(); Multipolygon_with_holes_2 rmp = pr.multipolygon(); std::ostringstream oss; diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 5ad3d31b15dc..6b1f35712690 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -39,7 +39,7 @@ Multipolygon_with_holes_2 repair(const Polygon_2 0) { pr.label_triangulation(); - pr.compute_hole_nesting(); + pr.compute_nesting(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } @@ -52,7 +52,7 @@ Multipolygon_with_holes_2 repair(const Polygon_with_ho pr.add_to_triangulation(p); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation(); - pr.compute_hole_nesting(); + pr.compute_nesting(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } @@ -65,7 +65,7 @@ Multipolygon_with_holes_2 repair(const Multipolygon_wi pr.add_to_triangulation(mp); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation(); - pr.compute_hole_nesting(); + pr.compute_nesting(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } @@ -211,13 +211,14 @@ class Polygon_repair_2 { void reconstruct_ring(std::list& ring, typename Triangulation::Face_handle face_adjacent_to_boundary, int opposite_vertex) { + // std::cout << "Reconstructing ring for face " << face_adjacent_to_boundary->label() << "..." << std::endl; // Create ring typename Triangulation::Face_handle current_face = face_adjacent_to_boundary; int current_opposite_vertex = opposite_vertex; do { typename Triangulation::Vertex_handle pivot_vertex = current_face->vertex(current_face->cw(current_opposite_vertex)); - // std::cout << "Adding point " << pivot_vertex->point() << std::endl; + // std::cout << "\tAdding point " << pivot_vertex->point() << std::endl; ring.push_back(pivot_vertex->point()); typename Triangulation::Face_circulator fc = t.incident_faces(pivot_vertex, current_face); do { @@ -239,21 +240,42 @@ class Polygon_repair_2 { } } - void compute_hole_nesting() { - nesting.resize(number_of_holes); - for (auto const &face: t.finite_face_handles()) { - if (face->label() >= -1) continue; // skip non-hole triangles + void compute_nesting() { + for (auto const face: t.all_face_handles()) { + face->processed() = false; + } polygon_nesting.resize(number_of_polygons); + hole_nesting.resize(number_of_holes); + std::list to_check; + to_check.push_back(t.infinite_face()); + t.infinite_face()->processed() = true; + while (!to_check.empty()) { + typename Triangulation::Face_handle face = to_check.front(); + to_check.pop_front(); for (int opposite_vertex = 0; opposite_vertex < 3; ++opposite_vertex) { - if (face->label() == face->neighbor(opposite_vertex)->label()) continue; - nesting[-face->label()-2].insert(face->neighbor(opposite_vertex)->label()); + if (face->neighbor(opposite_vertex)->processed()) continue; + if (face->label() == face->neighbor(opposite_vertex)->label()) { + to_check.push_front(face->neighbor(opposite_vertex)); + } else { + if (face->neighbor(opposite_vertex)->label() < -1) { + hole_nesting[-face->neighbor(opposite_vertex)->label()-2].insert(face->label()); + } else { + polygon_nesting[face->neighbor(opposite_vertex)->label()-1].insert(face->label()); + } to_check.push_back(face->neighbor(opposite_vertex)); + } face->neighbor(opposite_vertex)->processed() = true; } } - // int hole_label = -2; - // for (auto const &hole: nesting) { - // std::cout << "Hole " << hole_label-- << " contained in polygon(s): "; + // int polygon_label = 1; + // for (auto const &polygon: polygon_nesting) { + // std::cout << "Polygon " << polygon_label++ << " contained in hole(s):"; + // for (auto const& hole: polygon) { + // std::cout << " " << hole; + // } std::cout << std::endl; + // } int hole_label = -2; + // for (auto const &hole: hole_nesting) { + // std::cout << "Hole " << hole_label-- << " contained in polygon(s):"; // for (auto const &polygon: hole) { - // std::cout << polygon << " "; + // std::cout << " " << polygon; // } std::cout << std::endl; // } } @@ -270,38 +292,40 @@ class Polygon_repair_2 { face->processed() = false; } for (auto const &face: t.finite_face_handles()) { if (face->label() == -1) continue; // exterior triangle - if (face->label() < -1 && nesting[-face->label()-2].size() > 1) continue; // exterior triangle + if (face->label() < -1 && hole_nesting[-face->label()-2].size() > 1) continue; // exterior triangle if (face->processed()) continue; // already reconstructed for (int opposite_vertex = 0; opposite_vertex < 3; ++opposite_vertex) { - if (face->label() != face->neighbor(opposite_vertex)->label()) { - - std::list ring; - reconstruct_ring(ring, face, opposite_vertex); - if (face->label() > 0) { - polygons[face->label()-1].insert(polygons[face->label()-1].vertices_end(), - ring.begin(), ring.end()); - } else { - int hole_nesting = *(nesting[-face->label()-2].begin()); - // std::cout << "Hole: " << face->label() << " -> item " << -face->label()-2 << " -> in polygon " << hole_nesting << std::endl; - ring.push_back(ring.front()); - ring.pop_front(); - holes[hole_nesting-1].insert(Polygon_2(ring.rbegin(), ring.rend())); - } - - std::list to_check; - to_check.push_back(face); - while (!to_check.empty()) { - for (int neighbour = 0; neighbour < 3; ++neighbour) { - if (to_check.front()->label() == to_check.front()->neighbor(neighbour)->label() && - !to_check.front()->neighbor(neighbour)->processed()) { - to_check.push_back(to_check.front()->neighbor(neighbour)); - } - } to_check.front()->processed() = true; - to_check.pop_front(); - } + if (face->label() == face->neighbor(opposite_vertex)->label()) continue; // not adjacent to boundary + if (face->label() > 0) { + if (polygon_nesting[face->label()-1].count(face->neighbor(opposite_vertex)->label()) != 1) continue; // not adjacent to outer boundary + } else if (hole_nesting[-face->label()-2].count(face->neighbor(opposite_vertex)->label()) != 1) continue; // not adjacent to correct polygon + + std::list ring; + reconstruct_ring(ring, face, opposite_vertex); + if (face->label() > 0) { + polygons[face->label()-1].insert(polygons[face->label()-1].vertices_end(), + ring.begin(), ring.end()); + } else { + int polygon = *(hole_nesting[-face->label()-2].begin());; + // std::cout << "Hole: " << face->label() << " -> item " << -face->label()-2 << " -> in polygon " << polygon << std::endl; + ring.push_back(ring.front()); + ring.pop_front(); + holes[polygon-1].insert(Polygon_2(ring.rbegin(), ring.rend())); + } - break; + std::list to_check; + to_check.push_back(face); + while (!to_check.empty()) { + for (int neighbour = 0; neighbour < 3; ++neighbour) { + if (to_check.front()->label() == to_check.front()->neighbor(neighbour)->label() && + !to_check.front()->neighbor(neighbour)->processed()) { + to_check.push_back(to_check.front()->neighbor(neighbour)); + } + } to_check.front()->processed() = true; + to_check.pop_front(); } + + break; } } @@ -341,7 +365,7 @@ class Polygon_repair_2 { Triangulation t; Multipolygon_with_holes_2 mp; int number_of_polygons, number_of_holes; - std::vector> nesting; // note: holes are surrounded by exactly one polygon + std::vector> polygon_nesting, hole_nesting; // note: holes are surrounded by exactly one polygon }; } // namespace Polygon_repair_2 From 60a7ef65f9ffad78adc68fb1ebcea43087bda981 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 27 Jul 2023 21:45:45 -0600 Subject: [PATCH 045/182] ref output for nesting unit test --- Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting.wkt | 1 + 1 file changed, 1 insertion(+) create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting.wkt new file mode 100644 index 000000000000..15587830fca1 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0.1 0.1,0.1 0.9,0.9 0.9,0.9 0.1,0.1 0.1)),((0.2 0.2,0.8 0.2,0.8 0.8,0.2 0.8,0.2 0.2),(0.3 0.3,0.3 0.7,0.7 0.7,0.7 0.3,0.3 0.3))) \ No newline at end of file From 9d8309f80f509c4a2a51a04c5411c6332dac9b5c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 27 Jul 2023 21:46:10 -0600 Subject: [PATCH 046/182] code to write labelled triangulation --- .../write_labeled_triangulation.cpp | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp diff --git a/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp b/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp new file mode 100644 index 000000000000..8b4c48127795 --- /dev/null +++ b/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include + +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_2 = Kernel::Point_2; +using Polygon_2 = CGAL::Polygon_2; +using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; +using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; + +int main(int argc, char* argv[]) { + + // std::ifstream ifs("/Users/ken/Downloads/180927.wkt"); + // std::ofstream ofs("/Users/ken/Downloads/2.geojson"); + + // std::ifstream ifs("/Users/ken/Downloads/2018418.wkt"); + // std::ofstream ofs("/Users/ken/Downloads/1.geojson"); + + std::ifstream ifs("../../test/Polygon_repair_2/data/in/nesting.wkt"); + std::ofstream ofs("/Users/ken/Downloads/triangulation.geojson"); + + std::string in; + std::getline(ifs, in); + std::istringstream iss(in); + Multipolygon_with_holes_2 mp; + CGAL::IO::read_multi_polygon_WKT(iss, mp); + Polygon_repair_2 pr; + pr.add_to_triangulation(mp); + pr.label_triangulation(); + + // ofs << std::fixed; + // ofs << std::setprecision(15); + + // ofs << "{" << std::endl; + // ofs << "\t\"type\": \"FeatureCollection\"," << std::endl; + // ofs << "\t\"features\": [" << std::endl; + + // for (Polygon_repair_2::Triangulation::Finite_faces_iterator face = pr.triangulation().finite_faces_begin(); + // face != pr.triangulation().finite_faces_end(); ++face) { + // ofs << "\t\t{" << std::endl; + // ofs << "\t\t\t\"type\": \"Feature\"," << std::endl; + // ofs << "\t\t\t\"properties\": {" << std::endl; + // ofs << "\t\t\t\t\"label\": " << face->label() << std::endl; + // ofs << "\t\t\t}," << std::endl; + // ofs << "\t\t\t\"geometry\": {" << std::endl; + // ofs << "\t\t\t\t\"type\": \"Polygon\"," << std::endl; + // ofs << "\t\t\t\t\"coordinates\": [" << std::endl; + // ofs << "\t\t\t\t\t[" << std::endl; + // ofs << "\t\t\t\t\t\t[" << face->vertex(0)->point().x() << ", " << face->vertex(0)->point().y() << "]," << std::endl; + // ofs << "\t\t\t\t\t\t[" << face->vertex(1)->point().x() << ", " << face->vertex(1)->point().y() << "]," << std::endl; + // ofs << "\t\t\t\t\t\t[" << face->vertex(2)->point().x() << ", " << face->vertex(2)->point().y() << "]" << std::endl; + // ofs << "\t\t\t\t\t]" << std::endl; + // ofs << "\t\t\t\t]" << std::endl; + // ofs << "\t\t\t}" << std::endl; + // ofs << "\t\t}"; + // Polygon_repair_2::Triangulation::Finite_faces_iterator next_face = face; + // ++next_face; + // if (next_face != pr.triangulation().finite_faces_end()) ofs << ","; + // ofs << std::endl; + // } + + // ofs << "\t]" << std::endl; + // ofs << "}" << std::endl; + + pr.compute_nesting(); + pr.reconstruct_multipolygon(); + Multipolygon_with_holes_2 rmp = pr.multipolygon(); + // std::ostringstream oss; + // CGAL::IO::write_multi_polygon_WKT(oss, rmp); + // std::string out = oss.str(); + + // ofs << std::fixed; + // ofs << std::setprecision(15); + + + // ofs << "\t\"coordinates\": [" << std::endl; + // for (int i = 0; i < rmp.polygons().size(); ++i) { + // ofs << "\t\t[" << std::endl; + + // ofs << "\t\t\t[" << std::endl; + // for (int j = 0; j < rmp.polygons()[i].outer_boundary().size(); ++j) { + // ofs << "\t\t\t\t[" << rmp.polygons()[i].outer_boundary()[j].x() << + // ", " << rmp.polygons()[i].outer_boundary()[j].y() << "]"; + // if (j < rmp.polygons()[i].outer_boundary().size()-1) ofs << ","; + // ofs << std::endl; + // } ofs << "\t\t\t]"; + // if (rmp.polygons()[i].number_of_holes() > 0) ofs << ","; + // ofs << std::endl; + + // for (int j = 0; j < rmp.polygons()[i].holes().size(); ++j) { + // ofs << "\t\t\t[" << std::endl; + // for (int k = 0; k < rmp.polygons()[i].holes()[j].size(); ++k) { + // ofs << "\t\t\t\t[" << rmp.polygons()[i].holes()[j][k].x() << + // ", " << rmp.polygons()[i].holes()[j][k].y() << "]"; + // if (k < rmp.polygons()[i].holes()[j].size()-1) ofs << ","; + // ofs << std::endl; + // } + // ofs << "\t\t\t]"; + // if (j < rmp.polygons()[i].holes().size()-1) ofs << ","; + // ofs << std::endl; + // } + + // ofs << "\t\t]"; + // if (i < rmp.polygons().size()-1) ofs << ","; + // ofs << std::endl; + // } ofs << "\t]" << std::endl; + + + return 0; +} From cca727f5c34647864f0947e30ce98e63f1ab2d95 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 28 Jul 2023 10:58:42 -0600 Subject: [PATCH 047/182] c++17 --- Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt | 2 ++ Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp | 2 +- .../test/Polygon_repair_2/repair_polygon_2_test.cpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt index 365fba1a84c2..3f145cb62154 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt @@ -4,6 +4,8 @@ cmake_minimum_required(VERSION 3.1...3.23) project(Polygon_repair_2_Tests) +set(CMAKE_CXX_STANDARD 17) + find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) # create a target per cppfile diff --git a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp index 1c8c9366cfc1..c89f479c4958 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp @@ -19,7 +19,7 @@ using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; int main(int argc, char* argv[]) { - for (const auto& file: std::__fs::filesystem::directory_iterator("data/in")) { + for (const auto& file: std::filesystem::directory_iterator("data/in")) { if (file.path().filename().extension() != ".wkt") continue; std::cout << "Reading " << file.path().filename() << "..." << std::endl; diff --git a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp index a9e367b39b8c..50bbe4a0813b 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp @@ -16,7 +16,7 @@ using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; int main(int argc, char* argv[]) { - for (const auto& file: std::__fs::filesystem::directory_iterator("data/in")) { + for (const auto& file: std::filesystem::directory_iterator("data/in")) { if (file.path().filename().extension() != ".wkt") continue; std::cout << "Testing " << file.path().filename() << "... "; From 4fc0727298aad7d05ed4ca0b1cf9c9c660bc873e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 28 Jul 2023 21:11:25 -0600 Subject: [PATCH 048/182] consistent polygon vs hole orientation -> no need for nesting --- .../Polygon_repair_2/nasty_polygons.cpp | 1 - .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 85 +++---------------- 2 files changed, 12 insertions(+), 74 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp b/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp index 9e64c21ecb56..3170158ed334 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp @@ -30,7 +30,6 @@ int main(int argc, char* argv[]) { Polygon_repair_2 pr; pr.add_to_triangulation(p); pr.label_triangulation(); - pr.compute_nesting(); pr.reconstruct_multipolygon(); Multipolygon_with_holes_2 rmp = pr.multipolygon(); std::ostringstream oss; diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 6b1f35712690..fea6c0e2d6aa 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -39,7 +39,6 @@ Multipolygon_with_holes_2 repair(const Polygon_2 0) { pr.label_triangulation(); - pr.compute_nesting(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } @@ -52,7 +51,6 @@ Multipolygon_with_holes_2 repair(const Polygon_with_ho pr.add_to_triangulation(p); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation(); - pr.compute_nesting(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } @@ -65,7 +63,6 @@ Multipolygon_with_holes_2 repair(const Multipolygon_wi pr.add_to_triangulation(mp); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation(); - pr.compute_nesting(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } @@ -217,6 +214,8 @@ class Polygon_repair_2 { typename Triangulation::Face_handle current_face = face_adjacent_to_boundary; int current_opposite_vertex = opposite_vertex; do { + CGAL_assertion(current_face->label() == face_adjacent_to_boundary->label()); + current_face->processed() = true; typename Triangulation::Vertex_handle pivot_vertex = current_face->vertex(current_face->cw(current_opposite_vertex)); // std::cout << "\tAdding point " << pivot_vertex->point() << std::endl; ring.push_back(pivot_vertex->point()); @@ -240,46 +239,6 @@ class Polygon_repair_2 { } } - void compute_nesting() { - for (auto const face: t.all_face_handles()) { - face->processed() = false; - } polygon_nesting.resize(number_of_polygons); - hole_nesting.resize(number_of_holes); - std::list to_check; - to_check.push_back(t.infinite_face()); - t.infinite_face()->processed() = true; - while (!to_check.empty()) { - typename Triangulation::Face_handle face = to_check.front(); - to_check.pop_front(); - for (int opposite_vertex = 0; opposite_vertex < 3; ++opposite_vertex) { - if (face->neighbor(opposite_vertex)->processed()) continue; - if (face->label() == face->neighbor(opposite_vertex)->label()) { - to_check.push_front(face->neighbor(opposite_vertex)); - } else { - if (face->neighbor(opposite_vertex)->label() < -1) { - hole_nesting[-face->neighbor(opposite_vertex)->label()-2].insert(face->label()); - } else { - polygon_nesting[face->neighbor(opposite_vertex)->label()-1].insert(face->label()); - } to_check.push_back(face->neighbor(opposite_vertex)); - } face->neighbor(opposite_vertex)->processed() = true; - } - } - - // int polygon_label = 1; - // for (auto const &polygon: polygon_nesting) { - // std::cout << "Polygon " << polygon_label++ << " contained in hole(s):"; - // for (auto const& hole: polygon) { - // std::cout << " " << hole; - // } std::cout << std::endl; - // } int hole_label = -2; - // for (auto const &hole: hole_nesting) { - // std::cout << "Hole " << hole_label-- << " contained in polygon(s):"; - // for (auto const &polygon: hole) { - // std::cout << " " << polygon; - // } std::cout << std::endl; - // } - } - // Reconstruct multipolygon based on the triangles labeled as inside the polygon void reconstruct_multipolygon() { mp.clear(); @@ -290,42 +249,22 @@ class Polygon_repair_2 { for (auto const face: t.all_face_handles()) { face->processed() = false; - } for (auto const &face: t.finite_face_handles()) { - if (face->label() == -1) continue; // exterior triangle - if (face->label() < -1 && hole_nesting[-face->label()-2].size() > 1) continue; // exterior triangle + } + for (auto const &face: t.finite_face_handles()) { + if (face->label() < 1) continue; // exterior triangle if (face->processed()) continue; // already reconstructed for (int opposite_vertex = 0; opposite_vertex < 3; ++opposite_vertex) { if (face->label() == face->neighbor(opposite_vertex)->label()) continue; // not adjacent to boundary - if (face->label() > 0) { - if (polygon_nesting[face->label()-1].count(face->neighbor(opposite_vertex)->label()) != 1) continue; // not adjacent to outer boundary - } else if (hole_nesting[-face->label()-2].count(face->neighbor(opposite_vertex)->label()) != 1) continue; // not adjacent to correct polygon std::list ring; reconstruct_ring(ring, face, opposite_vertex); - if (face->label() > 0) { - polygons[face->label()-1].insert(polygons[face->label()-1].vertices_end(), - ring.begin(), ring.end()); + Polygon_2 polygon(ring.begin(), ring.end()); + // std::cout << "Reconstructed ring for polygon " << face->label() << " with ccw? " << (polygon.orientation() == CGAL::COUNTERCLOCKWISE) << std::endl; + if (polygon.orientation() == CGAL::COUNTERCLOCKWISE) { + polygons[face->label()-1] = polygon; } else { - int polygon = *(hole_nesting[-face->label()-2].begin());; - // std::cout << "Hole: " << face->label() << " -> item " << -face->label()-2 << " -> in polygon " << polygon << std::endl; - ring.push_back(ring.front()); - ring.pop_front(); - holes[polygon-1].insert(Polygon_2(ring.rbegin(), ring.rend())); - } - - std::list to_check; - to_check.push_back(face); - while (!to_check.empty()) { - for (int neighbour = 0; neighbour < 3; ++neighbour) { - if (to_check.front()->label() == to_check.front()->neighbor(neighbour)->label() && - !to_check.front()->neighbor(neighbour)->processed()) { - to_check.push_back(to_check.front()->neighbor(neighbour)); - } - } to_check.front()->processed() = true; - to_check.pop_front(); - } - - break; + holes[face->label()-1].insert(polygon); + } break; } } @@ -365,7 +304,7 @@ class Polygon_repair_2 { Triangulation t; Multipolygon_with_holes_2 mp; int number_of_polygons, number_of_holes; - std::vector> polygon_nesting, hole_nesting; // note: holes are surrounded by exactly one polygon + // std::vector> polygon_nesting, hole_nesting; }; } // namespace Polygon_repair_2 From eeea56a00aa83867af54f5f0f65a3d797caef9a5 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 28 Jul 2023 21:11:40 -0600 Subject: [PATCH 049/182] cleanup test files --- .../write_labeled_triangulation.cpp | 119 +++++++----------- .../Polygon_repair_2/draw_test_polygons.cpp | 2 +- 2 files changed, 44 insertions(+), 77 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp b/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp index 8b4c48127795..29ee0acfa7d3 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp @@ -22,95 +22,62 @@ int main(int argc, char* argv[]) { // std::ifstream ifs("/Users/ken/Downloads/2018418.wkt"); // std::ofstream ofs("/Users/ken/Downloads/1.geojson"); - std::ifstream ifs("../../test/Polygon_repair_2/data/in/nesting.wkt"); + std::ifstream ifs("../../test/Polygon_repair_2/data/in/nesting-spike.wkt"); std::ofstream ofs("/Users/ken/Downloads/triangulation.geojson"); std::string in; std::getline(ifs, in); std::istringstream iss(in); - Multipolygon_with_holes_2 mp; - CGAL::IO::read_multi_polygon_WKT(iss, mp); Polygon_repair_2 pr; - pr.add_to_triangulation(mp); - pr.label_triangulation(); + + if (in.find("POLYGON") == 0) { + Polygon_with_holes_2 p; + if (in != "POLYGON()") { // maybe should be checked in WKT reader + CGAL::IO::read_polygon_WKT(iss, p); + } pr.add_to_triangulation(p); + } else if (in.find("MULTIPOLYGON") == 0) { + Multipolygon_with_holes_2 mp; + CGAL::IO::read_multi_polygon_WKT(iss, mp); + pr.add_to_triangulation(mp); + } pr.label_triangulation(); // ofs << std::fixed; // ofs << std::setprecision(15); - // ofs << "{" << std::endl; - // ofs << "\t\"type\": \"FeatureCollection\"," << std::endl; - // ofs << "\t\"features\": [" << std::endl; - - // for (Polygon_repair_2::Triangulation::Finite_faces_iterator face = pr.triangulation().finite_faces_begin(); - // face != pr.triangulation().finite_faces_end(); ++face) { - // ofs << "\t\t{" << std::endl; - // ofs << "\t\t\t\"type\": \"Feature\"," << std::endl; - // ofs << "\t\t\t\"properties\": {" << std::endl; - // ofs << "\t\t\t\t\"label\": " << face->label() << std::endl; - // ofs << "\t\t\t}," << std::endl; - // ofs << "\t\t\t\"geometry\": {" << std::endl; - // ofs << "\t\t\t\t\"type\": \"Polygon\"," << std::endl; - // ofs << "\t\t\t\t\"coordinates\": [" << std::endl; - // ofs << "\t\t\t\t\t[" << std::endl; - // ofs << "\t\t\t\t\t\t[" << face->vertex(0)->point().x() << ", " << face->vertex(0)->point().y() << "]," << std::endl; - // ofs << "\t\t\t\t\t\t[" << face->vertex(1)->point().x() << ", " << face->vertex(1)->point().y() << "]," << std::endl; - // ofs << "\t\t\t\t\t\t[" << face->vertex(2)->point().x() << ", " << face->vertex(2)->point().y() << "]" << std::endl; - // ofs << "\t\t\t\t\t]" << std::endl; - // ofs << "\t\t\t\t]" << std::endl; - // ofs << "\t\t\t}" << std::endl; - // ofs << "\t\t}"; - // Polygon_repair_2::Triangulation::Finite_faces_iterator next_face = face; - // ++next_face; - // if (next_face != pr.triangulation().finite_faces_end()) ofs << ","; - // ofs << std::endl; - // } - - // ofs << "\t]" << std::endl; - // ofs << "}" << std::endl; + ofs << "{" << std::endl; + ofs << "\t\"type\": \"FeatureCollection\"," << std::endl; + ofs << "\t\"features\": [" << std::endl; + + for (Polygon_repair_2::Triangulation::Finite_faces_iterator face = pr.triangulation().finite_faces_begin(); + face != pr.triangulation().finite_faces_end(); ++face) { + ofs << "\t\t{" << std::endl; + ofs << "\t\t\t\"type\": \"Feature\"," << std::endl; + ofs << "\t\t\t\"properties\": {" << std::endl; + ofs << "\t\t\t\t\"label\": " << face->label() << std::endl; + ofs << "\t\t\t}," << std::endl; + ofs << "\t\t\t\"geometry\": {" << std::endl; + ofs << "\t\t\t\t\"type\": \"Polygon\"," << std::endl; + ofs << "\t\t\t\t\"coordinates\": [" << std::endl; + ofs << "\t\t\t\t\t[" << std::endl; + ofs << "\t\t\t\t\t\t[" << face->vertex(0)->point().x() << ", " << face->vertex(0)->point().y() << "]," << std::endl; + ofs << "\t\t\t\t\t\t[" << face->vertex(1)->point().x() << ", " << face->vertex(1)->point().y() << "]," << std::endl; + ofs << "\t\t\t\t\t\t[" << face->vertex(2)->point().x() << ", " << face->vertex(2)->point().y() << "]" << std::endl; + ofs << "\t\t\t\t\t]" << std::endl; + ofs << "\t\t\t\t]" << std::endl; + ofs << "\t\t\t}" << std::endl; + ofs << "\t\t}"; + Polygon_repair_2::Triangulation::Finite_faces_iterator next_face = face; + ++next_face; + if (next_face != pr.triangulation().finite_faces_end()) ofs << ","; + ofs << std::endl; + } + + ofs << "\t]" << std::endl; + ofs << "}" << std::endl; - pr.compute_nesting(); pr.reconstruct_multipolygon(); Multipolygon_with_holes_2 rmp = pr.multipolygon(); - // std::ostringstream oss; - // CGAL::IO::write_multi_polygon_WKT(oss, rmp); - // std::string out = oss.str(); - - // ofs << std::fixed; - // ofs << std::setprecision(15); - - - // ofs << "\t\"coordinates\": [" << std::endl; - // for (int i = 0; i < rmp.polygons().size(); ++i) { - // ofs << "\t\t[" << std::endl; - - // ofs << "\t\t\t[" << std::endl; - // for (int j = 0; j < rmp.polygons()[i].outer_boundary().size(); ++j) { - // ofs << "\t\t\t\t[" << rmp.polygons()[i].outer_boundary()[j].x() << - // ", " << rmp.polygons()[i].outer_boundary()[j].y() << "]"; - // if (j < rmp.polygons()[i].outer_boundary().size()-1) ofs << ","; - // ofs << std::endl; - // } ofs << "\t\t\t]"; - // if (rmp.polygons()[i].number_of_holes() > 0) ofs << ","; - // ofs << std::endl; - - // for (int j = 0; j < rmp.polygons()[i].holes().size(); ++j) { - // ofs << "\t\t\t[" << std::endl; - // for (int k = 0; k < rmp.polygons()[i].holes()[j].size(); ++k) { - // ofs << "\t\t\t\t[" << rmp.polygons()[i].holes()[j][k].x() << - // ", " << rmp.polygons()[i].holes()[j][k].y() << "]"; - // if (k < rmp.polygons()[i].holes()[j].size()-1) ofs << ","; - // ofs << std::endl; - // } - // ofs << "\t\t\t]"; - // if (j < rmp.polygons()[i].holes().size()-1) ofs << ","; - // ofs << std::endl; - // } - - // ofs << "\t\t]"; - // if (i < rmp.polygons().size()-1) ofs << ","; - // ofs << std::endl; - // } ofs << "\t]" << std::endl; - + CGAL::IO::write_multi_polygon_WKT(std::cout, rmp); return 0; } diff --git a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp index c89f479c4958..cd3330a3e207 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp @@ -23,7 +23,7 @@ int main(int argc, char* argv[]) { if (file.path().filename().extension() != ".wkt") continue; std::cout << "Reading " << file.path().filename() << "..." << std::endl; - // if (file.path().filename() != "nesting.wkt") continue; + if (file.path().filename() != "nesting-spike.wkt") continue; std::string in; std::getline(std::ifstream(file.path()), in); From 372244c5e2bc06f0ecae55eac6d580e829879ad4 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 28 Jul 2023 21:12:03 -0600 Subject: [PATCH 050/182] more unit tests --- .../test/Polygon_repair_2/data/in/crossing-polygons-nesting.wkt | 1 + .../test/Polygon_repair_2/data/in/crossing-polygons.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/in/nesting-spike.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/in/spike-long.wkt | 1 + .../test/Polygon_repair_2/data/ref/crossing-polygons-nesting.wkt | 1 + .../test/Polygon_repair_2/data/ref/crossing-polygons.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-long.wkt | 1 + 7 files changed, 7 insertions(+) create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons-nesting.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/nesting-spike.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/spike-long.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons-nesting.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-long.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons-nesting.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons-nesting.wkt new file mode 100644 index 000000000000..6b945e81ff7d --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons-nesting.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 1,3 1,3 2,0 2,0 1)),((1 0,2 0,2 3,1 3,1 0)),((1.25 1.25,1.75 1.25,1.75 1.75,1.25 1.75,1.25 1.25))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons.wkt new file mode 100644 index 000000000000..662e1017f9c6 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 1,3 1,3 2,0 2,0 1)),((1 0,2 0,2 3,1 3,1 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/nesting-spike.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/nesting-spike.wkt new file mode 100644 index 000000000000..e0df5a0dc7d8 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/nesting-spike.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0.1 0.1,0.9 0.1,0.9 0.9,0.1 0.9,0.1 0.1)),((0.2 0.2,2 1,0.2 0.2,0.8 0.2,0.8 0.8,0.2 0.8,0.2 0.2),(0.3 0.3,0.7 0.3,0.7 0.7,0.3 0.7,0.3 0.3))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-long.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-long.wkt new file mode 100644 index 000000000000..1668214ed240 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-long.wkt @@ -0,0 +1 @@ +POLYGON((0 0,2 1,0 0,1 0,1 1,0 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons-nesting.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons-nesting.wkt new file mode 100644 index 000000000000..64190bb04e92 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons-nesting.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 1,1 1,1 2,0 2,0 1)),((1 0,2 0,2 1,1 1,1 0)),((1 2,2 2,2 3,1 3,1 2)),((1.25 1.25,1.75 1.25,1.75 1.75,1.25 1.75,1.25 1.25)),((2 1,3 1,3 2,2 2,2 1))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons.wkt new file mode 100644 index 000000000000..815bc8c56258 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 1,1 1,1 2,0 2,0 1)),((1 0,2 0,2 1,1 1,1 0)),((1 2,2 2,2 3,1 3,1 2)),((2 1,3 1,3 2,2 2,2 1))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-long.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-long.wkt new file mode 100644 index 000000000000..511245f448ea --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-long.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0))) \ No newline at end of file From 1f98ff2244ffc930f87cd586bfe07f245661f4d8 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 28 Jul 2023 21:42:09 -0600 Subject: [PATCH 051/182] nesting spike reference file --- .../test/Polygon_repair_2/data/ref/nesting-spike.wkt | 1 + 1 file changed, 1 insertion(+) create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting-spike.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting-spike.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting-spike.wkt new file mode 100644 index 000000000000..15587830fca1 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting-spike.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0.1 0.1,0.1 0.9,0.9 0.9,0.9 0.1,0.1 0.1)),((0.2 0.2,0.8 0.2,0.8 0.8,0.2 0.8,0.2 0.2),(0.3 0.3,0.3 0.7,0.7 0.7,0.7 0.3,0.3 0.3))) \ No newline at end of file From cbed7ce3d4aaaaa45862d2e73170515e80a30e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 1 Aug 2023 13:17:37 +0200 Subject: [PATCH 052/182] remove trailing whitespaces --- .../include/CGAL/Polygon_repair_2/Polygon_repair_2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index fea6c0e2d6aa..8fb655405b89 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -249,7 +249,7 @@ class Polygon_repair_2 { for (auto const face: t.all_face_handles()) { face->processed() = false; - } + } for (auto const &face: t.finite_face_handles()) { if (face->label() < 1) continue; // exterior triangle if (face->processed()) continue; // already reconstructed From d33a2b276c5851c0e387b70438ed6c6501378bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 1 Aug 2023 13:43:02 +0200 Subject: [PATCH 053/182] fix change of meaning errors --- .../include/CGAL/Polygon_repair_2/Polygon_repair_2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 8fb655405b89..19e240322178 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -85,7 +85,7 @@ class Polygon_repair_2 { using Triangulation = Triangulation_with_odd_even_constraints_2; struct Polygon_less { - using Polygon_2 = Polygon_2; + using Polygon_2 = CGAL::Polygon_2; bool operator()(const Polygon_2& pa, const Polygon_2& pb) const { typename Polygon_2::Vertex_iterator va = pa.vertices_begin(); typename Polygon_2::Vertex_iterator vb = pb.vertices_begin(); @@ -100,7 +100,7 @@ class Polygon_repair_2 { }; struct Polygon_with_holes_less { - using Polygon_with_holes_2 = Polygon_with_holes_2; + using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; Polygon_less pl; bool operator()(const Polygon_with_holes_2& pa, const Polygon_with_holes_2& pb) const { if (pl(pa.outer_boundary(), pb.outer_boundary())) return true; From 45dc0bebfc2b1737a5ffdedc9ba3cec17dad3c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 1 Aug 2023 14:50:50 +0200 Subject: [PATCH 054/182] add missing dependencies --- .../Polygon_repair_2/dependencies | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Polygon_repair_2/package_info/Polygon_repair_2/dependencies diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/dependencies b/Polygon_repair_2/package_info/Polygon_repair_2/dependencies new file mode 100644 index 000000000000..f1acb2ceddc5 --- /dev/null +++ b/Polygon_repair_2/package_info/Polygon_repair_2/dependencies @@ -0,0 +1,27 @@ +Algebraic_foundations +Arithmetic_kernel +Cartesian_kernel +Circulator +Distance_2 +Distance_3 +Filtered_kernel +GraphicsView +Hash_map +Homogeneous_kernel +Installation +Intersections_2 +Intersections_3 +Interval_support +Kernel_23 +Kernel_d +Modular_arithmetic +Number_types +Polygon +Polygon_repair_2 +Profiling_tools +Property_map +STL_Extension +Spatial_sorting +Stream_support +TDS_2 +Triangulation_2 From bc858b3ed59bf121d5208eaf1fbaa40a02bf6392 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 1 Aug 2023 18:36:17 -0600 Subject: [PATCH 055/182] remove vertices in collinear segments --- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 39 ++++++++++++++++++- ...iangulation_face_base_with_repair_info_2.h | 2 +- ...riangulation_with_odd_even_constraints_2.h | 3 +- .../test/Polygon_repair_2/data/in/spiral.wkt | 1 + .../data/in/square-hole-rhombus.wkt | 1 + .../test/Polygon_repair_2/data/in/star.wkt | 1 + .../data/ref/overlapping-edge-partial.wkt | 2 +- .../data/ref/overlapping-edge.wkt | 2 +- .../test/Polygon_repair_2/data/ref/spiral.wkt | 1 + .../data/ref/square-hole-rhombus.wkt | 1 + .../test/Polygon_repair_2/data/ref/star.wkt | 1 + 11 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/spiral.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/square-hole-rhombus.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/star.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/spiral.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/square-hole-rhombus.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/star.wkt diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 19e240322178..444cc3801637 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -176,6 +176,38 @@ class Polygon_repair_2 { // Label triangles in triangulation void label_triangulation() { + + // Simplify collinear edges (gets rid of order dependency) + for (auto vertex: t.all_vertex_handles()) { + typename Triangulation::Edge_circulator first_edge = t.incident_edges(vertex); + typename Triangulation::Edge_circulator current_edge = first_edge; + std::vector incident_constrained_edges; + do { + if (t.is_constrained(*current_edge)) { + incident_constrained_edges.push_back(*current_edge); + } ++current_edge; + } while (current_edge != first_edge); + if (incident_constrained_edges.size() == 2) { + typename Kernel::Point_2 v1 = incident_constrained_edges.front().first->vertex(incident_constrained_edges.front().first->ccw(incident_constrained_edges.front().second))->point(); + typename Kernel::Point_2 v2 = incident_constrained_edges.back().first->vertex(incident_constrained_edges.back().first->ccw(incident_constrained_edges.back().second))->point(); + typename Kernel::Vector_2 tov1 = vertex->point()-v1; + typename Kernel::Vector_2 tov2 = vertex->point()-v2; + typename Kernel::FT angle = acos((tov1*tov2) / (sqrt(tov1.squared_length())*sqrt(tov2.squared_length()))); + double epsilon = 0.00001; + double pi = 3.14159265358979323846; + if (angle < pi+epsilon && angle > pi-epsilon) { + // std::cout << "Collinear points" << std::endl; + // std::cout << "v1: " << v1 << std::endl; + // std::cout << "in: " << vertex->point() << std::endl; + // std::cout << "v2: " << v2 << std::endl; + t.remove_incident_constraints(vertex); + t.remove(vertex); + t.insert_constraint(v1, v2); + } + } + } + + // Init labels for (auto const face: t.all_face_handles()) { face->label() = 0; face->processed() = false; @@ -242,8 +274,8 @@ class Polygon_repair_2 { // Reconstruct multipolygon based on the triangles labeled as inside the polygon void reconstruct_multipolygon() { mp.clear(); - std::vector> polygons; - std::vector, Polygon_less>> holes; // holes are ordered + std::vector> polygons; // outer boundaries + std::vector, Polygon_less>> holes; // holes are ordered (per polygon) polygons.resize(number_of_polygons); holes.resize(number_of_polygons); @@ -256,8 +288,11 @@ class Polygon_repair_2 { for (int opposite_vertex = 0; opposite_vertex < 3; ++opposite_vertex) { if (face->label() == face->neighbor(opposite_vertex)->label()) continue; // not adjacent to boundary + // Reconstruct ring std::list ring; reconstruct_ring(ring, face, opposite_vertex); + + // Put ring in polygons Polygon_2 polygon(ring.begin(), ring.end()); // std::cout << "Reconstructed ring for polygon " << face->label() << " with ccw? " << (polygon.orientation() == CGAL::COUNTERCLOCKWISE) << std::endl; if (polygon.orientation() == CGAL::COUNTERCLOCKWISE) { diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h index 770b332d86b9..68143c4a13bc 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h @@ -38,7 +38,7 @@ class Triangulation_face_base_with_repair_info_2 : public FaceBase { : FaceBase(v0, v1, v2) {} Triangulation_face_base_with_repair_info_2(Vertex_handle v0, Vertex_handle v1, Vertex_handle v2, - Face_handle n0, Face_handle n1, Face_handle n2 ) + Face_handle n0, Face_handle n1, Face_handle n2) : FaceBase(v0, v1, v2, n0, n1, n2) {} const bool& processed() const { return _processed; } diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index 957faf869c88..098021d91ad5 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -76,7 +76,8 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { // Degenerate edge if (va == vb) return; - // [va, vb] is an existing edge OR it is composed of shorter edges + // [va, vb] is either an existing edge OR + // there's an existing shorter edge from va in the direction of vb Vertex_handle vc; // [va, vc] is the first edge along [va, vb] Face_handle incident_face; // incident to [va, vc] int opposite_vertex; // opposite to [va, vc] diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spiral.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/spiral.wkt new file mode 100644 index 000000000000..d79a0892188c --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/spiral.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0.1 0.1,0.9 0.1,0.9 0.9,0.1 0.9,0.2 0.2,0.8 0.2,0.8 0.8,0.2 0.8,0.3 0.3,0.7 0.3,0.7 0.7,0.3 0.7,0.4 0.4,0.6 0.4,0.6 0.6,0.4 0.6,0.5 0.5,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/square-hole-rhombus.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/square-hole-rhombus.wkt new file mode 100644 index 000000000000..1cfa76db480b --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/square-hole-rhombus.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0),(0.5 0,1 0.5,0.5 1,0 0.5,0.5 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/star.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/star.wkt new file mode 100644 index 000000000000..eb43ea7debbf --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/star.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1.5 3,3 0,0 1.5,3 3,1.5 0,0 3,3 1.5,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-partial.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-partial.wkt index f7372fef3b31..5588dadf3e63 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-partial.wkt +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-partial.wkt @@ -1 +1 @@ -MULTIPOLYGON(((0 0,1 0,2 0,2 0.5,1 0.5,1 1,0 1,0 0))) \ No newline at end of file +MULTIPOLYGON(((0 0,2 0,2 0.5,1 0.5,1 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge.wkt index 33b6059e3993..ed4275a4e2a8 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge.wkt +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge.wkt @@ -1 +1 @@ -MULTIPOLYGON(((0 0,1 0,2 0,2 1,1 1,0 1,0 0))) \ No newline at end of file +MULTIPOLYGON(((0 0,2 0,2 1,0 1,0 0))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spiral.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spiral.wkt new file mode 100644 index 000000000000..9ba30e469e2d --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spiral.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0.1 0.1,0 0),(0.1 0.1,0.2 0.2,0.1 0.9,0.9 0.9,0.9 0.1,0.1 0.1)),((0.2 0.2,0.8 0.2,0.8 0.8,0.2 0.8,0.3 0.3,0.2 0.2),(0.3 0.3,0.4 0.4,0.3 0.7,0.7 0.7,0.7 0.3,0.3 0.3)),((0.4 0.4,0.6 0.4,0.6 0.6,0.4 0.6,0.5 0.5,0.4 0.4))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/square-hole-rhombus.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/square-hole-rhombus.wkt new file mode 100644 index 000000000000..d55952100cef --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/square-hole-rhombus.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,0.5 0,0 0.5,0 0)),((0 0.5,0.5 1,0 1,0 0.5)),((0.5 0,1 0,1 0.5,0.5 0)),((0.5 1,1 0.5,1 1,0.5 1))) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/star.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/star.wkt new file mode 100644 index 000000000000..b782e4bbd40e --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/star.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1.2 0.6,1 1,0.6 1.2,0 0)),((0 1.5,0.6 1.2,0.75 1.5,0.6 1.8,0 1.5)),((0 3,0.6 1.8,1 2,1.2 2.4,0 3)),((0.75 1.5,1 1,1.5 0.75,2 1,2.25 1.5,2 2,1.5 2.25,1 2,0.75 1.5)),((1.2 0.6,1.5 0,1.8 0.6,1.5 0.75,1.2 0.6)),((1.2 2.4,1.5 2.25,1.8 2.4,1.5 3,1.2 2.4)),((1.8 0.6,3 0,2.4 1.2,2 1,1.8 0.6)),((1.8 2.4,2 2,2.4 1.8,3 3,1.8 2.4)),((2.25 1.5,2.4 1.2,3 1.5,2.4 1.8,2.25 1.5))) \ No newline at end of file From a290df2e840741fd56ee221f39e58d92a2525207 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 1 Aug 2023 19:16:55 -0600 Subject: [PATCH 056/182] spikes test --- Polygon_repair_2/test/Polygon_repair_2/data/in/spikes.wkt | 1 + Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes.wkt | 1 + 2 files changed, 2 insertions(+) create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/spikes.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spikes.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/spikes.wkt new file mode 100644 index 000000000000..c831dd8e2506 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/spikes.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0 0),(0.5 0.5,1.5 0.5,0.5 0.5,1.5 0.7,0.5 0.5,1.5 0.9,0.5 0.5,1.5 1.1,0.5 0.5,1.5 1.3,0.5 0.5,1.5 1.5,0.5 0.5,1.3 1.5,0.5 0.5,1.1 1.5,0.5 0.5,0.9 1.5,0.5 0.5,0.7 1.5,0.5 0.5,0.5 1.5,0.5 0.5,0.3 1.5,0.5 0.5,0.1 1.5,0.5 0.5,-0.1 1.5,0.5 0.5,-0.3 1.5,0.5 0.5,-0.5 1.5,0.5 0.5,-0.5 1.3,0.5 0.5,-0.5 1.1,0.5 0.5,-0.5 0.9,0.5 0.5,-0.5 0.9,0.5 0.5,-0.5 0.7,0.5 0.5,-0.5 0.5,0.5 0.5,-0.5 0.3,0.5 0.5,-0.5 0.1,0.5 0.5,-0.5 -0.1,0.5 0.5,-0.5 -0.3,0.5 0.5,-0.5 -0.5,0.5 0.5,-0.3 -0.5,0.5 0.5,-0.1 -0.5,0.5 0.5,0.1 -0.5,0.5 0.5,0.3 -0.5,0.5 0.5,0.5 -0.5,0.5 0.5,0.7 -0.5,0.5 0.5,0.9 -0.5,0.5 0.5,1.1 -0.5,0.5 0.5,1.3 -0.5,0.5 0.5,1.5 -0.5,0.5 0.5,1.5 -0.3,0.5 0.5,1.5 -0.1,0.5 0.5,1.5 0.1,0.5 0.5,1.5 0.3,0.5 0.5)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes.wkt new file mode 100644 index 000000000000..511245f448ea --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0))) \ No newline at end of file From c559d6d54fdacdd8d7336e34f7793499944758b2 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 2 Aug 2023 19:44:08 -0600 Subject: [PATCH 057/182] preprocessing to get unique edges --- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 67 ++++++++++++++++--- .../Polygon_repair_2/data/in/spikes-fp.wkt | 1 + .../Polygon_repair_2/data/ref/spikes-fp.wkt | 1 + 3 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/in/spikes-fp.wkt create mode 100644 Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes-fp.wkt diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 444cc3801637..916c7c84764f 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -124,23 +124,75 @@ class Polygon_repair_2 { // Add edges of the polygon to the triangulation void add_to_triangulation(const Polygon_2& polygon) { + std::unordered_set, + boost::hash>> edges_to_insert; + for (auto const& edge: polygon.edges()) { - t.odd_even_insert_constraint(edge.source(), edge.target()); + if (edge.source() == edge.target()) continue; + std::pair pair = (edge.source() < edge.target())? + std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); + auto inserted = edges_to_insert.insert(pair); + if (!inserted.second) edges_to_insert.erase(inserted.first); + } + + for (auto const& edge: edges_to_insert) { + t.odd_even_insert_constraint(edge.first, edge.second); } } // Add edges of the polygon to the triangulation void add_to_triangulation(const Polygon_with_holes_2& polygon) { - add_to_triangulation(polygon.outer_boundary()); + std::unordered_set, + boost::hash>> edges_to_insert; + + for (auto const& edge: polygon.outer_boundary().edges()) { + if (edge.source() == edge.target()) continue; + std::pair pair = (edge.source() < edge.target())? + std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); + auto inserted = edges_to_insert.insert(pair); + if (!inserted.second) edges_to_insert.erase(inserted.first); + } for (auto const& hole: polygon.holes()) { - add_to_triangulation(hole); + for (auto const& edge: hole.edges()) { + if (edge.source() == edge.target()) continue; + std::pair pair = (edge.source() < edge.target())? + std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); + auto inserted = edges_to_insert.insert(pair); + if (!inserted.second) edges_to_insert.erase(inserted.first); + } + } + + for (auto const& edge: edges_to_insert) { + t.odd_even_insert_constraint(edge.first, edge.second); } } // Add edges of the polygon to the triangulation void add_to_triangulation(const Multipolygon_with_holes_2& multipolygon) { + std::unordered_set, + boost::hash>> edges_to_insert; + for (auto const& polygon: multipolygon.polygons()) { - add_to_triangulation(polygon); + for (auto const& edge: polygon.outer_boundary().edges()) { + if (edge.source() == edge.target()) continue; + std::pair pair = (edge.source() < edge.target())? + std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); + auto inserted = edges_to_insert.insert(pair); + if (!inserted.second) edges_to_insert.erase(inserted.first); + } + for (auto const& hole: polygon.holes()) { + for (auto const& edge: hole.edges()) { + if (edge.source() == edge.target()) continue; + std::pair pair = (edge.source() < edge.target())? + std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); + auto inserted = edges_to_insert.insert(pair); + if (!inserted.second) edges_to_insert.erase(inserted.first); + } + } + } + + for (auto const& edge: edges_to_insert) { + t.odd_even_insert_constraint(edge.first, edge.second); } } @@ -190,12 +242,7 @@ class Polygon_repair_2 { if (incident_constrained_edges.size() == 2) { typename Kernel::Point_2 v1 = incident_constrained_edges.front().first->vertex(incident_constrained_edges.front().first->ccw(incident_constrained_edges.front().second))->point(); typename Kernel::Point_2 v2 = incident_constrained_edges.back().first->vertex(incident_constrained_edges.back().first->ccw(incident_constrained_edges.back().second))->point(); - typename Kernel::Vector_2 tov1 = vertex->point()-v1; - typename Kernel::Vector_2 tov2 = vertex->point()-v2; - typename Kernel::FT angle = acos((tov1*tov2) / (sqrt(tov1.squared_length())*sqrt(tov2.squared_length()))); - double epsilon = 0.00001; - double pi = 3.14159265358979323846; - if (angle < pi+epsilon && angle > pi-epsilon) { + if (CGAL::collinear(v1, vertex->point(), v2)) { // std::cout << "Collinear points" << std::endl; // std::cout << "v1: " << v1 << std::endl; // std::cout << "in: " << vertex->point() << std::endl; diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spikes-fp.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/in/spikes-fp.wkt new file mode 100644 index 000000000000..2bb7ded142f5 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/in/spikes-fp.wkt @@ -0,0 +1 @@ +POLYGON((0.03 0.02,0.97 0.01,0.99 0.96,0.04 0.98,0.03 0.02),(0.5 0.5,1.5 0.5,0.5 0.5,1.5 0.7,0.5 0.5,1.5 0.9,0.5 0.5,1.5 1.1,0.5 0.5,1.5 1.3,0.5 0.5,1.5 1.5,0.5 0.5,1.3 1.5,0.5 0.5,1.1 1.5,0.5 0.5,0.9 1.5,0.5 0.5,0.7 1.5,0.5 0.5,0.5 1.5,0.5 0.5,0.3 1.5,0.5 0.5,0.1 1.5,0.5 0.5,-0.1 1.5,0.5 0.5,-0.3 1.5,0.5 0.5,-0.5 1.5,0.5 0.5,-0.5 1.3,0.5 0.5,-0.5 1.1,0.5 0.5,-0.5 0.9,0.5 0.5,-0.5 0.9,0.5 0.5,-0.5 0.7,0.5 0.5,-0.5 0.5,0.5 0.5,-0.5 0.3,0.5 0.5,-0.5 0.1,0.5 0.5,-0.5 -0.1,0.5 0.5,-0.5 -0.3,0.5 0.5,-0.5 -0.5,0.5 0.5,-0.3 -0.5,0.5 0.5,-0.1 -0.5,0.5 0.5,0.1 -0.5,0.5 0.5,0.3 -0.5,0.5 0.5,0.5 -0.5,0.5 0.5,0.7 -0.5,0.5 0.5,0.9 -0.5,0.5 0.5,1.1 -0.5,0.5 0.5,1.3 -0.5,0.5 0.5,1.5 -0.5,0.5 0.5,1.5 -0.3,0.5 0.5,1.5 -0.1,0.5 0.5,1.5 0.1,0.5 0.5,1.5 0.3,0.5 0.5)) \ No newline at end of file diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes-fp.wkt b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes-fp.wkt new file mode 100644 index 000000000000..861654da6079 --- /dev/null +++ b/Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes-fp.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0.03 0.02,0.97 0.01,0.99 0.96,0.04 0.98,0.03 0.02))) \ No newline at end of file From ffeeb58f938d4b1a102b99ed783590bcba803b8c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 2 Aug 2023 20:05:53 -0600 Subject: [PATCH 058/182] trailing whitespaces --- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 916c7c84764f..7da830e93467 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -129,11 +129,11 @@ class Polygon_repair_2 { for (auto const& edge: polygon.edges()) { if (edge.source() == edge.target()) continue; - std::pair pair = (edge.source() < edge.target())? + std::pair pair = (edge.source() < edge.target())? std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); auto inserted = edges_to_insert.insert(pair); if (!inserted.second) edges_to_insert.erase(inserted.first); - } + } for (auto const& edge: edges_to_insert) { t.odd_even_insert_constraint(edge.first, edge.second); @@ -147,15 +147,15 @@ class Polygon_repair_2 { for (auto const& edge: polygon.outer_boundary().edges()) { if (edge.source() == edge.target()) continue; - std::pair pair = (edge.source() < edge.target())? + std::pair pair = (edge.source() < edge.target())? std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); auto inserted = edges_to_insert.insert(pair); if (!inserted.second) edges_to_insert.erase(inserted.first); - } + } for (auto const& hole: polygon.holes()) { for (auto const& edge: hole.edges()) { if (edge.source() == edge.target()) continue; - std::pair pair = (edge.source() < edge.target())? + std::pair pair = (edge.source() < edge.target())? std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); auto inserted = edges_to_insert.insert(pair); if (!inserted.second) edges_to_insert.erase(inserted.first); @@ -175,15 +175,15 @@ class Polygon_repair_2 { for (auto const& polygon: multipolygon.polygons()) { for (auto const& edge: polygon.outer_boundary().edges()) { if (edge.source() == edge.target()) continue; - std::pair pair = (edge.source() < edge.target())? + std::pair pair = (edge.source() < edge.target())? std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); auto inserted = edges_to_insert.insert(pair); if (!inserted.second) edges_to_insert.erase(inserted.first); - } + } for (auto const& hole: polygon.holes()) { for (auto const& edge: hole.edges()) { if (edge.source() == edge.target()) continue; - std::pair pair = (edge.source() < edge.target())? + std::pair pair = (edge.source() < edge.target())? std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); auto inserted = edges_to_insert.insert(pair); if (!inserted.second) edges_to_insert.erase(inserted.first); From 506d51f1d32a668481f7d70b97fc4969ea865a10 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 3 Aug 2023 21:35:54 -0600 Subject: [PATCH 059/182] code to repair and generate svgs from the clipart files --- .../examples/Polygon_repair_2/CMakeLists.txt | 2 + .../examples/Polygon_repair_2/clipart.cpp | 117 ++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp diff --git a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt index 73263ecace7c..b7fedd3936a6 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt @@ -4,6 +4,8 @@ cmake_minimum_required(VERSION 3.1...3.23) project(Polygon_repair_2_Examples) +set(CMAKE_CXX_STANDARD 17) + find_package(CGAL REQUIRED) # create a target per cppfile diff --git a/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp b/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp new file mode 100644 index 000000000000..4c0a0ccd8548 --- /dev/null +++ b/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp @@ -0,0 +1,117 @@ +#include +#include +#include +#include + +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_2 = Kernel::Point_2; +using Polygon_2 = CGAL::Polygon_2; +using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; +using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; + +int main(int argc, char* argv[]) { + + std::string folder_in = "/Volumes/Toshiba/out_fix"; + std::string folder_out = "/Volumes/Toshiba/repaired"; + double desired_width = 500.0; + int current = 0, how_many = 10; + + for (const auto& file: std::filesystem::directory_iterator(folder_in)) { + if (file.path().filename().extension() != ".obj") continue; + std::cout << "Reading " << file.path().filename() << "..." << std::endl; + + Polygon_repair_2 pr; + std::vector vertices; + std::vector> edges; + + std::ifstream ifs(file.path()); + std::string line; + + while (std::getline(ifs, line)) { + std::istringstream iss(line); + + char c; + iss >> c; + + if (c == 'v') { + double x, y; + iss >> x >> y; + vertices.emplace_back(x, y); + } else if (c == 'l') { + unsigned int a, b; + iss >> a >> b; + edges.push_back(std::make_pair(vertices[a-1], vertices[b-1])); + } + } + + ifs.close(); + + std::unordered_set, + boost::hash>> edges_to_insert; + + for (auto const& edge: edges) { + if (edge.first == edge.second) continue; + std::pair pair = (edge.first < edge.second)? + std::make_pair(edge.first, edge.second) : std::make_pair(edge.second, edge.first); + auto inserted = edges_to_insert.insert(pair); + if (!inserted.second) edges_to_insert.erase(inserted.first); + } + + for (auto const& edge: edges_to_insert) { + pr.triangulation().odd_even_insert_constraint(edge.first, edge.second); + } + + // std::cout << pr.triangulation().number_of_faces() << " faces in the triangulation" << std::endl; + + if (pr.triangulation().number_of_faces() > 0) { + pr.label_triangulation(); + pr.reconstruct_multipolygon(); + } Multipolygon_with_holes_2 mp = pr.multipolygon(); + + // std::cout << mp << std::endl; + // std::cout << mp.number_of_polygons() << " polygons" << std::endl; + + if (mp.number_of_polygons() > 0) { + CGAL::Bbox_2 bbox = mp.polygons().front().bbox(); + for (auto const& polygon: mp.polygons()) { + bbox += polygon.outer_boundary().bbox(); + } // std::cout << bbox.xmin() << " " << bbox.xmax() << " " << bbox.ymin() << " " << bbox.ymax() << std::endl; + Kernel::Vector_2 translate(-bbox.xmin(), -bbox.ymin()); + double scale = desired_width/(bbox.xmax()-bbox.xmin()); + + + std::ofstream ofs(folder_out + "/" + std::string(file.path().stem()) + ".svg"); + ofs << "" << std::endl; + + for (auto const& polygon: mp.polygons()) { + // std::cout << polygon << std::endl; + ofs << "\t" << std::endl; + } + + for (auto const& polygon: mp.polygons()) { + for (auto const& hole: polygon.holes()) { + // std::cout << hole << std::endl; + ofs << "\t" << std::endl; + } + } + + ofs << ""; + ofs.close(); + } ++current; + +// if (current >= how_many) break; + } + + return 0; +} From f1b2adb2d4da990fc5c3e23a2425f02fac7d1539 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 4 Aug 2023 17:06:31 -0600 Subject: [PATCH 060/182] start vertex search from face incident to last insertion --- .../examples/Polygon_repair_2/clipart.cpp | 62 ++++++++++++++----- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 8 +-- ...riangulation_with_odd_even_constraints_2.h | 10 ++- 3 files changed, 61 insertions(+), 19 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp b/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp index 4c0a0ccd8548..5549158ae13e 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp @@ -14,17 +14,32 @@ using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; +void print_timer(clock_t start_time) { + clock_t stop_time = clock(); + double seconds = (stop_time-start_time)/(double)CLOCKS_PER_SEC; + std::cout << seconds << " seconds"; +} + int main(int argc, char* argv[]) { - std::string folder_in = "/Volumes/Toshiba/out_fix"; - std::string folder_out = "/Volumes/Toshiba/repaired"; +// std::string folder_in = "/Volumes/Toshiba/out_fix"; +// std::string folder_out = "/Volumes/Toshiba/repaired"; + std::string folder_in = "/Users/ken/Downloads/test"; + std::string folder_out = "/Users/ken/Downloads/test"; double desired_width = 500.0; - int current = 0, how_many = 10; + int current = 0, how_many = 100000; + clock_t start_time; for (const auto& file: std::filesystem::directory_iterator(folder_in)) { + if (file.path().filename().extension() != ".obj") continue; - std::cout << "Reading " << file.path().filename() << "..." << std::endl; - + std::cout << "Reading " << file.path().filename() << "..."; +// if (std::filesystem::exists(folder_out + "/" + std::string(file.path().stem()) + ".svg")) { +// std::cout << " skipped: already processed" << std::endl; +// continue; +// } + + start_time = clock(); Polygon_repair_2 pr; std::vector vertices; std::vector> edges; @@ -34,10 +49,8 @@ int main(int argc, char* argv[]) { while (std::getline(ifs, line)) { std::istringstream iss(line); - char c; iss >> c; - if (c == 'v') { double x, y; iss >> x >> y; @@ -47,10 +60,12 @@ int main(int argc, char* argv[]) { iss >> a >> b; edges.push_back(std::make_pair(vertices[a-1], vertices[b-1])); } - } - - ifs.close(); + } ifs.close(); + std::cout << "Read and parsed file in "; + print_timer(start_time); + std::cout << std::endl; + start_time = clock(); std::unordered_set, boost::hash>> edges_to_insert; @@ -60,17 +75,35 @@ int main(int argc, char* argv[]) { std::make_pair(edge.first, edge.second) : std::make_pair(edge.second, edge.first); auto inserted = edges_to_insert.insert(pair); if (!inserted.second) edges_to_insert.erase(inserted.first); - } + } std::cout << "Generated unique edges in "; + print_timer(start_time); + std::cout << std::endl; + start_time = clock(); + Polygon_repair_2::Triangulation::Face_handle search_start; for (auto const& edge: edges_to_insert) { - pr.triangulation().odd_even_insert_constraint(edge.first, edge.second); - } + Polygon_repair_2::Triangulation::Vertex_handle va = pr.triangulation().insert(edge.first, search_start); + Polygon_repair_2::Triangulation::Vertex_handle vb = pr.triangulation().insert(edge.second, va->face()); // vb is likely close to va + pr.triangulation().odd_even_insert_constraint(va, vb); + search_start = vb->face(); + } std::cout << "Inserted constraints in "; + print_timer(start_time); + std::cout << std::endl; // std::cout << pr.triangulation().number_of_faces() << " faces in the triangulation" << std::endl; if (pr.triangulation().number_of_faces() > 0) { + start_time = clock(); pr.label_triangulation(); + std::cout << "Labelled in "; + print_timer(start_time); + std::cout << std::endl; + + start_time = clock(); pr.reconstruct_multipolygon(); + std::cout << "Reconstructed multipolygon in "; + print_timer(start_time); + std::cout << std::endl; } Multipolygon_with_holes_2 mp = pr.multipolygon(); // std::cout << mp << std::endl; @@ -108,9 +141,10 @@ int main(int argc, char* argv[]) { ofs << ""; ofs.close(); + std::cout << " ok" << std::endl; } ++current; -// if (current >= how_many) break; + if (current >= how_many) break; } return 0; diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 7da830e93467..23e79c8706b2 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -136,7 +136,7 @@ class Polygon_repair_2 { } for (auto const& edge: edges_to_insert) { - t.odd_even_insert_constraint(edge.first, edge.second); + t.odd_even_insert_constraint(edge.first, edge.second, search_start); } } @@ -163,7 +163,7 @@ class Polygon_repair_2 { } for (auto const& edge: edges_to_insert) { - t.odd_even_insert_constraint(edge.first, edge.second); + t.odd_even_insert_constraint(edge.first, edge.second, search_start); } } @@ -192,7 +192,7 @@ class Polygon_repair_2 { } for (auto const& edge: edges_to_insert) { - t.odd_even_insert_constraint(edge.first, edge.second); + t.odd_even_insert_constraint(edge.first, edge.second, search_start); } } @@ -386,7 +386,7 @@ class Polygon_repair_2 { Triangulation t; Multipolygon_with_holes_2 mp; int number_of_polygons, number_of_holes; - // std::vector> polygon_nesting, hole_nesting; + typename Triangulation::Face_handle search_start; }; } // namespace Polygon_repair_2 diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index 098021d91ad5..4721aad31299 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -111,9 +111,17 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { // Add constraint from pa to pb using the odd-even rule void odd_even_insert_constraint(Point pa, Point pb) { Vertex_handle va = insert(pa); - Vertex_handle vb = insert(pb); + Vertex_handle vb = insert(pb, va->face()); // vb is likely close to va odd_even_insert_constraint(va, vb); } + + // Add constraint from pa to pb using the odd-even rule (updating search start face) + void odd_even_insert_constraint(Point pa, Point pb, Face_handle &f) { + Vertex_handle va = insert(pa, f); + Vertex_handle vb = insert(pb, va->face()); // vb is likely close to va + odd_even_insert_constraint(va, vb); + f = vb->face(); + } // Starts at an arbitrary interior face Interior_faces_iterator interior_faces_begin() { From a688d1affd3db6c242d7987f10648e4e169b05cb Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 4 Aug 2023 17:06:43 -0600 Subject: [PATCH 061/182] init bbox --- .../CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h index d8c9d47736ad..703e89b73e0a 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h @@ -95,6 +95,7 @@ class Mpwh_2_basic_viewer_qt : public Basic_viewer_qt { */ CGAL::Bbox_2 bounding_box() { Bbox_2 bbox; + if (m_mpwh.number_of_polygons() > 0) bbox = m_mpwh.polygons().front().outer_boundary().bbox(); for (auto const& pwh: m_mpwh.polygons()) { bbox += pwh.outer_boundary().bbox(); } From 26d25172e5b4919c14185af8e899b56bb2d377f3 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 8 Aug 2023 20:13:07 -0600 Subject: [PATCH 062/182] started with user manual --- .../doc/Polygon_repair_2/Polygon_repair_2.txt | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index 723a7d05053d..61b9085c7784 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -7,11 +7,33 @@ namespace CGAL { \cgalAutoToc \author Ken Arroyo Ohori -This chapter describes the ... +\section SectionPolygonRepair2_Introduction Introduction + +This package implements a polygon repair method based on a constrained triangulation \cgalCite{ledoux14prepair}. Starting from a possibly invalid input in the form of a polygon, polygon with holes or multipolygon with holes, the method performs a constrained triangulation of the input edges, applies a heuristic to label each triangle according to what it represents (exterior, polygon interior or hole), and reconstructs the polygon(s) represented by the triangulation. The method returns a valid output stored in a multipolygon with holes. Currently, the odd-even labeling heuristic is implemented in the package. \section SectionPolygonRepair2_Definitions Definitions -Section on definitions here ... +- A valid polygon (without holes) is a point set in \f$ \mathbb{R}^2\f$ that is bounded by a cycle of linear edges, which is known as its outer boundary. This outer boundary should be simple, meaning that the interiors of its edges are pairwise disjoint and all of its vertices have a degree of two. It is thus topologically equivalent to a disk and is represented internally as the sequence of points of the vertices of its outer boundary. + +- A valid polygon with holes is a point set in \f$ \mathbb{R}^2\f$ that is bounded by one outer boundary and zero or more inner boundaries, where each inner boundary represents a hole in the polygon. Considered by itself, each boundary should be simple. The different boundaries of a polygon are allowed to intersect tangentially at their common vertices (with no common edges), forming vertices with degrees larger than two at the tangential points. The interior of a polygon with holes should form a connected point set. Note that a valid polygon can also be represented as a valid polygon with zero holes. + +- A valid multipolygon with holes is a point set in \f$ \mathbb{R}^2\f$ that is represented by a set of zero or more valid polygons with holes. The interiors of the polygons with holes should be pairwise disjoint, but their are allowed to intersect tangentially at their common vertices. Note that a valid polygon with holes can also be represented as a valid multipolygon with holes. + +\subsection SubsectionPolygonRepair2_Output Output + +The conditions listed above are sufficient to define valid polygons, polygons with holes and multipolygons with holes for most applications. However, in order to ensure unique deterministic output, the valid multipolygons with holes returned by the package conform to more strict criteria: + +- Adjacent collinear edges touching at vertices of degree two are merged +- The sequence of vertices representing a boundary starts from its lexicographically smallest vertex +- Outer boundaries are oriented counterclockwise and inner boundaries are oriented clockwise +- The inner boundaries of a polygon with holes are stored in lexicographic order +- The polygons with holes of a multipolygon with holes are also stored in lexicographic order + +\section SectionPolygonRepair2_Algorithm Algorithm + +The method interprets the input + +If the input is already valid, the method will return a valid output representing the same area \section SectionPolygonRepair2_Examples Examples From cab7deb47f410569ded234d4730531e6544ceee2 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 8 Aug 2023 20:21:41 -0600 Subject: [PATCH 063/182] fix citation --- Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index 61b9085c7784..ece938dba1ad 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -9,7 +9,7 @@ namespace CGAL { \section SectionPolygonRepair2_Introduction Introduction -This package implements a polygon repair method based on a constrained triangulation \cgalCite{ledoux14prepair}. Starting from a possibly invalid input in the form of a polygon, polygon with holes or multipolygon with holes, the method performs a constrained triangulation of the input edges, applies a heuristic to label each triangle according to what it represents (exterior, polygon interior or hole), and reconstructs the polygon(s) represented by the triangulation. The method returns a valid output stored in a multipolygon with holes. Currently, the odd-even labeling heuristic is implemented in the package. +This package implements a polygon repair method based on a constrained triangulation \cgalCite{14cg}. Starting from a possibly invalid input in the form of a polygon, polygon with holes or multipolygon with holes, the method performs a constrained triangulation of the input edges, applies a heuristic to label each triangle according to what it represents (exterior, polygon interior or hole), and reconstructs the polygon(s) represented by the triangulation. The method returns a valid output stored in a multipolygon with holes. Currently, the odd-even labeling heuristic is implemented in the package. \section SectionPolygonRepair2_Definitions Definitions From ff1b359b1b59bdec813f5472a915986379ee6824 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 10 Aug 2023 22:19:42 -0600 Subject: [PATCH 064/182] more manual --- .../doc/Polygon_repair_2/Polygon_repair_2.txt | 130 ++++++++++++++---- 1 file changed, 107 insertions(+), 23 deletions(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index ece938dba1ad..0fc61840a73b 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -9,43 +9,127 @@ namespace CGAL { \section SectionPolygonRepair2_Introduction Introduction -This package implements a polygon repair method based on a constrained triangulation \cgalCite{14cg}. Starting from a possibly invalid input in the form of a polygon, polygon with holes or multipolygon with holes, the method performs a constrained triangulation of the input edges, applies a heuristic to label each triangle according to what it represents (exterior, polygon interior or hole), and reconstructs the polygon(s) represented by the triangulation. The method returns a valid output stored in a multipolygon with holes. Currently, the odd-even labeling heuristic is implemented in the package. +This package implements a polygon repair method based on a constrained +triangulation \cgalCite{14cg}. Starting from a possibly invalid input +in the form of a polygon, polygon with holes or multipolygon with holes, +the method performs a constrained triangulation of the input edges, labels +each triangle according to what it represents (exterior, polygon interior +or hole), and reconstructs the polygon(s) represented by the triangulation. +The method returns a valid output stored in a multipolygon with holes. -\section SectionPolygonRepair2_Definitions Definitions - -- A valid polygon (without holes) is a point set in \f$ \mathbb{R}^2\f$ that is bounded by a cycle of linear edges, which is known as its outer boundary. This outer boundary should be simple, meaning that the interiors of its edges are pairwise disjoint and all of its vertices have a degree of two. It is thus topologically equivalent to a disk and is represented internally as the sequence of points of the vertices of its outer boundary. - -- A valid polygon with holes is a point set in \f$ \mathbb{R}^2\f$ that is bounded by one outer boundary and zero or more inner boundaries, where each inner boundary represents a hole in the polygon. Considered by itself, each boundary should be simple. The different boundaries of a polygon are allowed to intersect tangentially at their common vertices (with no common edges), forming vertices with degrees larger than two at the tangential points. The interior of a polygon with holes should form a connected point set. Note that a valid polygon can also be represented as a valid polygon with zero holes. - -- A valid multipolygon with holes is a point set in \f$ \mathbb{R}^2\f$ that is represented by a set of zero or more valid polygons with holes. The interiors of the polygons with holes should be pairwise disjoint, but their are allowed to intersect tangentially at their common vertices. Note that a valid polygon with holes can also be represented as a valid multipolygon with holes. +Different triangulation and labelling heuristics are possible, but +currently only the odd-even heuristic is implemented in the package. -\subsection SubsectionPolygonRepair2_Output Output +\section SectionPolygonRepair2_Definitions Definitions -The conditions listed above are sufficient to define valid polygons, polygons with holes and multipolygons with holes for most applications. However, in order to ensure unique deterministic output, the valid multipolygons with holes returned by the package conform to more strict criteria: +- A valid polygon (without holes) is a point set in \f$ \mathbb{R}^2\f$ +that is bounded by a cycle of linear edges, which is known as its +outer boundary. This outer boundary should be simple, +meaning that the interiors of its edges are pairwise disjoint and all of +its vertices have a degree of two. It is thus topologically equivalent to a +disk and is represented internally as the sequence of points at the common +end points of the edges around its outer boundary. + +- A valid polygon with holes is a point set in \f$ \mathbb{R}^2\f$ +that is bounded by one outer boundary and zero or more inner boundaries, +where each inner boundary represents a hole in the polygon. Considered by +itself, each boundary should be simple. The different boundaries of a polygon +are allowed to intersect tangentially at their common vertices (with no common +edges), forming vertices with degrees larger than two at the tangential points. +The interior of a polygon with holes should form a connected point set. +Note that a valid polygon can also be represented as a valid polygon with +holes (where the number of holes is zero). + +- A valid multipolygon with holes is a point set in \f$ \mathbb{R}^2\f$ +that is represented by a set of zero or more valid polygons with holes. +The interiors of the polygons with holes should be pairwise disjoint, but they +are allowed to intersect tangentially at their common vertices. Note that +a valid polygon with holes can also be represented as a valid multipolygon +with holes. + +FIGURE + +\subsection SubsectionPolygonRepair2_Output Stricter conditions for output + +The conditions listed above are sufficient to define valid polygons, polygons +with holes and multipolygons with holes for most applications. However, in +order to ensure unique deterministic output from the repair algorithm, +the valid multipolygons with holes returned by the package conform to more +strict criteria: - Adjacent collinear edges touching at vertices of degree two are merged -- The sequence of vertices representing a boundary starts from its lexicographically smallest vertex -- Outer boundaries are oriented counterclockwise and inner boundaries are oriented clockwise -- The inner boundaries of a polygon with holes are stored in lexicographic order -- The polygons with holes of a multipolygon with holes are also stored in lexicographic order +- The sequence of vertices representing a boundary starts from its +lexicographically smallest vertex +- Outer boundaries are oriented counterclockwise and inner boundaries are +oriented clockwise +- The inner boundaries of a polygon with holes are stored in lexicographic +order +- The polygons with holes of a multipolygon with holes are also stored in +lexicographic order \section SectionPolygonRepair2_Algorithm Algorithm -The method interprets the input - -If the input is already valid, the method will return a valid output representing the same area +Broadly, the algorithm consists of three steps: + +-# Constrained triangulation: the edges in the polygon, polygon with +holes or multipolygon with holes are added as constraints in the triangulation. +-# Labeling of the faces: sets of faces forming contiguous regions that +are accessible from each other by following adjacency relationships without +passing through a constrained edge are labeled with ids according to +what they represent (exterior, polygon interior or hole). The faces iteratively +adjacent to the infinite face without passing through a constrained edge are +labeled as the exterior. +-# Reconstruction of the multipolygon: each boundary of each polygon +with holes is reconstructed by finding a polygon interior triangle that is +adjacent to the exterior or a hole, then following the boundary in an +orientation that is counterclockwise for outer boundaries and clockwise for +inner boundaries. This orientation and the polygon interior id is used to +determine what polygon with holes it belongs to and whether it is an outer or +an inner boundary. + +FIGURE + +If the input is already valid, the method will return a valid output representing +the same area. However, the output might be different in order to conform to the +stricter conditions to generate deterministic output (see +\ref SubsectionPolygonRepair2_Output). + +Also, it is worth noting that even the repair of a single polygon without holes +but with self-intersections can result in a multipolygon with holes. This is why +the repair function will always return a multipolygon with holes. The user can +then check whether it consists of a single polygon with holes, and whether this +polygon with holes has zero holes and treat it appropriately. + +\subsection SubsectionPolygonRepair2_OddEven Odd-even repair + +The odd-even repair heuristic results in areas that are alternatingly assigned +as polygon interiors and exterior/holes each time that an input edge is passed. +It doesn't distinguish between edges that are part of outer boundaries or inner +boundaries. + +FIGURE + +In order to generate consistent output, the odd-even heuristic requires it to be +applied to both edges and faces. For the edges, this heuristic means that only +the line segments that are present an odd number of times in the input will be +constrained edges in the triangulation. For the face labels, this heuristic means +that after the exterior faces have been labeled, the other faces will be +alternatingly labeled with polygon interior and hole ids every time that a +constrained edge is passed. + +FIGURE \section SectionPolygonRepair2_Examples Examples -\subsection SubsectionPolygonRepair2_FirstExample First Example +\subsection SubsectionPolygonRepair2_Multipolygon Defining and traversing a multipolygon + +\subsection SubsectionPolygonRepair2_WKTDraw Reading well-known text and drawing a multipolygon -The following example shows ... +\subsection SubsectionPolygonRepair2_Repair Repairing -\cgalExample{Polygon_repair_2/repair_polygon_2.cpp} +\subsection SubsectionPolygonRepair2_Repair Repairing (hidden API)? -\cgalFigureBegin{figPck,bench.png} -Left: ... -\cgalFigureEnd +\section SectionPolygonRepair2_Performance Performance */ } /* namespace CGAL */ From 88a4322de13033424c622238d6f6ed8ac3811d6d Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 11 Aug 2023 17:10:19 -0600 Subject: [PATCH 065/182] insert all vertices first, then all constrained edges --- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 107 +++++++++++++++--- ...riangulation_with_odd_even_constraints_2.h | 8 -- 2 files changed, 91 insertions(+), 24 deletions(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 23e79c8706b2..0da8a4e1259c 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -125,74 +125,149 @@ class Polygon_repair_2 { // Add edges of the polygon to the triangulation void add_to_triangulation(const Polygon_2& polygon) { std::unordered_set, - boost::hash>> edges_to_insert; + boost::hash>> unique_edges; + // Get unique edges for (auto const& edge: polygon.edges()) { if (edge.source() == edge.target()) continue; std::pair pair = (edge.source() < edge.target())? std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); - auto inserted = edges_to_insert.insert(pair); - if (!inserted.second) edges_to_insert.erase(inserted.first); + auto inserted = unique_edges.insert(pair); + if (!inserted.second) unique_edges.erase(inserted.first); } + // Insert vertices + std::unordered_map vertices; + std::vector> edges_to_insert; + edges_to_insert.reserve(unique_edges.size()); + for (auto const& edge: unique_edges) { + typename Triangulation::Vertex_handle first_vertex, second_vertex; + typename std::unordered_map::const_iterator found = vertices.find(edge.first); + if (found == vertices.end()) { + first_vertex = t.insert(edge.first, search_start); + vertices[edge.first] = first_vertex; + } else { + first_vertex = found->second; + } search_start = first_vertex->face(); + found = vertices.find(edge.second); + if (found == vertices.end()) { + second_vertex = t.insert(edge.second, search_start); + vertices[edge.second] = second_vertex; + } else { + second_vertex = found->second; + } search_start = second_vertex->face(); + edges_to_insert.emplace_back(first_vertex, second_vertex); + } + + // Insert edges for (auto const& edge: edges_to_insert) { - t.odd_even_insert_constraint(edge.first, edge.second, search_start); + t.odd_even_insert_constraint(edge.first, edge.second); } } // Add edges of the polygon to the triangulation void add_to_triangulation(const Polygon_with_holes_2& polygon) { std::unordered_set, - boost::hash>> edges_to_insert; + boost::hash>> unique_edges; + // Get unique edges for (auto const& edge: polygon.outer_boundary().edges()) { if (edge.source() == edge.target()) continue; std::pair pair = (edge.source() < edge.target())? std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); - auto inserted = edges_to_insert.insert(pair); - if (!inserted.second) edges_to_insert.erase(inserted.first); + auto inserted = unique_edges.insert(pair); + if (!inserted.second) unique_edges.erase(inserted.first); } for (auto const& hole: polygon.holes()) { for (auto const& edge: hole.edges()) { if (edge.source() == edge.target()) continue; std::pair pair = (edge.source() < edge.target())? std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); - auto inserted = edges_to_insert.insert(pair); - if (!inserted.second) edges_to_insert.erase(inserted.first); + auto inserted = unique_edges.insert(pair); + if (!inserted.second) unique_edges.erase(inserted.first); } } + // Insert vertices + std::unordered_map vertices; + std::vector> edges_to_insert; + edges_to_insert.reserve(unique_edges.size()); + for (auto const& edge: unique_edges) { + typename Triangulation::Vertex_handle first_vertex, second_vertex; + typename std::unordered_map::const_iterator found = vertices.find(edge.first); + if (found == vertices.end()) { + first_vertex = t.insert(edge.first, search_start); + vertices[edge.first] = first_vertex; + } else { + first_vertex = found->second; + } search_start = first_vertex->face(); + found = vertices.find(edge.second); + if (found == vertices.end()) { + second_vertex = t.insert(edge.second, search_start); + vertices[edge.second] = second_vertex; + } else { + second_vertex = found->second; + } search_start = second_vertex->face(); + edges_to_insert.emplace_back(first_vertex, second_vertex); + } + + // Insert edges for (auto const& edge: edges_to_insert) { - t.odd_even_insert_constraint(edge.first, edge.second, search_start); + t.odd_even_insert_constraint(edge.first, edge.second); } } // Add edges of the polygon to the triangulation void add_to_triangulation(const Multipolygon_with_holes_2& multipolygon) { std::unordered_set, - boost::hash>> edges_to_insert; + boost::hash>> unique_edges; + // Get unique edges for (auto const& polygon: multipolygon.polygons()) { for (auto const& edge: polygon.outer_boundary().edges()) { if (edge.source() == edge.target()) continue; std::pair pair = (edge.source() < edge.target())? std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); - auto inserted = edges_to_insert.insert(pair); - if (!inserted.second) edges_to_insert.erase(inserted.first); + auto inserted = unique_edges.insert(pair); + if (!inserted.second) unique_edges.erase(inserted.first); } for (auto const& hole: polygon.holes()) { for (auto const& edge: hole.edges()) { if (edge.source() == edge.target()) continue; std::pair pair = (edge.source() < edge.target())? std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source()); - auto inserted = edges_to_insert.insert(pair); - if (!inserted.second) edges_to_insert.erase(inserted.first); + auto inserted = unique_edges.insert(pair); + if (!inserted.second) unique_edges.erase(inserted.first); } } } + // Insert vertices + std::unordered_map vertices; + std::vector> edges_to_insert; + edges_to_insert.reserve(unique_edges.size()); + for (auto const& edge: unique_edges) { + typename Triangulation::Vertex_handle first_vertex, second_vertex; + typename std::unordered_map::const_iterator found = vertices.find(edge.first); + if (found == vertices.end()) { + first_vertex = t.insert(edge.first, search_start); + vertices[edge.first] = first_vertex; + } else { + first_vertex = found->second; + } search_start = first_vertex->face(); + found = vertices.find(edge.second); + if (found == vertices.end()) { + second_vertex = t.insert(edge.second, search_start); + vertices[edge.second] = second_vertex; + } else { + second_vertex = found->second; + } search_start = second_vertex->face(); + edges_to_insert.emplace_back(first_vertex, second_vertex); + } + + // Insert edges for (auto const& edge: edges_to_insert) { - t.odd_even_insert_constraint(edge.first, edge.second, search_start); + t.odd_even_insert_constraint(edge.first, edge.second); } } diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h index 4721aad31299..f496d1154092 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h @@ -114,14 +114,6 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { Vertex_handle vb = insert(pb, va->face()); // vb is likely close to va odd_even_insert_constraint(va, vb); } - - // Add constraint from pa to pb using the odd-even rule (updating search start face) - void odd_even_insert_constraint(Point pa, Point pb, Face_handle &f) { - Vertex_handle va = insert(pa, f); - Vertex_handle vb = insert(pb, va->face()); // vb is likely close to va - odd_even_insert_constraint(va, vb); - f = vb->face(); - } // Starts at an arbitrary interior face Interior_faces_iterator interior_faces_begin() { From 59f2cb0901ab0d062d258e12a4077611c4ff8f2a Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 11 Aug 2023 17:25:21 -0600 Subject: [PATCH 066/182] renamed functions with repair method --- .../examples/Polygon_repair_2/clipart.cpp | 10 +++---- .../Polygon_repair_2/nasty_polygons.cpp | 4 +-- .../write_labeled_triangulation.cpp | 6 ++--- .../CGAL/Polygon_repair_2/Polygon_repair_2.h | 26 +++++++++---------- .../Polygon_repair_2/draw_test_polygons.cpp | 4 +-- .../repair_polygon_2_test.cpp | 4 +-- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp b/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp index 5549158ae13e..421e68e7334e 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp @@ -31,14 +31,14 @@ int main(int argc, char* argv[]) { clock_t start_time; for (const auto& file: std::filesystem::directory_iterator(folder_in)) { - + if (file.path().filename().extension() != ".obj") continue; std::cout << "Reading " << file.path().filename() << "..."; // if (std::filesystem::exists(folder_out + "/" + std::string(file.path().stem()) + ".svg")) { // std::cout << " skipped: already processed" << std::endl; // continue; // } - + start_time = clock(); Polygon_repair_2 pr; std::vector vertices; @@ -94,11 +94,11 @@ int main(int argc, char* argv[]) { if (pr.triangulation().number_of_faces() > 0) { start_time = clock(); - pr.label_triangulation(); + pr.label_triangulation_odd_even(); std::cout << "Labelled in "; print_timer(start_time); std::cout << std::endl; - + start_time = clock(); pr.reconstruct_multipolygon(); std::cout << "Reconstructed multipolygon in "; @@ -143,7 +143,7 @@ int main(int argc, char* argv[]) { ofs.close(); std::cout << " ok" << std::endl; } ++current; - + if (current >= how_many) break; } diff --git a/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp b/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp index 3170158ed334..97ed92f25150 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp @@ -28,8 +28,8 @@ int main(int argc, char* argv[]) { Polygon_with_holes_2 p; CGAL::IO::read_polygon_WKT(iss, p); Polygon_repair_2 pr; - pr.add_to_triangulation(p); - pr.label_triangulation(); + pr.add_to_triangulation_odd_even(p); + pr.label_triangulation_odd_even(); pr.reconstruct_multipolygon(); Multipolygon_with_holes_2 rmp = pr.multipolygon(); std::ostringstream oss; diff --git a/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp b/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp index 29ee0acfa7d3..d7e8333d075f 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp @@ -34,12 +34,12 @@ int main(int argc, char* argv[]) { Polygon_with_holes_2 p; if (in != "POLYGON()") { // maybe should be checked in WKT reader CGAL::IO::read_polygon_WKT(iss, p); - } pr.add_to_triangulation(p); + } pr.add_to_triangulation_odd_even(p); } else if (in.find("MULTIPOLYGON") == 0) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); - pr.add_to_triangulation(mp); - } pr.label_triangulation(); + pr.add_to_triangulation_odd_even(mp); + } pr.label_triangulation_odd_even(); // ofs << std::fixed; // ofs << std::setprecision(15); diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h index 0da8a4e1259c..85ef9d1673de 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h @@ -34,11 +34,11 @@ class Polygon_repair_2; /// \ingroup PkgPolygonRepair2Functions /// Repair a polygon without holes template -Multipolygon_with_holes_2 repair(const Polygon_2& p) { +Multipolygon_with_holes_2 repair_odd_even(const Polygon_2& p) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; - pr.add_to_triangulation(p); + pr.add_to_triangulation_odd_even(p); if (pr.triangulation().number_of_faces() > 0) { - pr.label_triangulation(); + pr.label_triangulation_odd_even(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } @@ -46,11 +46,11 @@ Multipolygon_with_holes_2 repair(const Polygon_2 -Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p) { +Multipolygon_with_holes_2 repair_odd_even(const Polygon_with_holes_2& p) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; - pr.add_to_triangulation(p); + pr.add_to_triangulation_odd_even(p); if (pr.triangulation().number_of_faces() > 0) { - pr.label_triangulation(); + pr.label_triangulation_odd_even(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } @@ -58,11 +58,11 @@ Multipolygon_with_holes_2 repair(const Polygon_with_ho /// \ingroup PkgPolygonRepair2Functions /// Repair a multipolygon with holes template -Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& mp) { +Multipolygon_with_holes_2 repair_odd_even(const Multipolygon_with_holes_2& mp) { CGAL::Polygon_repair_2::Polygon_repair_2 pr; - pr.add_to_triangulation(mp); + pr.add_to_triangulation_odd_even(mp); if (pr.triangulation().number_of_faces() > 0) { - pr.label_triangulation(); + pr.label_triangulation_odd_even(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } @@ -123,7 +123,7 @@ class Polygon_repair_2 { /// @{ // Add edges of the polygon to the triangulation - void add_to_triangulation(const Polygon_2& polygon) { + void add_to_triangulation_odd_even(const Polygon_2& polygon) { std::unordered_set, boost::hash>> unique_edges; @@ -166,7 +166,7 @@ class Polygon_repair_2 { } // Add edges of the polygon to the triangulation - void add_to_triangulation(const Polygon_with_holes_2& polygon) { + void add_to_triangulation_odd_even(const Polygon_with_holes_2& polygon) { std::unordered_set, boost::hash>> unique_edges; @@ -218,7 +218,7 @@ class Polygon_repair_2 { } // Add edges of the polygon to the triangulation - void add_to_triangulation(const Multipolygon_with_holes_2& multipolygon) { + void add_to_triangulation_odd_even(const Multipolygon_with_holes_2& multipolygon) { std::unordered_set, boost::hash>> unique_edges; @@ -302,7 +302,7 @@ class Polygon_repair_2 { } // Label triangles in triangulation - void label_triangulation() { + void label_triangulation_odd_even() { // Simplify collinear edges (gets rid of order dependency) for (auto vertex: t.all_vertex_handles()) { diff --git a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp index cd3330a3e207..8b6d05807446 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp @@ -35,12 +35,12 @@ int main(int argc, char* argv[]) { if (in != "POLYGON()") { // maybe should be checked in WKT reader CGAL::IO::read_polygon_WKT(iss, p); } CGAL::draw(p); - rmp = CGAL::Polygon_repair_2::repair(p); + rmp = CGAL::Polygon_repair_2::repair_odd_even(p); } else if (in.find("MULTIPOLYGON") == 0) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); CGAL::draw(mp); - rmp = CGAL::Polygon_repair_2::repair(mp); + rmp = CGAL::Polygon_repair_2::repair_odd_even(mp); } std::ostringstream oss; CGAL::IO::write_multi_polygon_WKT(oss, rmp); std::string out = oss.str(); diff --git a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp index 50bbe4a0813b..bc3e937d9dec 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp +++ b/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp @@ -31,11 +31,11 @@ int main(int argc, char* argv[]) { Polygon_with_holes_2 p; if (in != "POLYGON()") { // maybe should be checked in WKT reader CGAL::IO::read_polygon_WKT(iss, p); - } rmp = CGAL::Polygon_repair_2::repair(p); + } rmp = CGAL::Polygon_repair_2::repair_odd_even(p); } else if (in.find("MULTIPOLYGON") == 0) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); - rmp = CGAL::Polygon_repair_2::repair(mp); + rmp = CGAL::Polygon_repair_2::repair_odd_even(mp); } std::ostringstream oss; CGAL::IO::write_multi_polygon_WKT(oss, rmp); std::string out = oss.str(); From 00832504801616c104e24e224ec793ae0ee2e487 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 11 Aug 2023 20:10:59 -0600 Subject: [PATCH 067/182] simple multipolygon example --- .../doc/Polygon_repair_2/Polygon_repair_2.txt | 7 ++++- .../Polygon_repair_2/multipolygon.cpp | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index 0fc61840a73b..9300210f5255 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -121,7 +121,12 @@ FIGURE \section SectionPolygonRepair2_Examples Examples -\subsection SubsectionPolygonRepair2_Multipolygon Defining and traversing a multipolygon +\subsection SubsectionPolygonRepair2_Multipolygon The multipolygon with holes class + +The following example shows the creation of a multipolygon with holes and the traversal +of the polygons in it. + +\cgalExample{Polygon_repair_2/multipolygon.cpp} \subsection SubsectionPolygonRepair2_WKTDraw Reading well-known text and drawing a multipolygon diff --git a/Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp b/Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp new file mode 100644 index 000000000000..aa77c84edf64 --- /dev/null +++ b/Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp @@ -0,0 +1,29 @@ +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_2 = Kernel::Point_2; +using Polygon_2 = CGAL::Polygon_2; +using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; + +int main(int argc, char* argv[]) { + + Point_2 p1_outer[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; + Point_2 p1_inner[] = {Point_2(0.2,0.2), Point_2(0.8,0.2), Point_2(0.8,0.8), Point_2(0.2,0.8)}; + + Polygon_with_holes_2 p1(Polygon_2(p1_outer, p1_outer+4)); + Polygon_2 h(p1_inner, p1_inner+4); + p1.add_hole(h); + + Point_2 p2_outer[] = {Point_2(0.4,0.4), Point_2(0.6,0.4), Point_2(0.6,0.6), Point_2(0.4,0.6)}; + Polygon_with_holes_2 p2(Polygon_2(p2_outer, p2_outer+4)); + + Multipolygon_with_holes_2 mp; + mp.add_polygon(p1); + mp.add_polygon(p2); + + for (auto const& p: mp.polygons()) { + std::cout << p << std::endl; + } +} \ No newline at end of file From 5a9e002874bf379f756d8fefbe37586220cbc476 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Sun, 20 Aug 2023 15:35:09 +0200 Subject: [PATCH 068/182] Update Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt Co-authored-by: Sebastien Loriot --- Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index 9300210f5255..70aed0a15555 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -32,8 +32,7 @@ end points of the edges around its outer boundary. - A valid polygon with holes is a point set in \f$ \mathbb{R}^2\f$ that is bounded by one outer boundary and zero or more inner boundaries, -where each inner boundary represents a hole in the polygon. Considered by -itself, each boundary should be simple. The different boundaries of a polygon +where each inner boundary represents a hole in the polygon. Considered independently, each boundary should be simple. The different boundaries of a polygon are allowed to intersect tangentially at their common vertices (with no common edges), forming vertices with degrees larger than two at the tangential points. The interior of a polygon with holes should form a connected point set. From 634fb06f1dfad9ff44f53900b24b8b03b0c2648b Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Sun, 20 Aug 2023 15:35:22 +0200 Subject: [PATCH 069/182] Update Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt Co-authored-by: Sebastien Loriot --- Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index 70aed0a15555..33e5f8ea5702 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -48,7 +48,7 @@ with holes. FIGURE -\subsection SubsectionPolygonRepair2_Output Stricter conditions for output +\subsection SubsectionPolygonRepair2_Output Stricter Conditions for Output The conditions listed above are sufficient to define valid polygons, polygons with holes and multipolygons with holes for most applications. However, in From 4ef71dcfd08d986521e18e0e95da95ee938e47f8 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Sun, 20 Aug 2023 15:35:37 +0200 Subject: [PATCH 070/182] Update Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h Co-authored-by: Sebastien Loriot --- .../include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h index a584d088cab8..8d13989b4e82 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h +++ b/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h @@ -89,7 +89,7 @@ class Multipolygon_with_holes_2 { }; /*! -This operator exports a multipolygon with holes to the output stream `os`. +exports a multipolygon with holes to the output stream `os`. An \ascii and a binary format exist. The format can be selected with the \cgal modifiers for streams, `set_ascii_mode()` and `set_binary_mode()`, From 5ee8cda82012118c28657b572cd1780711450224 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Sun, 20 Aug 2023 16:02:47 +0200 Subject: [PATCH 071/182] draw multipolygon doc --- .../doc/Polygon_repair_2/Polygon_repair_2.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index 9300210f5255..1666dbc1e8e7 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -128,7 +128,17 @@ of the polygons in it. \cgalExample{Polygon_repair_2/multipolygon.cpp} -\subsection SubsectionPolygonRepair2_WKTDraw Reading well-known text and drawing a multipolygon +\subsection SubsectionPolygonRepair2_WKTDraw Draw a multipolygon + +A multipolygon can be visualized by calling the \link PkgPolygonRepair2Ref CGAL::draw

() \endlink function as shown in the following example. This function opens a new window showing the given polygon. A call to this function is blocking, that is the program continues as soon as the user closes the window (versions for polygons and polygons with holes also exist, cf. \link PkgDrawPolygon2 CGAL::draw() \endlink and \link PkgDrawPolygonWithHoles2 CGAL::draw() \endlink). + +\cgalExample{Polygon_repair_2/draw_multipolygon.cpp} + +This function requires `CGAL_Qt5`, and is only available if the macro `CGAL_USE_BASIC_VIEWER` is defined. +Linking with the cmake target `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` and add the definition `CGAL_USE_BASIC_VIEWER`. + +FIGURE +Result of the run of the draw_polygon program. A window shows the multipolygon and allows to navigate through the scene. \subsection SubsectionPolygonRepair2_Repair Repairing From 72c38e46fc8469c489a9b32311aefb6ca8b23c12 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 21 Aug 2023 11:25:43 +0200 Subject: [PATCH 072/182] rest of draw_multipolygon example --- .../doc/Polygon_repair_2/Polygon_repair_2.txt | 28 +++++++++++++------ .../examples/Polygon_repair_2/CMakeLists.txt | 8 ++++-- .../Polygon_repair_2/draw_multipolygon.cpp | 18 ++++++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index 158d5e1c2f75..0ccbde4e058b 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -32,7 +32,8 @@ end points of the edges around its outer boundary. - A valid polygon with holes is a point set in \f$ \mathbb{R}^2\f$ that is bounded by one outer boundary and zero or more inner boundaries, -where each inner boundary represents a hole in the polygon. Considered independently, each boundary should be simple. The different boundaries of a polygon +where each inner boundary represents a hole in the polygon. Considered +independently, each boundary should be simple. The different boundaries of a polygon are allowed to intersect tangentially at their common vertices (with no common edges), forming vertices with degrees larger than two at the tangential points. The interior of a polygon with holes should form a connected point set. @@ -44,7 +45,7 @@ that is represented by a set of zero or more valid polygons with holes. The interiors of the polygons with holes should be pairwise disjoint, but they are allowed to intersect tangentially at their common vertices. Note that a valid polygon with holes can also be represented as a valid multipolygon -with holes. +with holes. For simplicity, we call multipolygons with holes as multipolygons. FIGURE @@ -129,19 +130,30 @@ of the polygons in it. \subsection SubsectionPolygonRepair2_WKTDraw Draw a multipolygon -A multipolygon can be visualized by calling the \link PkgPolygonRepair2Ref CGAL::draw

() \endlink function as shown in the following example. This function opens a new window showing the given polygon. A call to this function is blocking, that is the program continues as soon as the user closes the window (versions for polygons and polygons with holes also exist, cf. \link PkgDrawPolygon2 CGAL::draw() \endlink and \link PkgDrawPolygonWithHoles2 CGAL::draw() \endlink). +A multipolygon can be visualized by calling the \link PkgPolygonRepair2Ref +CGAL::draw() \endlink function as shown in the following example. +This function opens a new window showing the given polygon. A call to this function +is blocking, that is the program continues as soon as the user closes the window. +Versions for polygons and polygons with holes also exist, cf. \link PkgDrawPolygon2 +CGAL::draw

() \endlink and \link PkgDrawPolygonWithHoles2 CGAL::draw() \endlink. + +The multipolygon shown in this example is created using the well-known text (WKT) reader, +which can read and write multipolygons. \cgalExample{Polygon_repair_2/draw_multipolygon.cpp} -This function requires `CGAL_Qt5`, and is only available if the macro `CGAL_USE_BASIC_VIEWER` is defined. -Linking with the cmake target `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` and add the definition `CGAL_USE_BASIC_VIEWER`. +This function requires `CGAL_Qt5`, and is only available if the macro `CGAL_USE_BASIC_VIEWER` +is defined. Linking with the cmake target `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` +and add the definition `CGAL_USE_BASIC_VIEWER`. -FIGURE -Result of the run of the draw_polygon program. A window shows the multipolygon and allows to navigate through the scene. +\cgalFigureBegin{draw_multipolygon, draw_multipolygon.png} +Result of the run of the draw_multipolygon program. A window shows the multipolygon +and allows to navigate through the scene. +\cgalFigureEnd \subsection SubsectionPolygonRepair2_Repair Repairing -\subsection SubsectionPolygonRepair2_Repair Repairing (hidden API)? +\subsection SubsectionPolygonRepair2_RepairHiddenApi Step by step repairing \section SectionPolygonRepair2_Performance Performance diff --git a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt index b7fedd3936a6..3c6c418ecdee 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt @@ -6,7 +6,7 @@ project(Polygon_repair_2_Examples) set(CMAKE_CXX_STANDARD 17) -find_package(CGAL REQUIRED) +find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) # create a target per cppfile file( @@ -15,4 +15,8 @@ file( ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) create_single_source_cgal_program("${cppfile}") -endforeach() \ No newline at end of file +endforeach() + +if(CGAL_Qt5_FOUND) + target_link_libraries(draw_multipolygon PUBLIC CGAL::CGAL_Basic_viewer) +endif() \ No newline at end of file diff --git a/Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp b/Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp new file mode 100644 index 000000000000..2e0e77128139 --- /dev/null +++ b/Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp @@ -0,0 +1,18 @@ +#include +#include + +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; + +int main(int argc, char* argv[]) { + std::ifstream in("data/nesting.wkt"); + Multipolygon_with_holes_2 mp; + CGAL::IO::read_multi_polygon_WKT(in, mp); + CGAL::draw(mp); + + return 0; +} From 6db7abbb6c8d0403444a53e080950e7055ae2707 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 21 Aug 2023 11:36:56 +0200 Subject: [PATCH 073/182] put wkt directly in example --- Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt | 6 ++++-- .../examples/Polygon_repair_2/draw_multipolygon.cpp | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index 0ccbde4e058b..3953d64aa0e2 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -32,7 +32,7 @@ end points of the edges around its outer boundary. - A valid polygon with holes is a point set in \f$ \mathbb{R}^2\f$ that is bounded by one outer boundary and zero or more inner boundaries, -where each inner boundary represents a hole in the polygon. Considered +where each inner boundary represents a hole in the polygon. Considered independently, each boundary should be simple. The different boundaries of a polygon are allowed to intersect tangentially at their common vertices (with no common edges), forming vertices with degrees larger than two at the tangential points. @@ -151,7 +151,9 @@ Result of the run of the draw_multipolygon program. A window shows the multipoly and allows to navigate through the scene. \cgalFigureEnd -\subsection SubsectionPolygonRepair2_Repair Repairing +\subsection SubsectionPolygonRepair2_Repair Repairing a (multi)polygon + +\cgalExample{Polygon_repair_2/repair_polygon_2.cpp} \subsection SubsectionPolygonRepair2_RepairHiddenApi Step by step repairing diff --git a/Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp b/Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp index 2e0e77128139..d7ec18926ffa 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -9,9 +9,10 @@ using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; int main(int argc, char* argv[]) { - std::ifstream in("data/nesting.wkt"); + std::string wkt = "MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0.1 0.1,0.1 0.9,0.9 0.9,0.9 0.1,0.1 0.1)),((0.2 0.2,0.8 0.2,0.8 0.8,0.2 0.8,0.2 0.2),(0.3 0.3,0.3 0.7,0.7 0.7,0.7 0.3,0.3 0.3)))"; + std::istringstream iss(wkt); Multipolygon_with_holes_2 mp; - CGAL::IO::read_multi_polygon_WKT(in, mp); + CGAL::IO::read_multi_polygon_WKT(iss, mp); CGAL::draw(mp); return 0; From 55d2fe82b3fcf9fefecdcc7a00a9b881f3e76d7d Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 21 Aug 2023 11:40:43 +0200 Subject: [PATCH 074/182] c++17 from master --- Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt | 2 -- Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt | 2 -- 2 files changed, 4 deletions(-) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt index 3c6c418ecdee..417109e78275 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt @@ -4,8 +4,6 @@ cmake_minimum_required(VERSION 3.1...3.23) project(Polygon_repair_2_Examples) -set(CMAKE_CXX_STANDARD 17) - find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) # create a target per cppfile diff --git a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt b/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt index 3f145cb62154..365fba1a84c2 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt @@ -4,8 +4,6 @@ cmake_minimum_required(VERSION 3.1...3.23) project(Polygon_repair_2_Tests) -set(CMAKE_CXX_STANDARD 17) - find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) # create a target per cppfile From b9ffb31bf67fffef4cbf9641b1dcd74470ba4904 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 21 Aug 2023 12:44:08 +0200 Subject: [PATCH 075/182] clipart in test --- Polygon_repair_2/{examples => test}/Polygon_repair_2/clipart.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Polygon_repair_2/{examples => test}/Polygon_repair_2/clipart.cpp (100%) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp b/Polygon_repair_2/test/Polygon_repair_2/clipart.cpp similarity index 100% rename from Polygon_repair_2/examples/Polygon_repair_2/clipart.cpp rename to Polygon_repair_2/test/Polygon_repair_2/clipart.cpp From 96007f246d57797bf5ef6a0e2761dcc7246320da Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 21 Aug 2023 12:45:35 +0200 Subject: [PATCH 076/182] data for example --- Polygon_repair_2/examples/Polygon_repair_2/data/bridge-edge.wkt | 1 + Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 Polygon_repair_2/examples/Polygon_repair_2/data/bridge-edge.wkt diff --git a/Polygon_repair_2/examples/Polygon_repair_2/data/bridge-edge.wkt b/Polygon_repair_2/examples/Polygon_repair_2/data/bridge-edge.wkt new file mode 100644 index 000000000000..1e86cf795061 --- /dev/null +++ b/Polygon_repair_2/examples/Polygon_repair_2/data/bridge-edge.wkt @@ -0,0 +1 @@ +POLYGON((0 0,1 0,1 1,0 1,0.25 0.75,0.75 0.75,0.75 0.25,0.25 0.25,0.25 0.75,0 1,0 0)) \ No newline at end of file diff --git a/Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp b/Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp index aa77c84edf64..cc9b5df84179 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp @@ -26,4 +26,6 @@ int main(int argc, char* argv[]) { for (auto const& p: mp.polygons()) { std::cout << p << std::endl; } + + return 0; } \ No newline at end of file From 28cfa7e4dfdada53e9f6eb10422df1ed501500d2 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 21 Aug 2023 16:43:48 +0200 Subject: [PATCH 077/182] step by step example --- .../doc/Polygon_repair_2/Polygon_repair_2.txt | 26 ++++-- .../doc/Polygon_repair_2/examples.txt | 3 + .../Polygon_repair_2/data/nesting-spike.wkt | 1 + .../Polygon_repair_2/repair_polygon_2.cpp | 27 +++++++ .../write_labeled_triangulation.cpp | 80 +++++++------------ 5 files changed, 78 insertions(+), 59 deletions(-) create mode 100644 Polygon_repair_2/examples/Polygon_repair_2/data/nesting-spike.wkt create mode 100644 Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index 3953d64aa0e2..e3ecf4f287d1 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -45,7 +45,7 @@ that is represented by a set of zero or more valid polygons with holes. The interiors of the polygons with holes should be pairwise disjoint, but they are allowed to intersect tangentially at their common vertices. Note that a valid polygon with holes can also be represented as a valid multipolygon -with holes. For simplicity, we call multipolygons with holes as multipolygons. +with holes. FIGURE @@ -89,6 +89,9 @@ an inner boundary. FIGURE +For the purposes of the repair operation, the input polygon, polygon with holes +or multipolygon is merely used as a container of input line segments. + If the input is already valid, the method will return a valid output representing the same area. However, the output might be different in order to conform to the stricter conditions to generate deterministic output (see @@ -130,33 +133,40 @@ of the polygons in it. \subsection SubsectionPolygonRepair2_WKTDraw Draw a multipolygon -A multipolygon can be visualized by calling the \link PkgPolygonRepair2Ref +A multipolygon with holes can be visualized by calling the \link PkgPolygonRepair2Ref CGAL::draw() \endlink function as shown in the following example. This function opens a new window showing the given polygon. A call to this function is blocking, that is the program continues as soon as the user closes the window. Versions for polygons and polygons with holes also exist, cf. \link PkgDrawPolygon2 CGAL::draw

() \endlink and \link PkgDrawPolygonWithHoles2 CGAL::draw() \endlink. -The multipolygon shown in this example is created using the well-known text (WKT) reader, -which can read and write multipolygons. +The multipolygon with holes shown in this example is created using the well-known text +(WKT) reader, which can read and write multipolygons with holes. \cgalExample{Polygon_repair_2/draw_multipolygon.cpp} -This function requires `CGAL_Qt5`, and is only available if the macro `CGAL_USE_BASIC_VIEWER` -is defined. Linking with the cmake target `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` -and add the definition `CGAL_USE_BASIC_VIEWER`. +This function requires `CGAL_Qt5`, and is only available if the macro +`CGAL_USE_BASIC_VIEWER` is defined. Linking with the cmake target +`CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` and add the definition +`CGAL_USE_BASIC_VIEWER`. \cgalFigureBegin{draw_multipolygon, draw_multipolygon.png} Result of the run of the draw_multipolygon program. A window shows the multipolygon -and allows to navigate through the scene. +with holes and allows to navigate through the scene. \cgalFigureEnd \subsection SubsectionPolygonRepair2_Repair Repairing a (multi)polygon +\cgalFigureBegin{bridge_edge, bridge_edge.png} +(a) Before repair (b) After repair +\cgalFigureEnd + \cgalExample{Polygon_repair_2/repair_polygon_2.cpp} \subsection SubsectionPolygonRepair2_RepairHiddenApi Step by step repairing +\cgalExample{Polygon_repair_2/write_labeled_triangulation.cpp} + \section SectionPolygonRepair2_Performance Performance */ diff --git a/Polygon_repair_2/doc/Polygon_repair_2/examples.txt b/Polygon_repair_2/doc/Polygon_repair_2/examples.txt index c3d2195f5d89..b1318b5691ee 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/examples.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/examples.txt @@ -1,3 +1,6 @@ /*! +\example Polygon_repair_2/multipolygon.cpp +\example Polygon_repair_2/draw_multipolygon.cpp \example Polygon_repair_2/repair_polygon_2.cpp +\example Polygon_repair_2/write_labeled_triangulation.cpp */ diff --git a/Polygon_repair_2/examples/Polygon_repair_2/data/nesting-spike.wkt b/Polygon_repair_2/examples/Polygon_repair_2/data/nesting-spike.wkt new file mode 100644 index 000000000000..e0df5a0dc7d8 --- /dev/null +++ b/Polygon_repair_2/examples/Polygon_repair_2/data/nesting-spike.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0.1 0.1,0.9 0.1,0.9 0.9,0.1 0.9,0.1 0.1)),((0.2 0.2,2 1,0.2 0.2,0.8 0.2,0.8 0.8,0.2 0.8,0.2 0.2),(0.3 0.3,0.7 0.3,0.7 0.7,0.3 0.7,0.3 0.3))) \ No newline at end of file diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp new file mode 100644 index 000000000000..89b4580519dd --- /dev/null +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -0,0 +1,27 @@ +#include +#include + +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_2 = Kernel::Point_2; +using Polygon_2 = CGAL::Polygon_2; +using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; + +int main(int argc, char* argv[]) { + std::ifstream in("data/bridge-edge.wkt"); + Polygon_with_holes_2 pin; + CGAL::IO::read_polygon_WKT(in, pin); + + Multipolygon_with_holes_2 mp = CGAL::Polygon_repair_2::repair_odd_even(pin); + if (mp.number_of_polygons() > 1) { + CGAL::IO::write_multi_polygon_WKT(std::cout, mp); + } else { + CGAL::IO::write_polygon_WKT(std::cout, mp.polygons()[0]); + } + + return 0; +} diff --git a/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp b/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp index d7e8333d075f..3dde85eb920a 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp @@ -1,7 +1,5 @@ #include #include -#include -#include #include #include @@ -16,68 +14,48 @@ using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; int main(int argc, char* argv[]) { - // std::ifstream ifs("/Users/ken/Downloads/180927.wkt"); - // std::ofstream ofs("/Users/ken/Downloads/2.geojson"); + std::ifstream ifs("data/nesting-spike.wkt"); - // std::ifstream ifs("/Users/ken/Downloads/2018418.wkt"); - // std::ofstream ofs("/Users/ken/Downloads/1.geojson"); + Multipolygon_with_holes_2 mp; + CGAL::IO::read_multi_polygon_WKT(ifs, mp); - std::ifstream ifs("../../test/Polygon_repair_2/data/in/nesting-spike.wkt"); - std::ofstream ofs("/Users/ken/Downloads/triangulation.geojson"); - - std::string in; - std::getline(ifs, in); - std::istringstream iss(in); Polygon_repair_2 pr; + pr.add_to_triangulation_odd_even(mp); + pr.label_triangulation_odd_even(); - if (in.find("POLYGON") == 0) { - Polygon_with_holes_2 p; - if (in != "POLYGON()") { // maybe should be checked in WKT reader - CGAL::IO::read_polygon_WKT(iss, p); - } pr.add_to_triangulation_odd_even(p); - } else if (in.find("MULTIPOLYGON") == 0) { - Multipolygon_with_holes_2 mp; - CGAL::IO::read_multi_polygon_WKT(iss, mp); - pr.add_to_triangulation_odd_even(mp); - } pr.label_triangulation_odd_even(); - - // ofs << std::fixed; - // ofs << std::setprecision(15); - - ofs << "{" << std::endl; - ofs << "\t\"type\": \"FeatureCollection\"," << std::endl; - ofs << "\t\"features\": [" << std::endl; + std::cout << "{" << std::endl; + std::cout << "\t\"type\": \"FeatureCollection\"," << std::endl; + std::cout << "\t\"features\": [" << std::endl; for (Polygon_repair_2::Triangulation::Finite_faces_iterator face = pr.triangulation().finite_faces_begin(); face != pr.triangulation().finite_faces_end(); ++face) { - ofs << "\t\t{" << std::endl; - ofs << "\t\t\t\"type\": \"Feature\"," << std::endl; - ofs << "\t\t\t\"properties\": {" << std::endl; - ofs << "\t\t\t\t\"label\": " << face->label() << std::endl; - ofs << "\t\t\t}," << std::endl; - ofs << "\t\t\t\"geometry\": {" << std::endl; - ofs << "\t\t\t\t\"type\": \"Polygon\"," << std::endl; - ofs << "\t\t\t\t\"coordinates\": [" << std::endl; - ofs << "\t\t\t\t\t[" << std::endl; - ofs << "\t\t\t\t\t\t[" << face->vertex(0)->point().x() << ", " << face->vertex(0)->point().y() << "]," << std::endl; - ofs << "\t\t\t\t\t\t[" << face->vertex(1)->point().x() << ", " << face->vertex(1)->point().y() << "]," << std::endl; - ofs << "\t\t\t\t\t\t[" << face->vertex(2)->point().x() << ", " << face->vertex(2)->point().y() << "]" << std::endl; - ofs << "\t\t\t\t\t]" << std::endl; - ofs << "\t\t\t\t]" << std::endl; - ofs << "\t\t\t}" << std::endl; - ofs << "\t\t}"; + std::cout << "\t\t{" << std::endl; + std::cout << "\t\t\t\"type\": \"Feature\"," << std::endl; + std::cout << "\t\t\t\"properties\": {" << std::endl; + std::cout << "\t\t\t\t\"label\": " << face->label() << std::endl; + std::cout << "\t\t\t}," << std::endl; + std::cout << "\t\t\t\"geometry\": {" << std::endl; + std::cout << "\t\t\t\t\"type\": \"Polygon\"," << std::endl; + std::cout << "\t\t\t\t\"coordinates\": [" << std::endl; + std::cout << "\t\t\t\t\t[" << std::endl; + std::cout << "\t\t\t\t\t\t[" << face->vertex(0)->point().x() << ", " << face->vertex(0)->point().y() << "]," << std::endl; + std::cout << "\t\t\t\t\t\t[" << face->vertex(1)->point().x() << ", " << face->vertex(1)->point().y() << "]," << std::endl; + std::cout << "\t\t\t\t\t\t[" << face->vertex(2)->point().x() << ", " << face->vertex(2)->point().y() << "]" << std::endl; + std::cout << "\t\t\t\t\t]" << std::endl; + std::cout << "\t\t\t\t]" << std::endl; + std::cout << "\t\t\t}" << std::endl; + std::cout << "\t\t}"; Polygon_repair_2::Triangulation::Finite_faces_iterator next_face = face; ++next_face; - if (next_face != pr.triangulation().finite_faces_end()) ofs << ","; - ofs << std::endl; + if (next_face != pr.triangulation().finite_faces_end()) std::cout << ","; + std::cout << std::endl; } - ofs << "\t]" << std::endl; - ofs << "}" << std::endl; + std::cout << "\t]" << std::endl; + std::cout << "}" << std::endl; pr.reconstruct_multipolygon(); - Multipolygon_with_holes_2 rmp = pr.multipolygon(); - CGAL::IO::write_multi_polygon_WKT(std::cout, rmp); + Multipolygon_with_holes_2 repaired = pr.multipolygon(); return 0; } From edfa1902162982211a7d143e7574d0fa351640d2 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 22 Aug 2023 13:59:16 +0200 Subject: [PATCH 078/182] more of the manual --- .../doc/Polygon_repair_2/Polygon_repair_2.txt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index e3ecf4f287d1..a648cf1b0315 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -89,6 +89,8 @@ an inner boundary. FIGURE +STEPS IN DETAIL + For the purposes of the repair operation, the input polygon, polygon with holes or multipolygon is merely used as a container of input line segments. @@ -157,14 +159,29 @@ with holes and allows to navigate through the scene. \subsection SubsectionPolygonRepair2_Repair Repairing a (multi)polygon +It's possible to repair a polygon, polygon with holes or multipolygon with holes +using the odd-even rule by calling the `repair_odd_even` function as shown in the +following example. This function returns a repaired multipolygon with holes. + \cgalFigureBegin{bridge_edge, bridge_edge.png} -(a) Before repair (b) After repair +(a) Before repair: A polygon with a single loop that implicitly creates a hole +using a bridge edge (b) After repair: the same area represented as a polygon with +a hole. \cgalFigureEnd \cgalExample{Polygon_repair_2/repair_polygon_2.cpp} \subsection SubsectionPolygonRepair2_RepairHiddenApi Step by step repairing +The following example shows to do the repair process step by step, including how +to extract the labeled triangulation, which is written as a GeoJSON file consisting +of the individual triangles with their labels. + +\cgalFigureBegin{triangulation, triangulation.png} +(a) A multipolygon consisting of two polygons with one hole each, where one polygon +is inside the hole of the other (b) The labeled triangulation of the multipolygon +\cgalFigureEnd + \cgalExample{Polygon_repair_2/write_labeled_triangulation.cpp} \section SectionPolygonRepair2_Performance Performance From f35625944af0b2e19619018702f35f8857cd400c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 23 Aug 2023 15:57:15 +0200 Subject: [PATCH 079/182] more details about algorithm --- .../doc/Polygon_repair_2/Polygon_repair_2.txt | 82 ++++++++++++------- .../Polygon_repair_2/repair_polygon_2.cpp | 2 +- 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt index a648cf1b0315..2dd4f985ec89 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt @@ -19,6 +19,10 @@ The method returns a valid output stored in a multipolygon with holes. Different triangulation and labelling heuristics are possible, but currently only the odd-even heuristic is implemented in the package. +This heuristic results in areas that are alternately assigned as polygon +interiors and exterior/holes each time that an input edge is passed. +It doesn't distinguish between edges that are part of outer boundaries +from those of inner boundaries. \section SectionPolygonRepair2_Definitions Definitions @@ -35,7 +39,7 @@ that is bounded by one outer boundary and zero or more inner boundaries, where each inner boundary represents a hole in the polygon. Considered independently, each boundary should be simple. The different boundaries of a polygon are allowed to intersect tangentially at their common vertices (with no common -edges), forming vertices with degrees larger than two at the tangential points. +edges), forming vertices with degrees of a multiple of two the tangential points. The interior of a polygon with holes should form a connected point set. Note that a valid polygon can also be represented as a valid polygon with holes (where the number of holes is zero). @@ -45,9 +49,12 @@ that is represented by a set of zero or more valid polygons with holes. The interiors of the polygons with holes should be pairwise disjoint, but they are allowed to intersect tangentially at their common vertices. Note that a valid polygon with holes can also be represented as a valid multipolygon -with holes. +with holes (with only one polygon). -FIGURE +\cgalFigureBegin{multipolygons, multipolygons.png} +Valid: (a) polygon, (b-c) polygons with holes, (d-e) multipolygons with holes. +(c) and (e) show cases where boundaries intersect tangentially at a single vertex. +\cgalFigureEnd \subsection SubsectionPolygonRepair2_Output Stricter Conditions for Output @@ -60,7 +67,7 @@ strict criteria: - Adjacent collinear edges touching at vertices of degree two are merged - The sequence of vertices representing a boundary starts from its lexicographically smallest vertex -- Outer boundaries are oriented counterclockwise and inner boundaries are +- Outer boundaries are oriented counter-clockwise and inner boundaries are oriented clockwise - The inner boundaries of a polygon with holes are stored in lexicographic order @@ -82,17 +89,55 @@ labeled as the exterior. -# Reconstruction of the multipolygon: each boundary of each polygon with holes is reconstructed by finding a polygon interior triangle that is adjacent to the exterior or a hole, then following the boundary in an -orientation that is counterclockwise for outer boundaries and clockwise for +orientation that is counter-clockwise for outer boundaries and clockwise for inner boundaries. This orientation and the polygon interior id is used to determine what polygon with holes it belongs to and whether it is an outer or an inner boundary. FIGURE -STEPS IN DETAIL +\subsection SubsectionPolygonRepair2_Triangulation Constrained triangulation For the purposes of the repair operation, the input polygon, polygon with holes -or multipolygon is merely used as a container of input line segments. +or multipolygon is merely used as a container of input line segments. These line +segments are added to the constrained triangulation as constraints. + +With the odd-even heuristic, only the edges that are present an odd number of +times in the input will be constrained edges in the triangulation. +When these edges are only partially overlapping, only the parts that overlap +an odd number of times will be constrained edges in the triangulation. + +This procedure is done in two steps: 1. preprocessing to eliminate identical +edges that are present an even number of times, and 2. an odd-even constraint +counting mechanism that erases existing constraints when new overlapping ones +are added. + +\subsection SubsectionPolygonRepair2_Labeling Labeling + +First, all of the polygon exterior is labeled. For this, the faces that can be +accessed by following the adjacency relationships from the infinite face without +passing through a constrained edge are labeled as exterior faces. + +Then, with the odd-even heuristic, groups of faces that are adjacent to each other +without passing through a constrained edge are labeled. The label applied alternates +between polygon interior and hole every time that a constrained edge is passed. + +\subsection SubsectionPolygonRepair2_Reconstruction Reconstruction of the multipolygon + +The algorithm reconstructs the multipolygon boundary by boundary, repeating the +process until all boundaries have been reconstructed. +Starting from a triangulation face with a polygon interior label that is adjacent +to a face with an exterior or hole label, the boundary of the polygon that contains +the edge between the two triangles is reconstructed. +The successive edges of the boundary is obtained by rotating counter-clockwise +around their common vertex, resulting in counter-clockwise cycles for outer +boundaries and clockwise cycles for inner boundaries. + +Finally, the boundaries are assembled into multipolygons using the unique labels +to know which polygon inner/outer boundaries belong to, and using the orientation +to distinguish between outer and inner boundaries. + +\subsection SubsectionPolygonRepair2_Output Notes on the Output If the input is already valid, the method will return a valid output representing the same area. However, the output might be different in order to conform to the @@ -102,27 +147,8 @@ stricter conditions to generate deterministic output (see Also, it is worth noting that even the repair of a single polygon without holes but with self-intersections can result in a multipolygon with holes. This is why the repair function will always return a multipolygon with holes. The user can -then check whether it consists of a single polygon with holes, and whether this -polygon with holes has zero holes and treat it appropriately. - -\subsection SubsectionPolygonRepair2_OddEven Odd-even repair - -The odd-even repair heuristic results in areas that are alternatingly assigned -as polygon interiors and exterior/holes each time that an input edge is passed. -It doesn't distinguish between edges that are part of outer boundaries or inner -boundaries. - -FIGURE - -In order to generate consistent output, the odd-even heuristic requires it to be -applied to both edges and faces. For the edges, this heuristic means that only -the line segments that are present an odd number of times in the input will be -constrained edges in the triangulation. For the face labels, this heuristic means -that after the exterior faces have been labeled, the other faces will be -alternatingly labeled with polygon interior and hole ids every time that a -constrained edge is passed. - -FIGURE +then check whether it consists of a single polygon with holes, and if a polygon +with holes has zero holes and extract these if needed. \section SectionPolygonRepair2_Examples Examples diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp index 89b4580519dd..06d0ccdbd125 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp @@ -22,6 +22,6 @@ int main(int argc, char* argv[]) { } else { CGAL::IO::write_polygon_WKT(std::cout, mp.polygons()[0]); } - + return 0; } From 6c703f7fd82c4d1778ee34900187b40641c911dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 24 Aug 2023 13:35:51 +0200 Subject: [PATCH 080/182] Polygon_repair_2 -> Polygon_repair --- Documentation/doc/Documentation/packages.txt | 2 +- .../{Polygon_repair_2.h => Polygon_repair.h} | 20 +++++----- .../Concepts/MultiPolygonWithHoles_2.h | 2 +- .../doc/Polygon_repair}/Doxyfile.in | 0 .../Polygon_repair}/PackageDescription.txt | 24 +++++------ .../doc/Polygon_repair/Polygon_repair.txt | 40 +++++++++---------- .../doc/Polygon_repair}/dependencies | 0 .../doc/Polygon_repair/examples.txt | 6 +++ .../examples/Polygon_repair}/CMakeLists.txt | 2 +- .../Polygon_repair}/data/bridge-edge.wkt | 0 .../Polygon_repair}/data/nesting-spike.wkt | 0 .../Polygon_repair}/draw_multipolygon.cpp | 2 +- .../examples/Polygon_repair}/multipolygon.cpp | 2 +- .../Polygon_repair}/nasty_polygons.cpp | 6 +-- .../Polygon_repair}/repair_polygon_2.cpp | 4 +- .../write_labeled_triangulation.cpp | 10 ++--- .../Multipolygon_with_holes_2.h | 4 +- .../CGAL/Polygon_repair/Polygon_repair.h | 40 +++++++++---------- ...iangulation_face_base_with_repair_info_2.h | 2 +- ...riangulation_with_odd_even_constraints_2.h | 4 +- .../draw_multipolygon_with_holes_2.h | 4 +- .../package_info/Polygon_repair}/copyright | 0 .../package_info/Polygon_repair}/dependencies | 2 +- .../Polygon_repair/description.txt | 1 + .../package_info/Polygon_repair}/license.txt | 0 .../Polygon_repair}/long_description.txt | 0 .../package_info/Polygon_repair}/maintainer | 0 .../test/Polygon_repair}/CMakeLists.txt | 2 +- .../test/Polygon_repair}/clipart.cpp | 12 +++--- .../data/in/back-and-forth.wkt | 0 .../test/Polygon_repair}/data/in/bowtie.wkt | 0 .../Polygon_repair}/data/in/bridge-edge.wkt | 0 .../data/in/crossing-polygons-nesting.wkt | 0 .../data/in/crossing-polygons.wkt | 0 .../test/Polygon_repair}/data/in/edge.wkt | 0 .../data/in/empty-multipolygon.wkt | 0 .../Polygon_repair}/data/in/empty-polygon.wkt | 0 .../test/Polygon_repair}/data/in/hole-all.wkt | 0 .../Polygon_repair}/data/in/hole-as-loop.wkt | 0 .../Polygon_repair}/data/in/hole-carved.wkt | 0 .../Polygon_repair}/data/in/hole-filled.wkt | 0 .../Polygon_repair}/data/in/hole-outside.wkt | 0 .../data/in/hole-partly-outside.wkt | 0 .../data/in/hole-touching-edge.wkt | 0 .../data/in/hole-touching-once.wkt | 0 .../data/in/hole-touching-twice.wkt | 0 .../test/Polygon_repair}/data/in/hole.wkt | 0 .../Polygon_repair}/data/in/nesting-spike.wkt | 0 .../test/Polygon_repair}/data/in/nesting.wkt | 0 .../Polygon_repair}/data/in/not-closed.wkt | 0 .../data/in/overlapping-edge-inside.wkt | 0 .../data/in/overlapping-edge-partial.wkt | 0 .../data/in/overlapping-edge.wkt | 0 .../Polygon_repair}/data/in/point-double.wkt | 0 .../test/Polygon_repair}/data/in/point.wkt | 0 .../data/in/spike-boundary.wkt | 0 .../test/Polygon_repair}/data/in/spike-in.wkt | 0 .../Polygon_repair}/data/in/spike-long.wkt | 0 .../Polygon_repair}/data/in/spike-out.wkt | 0 .../Polygon_repair}/data/in/spikes-fp.wkt | 0 .../test/Polygon_repair}/data/in/spikes.wkt | 0 .../test/Polygon_repair}/data/in/spiral.wkt | 0 .../data/in/square-hole-rhombus.wkt | 0 .../test/Polygon_repair}/data/in/square.wkt | 0 .../test/Polygon_repair}/data/in/star.wkt | 0 .../data/ref/back-and-forth.wkt | 0 .../test/Polygon_repair}/data/ref/bowtie.wkt | 0 .../Polygon_repair}/data/ref/bridge-edge.wkt | 0 .../data/ref/crossing-polygons-nesting.wkt | 0 .../data/ref/crossing-polygons.wkt | 0 .../test/Polygon_repair}/data/ref/edge.wkt | 0 .../data/ref/empty-multipolygon.wkt | 0 .../data/ref/empty-polygon.wkt | 0 .../Polygon_repair}/data/ref/hole-all.wkt | 0 .../Polygon_repair}/data/ref/hole-as-loop.wkt | 0 .../Polygon_repair}/data/ref/hole-carved.wkt | 0 .../Polygon_repair}/data/ref/hole-filled.wkt | 0 .../Polygon_repair}/data/ref/hole-outside.wkt | 0 .../data/ref/hole-partly-outside.wkt | 0 .../data/ref/hole-touching-edge.wkt | 0 .../data/ref/hole-touching-once.wkt | 0 .../data/ref/hole-touching-twice.wkt | 0 .../test/Polygon_repair}/data/ref/hole.wkt | 0 .../data/ref/nesting-spike.wkt | 0 .../test/Polygon_repair}/data/ref/nesting.wkt | 0 .../Polygon_repair}/data/ref/not-closed.wkt | 0 .../data/ref/overlapping-edge-inside.wkt | 0 .../data/ref/overlapping-edge-partial.wkt | 0 .../data/ref/overlapping-edge.wkt | 0 .../Polygon_repair}/data/ref/point-double.wkt | 0 .../test/Polygon_repair}/data/ref/point.wkt | 0 .../data/ref/spike-boundary.wkt | 0 .../Polygon_repair}/data/ref/spike-in.wkt | 0 .../Polygon_repair}/data/ref/spike-long.wkt | 0 .../Polygon_repair}/data/ref/spike-out.wkt | 0 .../Polygon_repair}/data/ref/spikes-fp.wkt | 0 .../test/Polygon_repair}/data/ref/spikes.wkt | 0 .../test/Polygon_repair}/data/ref/spiral.wkt | 0 .../data/ref/square-hole-rhombus.wkt | 0 .../test/Polygon_repair}/data/ref/square.wkt | 0 .../test/Polygon_repair}/data/ref/star.wkt | 0 .../Polygon_repair}/draw_test_polygons.cpp | 10 ++--- .../Polygon_repair}/repair_polygon_2_test.cpp | 8 ++-- .../doc/Polygon_repair_2/examples.txt | 6 --- .../Polygon_repair_2/description.txt | 1 - .../examples/Stream_support/Polygon_WKT.cpp | 2 +- Stream_support/include/CGAL/IO/WKT.h | 2 +- .../package_info/Stream_support/dependencies | 2 +- 108 files changed, 111 insertions(+), 111 deletions(-) rename Installation/include/CGAL/license/{Polygon_repair_2.h => Polygon_repair.h} (68%) rename {Polygon_repair_2/doc/Polygon_repair_2 => Polygon_repair/doc/Polygon_repair}/Concepts/MultiPolygonWithHoles_2.h (97%) rename {Polygon_repair_2/doc/Polygon_repair_2 => Polygon_repair/doc/Polygon_repair}/Doxyfile.in (100%) rename {Polygon_repair_2/doc/Polygon_repair_2 => Polygon_repair/doc/Polygon_repair}/PackageDescription.txt (65%) rename Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt => Polygon_repair/doc/Polygon_repair/Polygon_repair.txt (88%) rename {Polygon_repair_2/doc/Polygon_repair_2 => Polygon_repair/doc/Polygon_repair}/dependencies (100%) create mode 100644 Polygon_repair/doc/Polygon_repair/examples.txt rename {Polygon_repair_2/examples/Polygon_repair_2 => Polygon_repair/examples/Polygon_repair}/CMakeLists.txt (93%) rename {Polygon_repair_2/examples/Polygon_repair_2 => Polygon_repair/examples/Polygon_repair}/data/bridge-edge.wkt (100%) rename {Polygon_repair_2/examples/Polygon_repair_2 => Polygon_repair/examples/Polygon_repair}/data/nesting-spike.wkt (100%) rename {Polygon_repair_2/examples/Polygon_repair_2 => Polygon_repair/examples/Polygon_repair}/draw_multipolygon.cpp (90%) rename {Polygon_repair_2/examples/Polygon_repair_2 => Polygon_repair/examples/Polygon_repair}/multipolygon.cpp (94%) rename {Polygon_repair_2/examples/Polygon_repair_2 => Polygon_repair/examples/Polygon_repair}/nasty_polygons.cpp (94%) rename {Polygon_repair_2/examples/Polygon_repair_2 => Polygon_repair/examples/Polygon_repair}/repair_polygon_2.cpp (85%) rename {Polygon_repair_2/examples/Polygon_repair_2 => Polygon_repair/examples/Polygon_repair}/write_labeled_triangulation.cpp (86%) rename {Polygon_repair_2/include/CGAL/Polygon_repair_2 => Polygon_repair/include/CGAL/Polygon_repair}/Multipolygon_with_holes_2.h (98%) rename Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h => Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h (95%) rename {Polygon_repair_2/include/CGAL/Polygon_repair_2 => Polygon_repair/include/CGAL/Polygon_repair}/Triangulation_face_base_with_repair_info_2.h (97%) rename {Polygon_repair_2/include/CGAL/Polygon_repair_2 => Polygon_repair/include/CGAL/Polygon_repair}/Triangulation_with_odd_even_constraints_2.h (98%) rename {Polygon_repair_2/include/CGAL/Polygon_repair_2 => Polygon_repair/include/CGAL/Polygon_repair}/draw_multipolygon_with_holes_2.h (98%) rename {Polygon_repair_2/package_info/Polygon_repair_2 => Polygon_repair/package_info/Polygon_repair}/copyright (100%) rename {Polygon_repair_2/package_info/Polygon_repair_2 => Polygon_repair/package_info/Polygon_repair}/dependencies (95%) create mode 100644 Polygon_repair/package_info/Polygon_repair/description.txt rename {Polygon_repair_2/package_info/Polygon_repair_2 => Polygon_repair/package_info/Polygon_repair}/license.txt (100%) rename {Polygon_repair_2/package_info/Polygon_repair_2 => Polygon_repair/package_info/Polygon_repair}/long_description.txt (100%) rename {Polygon_repair_2/package_info/Polygon_repair_2 => Polygon_repair/package_info/Polygon_repair}/maintainer (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/CMakeLists.txt (94%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/clipart.cpp (92%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/back-and-forth.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/bowtie.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/bridge-edge.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/crossing-polygons-nesting.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/crossing-polygons.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/edge.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/empty-multipolygon.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/empty-polygon.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/hole-all.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/hole-as-loop.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/hole-carved.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/hole-filled.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/hole-outside.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/hole-partly-outside.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/hole-touching-edge.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/hole-touching-once.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/hole-touching-twice.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/hole.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/nesting-spike.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/nesting.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/not-closed.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/overlapping-edge-inside.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/overlapping-edge-partial.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/overlapping-edge.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/point-double.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/point.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/spike-boundary.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/spike-in.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/spike-long.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/spike-out.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/spikes-fp.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/spikes.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/spiral.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/square-hole-rhombus.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/square.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/in/star.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/back-and-forth.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/bowtie.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/bridge-edge.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/crossing-polygons-nesting.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/crossing-polygons.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/edge.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/empty-multipolygon.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/empty-polygon.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/hole-all.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/hole-as-loop.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/hole-carved.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/hole-filled.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/hole-outside.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/hole-partly-outside.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/hole-touching-edge.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/hole-touching-once.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/hole-touching-twice.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/hole.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/nesting-spike.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/nesting.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/not-closed.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/overlapping-edge-inside.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/overlapping-edge-partial.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/overlapping-edge.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/point-double.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/point.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/spike-boundary.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/spike-in.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/spike-long.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/spike-out.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/spikes-fp.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/spikes.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/spiral.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/square-hole-rhombus.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/square.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/data/ref/star.wkt (100%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/draw_test_polygons.cpp (83%) rename {Polygon_repair_2/test/Polygon_repair_2 => Polygon_repair/test/Polygon_repair}/repair_polygon_2_test.cpp (90%) delete mode 100644 Polygon_repair_2/doc/Polygon_repair_2/examples.txt delete mode 100644 Polygon_repair_2/package_info/Polygon_repair_2/description.txt diff --git a/Documentation/doc/Documentation/packages.txt b/Documentation/doc/Documentation/packages.txt index d89ade951422..7002020a1a07 100644 --- a/Documentation/doc/Documentation/packages.txt +++ b/Documentation/doc/Documentation/packages.txt @@ -31,7 +31,7 @@ \cgalPackageSection{PartPolygons,Polygons} \package_listing{Polygon} -\package_listing{Polygon_repair_2} +\package_listing{Polygon_repair} \package_listing{Boolean_set_operations_2} \package_listing{Nef_2} \package_listing{Nef_S2} diff --git a/Installation/include/CGAL/license/Polygon_repair_2.h b/Installation/include/CGAL/license/Polygon_repair.h similarity index 68% rename from Installation/include/CGAL/license/Polygon_repair_2.h rename to Installation/include/CGAL/license/Polygon_repair.h index 11c0f94e3c5a..b1fc77cedb6a 100644 --- a/Installation/include/CGAL/license/Polygon_repair_2.h +++ b/Installation/include/CGAL/license/Polygon_repair.h @@ -11,15 +11,15 @@ // // Warning: this file is generated, see include/CGAL/license/README.md -#ifndef CGAL_LICENSE_POLYGON_REPAIR_2_H -#define CGAL_LICENSE_POLYGON_REPAIR_2_H +#ifndef CGAL_LICENSE_POLYGON_REPAIR_H +#define CGAL_LICENSE_POLYGON_REPAIR_H #include #include -#ifdef CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE +#ifdef CGAL_POLYGON_REPAIR_COMMERCIAL_LICENSE -# if CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE +# if CGAL_POLYGON_REPAIR_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE # if defined(CGAL_LICENSE_WARNING) @@ -33,22 +33,22 @@ You get this error, as you defined CGAL_LICENSE_ERROR." # endif // CGAL_LICENSE_ERROR -# endif // CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE +# endif // CGAL_POLYGON_REPAIR_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE -#else // no CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE +#else // no CGAL_POLYGON_REPAIR_COMMERCIAL_LICENSE # if defined(CGAL_LICENSE_WARNING) - CGAL_pragma_warning("\nThe macro CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE is not defined." + CGAL_pragma_warning("\nThe macro CGAL_POLYGON_REPAIR_COMMERCIAL_LICENSE is not defined." "\nYou use the CGAL 2D Polygon Repair package under " "the terms of the GPLv3+.") # endif // CGAL_LICENSE_WARNING # ifdef CGAL_LICENSE_ERROR -# error "The macro CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE is not defined.\ +# error "The macro CGAL_POLYGON_REPAIR_COMMERCIAL_LICENSE is not defined.\ You use the CGAL 2D Polygon Repair package under the terms of \ the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." # endif // CGAL_LICENSE_ERROR -#endif // no CGAL_POLYGON_REPAIR_2_COMMERCIAL_LICENSE +#endif // no CGAL_POLYGON_REPAIR_COMMERCIAL_LICENSE -#endif // CGAL_LICENSE_POLYGON_REPAIR_2_H +#endif // CGAL_LICENSE_POLYGON_REPAIR_H diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h b/Polygon_repair/doc/Polygon_repair/Concepts/MultiPolygonWithHoles_2.h similarity index 97% rename from Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h rename to Polygon_repair/doc/Polygon_repair/Concepts/MultiPolygonWithHoles_2.h index 1054217ddce7..d7f037be4d6d 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon_repair/doc/Polygon_repair/Concepts/MultiPolygonWithHoles_2.h @@ -1,4 +1,4 @@ -/*! \ingroup PkgPolygonRepair2Concepts +/*! \ingroup PkgPolygonRepairConcepts * \cgalConcept * * \cgalRefines{CopyConstructible,Assignable,DefaultConstructible} diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in b/Polygon_repair/doc/Polygon_repair/Doxyfile.in similarity index 100% rename from Polygon_repair_2/doc/Polygon_repair_2/Doxyfile.in rename to Polygon_repair/doc/Polygon_repair/Doxyfile.in diff --git a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt similarity index 65% rename from Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt rename to Polygon_repair/doc/Polygon_repair/PackageDescription.txt index e74c1ef034f8..4259a9f0808f 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/PackageDescription.txt +++ b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt @@ -1,12 +1,12 @@ // PRETTY PACKAGE NAME should equal the project title in Doxyfile.in -/// \defgroup PkgPolygonRepair2Ref 2D Polygon Repair Reference +/// \defgroup PkgPolygonRepairRef 2D Polygon Repair Reference -/// \defgroup PkgPolygonRepair2Concepts Concepts -/// \ingroup PkgPolygonRepair2Ref +/// \defgroup PkgPolygonRepairConcepts Concepts +/// \ingroup PkgPolygonRepairRef -/// \defgroup PkgPolygonRepair2Functions Functions -/// \ingroup PkgPolygonRepair2Ref +/// \defgroup PkgPolygonRepairFunctions Functions +/// \ingroup PkgPolygonRepairRef /*! \code @@ -14,19 +14,19 @@ \endcode */ /// \defgroup PkgDrawMultipolygonWithHoles2 Draw a 2D Multipolygon with holes -/// \ingroup PkgPolygonRepair2Ref +/// \ingroup PkgPolygonRepairRef /*! -\addtogroup PkgPolygonRepair2Ref +\addtogroup PkgPolygonRepairRef \todo check generated documentation -\cgalPkgDescriptionBegin{2D Polygon Repair,PkgPolygonRepair2} -\cgalPkgPicture{Polygon_repair_2-small.png} +\cgalPkgDescriptionBegin{2D Polygon Repair,PkgPolygonRepair} +\cgalPkgPicture{Polygon_repair-small.png} \cgalPkgSummaryBegin \cgalPkgAuthors{Ken Arroyo Ohori} \cgalPkgDesc{The package provides a 2D multipolygon class and algorithms to repair 2D (multi)polygons. } -\cgalPkgManuals{Chapter_2D_Polygon_repair,PkgPolygonRepair2Ref} +\cgalPkgManuals{Chapter_2D_Polygon_repair,PkgPolygonRepairRef} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin @@ -46,10 +46,10 @@ \cgalCRPSection{Classes} - `CGAL::Multipolygon_with_holes_2` -- `CGAL::Polygon_repair_2` +- `CGAL::Polygon_repair` \cgalCRPSection{Functions} -- `CGAL::Polygon_repair_2::repair()` +- `CGAL::Polygon_repair::repair()` \cgalCRPSection{Draw a Multipolygon_with_holes_2} - \link PkgDrawMultipolygonWithHoles2 CGAL::draw() \endlink diff --git a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt similarity index 88% rename from Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt rename to Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 2dd4f985ec89..53dd72489cd1 100644 --- a/Polygon_repair_2/doc/Polygon_repair_2/Polygon_repair_2.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -7,7 +7,7 @@ namespace CGAL { \cgalAutoToc \author Ken Arroyo Ohori -\section SectionPolygonRepair2_Introduction Introduction +\section SectionPolygonRepair_Introduction Introduction This package implements a polygon repair method based on a constrained triangulation \cgalCite{14cg}. Starting from a possibly invalid input @@ -24,7 +24,7 @@ interiors and exterior/holes each time that an input edge is passed. It doesn't distinguish between edges that are part of outer boundaries from those of inner boundaries. -\section SectionPolygonRepair2_Definitions Definitions +\section SectionPolygonRepair_Definitions Definitions - A valid polygon (without holes) is a point set in \f$ \mathbb{R}^2\f$ that is bounded by a cycle of linear edges, which is known as its @@ -56,7 +56,7 @@ Valid: (a) polygon, (b-c) polygons with holes, (d-e) multipolygons with holes. (c) and (e) show cases where boundaries intersect tangentially at a single vertex. \cgalFigureEnd -\subsection SubsectionPolygonRepair2_Output Stricter Conditions for Output +\subsection SubsectionPolygonRepair_Output Stricter Conditions for Output The conditions listed above are sufficient to define valid polygons, polygons with holes and multipolygons with holes for most applications. However, in @@ -74,7 +74,7 @@ order - The polygons with holes of a multipolygon with holes are also stored in lexicographic order -\section SectionPolygonRepair2_Algorithm Algorithm +\section SectionPolygonRepair_Algorithm Algorithm Broadly, the algorithm consists of three steps: @@ -96,7 +96,7 @@ an inner boundary. FIGURE -\subsection SubsectionPolygonRepair2_Triangulation Constrained triangulation +\subsection SubsectionPolygonRepair_Triangulation Constrained triangulation For the purposes of the repair operation, the input polygon, polygon with holes or multipolygon is merely used as a container of input line segments. These line @@ -112,7 +112,7 @@ edges that are present an even number of times, and 2. an odd-even constraint counting mechanism that erases existing constraints when new overlapping ones are added. -\subsection SubsectionPolygonRepair2_Labeling Labeling +\subsection SubsectionPolygonRepair_Labeling Labeling First, all of the polygon exterior is labeled. For this, the faces that can be accessed by following the adjacency relationships from the infinite face without @@ -122,7 +122,7 @@ Then, with the odd-even heuristic, groups of faces that are adjacent to each oth without passing through a constrained edge are labeled. The label applied alternates between polygon interior and hole every time that a constrained edge is passed. -\subsection SubsectionPolygonRepair2_Reconstruction Reconstruction of the multipolygon +\subsection SubsectionPolygonRepair_Reconstruction Reconstruction of the multipolygon The algorithm reconstructs the multipolygon boundary by boundary, repeating the process until all boundaries have been reconstructed. @@ -137,12 +137,12 @@ Finally, the boundaries are assembled into multipolygons using the unique labels to know which polygon inner/outer boundaries belong to, and using the orientation to distinguish between outer and inner boundaries. -\subsection SubsectionPolygonRepair2_Output Notes on the Output +\subsection SubsectionPolygonRepair_Notes Notes on the Output If the input is already valid, the method will return a valid output representing the same area. However, the output might be different in order to conform to the stricter conditions to generate deterministic output (see -\ref SubsectionPolygonRepair2_Output). +\ref SubsectionPolygonRepair_Output). Also, it is worth noting that even the repair of a single polygon without holes but with self-intersections can result in a multipolygon with holes. This is why @@ -150,18 +150,18 @@ the repair function will always return a multipolygon with holes. The user can then check whether it consists of a single polygon with holes, and if a polygon with holes has zero holes and extract these if needed. -\section SectionPolygonRepair2_Examples Examples +\section SectionPolygonRepair_Examples Examples -\subsection SubsectionPolygonRepair2_Multipolygon The multipolygon with holes class +\subsection SubsectionPolygonRepair_Multipolygon The multipolygon with holes class The following example shows the creation of a multipolygon with holes and the traversal of the polygons in it. -\cgalExample{Polygon_repair_2/multipolygon.cpp} +\cgalExample{Polygon_repair/multipolygon.cpp} -\subsection SubsectionPolygonRepair2_WKTDraw Draw a multipolygon +\subsection SubsectionPolygonRepair_WKTDraw Draw a multipolygon -A multipolygon with holes can be visualized by calling the \link PkgPolygonRepair2Ref +A multipolygon with holes can be visualized by calling the \link PkgPolygonRepairRef CGAL::draw() \endlink function as shown in the following example. This function opens a new window showing the given polygon. A call to this function is blocking, that is the program continues as soon as the user closes the window. @@ -171,7 +171,7 @@ CGAL::draw

() \endlink and \link PkgDrawPolygonWithHoles2 CGAL::draw() \en The multipolygon with holes shown in this example is created using the well-known text (WKT) reader, which can read and write multipolygons with holes. -\cgalExample{Polygon_repair_2/draw_multipolygon.cpp} +\cgalExample{Polygon_repair/draw_multipolygon.cpp} This function requires `CGAL_Qt5`, and is only available if the macro `CGAL_USE_BASIC_VIEWER` is defined. Linking with the cmake target @@ -183,7 +183,7 @@ Result of the run of the draw_multipolygon program. A window shows the multipoly with holes and allows to navigate through the scene. \cgalFigureEnd -\subsection SubsectionPolygonRepair2_Repair Repairing a (multi)polygon +\subsection SubsectionPolygonRepair_Repair Repairing a (multi)polygon It's possible to repair a polygon, polygon with holes or multipolygon with holes using the odd-even rule by calling the `repair_odd_even` function as shown in the @@ -195,9 +195,9 @@ using a bridge edge (b) After repair: the same area represented as a polygon wit a hole. \cgalFigureEnd -\cgalExample{Polygon_repair_2/repair_polygon_2.cpp} +\cgalExample{Polygon_repair/repair_polygon_2.cpp} -\subsection SubsectionPolygonRepair2_RepairHiddenApi Step by step repairing +\subsection SubsectionPolygonRepair_RepairHiddenApi Step by step repairing The following example shows to do the repair process step by step, including how to extract the labeled triangulation, which is written as a GeoJSON file consisting @@ -208,9 +208,9 @@ of the individual triangles with their labels. is inside the hole of the other (b) The labeled triangulation of the multipolygon \cgalFigureEnd -\cgalExample{Polygon_repair_2/write_labeled_triangulation.cpp} +\cgalExample{Polygon_repair/write_labeled_triangulation.cpp} -\section SectionPolygonRepair2_Performance Performance +\section SectionPolygonRepair_Performance Performance */ } /* namespace CGAL */ diff --git a/Polygon_repair_2/doc/Polygon_repair_2/dependencies b/Polygon_repair/doc/Polygon_repair/dependencies similarity index 100% rename from Polygon_repair_2/doc/Polygon_repair_2/dependencies rename to Polygon_repair/doc/Polygon_repair/dependencies diff --git a/Polygon_repair/doc/Polygon_repair/examples.txt b/Polygon_repair/doc/Polygon_repair/examples.txt new file mode 100644 index 000000000000..c0a827972362 --- /dev/null +++ b/Polygon_repair/doc/Polygon_repair/examples.txt @@ -0,0 +1,6 @@ +/*! +\example Polygon_repair/multipolygon.cpp +\example Polygon_repair/draw_multipolygon.cpp +\example Polygon_repair/repair_polygon_2.cpp +\example Polygon_repair/write_labeled_triangulation.cpp +*/ diff --git a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt b/Polygon_repair/examples/Polygon_repair/CMakeLists.txt similarity index 93% rename from Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt rename to Polygon_repair/examples/Polygon_repair/CMakeLists.txt index 417109e78275..930b4dc25676 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair/examples/Polygon_repair/CMakeLists.txt @@ -2,7 +2,7 @@ # This is the CMake script for compiling a CGAL application. cmake_minimum_required(VERSION 3.1...3.23) -project(Polygon_repair_2_Examples) +project(Polygon_repair_Examples) find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) diff --git a/Polygon_repair_2/examples/Polygon_repair_2/data/bridge-edge.wkt b/Polygon_repair/examples/Polygon_repair/data/bridge-edge.wkt similarity index 100% rename from Polygon_repair_2/examples/Polygon_repair_2/data/bridge-edge.wkt rename to Polygon_repair/examples/Polygon_repair/data/bridge-edge.wkt diff --git a/Polygon_repair_2/examples/Polygon_repair_2/data/nesting-spike.wkt b/Polygon_repair/examples/Polygon_repair/data/nesting-spike.wkt similarity index 100% rename from Polygon_repair_2/examples/Polygon_repair_2/data/nesting-spike.wkt rename to Polygon_repair/examples/Polygon_repair/data/nesting-spike.wkt diff --git a/Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp b/Polygon_repair/examples/Polygon_repair/draw_multipolygon.cpp similarity index 90% rename from Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp rename to Polygon_repair/examples/Polygon_repair/draw_multipolygon.cpp index d7ec18926ffa..3451b98de51a 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/draw_multipolygon.cpp +++ b/Polygon_repair/examples/Polygon_repair/draw_multipolygon.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; diff --git a/Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp b/Polygon_repair/examples/Polygon_repair/multipolygon.cpp similarity index 94% rename from Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp rename to Polygon_repair/examples/Polygon_repair/multipolygon.cpp index cc9b5df84179..ce0cdf27f411 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/multipolygon.cpp +++ b/Polygon_repair/examples/Polygon_repair/multipolygon.cpp @@ -1,5 +1,5 @@ #include -#include +#include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; using Point_2 = Kernel::Point_2; diff --git a/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp b/Polygon_repair/examples/Polygon_repair/nasty_polygons.cpp similarity index 94% rename from Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp rename to Polygon_repair/examples/Polygon_repair/nasty_polygons.cpp index 97ed92f25150..2e663b265f61 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/nasty_polygons.cpp +++ b/Polygon_repair/examples/Polygon_repair/nasty_polygons.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; @@ -12,7 +12,7 @@ using Point_2 = Kernel::Point_2; using Polygon_2 = CGAL::Polygon_2; using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; -using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; +using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; int main(int argc, char* argv[]) { @@ -27,7 +27,7 @@ int main(int argc, char* argv[]) { std::istringstream iss(in); Polygon_with_holes_2 p; CGAL::IO::read_polygon_WKT(iss, p); - Polygon_repair_2 pr; + Polygon_repair pr; pr.add_to_triangulation_odd_even(p); pr.label_triangulation_odd_even(); pr.reconstruct_multipolygon(); diff --git a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp similarity index 85% rename from Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp rename to Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp index 06d0ccdbd125..c8a91fb0c1b7 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/repair_polygon_2.cpp +++ b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; @@ -16,7 +16,7 @@ int main(int argc, char* argv[]) { Polygon_with_holes_2 pin; CGAL::IO::read_polygon_WKT(in, pin); - Multipolygon_with_holes_2 mp = CGAL::Polygon_repair_2::repair_odd_even(pin); + Multipolygon_with_holes_2 mp = CGAL::Polygon_repair::repair_odd_even(pin); if (mp.number_of_polygons() > 1) { CGAL::IO::write_multi_polygon_WKT(std::cout, mp); } else { diff --git a/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp b/Polygon_repair/examples/Polygon_repair/write_labeled_triangulation.cpp similarity index 86% rename from Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp rename to Polygon_repair/examples/Polygon_repair/write_labeled_triangulation.cpp index 3dde85eb920a..24837d7c14ad 100644 --- a/Polygon_repair_2/examples/Polygon_repair_2/write_labeled_triangulation.cpp +++ b/Polygon_repair/examples/Polygon_repair/write_labeled_triangulation.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; @@ -10,7 +10,7 @@ using Point_2 = Kernel::Point_2; using Polygon_2 = CGAL::Polygon_2; using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; -using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; +using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; int main(int argc, char* argv[]) { @@ -19,7 +19,7 @@ int main(int argc, char* argv[]) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(ifs, mp); - Polygon_repair_2 pr; + Polygon_repair pr; pr.add_to_triangulation_odd_even(mp); pr.label_triangulation_odd_even(); @@ -27,7 +27,7 @@ int main(int argc, char* argv[]) { std::cout << "\t\"type\": \"FeatureCollection\"," << std::endl; std::cout << "\t\"features\": [" << std::endl; - for (Polygon_repair_2::Triangulation::Finite_faces_iterator face = pr.triangulation().finite_faces_begin(); + for (Polygon_repair::Triangulation::Finite_faces_iterator face = pr.triangulation().finite_faces_begin(); face != pr.triangulation().finite_faces_end(); ++face) { std::cout << "\t\t{" << std::endl; std::cout << "\t\t\t\"type\": \"Feature\"," << std::endl; @@ -45,7 +45,7 @@ int main(int argc, char* argv[]) { std::cout << "\t\t\t\t]" << std::endl; std::cout << "\t\t\t}" << std::endl; std::cout << "\t\t}"; - Polygon_repair_2::Triangulation::Finite_faces_iterator next_face = face; + Polygon_repair::Triangulation::Finite_faces_iterator next_face = face; ++next_face; if (next_face != pr.triangulation().finite_faces_end()) std::cout << ","; std::cout << std::endl; diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h b/Polygon_repair/include/CGAL/Polygon_repair/Multipolygon_with_holes_2.h similarity index 98% rename from Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h rename to Polygon_repair/include/CGAL/Polygon_repair/Multipolygon_with_holes_2.h index 8d13989b4e82..2035b8fb84ce 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Multipolygon_with_holes_2.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Multipolygon_with_holes_2.h @@ -12,13 +12,13 @@ #ifndef CGAL_MULTIPOLYGON_WITH_HOLES_2_H #define CGAL_MULTIPOLYGON_WITH_HOLES_2_H -#include +#include #include namespace CGAL { -/*! \ingroup PkgPolygonRepair2Ref +/*! \ingroup PkgPolygonRepairRef * * The class `Multipolygon_with_holes_2` models the concept `MultipolygonWithHoles_2`. * It is parameterized with two types (`Kernel` and `Container`) that are used to instantiate diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h similarity index 95% rename from Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h rename to Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 85ef9d1673de..6a06b95ac28f 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Polygon_repair_2.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -10,32 +10,32 @@ // Author(s) : Ken Arroyo Ohori // Guillaume Damiand -#ifndef CGAL_POLYGON_REPAIR_2_H -#define CGAL_POLYGON_REPAIR_2_H +#ifndef CGAL_POLYGON_REPAIR_H +#define CGAL_POLYGON_REPAIR_H -#include +#include #include #include #include #include -#include -#include -#include +#include +#include +#include namespace CGAL { -namespace Polygon_repair_2 { +namespace Polygon_repair { template -class Polygon_repair_2; +class Polygon_repair; -/// \ingroup PkgPolygonRepair2Functions +/// \ingroup PkgPolygonRepairFunctions /// Repair a polygon without holes template Multipolygon_with_holes_2 repair_odd_even(const Polygon_2& p) { - CGAL::Polygon_repair_2::Polygon_repair_2 pr; + CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_odd_even(p); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation_odd_even(); @@ -43,11 +43,11 @@ Multipolygon_with_holes_2 repair_odd_even(const Polygo } return pr.multipolygon(); } -/// \ingroup PkgPolygonRepair2Functions +/// \ingroup PkgPolygonRepairFunctions /// Repair a polygon with holes template Multipolygon_with_holes_2 repair_odd_even(const Polygon_with_holes_2& p) { - CGAL::Polygon_repair_2::Polygon_repair_2 pr; + CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_odd_even(p); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation_odd_even(); @@ -55,11 +55,11 @@ Multipolygon_with_holes_2 repair_odd_even(const Polygo } return pr.multipolygon(); } -/// \ingroup PkgPolygonRepair2Functions +/// \ingroup PkgPolygonRepairFunctions /// Repair a multipolygon with holes template Multipolygon_with_holes_2 repair_odd_even(const Multipolygon_with_holes_2& mp) { - CGAL::Polygon_repair_2::Polygon_repair_2 pr; + CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_odd_even(mp); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation_odd_even(); @@ -67,14 +67,14 @@ Multipolygon_with_holes_2 repair_odd_even(const Multip } return pr.multipolygon(); } -/*! \ingroup PkgPolygonRepair2Ref +/*! \ingroup PkgPolygonRepairRef * - * The class `Polygon_repair_2` builds on a constrained + * The class `Polygon_repair` builds on a constrained * triangulation to remove the parts of constraints that overlap an even number of times */ template > -class Polygon_repair_2 { +class Polygon_repair { public: using Vertex_base = CGAL::Triangulation_vertex_base_2; using Face_base = CGAL::Constrained_triangulation_face_base_2; @@ -117,7 +117,7 @@ class Polygon_repair_2 { }; /// \name Creation - Polygon_repair_2() : number_of_polygons(0), number_of_holes(0) {} + Polygon_repair() : number_of_polygons(0), number_of_holes(0) {} /// \name Modifiers /// @{ @@ -464,7 +464,7 @@ class Polygon_repair_2 { typename Triangulation::Face_handle search_start; }; -} // namespace Polygon_repair_2 +} // namespace Polygon_repair } // namespace CGAL -#endif // CGAL_POLYGON_REPAIR_2_H +#endif // CGAL_POLYGON_REPAIR_H diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h b/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_face_base_with_repair_info_2.h similarity index 97% rename from Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h rename to Polygon_repair/include/CGAL/Polygon_repair/Triangulation_face_base_with_repair_info_2.h index 68143c4a13bc..61389d4e33ee 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_face_base_with_repair_info_2.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_face_base_with_repair_info_2.h @@ -12,7 +12,7 @@ #ifndef CGAL_TRIANGULATION_WITH_REPAIR_INFO_2_H #define CGAL_TRIANGULATION_WITH_REPAIR_INFO_2_H -#include +#include #include diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_with_odd_even_constraints_2.h similarity index 98% rename from Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h rename to Polygon_repair/include/CGAL/Polygon_repair/Triangulation_with_odd_even_constraints_2.h index f496d1154092..9a693be3d94d 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_with_odd_even_constraints_2.h @@ -12,12 +12,12 @@ #ifndef CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H #define CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H -#include +#include #include namespace CGAL { -/*! \ingroup PkgPolygonRepair2Ref +/*! \ingroup PkgPolygonRepairRef * * The class `Triangulation_with_odd_even_constraints_2` builds on a constrained * triangulation to remove the parts of constraints that overlap an even number of times diff --git a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h b/Polygon_repair/include/CGAL/Polygon_repair/draw_multipolygon_with_holes_2.h similarity index 98% rename from Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h rename to Polygon_repair/include/CGAL/Polygon_repair/draw_multipolygon_with_holes_2.h index 703e89b73e0a..749a30579c40 100644 --- a/Polygon_repair_2/include/CGAL/Polygon_repair_2/draw_multipolygon_with_holes_2.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/draw_multipolygon_with_holes_2.h @@ -12,7 +12,7 @@ #ifndef CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H #define CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H -#include +#include #include @@ -43,7 +43,7 @@ void draw(const PH& aph); #ifdef CGAL_USE_BASIC_VIEWER #include -#include +#include namespace CGAL { diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/copyright b/Polygon_repair/package_info/Polygon_repair/copyright similarity index 100% rename from Polygon_repair_2/package_info/Polygon_repair_2/copyright rename to Polygon_repair/package_info/Polygon_repair/copyright diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/dependencies b/Polygon_repair/package_info/Polygon_repair/dependencies similarity index 95% rename from Polygon_repair_2/package_info/Polygon_repair_2/dependencies rename to Polygon_repair/package_info/Polygon_repair/dependencies index f1acb2ceddc5..f30877d02528 100644 --- a/Polygon_repair_2/package_info/Polygon_repair_2/dependencies +++ b/Polygon_repair/package_info/Polygon_repair/dependencies @@ -17,7 +17,7 @@ Kernel_d Modular_arithmetic Number_types Polygon -Polygon_repair_2 +Polygon_repair Profiling_tools Property_map STL_Extension diff --git a/Polygon_repair/package_info/Polygon_repair/description.txt b/Polygon_repair/package_info/Polygon_repair/description.txt new file mode 100644 index 000000000000..faa7c2ab3f9c --- /dev/null +++ b/Polygon_repair/package_info/Polygon_repair/description.txt @@ -0,0 +1 @@ +Package Polygon_repair provides functions to repair polygons. diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/license.txt b/Polygon_repair/package_info/Polygon_repair/license.txt similarity index 100% rename from Polygon_repair_2/package_info/Polygon_repair_2/license.txt rename to Polygon_repair/package_info/Polygon_repair/license.txt diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/long_description.txt b/Polygon_repair/package_info/Polygon_repair/long_description.txt similarity index 100% rename from Polygon_repair_2/package_info/Polygon_repair_2/long_description.txt rename to Polygon_repair/package_info/Polygon_repair/long_description.txt diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/maintainer b/Polygon_repair/package_info/Polygon_repair/maintainer similarity index 100% rename from Polygon_repair_2/package_info/Polygon_repair_2/maintainer rename to Polygon_repair/package_info/Polygon_repair/maintainer diff --git a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt b/Polygon_repair/test/Polygon_repair/CMakeLists.txt similarity index 94% rename from Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt rename to Polygon_repair/test/Polygon_repair/CMakeLists.txt index 365fba1a84c2..858e342b24ab 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/CMakeLists.txt +++ b/Polygon_repair/test/Polygon_repair/CMakeLists.txt @@ -2,7 +2,7 @@ # This is the CMake script for compiling a CGAL application. cmake_minimum_required(VERSION 3.1...3.23) -project(Polygon_repair_2_Tests) +project(Polygon_repair_Tests) find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) diff --git a/Polygon_repair_2/test/Polygon_repair_2/clipart.cpp b/Polygon_repair/test/Polygon_repair/clipart.cpp similarity index 92% rename from Polygon_repair_2/test/Polygon_repair_2/clipart.cpp rename to Polygon_repair/test/Polygon_repair/clipart.cpp index 421e68e7334e..68b9f86e001d 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/clipart.cpp +++ b/Polygon_repair/test/Polygon_repair/clipart.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; @@ -12,7 +12,7 @@ using Point_2 = Kernel::Point_2; using Polygon_2 = CGAL::Polygon_2; using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; -using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; +using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; void print_timer(clock_t start_time) { clock_t stop_time = clock(); @@ -40,7 +40,7 @@ int main(int argc, char* argv[]) { // } start_time = clock(); - Polygon_repair_2 pr; + Polygon_repair pr; std::vector vertices; std::vector> edges; @@ -80,10 +80,10 @@ int main(int argc, char* argv[]) { std::cout << std::endl; start_time = clock(); - Polygon_repair_2::Triangulation::Face_handle search_start; + Polygon_repair::Triangulation::Face_handle search_start; for (auto const& edge: edges_to_insert) { - Polygon_repair_2::Triangulation::Vertex_handle va = pr.triangulation().insert(edge.first, search_start); - Polygon_repair_2::Triangulation::Vertex_handle vb = pr.triangulation().insert(edge.second, va->face()); // vb is likely close to va + Polygon_repair::Triangulation::Vertex_handle va = pr.triangulation().insert(edge.first, search_start); + Polygon_repair::Triangulation::Vertex_handle vb = pr.triangulation().insert(edge.second, va->face()); // vb is likely close to va pr.triangulation().odd_even_insert_constraint(va, vb); search_start = vb->face(); } std::cout << "Inserted constraints in "; diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/back-and-forth.wkt b/Polygon_repair/test/Polygon_repair/data/in/back-and-forth.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/back-and-forth.wkt rename to Polygon_repair/test/Polygon_repair/data/in/back-and-forth.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/bowtie.wkt b/Polygon_repair/test/Polygon_repair/data/in/bowtie.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/bowtie.wkt rename to Polygon_repair/test/Polygon_repair/data/in/bowtie.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/bridge-edge.wkt b/Polygon_repair/test/Polygon_repair/data/in/bridge-edge.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/bridge-edge.wkt rename to Polygon_repair/test/Polygon_repair/data/in/bridge-edge.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons-nesting.wkt b/Polygon_repair/test/Polygon_repair/data/in/crossing-polygons-nesting.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons-nesting.wkt rename to Polygon_repair/test/Polygon_repair/data/in/crossing-polygons-nesting.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons.wkt b/Polygon_repair/test/Polygon_repair/data/in/crossing-polygons.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/crossing-polygons.wkt rename to Polygon_repair/test/Polygon_repair/data/in/crossing-polygons.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/edge.wkt b/Polygon_repair/test/Polygon_repair/data/in/edge.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/edge.wkt rename to Polygon_repair/test/Polygon_repair/data/in/edge.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/empty-multipolygon.wkt b/Polygon_repair/test/Polygon_repair/data/in/empty-multipolygon.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/empty-multipolygon.wkt rename to Polygon_repair/test/Polygon_repair/data/in/empty-multipolygon.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/empty-polygon.wkt b/Polygon_repair/test/Polygon_repair/data/in/empty-polygon.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/empty-polygon.wkt rename to Polygon_repair/test/Polygon_repair/data/in/empty-polygon.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-all.wkt b/Polygon_repair/test/Polygon_repair/data/in/hole-all.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/hole-all.wkt rename to Polygon_repair/test/Polygon_repair/data/in/hole-all.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-as-loop.wkt b/Polygon_repair/test/Polygon_repair/data/in/hole-as-loop.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/hole-as-loop.wkt rename to Polygon_repair/test/Polygon_repair/data/in/hole-as-loop.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-carved.wkt b/Polygon_repair/test/Polygon_repair/data/in/hole-carved.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/hole-carved.wkt rename to Polygon_repair/test/Polygon_repair/data/in/hole-carved.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-filled.wkt b/Polygon_repair/test/Polygon_repair/data/in/hole-filled.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/hole-filled.wkt rename to Polygon_repair/test/Polygon_repair/data/in/hole-filled.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-outside.wkt b/Polygon_repair/test/Polygon_repair/data/in/hole-outside.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/hole-outside.wkt rename to Polygon_repair/test/Polygon_repair/data/in/hole-outside.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-partly-outside.wkt b/Polygon_repair/test/Polygon_repair/data/in/hole-partly-outside.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/hole-partly-outside.wkt rename to Polygon_repair/test/Polygon_repair/data/in/hole-partly-outside.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-edge.wkt b/Polygon_repair/test/Polygon_repair/data/in/hole-touching-edge.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-edge.wkt rename to Polygon_repair/test/Polygon_repair/data/in/hole-touching-edge.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-once.wkt b/Polygon_repair/test/Polygon_repair/data/in/hole-touching-once.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-once.wkt rename to Polygon_repair/test/Polygon_repair/data/in/hole-touching-once.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-twice.wkt b/Polygon_repair/test/Polygon_repair/data/in/hole-touching-twice.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/hole-touching-twice.wkt rename to Polygon_repair/test/Polygon_repair/data/in/hole-touching-twice.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/hole.wkt b/Polygon_repair/test/Polygon_repair/data/in/hole.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/hole.wkt rename to Polygon_repair/test/Polygon_repair/data/in/hole.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/nesting-spike.wkt b/Polygon_repair/test/Polygon_repair/data/in/nesting-spike.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/nesting-spike.wkt rename to Polygon_repair/test/Polygon_repair/data/in/nesting-spike.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/nesting.wkt b/Polygon_repair/test/Polygon_repair/data/in/nesting.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/nesting.wkt rename to Polygon_repair/test/Polygon_repair/data/in/nesting.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/not-closed.wkt b/Polygon_repair/test/Polygon_repair/data/in/not-closed.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/not-closed.wkt rename to Polygon_repair/test/Polygon_repair/data/in/not-closed.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-inside.wkt b/Polygon_repair/test/Polygon_repair/data/in/overlapping-edge-inside.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-inside.wkt rename to Polygon_repair/test/Polygon_repair/data/in/overlapping-edge-inside.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-partial.wkt b/Polygon_repair/test/Polygon_repair/data/in/overlapping-edge-partial.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge-partial.wkt rename to Polygon_repair/test/Polygon_repair/data/in/overlapping-edge-partial.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge.wkt b/Polygon_repair/test/Polygon_repair/data/in/overlapping-edge.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/overlapping-edge.wkt rename to Polygon_repair/test/Polygon_repair/data/in/overlapping-edge.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/point-double.wkt b/Polygon_repair/test/Polygon_repair/data/in/point-double.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/point-double.wkt rename to Polygon_repair/test/Polygon_repair/data/in/point-double.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/point.wkt b/Polygon_repair/test/Polygon_repair/data/in/point.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/point.wkt rename to Polygon_repair/test/Polygon_repair/data/in/point.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-boundary.wkt b/Polygon_repair/test/Polygon_repair/data/in/spike-boundary.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/spike-boundary.wkt rename to Polygon_repair/test/Polygon_repair/data/in/spike-boundary.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-in.wkt b/Polygon_repair/test/Polygon_repair/data/in/spike-in.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/spike-in.wkt rename to Polygon_repair/test/Polygon_repair/data/in/spike-in.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-long.wkt b/Polygon_repair/test/Polygon_repair/data/in/spike-long.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/spike-long.wkt rename to Polygon_repair/test/Polygon_repair/data/in/spike-long.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spike-out.wkt b/Polygon_repair/test/Polygon_repair/data/in/spike-out.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/spike-out.wkt rename to Polygon_repair/test/Polygon_repair/data/in/spike-out.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spikes-fp.wkt b/Polygon_repair/test/Polygon_repair/data/in/spikes-fp.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/spikes-fp.wkt rename to Polygon_repair/test/Polygon_repair/data/in/spikes-fp.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spikes.wkt b/Polygon_repair/test/Polygon_repair/data/in/spikes.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/spikes.wkt rename to Polygon_repair/test/Polygon_repair/data/in/spikes.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/spiral.wkt b/Polygon_repair/test/Polygon_repair/data/in/spiral.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/spiral.wkt rename to Polygon_repair/test/Polygon_repair/data/in/spiral.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/square-hole-rhombus.wkt b/Polygon_repair/test/Polygon_repair/data/in/square-hole-rhombus.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/square-hole-rhombus.wkt rename to Polygon_repair/test/Polygon_repair/data/in/square-hole-rhombus.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/square.wkt b/Polygon_repair/test/Polygon_repair/data/in/square.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/square.wkt rename to Polygon_repair/test/Polygon_repair/data/in/square.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/in/star.wkt b/Polygon_repair/test/Polygon_repair/data/in/star.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/in/star.wkt rename to Polygon_repair/test/Polygon_repair/data/in/star.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/back-and-forth.wkt b/Polygon_repair/test/Polygon_repair/data/ref/back-and-forth.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/back-and-forth.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/back-and-forth.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/bowtie.wkt b/Polygon_repair/test/Polygon_repair/data/ref/bowtie.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/bowtie.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/bowtie.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/bridge-edge.wkt b/Polygon_repair/test/Polygon_repair/data/ref/bridge-edge.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/bridge-edge.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/bridge-edge.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons-nesting.wkt b/Polygon_repair/test/Polygon_repair/data/ref/crossing-polygons-nesting.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons-nesting.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/crossing-polygons-nesting.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons.wkt b/Polygon_repair/test/Polygon_repair/data/ref/crossing-polygons.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/crossing-polygons.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/crossing-polygons.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/edge.wkt b/Polygon_repair/test/Polygon_repair/data/ref/edge.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/edge.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/edge.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-multipolygon.wkt b/Polygon_repair/test/Polygon_repair/data/ref/empty-multipolygon.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-multipolygon.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/empty-multipolygon.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-polygon.wkt b/Polygon_repair/test/Polygon_repair/data/ref/empty-polygon.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/empty-polygon.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/empty-polygon.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-all.wkt b/Polygon_repair/test/Polygon_repair/data/ref/hole-all.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-all.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/hole-all.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-as-loop.wkt b/Polygon_repair/test/Polygon_repair/data/ref/hole-as-loop.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-as-loop.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/hole-as-loop.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-carved.wkt b/Polygon_repair/test/Polygon_repair/data/ref/hole-carved.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-carved.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/hole-carved.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-filled.wkt b/Polygon_repair/test/Polygon_repair/data/ref/hole-filled.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-filled.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/hole-filled.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-outside.wkt b/Polygon_repair/test/Polygon_repair/data/ref/hole-outside.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-outside.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/hole-outside.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-partly-outside.wkt b/Polygon_repair/test/Polygon_repair/data/ref/hole-partly-outside.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-partly-outside.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/hole-partly-outside.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-edge.wkt b/Polygon_repair/test/Polygon_repair/data/ref/hole-touching-edge.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-edge.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/hole-touching-edge.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-once.wkt b/Polygon_repair/test/Polygon_repair/data/ref/hole-touching-once.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-once.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/hole-touching-once.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-twice.wkt b/Polygon_repair/test/Polygon_repair/data/ref/hole-touching-twice.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/hole-touching-twice.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/hole-touching-twice.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/hole.wkt b/Polygon_repair/test/Polygon_repair/data/ref/hole.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/hole.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/hole.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting-spike.wkt b/Polygon_repair/test/Polygon_repair/data/ref/nesting-spike.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting-spike.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/nesting-spike.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting.wkt b/Polygon_repair/test/Polygon_repair/data/ref/nesting.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/nesting.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/nesting.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/not-closed.wkt b/Polygon_repair/test/Polygon_repair/data/ref/not-closed.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/not-closed.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/not-closed.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-inside.wkt b/Polygon_repair/test/Polygon_repair/data/ref/overlapping-edge-inside.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-inside.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/overlapping-edge-inside.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-partial.wkt b/Polygon_repair/test/Polygon_repair/data/ref/overlapping-edge-partial.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge-partial.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/overlapping-edge-partial.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge.wkt b/Polygon_repair/test/Polygon_repair/data/ref/overlapping-edge.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/overlapping-edge.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/overlapping-edge.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/point-double.wkt b/Polygon_repair/test/Polygon_repair/data/ref/point-double.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/point-double.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/point-double.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/point.wkt b/Polygon_repair/test/Polygon_repair/data/ref/point.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/point.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/point.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-boundary.wkt b/Polygon_repair/test/Polygon_repair/data/ref/spike-boundary.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-boundary.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/spike-boundary.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-in.wkt b/Polygon_repair/test/Polygon_repair/data/ref/spike-in.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-in.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/spike-in.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-long.wkt b/Polygon_repair/test/Polygon_repair/data/ref/spike-long.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-long.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/spike-long.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-out.wkt b/Polygon_repair/test/Polygon_repair/data/ref/spike-out.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/spike-out.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/spike-out.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes-fp.wkt b/Polygon_repair/test/Polygon_repair/data/ref/spikes-fp.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes-fp.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/spikes-fp.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes.wkt b/Polygon_repair/test/Polygon_repair/data/ref/spikes.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/spikes.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/spikes.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/spiral.wkt b/Polygon_repair/test/Polygon_repair/data/ref/spiral.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/spiral.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/spiral.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/square-hole-rhombus.wkt b/Polygon_repair/test/Polygon_repair/data/ref/square-hole-rhombus.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/square-hole-rhombus.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/square-hole-rhombus.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/square.wkt b/Polygon_repair/test/Polygon_repair/data/ref/square.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/square.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/square.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/data/ref/star.wkt b/Polygon_repair/test/Polygon_repair/data/ref/star.wkt similarity index 100% rename from Polygon_repair_2/test/Polygon_repair_2/data/ref/star.wkt rename to Polygon_repair/test/Polygon_repair/data/ref/star.wkt diff --git a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp b/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp similarity index 83% rename from Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp rename to Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp index 8b6d05807446..c20f298f847b 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/draw_test_polygons.cpp +++ b/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp @@ -4,10 +4,10 @@ #include #include -#include +#include #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; @@ -15,7 +15,7 @@ using Point_2 = Kernel::Point_2; using Polygon_2 = CGAL::Polygon_2; using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; -using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; +using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; int main(int argc, char* argv[]) { @@ -35,12 +35,12 @@ int main(int argc, char* argv[]) { if (in != "POLYGON()") { // maybe should be checked in WKT reader CGAL::IO::read_polygon_WKT(iss, p); } CGAL::draw(p); - rmp = CGAL::Polygon_repair_2::repair_odd_even(p); + rmp = CGAL::Polygon_repair::repair_odd_even(p); } else if (in.find("MULTIPOLYGON") == 0) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); CGAL::draw(mp); - rmp = CGAL::Polygon_repair_2::repair_odd_even(mp); + rmp = CGAL::Polygon_repair::repair_odd_even(mp); } std::ostringstream oss; CGAL::IO::write_multi_polygon_WKT(oss, rmp); std::string out = oss.str(); diff --git a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp similarity index 90% rename from Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp rename to Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp index bc3e937d9dec..a4d38c88e587 100644 --- a/Polygon_repair_2/test/Polygon_repair_2/repair_polygon_2_test.cpp +++ b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; @@ -12,7 +12,7 @@ using Point_2 = Kernel::Point_2; using Polygon_2 = CGAL::Polygon_2; using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; -using Polygon_repair_2 = CGAL::Polygon_repair_2::Polygon_repair_2; +using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; int main(int argc, char* argv[]) { @@ -31,11 +31,11 @@ int main(int argc, char* argv[]) { Polygon_with_holes_2 p; if (in != "POLYGON()") { // maybe should be checked in WKT reader CGAL::IO::read_polygon_WKT(iss, p); - } rmp = CGAL::Polygon_repair_2::repair_odd_even(p); + } rmp = CGAL::Polygon_repair::repair_odd_even(p); } else if (in.find("MULTIPOLYGON") == 0) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); - rmp = CGAL::Polygon_repair_2::repair_odd_even(mp); + rmp = CGAL::Polygon_repair::repair_odd_even(mp); } std::ostringstream oss; CGAL::IO::write_multi_polygon_WKT(oss, rmp); std::string out = oss.str(); diff --git a/Polygon_repair_2/doc/Polygon_repair_2/examples.txt b/Polygon_repair_2/doc/Polygon_repair_2/examples.txt deleted file mode 100644 index b1318b5691ee..000000000000 --- a/Polygon_repair_2/doc/Polygon_repair_2/examples.txt +++ /dev/null @@ -1,6 +0,0 @@ -/*! -\example Polygon_repair_2/multipolygon.cpp -\example Polygon_repair_2/draw_multipolygon.cpp -\example Polygon_repair_2/repair_polygon_2.cpp -\example Polygon_repair_2/write_labeled_triangulation.cpp -*/ diff --git a/Polygon_repair_2/package_info/Polygon_repair_2/description.txt b/Polygon_repair_2/package_info/Polygon_repair_2/description.txt deleted file mode 100644 index 4fee1c792710..000000000000 --- a/Polygon_repair_2/package_info/Polygon_repair_2/description.txt +++ /dev/null @@ -1 +0,0 @@ -Package Polygon_repair_2 provides functions to repair polygons. diff --git a/Stream_support/examples/Stream_support/Polygon_WKT.cpp b/Stream_support/examples/Stream_support/Polygon_WKT.cpp index 7c7acf1b95d6..f725dcd37494 100644 --- a/Stream_support/examples/Stream_support/Polygon_WKT.cpp +++ b/Stream_support/examples/Stream_support/Polygon_WKT.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/Stream_support/include/CGAL/IO/WKT.h b/Stream_support/include/CGAL/IO/WKT.h index e91af554199e..51cf67aea6c6 100644 --- a/Stream_support/include/CGAL/IO/WKT.h +++ b/Stream_support/include/CGAL/IO/WKT.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff --git a/Stream_support/package_info/Stream_support/dependencies b/Stream_support/package_info/Stream_support/dependencies index 33648bd70333..825609cbfe86 100644 --- a/Stream_support/package_info/Stream_support/dependencies +++ b/Stream_support/package_info/Stream_support/dependencies @@ -7,7 +7,7 @@ Kernel_23 Modular_arithmetic Number_types Polygon -Polygon_repair_2 +Polygon_repair Profiling_tools Property_map STL_Extension From 1e77a2900348080518a443c60645f5a299bed3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 24 Aug 2023 13:38:41 +0200 Subject: [PATCH 081/182] add bibtex and fix cite --- Documentation/doc/biblio/geom.bib | 10 ++++++++++ Polygon_repair/doc/Polygon_repair/Polygon_repair.txt | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Documentation/doc/biblio/geom.bib b/Documentation/doc/biblio/geom.bib index 969a1a79b5ba..f434a4aed0bd 100644 --- a/Documentation/doc/biblio/geom.bib +++ b/Documentation/doc/biblio/geom.bib @@ -152054,3 +152054,13 @@ @inproceedings{tang2009interactive year={2009}, organization={ACM} } + +@article{ledoux2014triangulation, + title={A triangulation-based approach to automatically repair GIS polygons}, + author={Ledoux, Hugo and Ohori, Ken Arroyo and Meijers, Martijn}, + journal={Computers \& Geosciences}, + volume={66}, + pages={121--131}, + year={2014}, + publisher={Elsevier} +} diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 53dd72489cd1..f18f5a803953 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -10,7 +10,7 @@ namespace CGAL { \section SectionPolygonRepair_Introduction Introduction This package implements a polygon repair method based on a constrained -triangulation \cgalCite{14cg}. Starting from a possibly invalid input +triangulation \cgalCite{ledoux2014triangulation}. Starting from a possibly invalid input in the form of a polygon, polygon with holes or multipolygon with holes, the method performs a constrained triangulation of the input edges, labels each triangle according to what it represents (exterior, polygon interior From 4613aa78a4f9b46b421a283fe6c2412720957dcd Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 24 Aug 2023 15:59:19 +0200 Subject: [PATCH 082/182] move multipolygon to polygon package --- .../Concepts/MultiPolygonWithHoles_2.h | 2 +- Polygon/doc/Polygon/PackageDescription.txt | 13 +- Polygon/doc/Polygon/Polygon.txt | 3 +- Polygon/doc/Polygon/examples.txt | 2 + Polygon/examples/Polygon/CMakeLists.txt | 1 + .../Polygon/draw_multipolygon_with_holes.cpp | 2 +- .../examples/Polygon}/multipolygon.cpp | 2 +- .../include/CGAL}/Multipolygon_with_holes_2.h | 17 +- .../CGAL/draw_multipolygon_with_holes_2.h | 211 ++++++++++++++++++ .../doc/Polygon_repair/PackageDescription.txt | 17 +- .../doc/Polygon_repair/examples.txt | 2 - .../examples/Polygon_repair/CMakeLists.txt | 8 +- .../CGAL/Polygon_repair/Polygon_repair.h | 2 +- .../Polygon_repair/draw_test_polygons.cpp | 2 +- Stream_support/include/CGAL/IO/WKT.h | 2 +- 15 files changed, 247 insertions(+), 39 deletions(-) rename {Polygon_repair/doc/Polygon_repair => Polygon/doc/Polygon}/Concepts/MultiPolygonWithHoles_2.h (97%) rename Polygon_repair/examples/Polygon_repair/draw_multipolygon.cpp => Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp (90%) rename {Polygon_repair/examples/Polygon_repair => Polygon/examples/Polygon}/multipolygon.cpp (94%) rename {Polygon_repair/include/CGAL/Polygon_repair => Polygon/include/CGAL}/Multipolygon_with_holes_2.h (91%) create mode 100644 Polygon/include/CGAL/draw_multipolygon_with_holes_2.h diff --git a/Polygon_repair/doc/Polygon_repair/Concepts/MultiPolygonWithHoles_2.h b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h similarity index 97% rename from Polygon_repair/doc/Polygon_repair/Concepts/MultiPolygonWithHoles_2.h rename to Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h index d7f037be4d6d..1c315df5a6bb 100644 --- a/Polygon_repair/doc/Polygon_repair/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h @@ -1,4 +1,4 @@ -/*! \ingroup PkgPolygonRepairConcepts +/*! \ingroup PkgPolygon2Concepts * \cgalConcept * * \cgalRefines{CopyConstructible,Assignable,DefaultConstructible} diff --git a/Polygon/doc/Polygon/PackageDescription.txt b/Polygon/doc/Polygon/PackageDescription.txt index 1d48e74493c8..7748ee535ee9 100644 --- a/Polygon/doc/Polygon/PackageDescription.txt +++ b/Polygon/doc/Polygon/PackageDescription.txt @@ -20,7 +20,13 @@ \endcode */ /// \defgroup PkgDrawPolygonWithHoles2 Draw a 2D Polygon with Holes -/// \ingroup PkgPolygon2Ref + +/*! + \code + #include + \endcode +*/ +/// \defgroup PkgDrawMultipolygonWithHoles2 Draw a 2D Multipolygon with Holes /*! \addtogroup PkgPolygon2Ref @@ -46,11 +52,13 @@ \cgalCRPSection{Concepts} - `PolygonTraits_2` - `GeneralPolygonWithHoles_2` +- `MultipolygonWithHoles_2` \cgalCRPSection{Classes} - `CGAL::Polygon_2` - `CGAL::Polygon_with_holes_2` - `CGAL::General_polygon_with_holes_2` +- `CGAL::Multipolygon_with_holes_2` \cgalCRPSection{Global Functions} - `CGAL::area_2()` @@ -71,4 +79,7 @@ \cgalCRPSection{Draw a Polygon_with_holes_2} - \link PkgDrawPolygonWithHoles2 CGAL::draw() \endlink +\cgalCRPSection{Draw a Multipolygon_with_holes_2} +- \link PkgDrawMultipolygonWithHoles2 CGAL::draw() \endlink + */ diff --git a/Polygon/doc/Polygon/Polygon.txt b/Polygon/doc/Polygon/Polygon.txt index b21d57325e70..9e50406194b3 100644 --- a/Polygon/doc/Polygon/Polygon.txt +++ b/Polygon/doc/Polygon/Polygon.txt @@ -82,7 +82,8 @@ vertices. It additionally provides a member function `Polygon_2::vertices()` tha \subsection subsecPolygonDraw Draw a Polygon -A polygon can be visualized by calling the \link PkgDrawPolygon2 CGAL::draw

() \endlink function as shown in the following example. This function opens a new window showing the given polygon. A call to this function is blocking, that is the program continues as soon as the user closes the window (a version exists for polygon with holes, cf. \link PkgDrawPolygonWithHoles2 CGAL::draw() \endlink). +A polygon can be visualized by calling the \link PkgDrawPolygon2 CGAL::draw

() \endlink function as shown in the following example. This function opens a new window showing the given polygon. A call to this function is blocking, that is the program continues as soon as the user closes the window. Versions for polygons with holes and multipolygons with holes also exist, cf. \link PkgDrawPolygonWithHoles2 CGAL::draw() \endlink and \link PkgDrawMultipolygonWithHoles2 +CGAL::draw() \endlink. \cgalExample{Polygon/draw_polygon.cpp} diff --git a/Polygon/doc/Polygon/examples.txt b/Polygon/doc/Polygon/examples.txt index 3a608da09f40..2341aa5721d6 100644 --- a/Polygon/doc/Polygon/examples.txt +++ b/Polygon/doc/Polygon/examples.txt @@ -7,4 +7,6 @@ \example Stream_support/Polygon_WKT.cpp \example Polygon/draw_polygon.cpp \example Polygon/draw_polygon_with_holes.cpp +\example Polygon/multipolygon.cpp +\example Polygon/draw_multipolygon_with_holes.cpp */ diff --git a/Polygon/examples/Polygon/CMakeLists.txt b/Polygon/examples/Polygon/CMakeLists.txt index c9fdf0aa007a..e774514708e0 100644 --- a/Polygon/examples/Polygon/CMakeLists.txt +++ b/Polygon/examples/Polygon/CMakeLists.txt @@ -18,4 +18,5 @@ endforeach() if(CGAL_Qt5_FOUND) target_link_libraries(draw_polygon PUBLIC CGAL::CGAL_Basic_viewer) target_link_libraries(draw_polygon_with_holes PUBLIC CGAL::CGAL_Basic_viewer) + target_link_libraries(draw_multipolygon_with_holes PUBLIC CGAL::CGAL_Basic_viewer) endif() diff --git a/Polygon_repair/examples/Polygon_repair/draw_multipolygon.cpp b/Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp similarity index 90% rename from Polygon_repair/examples/Polygon_repair/draw_multipolygon.cpp rename to Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp index 3451b98de51a..5db6ececb9ee 100644 --- a/Polygon_repair/examples/Polygon_repair/draw_multipolygon.cpp +++ b/Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; diff --git a/Polygon_repair/examples/Polygon_repair/multipolygon.cpp b/Polygon/examples/Polygon/multipolygon.cpp similarity index 94% rename from Polygon_repair/examples/Polygon_repair/multipolygon.cpp rename to Polygon/examples/Polygon/multipolygon.cpp index ce0cdf27f411..b98a6fda3cfd 100644 --- a/Polygon_repair/examples/Polygon_repair/multipolygon.cpp +++ b/Polygon/examples/Polygon/multipolygon.cpp @@ -1,5 +1,5 @@ #include -#include +#include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; using Point_2 = Kernel::Point_2; diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h similarity index 91% rename from Polygon_repair/include/CGAL/Polygon_repair/Multipolygon_with_holes_2.h rename to Polygon/include/CGAL/Multipolygon_with_holes_2.h index 2035b8fb84ce..d2744339c7ef 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Multipolygon_with_holes_2.h +++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h @@ -1,19 +1,22 @@ -// Copyright (c) 2023 GeometryFactory. -// All rights reserved. +// Copyright (c) 2005 +// Utrecht University (The Netherlands), +// ETH Zurich (Switzerland), +// INRIA Sophia-Antipolis (France), +// Max-Planck-Institute Saarbruecken (Germany), +// and Tel-Aviv University (Israel). All rights reserved. // -// This file is part of CGAL (www.cgal.org). +// This file is part of CGAL (www.cgal.org) // // $URL$ // $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Ken Arroyo Ohori +// +// Author(s): Ken Arroyo Ohori #ifndef CGAL_MULTIPOLYGON_WITH_HOLES_2_H #define CGAL_MULTIPOLYGON_WITH_HOLES_2_H -#include - #include namespace CGAL { diff --git a/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h b/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h new file mode 100644 index 000000000000..814723411c7a --- /dev/null +++ b/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h @@ -0,0 +1,211 @@ +// Copyright (c) 1997 +// Utrecht University (The Netherlands), +// ETH Zurich (Switzerland), +// INRIA Sophia-Antipolis (France), +// Max-Planck-Institute Saarbruecken (Germany), +// and Tel-Aviv University (Israel). All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Ken Arroyo Ohori +// Guillaume Damiand + +#ifndef CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H +#define CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H + +#include + +#ifdef DOXYGEN_RUNNING +namespace CGAL { + +/*! + * \ingroup PkgDrawMultipolygonWithHoles2 + * + * opens a new window and draws `aph`, an instance of the + * `CGAL::Multipolygon_with_holes_2` class. A call to this function is blocking, that + * is the program continues as soon as the user closes the window. This function + * requires `CGAL_Qt5`, and is only available if the macro + * `CGAL_USE_BASIC_VIEWER` is defined. Linking with the cmake target + * `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` and add the definition + * `CGAL_USE_BASIC_VIEWER`. + * \tparam PH an instance of the `CGAL::Multipolygon_with_holes_2` class. + * \param aph the multipolygon with holes to draw. + */ + +template +void draw(const MPH& aph); + +} /* namespace CGAL */ + +#endif + +#ifdef CGAL_USE_BASIC_VIEWER + +#include +#include + +namespace CGAL { + +// Viewer class for Multipolygon_with_holes_2 +template +class Mpwh_2_basic_viewer_qt : public Basic_viewer_qt { + using Base = Basic_viewer_qt; + using Mpwh = Multipolygon; + using Pwh = typename Mpwh::Polygon_with_holes_2; + using Pgn = typename Mpwh::Polygon_2; + using Pnt = typename Pgn::Point_2; + +public: + /// Construct the viewer. + /// @param parent the active window to draw + /// @param mpwh the multipolygon to view + /// @param title the title of the window + Mpwh_2_basic_viewer_qt(QWidget* parent, const Mpwh& mpwh, + const char* title = "Basic Multipolygon_with_holes_2 Viewer") : + Base(parent, title, true, true, true, false, false), + m_mpwh(mpwh) { + if (mpwh.number_of_polygons() == 0) return; + + // mimic the computation of Camera::pixelGLRatio() + auto bbox = bounding_box(); + CGAL::qglviewer::Vec minv(bbox.xmin(), bbox.ymin(), 0); + CGAL::qglviewer::Vec maxv(bbox.xmax(), bbox.ymax(), 0); + auto diameter = (maxv - minv).norm(); + m_pixel_ratio = diameter / m_height; + } + + /*! Intercept the resizing of the window. + */ + virtual void resizeGL(int width, int height) { + CGAL::QGLViewer::resizeGL(width, height); + m_width = width; + m_height = height; + CGAL::qglviewer::Vec p; + auto ratio = camera()->pixelGLRatio(p); + m_pixel_ratio = ratio; + add_elements(); + } + + /*! Obtain the pixel ratio. + */ + double pixel_ratio() const { return m_pixel_ratio; } + + /*! Compute the bounding box. + */ + CGAL::Bbox_2 bounding_box() { + Bbox_2 bbox; + if (m_mpwh.number_of_polygons() > 0) bbox = m_mpwh.polygons().front().outer_boundary().bbox(); + for (auto const& pwh: m_mpwh.polygons()) { + bbox += pwh.outer_boundary().bbox(); + } + return bbox; + } + + /*! Compute the elements of a multipolygon with holes. + */ + void add_elements() { + clear(); + + for (auto const& p: m_mpwh.polygons()) { + CGAL::IO::Color c(rand()%255,rand()%255,rand()%255); + face_begin(c); + + const Pnt* point_in_face; + const auto& outer_boundary = p.outer_boundary(); + compute_loop(outer_boundary, false); + point_in_face = &(outer_boundary.vertex(outer_boundary.size()-1)); + + for (auto it = p.holes_begin(); it != p.holes_end(); ++it) { + compute_loop(*it, true); + add_point_in_face(*point_in_face); + } + + face_end(); + } + } + +protected: + /*! Compute the face + */ + void compute_loop(const Pgn& p, bool hole) { + if (hole) add_point_in_face(p.vertex(p.size()-1)); + + auto prev = p.vertices_begin(); + auto it = prev; + add_point(*it); + add_point_in_face(*it); + for (++it; it != p.vertices_end(); ++it) { + add_segment(*prev, *it); // add segment with previous point + add_point(*it); + add_point_in_face(*it); // add point in face + prev = it; + } + + // Add the last segment between the last point and the first one + add_segment(*prev, *(p.vertices_begin())); + } + + virtual void keyPressEvent(QKeyEvent* e) { + // Test key pressed: + // const ::Qt::KeyboardModifiers modifiers = e->modifiers(); + // if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::NoButton)) { ... } + + // Call: * add_elements() if the model changed, followed by + // * redraw() if some viewing parameters changed that implies some + // modifications of the buffers + // (eg. type of normal, color/mono) + // * update() just to update the drawing + + // Call the base method to process others/classicals key + Base::keyPressEvent(e); + } + +private: + //! The window width in pixels. + int m_width = CGAL_BASIC_VIEWER_INIT_SIZE_X; + + //! The window height in pixels. + int m_height = CGAL_BASIC_VIEWER_INIT_SIZE_Y; + + //! The ratio between pixel and opengl units (in world coordinate system). + double m_pixel_ratio = 1; + + //! The polygon with holes to draw. + const Mpwh& m_mpwh; +}; + +// Specialization of draw function. +template +void draw(const CGAL::Multipolygon_with_holes_2& mpwh, + const char* title = "Multipolygon_with_holes_2 Basic Viewer") +{ +#if defined(CGAL_TEST_SUITE) + bool cgal_test_suite = true; +#else + bool cgal_test_suite = qEnvironmentVariableIsSet("CGAL_TEST_SUITE"); +#endif + + if (! cgal_test_suite) { + using Mpwh = CGAL::Multipolygon_with_holes_2; + using Viewer = Mpwh_2_basic_viewer_qt; + CGAL::Qt::init_ogl_context(4,3); + int argc = 1; + const char* argv[2] = {"t2_viewer", nullptr}; + QApplication app(argc, const_cast(argv)); + Viewer mainwindow(app.activeWindow(), mpwh, title); + mainwindow.add_elements(); + mainwindow.show(); + app.exec(); + } +} + +} // End namespace CGAL + +#endif // CGAL_USE_BASIC_VIEWER + +#endif // CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H diff --git a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt index 4259a9f0808f..0f63f0844b7d 100644 --- a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt +++ b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt @@ -8,14 +8,6 @@ /// \defgroup PkgPolygonRepairFunctions Functions /// \ingroup PkgPolygonRepairRef -/*! - \code - #include - \endcode -*/ -/// \defgroup PkgDrawMultipolygonWithHoles2 Draw a 2D Multipolygon with holes -/// \ingroup PkgPolygonRepairRef - /*! \addtogroup PkgPolygonRepairRef \todo check generated documentation @@ -25,7 +17,7 @@ \cgalPkgSummaryBegin \cgalPkgAuthors{Ken Arroyo Ohori} -\cgalPkgDesc{The package provides a 2D multipolygon class and algorithms to repair 2D (multi)polygons. } +\cgalPkgDesc{The package provides algorithms to repair 2D (multi)polygons. } \cgalPkgManuals{Chapter_2D_Polygon_repair,PkgPolygonRepairRef} \cgalPkgSummaryEnd @@ -41,17 +33,10 @@ \cgalClassifedRefPages -\cgalCRPSection{Concepts} -- `MultipolygonWithHoles_2` - \cgalCRPSection{Classes} -- `CGAL::Multipolygon_with_holes_2` - `CGAL::Polygon_repair` \cgalCRPSection{Functions} - `CGAL::Polygon_repair::repair()` -\cgalCRPSection{Draw a Multipolygon_with_holes_2} -- \link PkgDrawMultipolygonWithHoles2 CGAL::draw() \endlink - */ diff --git a/Polygon_repair/doc/Polygon_repair/examples.txt b/Polygon_repair/doc/Polygon_repair/examples.txt index c0a827972362..1797f7165775 100644 --- a/Polygon_repair/doc/Polygon_repair/examples.txt +++ b/Polygon_repair/doc/Polygon_repair/examples.txt @@ -1,6 +1,4 @@ /*! -\example Polygon_repair/multipolygon.cpp -\example Polygon_repair/draw_multipolygon.cpp \example Polygon_repair/repair_polygon_2.cpp \example Polygon_repair/write_labeled_triangulation.cpp */ diff --git a/Polygon_repair/examples/Polygon_repair/CMakeLists.txt b/Polygon_repair/examples/Polygon_repair/CMakeLists.txt index 930b4dc25676..4350cb892272 100644 --- a/Polygon_repair/examples/Polygon_repair/CMakeLists.txt +++ b/Polygon_repair/examples/Polygon_repair/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1...3.23) project(Polygon_repair_Examples) -find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) +find_package(CGAL REQUIRED) # create a target per cppfile file( @@ -13,8 +13,4 @@ file( ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) create_single_source_cgal_program("${cppfile}") -endforeach() - -if(CGAL_Qt5_FOUND) - target_link_libraries(draw_multipolygon PUBLIC CGAL::CGAL_Basic_viewer) -endif() \ No newline at end of file +endforeach() \ No newline at end of file diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 6a06b95ac28f..ac08e4ad0ef3 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -18,9 +18,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp b/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp index c20f298f847b..db22777f457a 100644 --- a/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp +++ b/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; diff --git a/Stream_support/include/CGAL/IO/WKT.h b/Stream_support/include/CGAL/IO/WKT.h index 51cf67aea6c6..ef8c7dee1f0e 100644 --- a/Stream_support/include/CGAL/IO/WKT.h +++ b/Stream_support/include/CGAL/IO/WKT.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include From 9bfe91fd405841b5653081f01da58c2cc6aee6c4 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 24 Aug 2023 16:00:55 +0200 Subject: [PATCH 083/182] missed draw function for multipolygons --- .../draw_multipolygon_with_holes_2.h | 207 ------------------ 1 file changed, 207 deletions(-) delete mode 100644 Polygon_repair/include/CGAL/Polygon_repair/draw_multipolygon_with_holes_2.h diff --git a/Polygon_repair/include/CGAL/Polygon_repair/draw_multipolygon_with_holes_2.h b/Polygon_repair/include/CGAL/Polygon_repair/draw_multipolygon_with_holes_2.h deleted file mode 100644 index 749a30579c40..000000000000 --- a/Polygon_repair/include/CGAL/Polygon_repair/draw_multipolygon_with_holes_2.h +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) 2023 GeometryFactory. -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Ken Arroyo Ohori - -#ifndef CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H -#define CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H - -#include - -#include - -#ifdef DOXYGEN_RUNNING -namespace CGAL { - -/*! - * \ingroup PkgDrawMultipolygonWithHoles2 - * - * opens a new window and draws `aph`, an instance of the - * `CGAL::Multipolygon_with_holes_2` class. A call to this function is blocking, that - * is the program continues as soon as the user closes the window. This function - * requires `CGAL_Qt5`, and is only available if the macro - * `CGAL_USE_BASIC_VIEWER` is defined. Linking with the cmake target - * `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` and add the definition - * `CGAL_USE_BASIC_VIEWER`. - * \tparam PH an instance of the `CGAL::Multipolygon_with_holes_2` class. - * \param aph the polygon with holes to draw. - */ - -template -void draw(const PH& aph); - -} /* namespace CGAL */ - -#endif - -#ifdef CGAL_USE_BASIC_VIEWER - -#include -#include - -namespace CGAL { - -// Viewer class for Multipolygon_with_holes_2 -template -class Mpwh_2_basic_viewer_qt : public Basic_viewer_qt { - using Base = Basic_viewer_qt; - using Mpwh = Multipolygon; - using Pwh = typename Mpwh::Polygon_with_holes_2; - using Pgn = typename Mpwh::Polygon_2; - using Pnt = typename Pgn::Point_2; - -public: - /// Construct the viewer. - /// @param parent the active window to draw - /// @param mpwh the multipolygon to view - /// @param title the title of the window - Mpwh_2_basic_viewer_qt(QWidget* parent, const Mpwh& mpwh, - const char* title = "Basic Multipolygon_with_holes_2 Viewer") : - Base(parent, title, true, true, true, false, false), - m_mpwh(mpwh) { - if (mpwh.number_of_polygons() == 0) return; - - // mimic the computation of Camera::pixelGLRatio() - auto bbox = bounding_box(); - CGAL::qglviewer::Vec minv(bbox.xmin(), bbox.ymin(), 0); - CGAL::qglviewer::Vec maxv(bbox.xmax(), bbox.ymax(), 0); - auto diameter = (maxv - minv).norm(); - m_pixel_ratio = diameter / m_height; - } - - /*! Intercept the resizing of the window. - */ - virtual void resizeGL(int width, int height) { - CGAL::QGLViewer::resizeGL(width, height); - m_width = width; - m_height = height; - CGAL::qglviewer::Vec p; - auto ratio = camera()->pixelGLRatio(p); - m_pixel_ratio = ratio; - add_elements(); - } - - /*! Obtain the pixel ratio. - */ - double pixel_ratio() const { return m_pixel_ratio; } - - /*! Compute the bounding box. - */ - CGAL::Bbox_2 bounding_box() { - Bbox_2 bbox; - if (m_mpwh.number_of_polygons() > 0) bbox = m_mpwh.polygons().front().outer_boundary().bbox(); - for (auto const& pwh: m_mpwh.polygons()) { - bbox += pwh.outer_boundary().bbox(); - } - return bbox; - } - - /*! Compute the elements of a multipolygon with holes. - */ - void add_elements() { - clear(); - - for (auto const& p: m_mpwh.polygons()) { - CGAL::IO::Color c(rand()%255,rand()%255,rand()%255); - face_begin(c); - - const Pnt* point_in_face; - const auto& outer_boundary = p.outer_boundary(); - compute_loop(outer_boundary, false); - point_in_face = &(outer_boundary.vertex(outer_boundary.size()-1)); - - for (auto it = p.holes_begin(); it != p.holes_end(); ++it) { - compute_loop(*it, true); - add_point_in_face(*point_in_face); - } - - face_end(); - } - } - -protected: - /*! Compute the face - */ - void compute_loop(const Pgn& p, bool hole) { - if (hole) add_point_in_face(p.vertex(p.size()-1)); - - auto prev = p.vertices_begin(); - auto it = prev; - add_point(*it); - add_point_in_face(*it); - for (++it; it != p.vertices_end(); ++it) { - add_segment(*prev, *it); // add segment with previous point - add_point(*it); - add_point_in_face(*it); // add point in face - prev = it; - } - - // Add the last segment between the last point and the first one - add_segment(*prev, *(p.vertices_begin())); - } - - virtual void keyPressEvent(QKeyEvent* e) { - // Test key pressed: - // const ::Qt::KeyboardModifiers modifiers = e->modifiers(); - // if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::NoButton)) { ... } - - // Call: * add_elements() if the model changed, followed by - // * redraw() if some viewing parameters changed that implies some - // modifications of the buffers - // (eg. type of normal, color/mono) - // * update() just to update the drawing - - // Call the base method to process others/classicals key - Base::keyPressEvent(e); - } - -private: - //! The window width in pixels. - int m_width = CGAL_BASIC_VIEWER_INIT_SIZE_X; - - //! The window height in pixels. - int m_height = CGAL_BASIC_VIEWER_INIT_SIZE_Y; - - //! The ratio between pixel and opengl units (in world coordinate system). - double m_pixel_ratio = 1; - - //! The polygon with holes to draw. - const Mpwh& m_mpwh; -}; - -// Specialization of draw function. -template -void draw(const CGAL::Multipolygon_with_holes_2& mpwh, - const char* title = "Multipolygon_with_holes_2 Basic Viewer") -{ -#if defined(CGAL_TEST_SUITE) - bool cgal_test_suite = true; -#else - bool cgal_test_suite = qEnvironmentVariableIsSet("CGAL_TEST_SUITE"); -#endif - - if (! cgal_test_suite) { - using Mpwh = CGAL::Multipolygon_with_holes_2; - using Viewer = Mpwh_2_basic_viewer_qt; - CGAL::Qt::init_ogl_context(4,3); - int argc = 1; - const char* argv[2] = {"t2_viewer", nullptr}; - QApplication app(argc, const_cast(argv)); - Viewer mainwindow(app.activeWindow(), mpwh, title); - mainwindow.add_elements(); - mainwindow.show(); - app.exec(); - } -} - -} // End namespace CGAL - -#endif // CGAL_USE_BASIC_VIEWER - -#endif // CGAL_DRAW_MULTIPOLYGON_WITH_HOLES_2_H From 3e1537dfbb451c25a74882e5543a37c9311d1c58 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 24 Aug 2023 16:01:35 +0200 Subject: [PATCH 084/182] move old examples to tests --- Polygon_repair/doc/Polygon_repair/examples.txt | 1 - .../Polygon_repair/write_labeled_triangulation.cpp | 0 .../Polygon_repair/write_repaired_polygons.cpp} | 0 3 files changed, 1 deletion(-) rename Polygon_repair/{examples => test}/Polygon_repair/write_labeled_triangulation.cpp (100%) rename Polygon_repair/{examples/Polygon_repair/nasty_polygons.cpp => test/Polygon_repair/write_repaired_polygons.cpp} (100%) diff --git a/Polygon_repair/doc/Polygon_repair/examples.txt b/Polygon_repair/doc/Polygon_repair/examples.txt index 1797f7165775..278e5049cf22 100644 --- a/Polygon_repair/doc/Polygon_repair/examples.txt +++ b/Polygon_repair/doc/Polygon_repair/examples.txt @@ -1,4 +1,3 @@ /*! \example Polygon_repair/repair_polygon_2.cpp -\example Polygon_repair/write_labeled_triangulation.cpp */ diff --git a/Polygon_repair/examples/Polygon_repair/write_labeled_triangulation.cpp b/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp similarity index 100% rename from Polygon_repair/examples/Polygon_repair/write_labeled_triangulation.cpp rename to Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp diff --git a/Polygon_repair/examples/Polygon_repair/nasty_polygons.cpp b/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp similarity index 100% rename from Polygon_repair/examples/Polygon_repair/nasty_polygons.cpp rename to Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp From 982059556a7bc00f5b02d6f26687b6ada8da6152 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 24 Aug 2023 16:34:46 +0200 Subject: [PATCH 085/182] doc with history and w/o triangulation, mp --- .../doc/Polygon_repair/Polygon_repair.txt | 137 ++++++------------ 1 file changed, 46 insertions(+), 91 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index f18f5a803953..39f44deed4e8 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -9,15 +9,14 @@ namespace CGAL { \section SectionPolygonRepair_Introduction Introduction -This package implements a polygon repair method based on a constrained -triangulation \cgalCite{ledoux2014triangulation}. Starting from a possibly invalid input -in the form of a polygon, polygon with holes or multipolygon with holes, -the method performs a constrained triangulation of the input edges, labels -each triangle according to what it represents (exterior, polygon interior -or hole), and reconstructs the polygon(s) represented by the triangulation. -The method returns a valid output stored in a multipolygon with holes. - -Different triangulation and labelling heuristics are possible, but +This package implements a polygon repair method. Starting from possibly +invalid input in the form of a polygon, polygon with holes or multipolygon +with holes, the method computes an arrangement of the input edges, labels +each face according to what it represents (exterior, polygon interior +or hole), and reconstructs the polygon(s) represented by the arrangement. +The method returns valid output stored in a multipolygon with holes. + +Different arrangement and labelling heuristics are possible, but currently only the odd-even heuristic is implemented in the package. This heuristic results in areas that are alternately assigned as polygon interiors and exterior/holes each time that an input edge is passed. @@ -56,6 +55,8 @@ Valid: (a) polygon, (b-c) polygons with holes, (d-e) multipolygons with holes. (c) and (e) show cases where boundaries intersect tangentially at a single vertex. \cgalFigureEnd +FIGURE with invalid + \subsection SubsectionPolygonRepair_Output Stricter Conditions for Output The conditions listed above are sufficient to define valid polygons, polygons @@ -78,64 +79,50 @@ lexicographic order Broadly, the algorithm consists of three steps: --# Constrained triangulation: the edges in the polygon, polygon with -holes or multipolygon with holes are added as constraints in the triangulation. --# Labeling of the faces: sets of faces forming contiguous regions that -are accessible from each other by following adjacency relationships without -passing through a constrained edge are labeled with ids according to -what they represent (exterior, polygon interior or hole). The faces iteratively -adjacent to the infinite face without passing through a constrained edge are -labeled as the exterior. --# Reconstruction of the multipolygon: each boundary of each polygon -with holes is reconstructed by finding a polygon interior triangle that is -adjacent to the exterior or a hole, then following the boundary in an -orientation that is counter-clockwise for outer boundaries and clockwise for -inner boundaries. This orientation and the polygon interior id is used to -determine what polygon with holes it belongs to and whether it is an outer or -an inner boundary. +-# Arrangement: the edges in the polygon, polygon with +holes or multipolygon with holes are added as edges in the arrangement. +-# Labeling of the faces: the resulting faces are labeled with ids +according to what they represent (exterior, polygon interior or hole). +-# Reconstruction of the multipolygon: each boundary is reconstructed, +then these are assembled into individual polygons with holes and put into a +single multipolygon with holes. FIGURE -\subsection SubsectionPolygonRepair_Triangulation Constrained triangulation +\subsection SubsectionPolygonRepair_Arrangement Arrangement For the purposes of the repair operation, the input polygon, polygon with holes or multipolygon is merely used as a container of input line segments. These line -segments are added to the constrained triangulation as constraints. +segments are added to the arrangement as edges. Internally, this is done using +a constrained triangulation where they added as constraints. With the odd-even heuristic, only the edges that are present an odd number of -times in the input will be constrained edges in the triangulation. +times in the input will be edges in the final arrangement. When these edges are only partially overlapping, only the parts that overlap -an odd number of times will be constrained edges in the triangulation. +an odd number of times will be edges in the final arrangement. This procedure is done in two steps: 1. preprocessing to eliminate identical -edges that are present an even number of times, and 2. an odd-even constraint -counting mechanism that erases existing constraints when new overlapping ones -are added. +edges that are present an even number of times, and 2. adding edges incrementally +while applying an odd-even counting mechanism, which erases existing (parts of) +edges when new overlapping ones are added. \subsection SubsectionPolygonRepair_Labeling Labeling -First, all of the polygon exterior is labeled. For this, the faces that can be -accessed by following the adjacency relationships from the infinite face without -passing through a constrained edge are labeled as exterior faces. +First, the polygon exterior is labeled. For this, all of the faces that can be +accessed from the exterior without passing through an edge are labeled as exterior +faces. -Then, with the odd-even heuristic, groups of faces that are adjacent to each other -without passing through a constrained edge are labeled. The label applied alternates -between polygon interior and hole every time that a constrained edge is passed. +Then, all other faces are labeled. For the odd-even heuristic, the label applied +alternates between polygon interior and hole every time that an edge is passed. \subsection SubsectionPolygonRepair_Reconstruction Reconstruction of the multipolygon -The algorithm reconstructs the multipolygon boundary by boundary, repeating the -process until all boundaries have been reconstructed. -Starting from a triangulation face with a polygon interior label that is adjacent -to a face with an exterior or hole label, the boundary of the polygon that contains -the edge between the two triangles is reconstructed. -The successive edges of the boundary is obtained by rotating counter-clockwise -around their common vertex, resulting in counter-clockwise cycles for outer -boundaries and clockwise cycles for inner boundaries. - -Finally, the boundaries are assembled into multipolygons using the unique labels -to know which polygon inner/outer boundaries belong to, and using the orientation -to distinguish between outer and inner boundaries. +The algorithm reconstructs the multipolygon boundary by boundary, obtaining +counter-clockwise cycles for outer boundaries and clockwise cycles for inner +boundaries. Once all boundaries have been reconstructed, the boundaries are assembled +into multipolygons using the face labels to know which polygon with holes inner/outer +boundaries belong to, and using the orientation to distinguish between the outer and +inner boundaries of each polygon with holes. \subsection SubsectionPolygonRepair_Notes Notes on the Output @@ -152,37 +139,6 @@ with holes has zero holes and extract these if needed. \section SectionPolygonRepair_Examples Examples -\subsection SubsectionPolygonRepair_Multipolygon The multipolygon with holes class - -The following example shows the creation of a multipolygon with holes and the traversal -of the polygons in it. - -\cgalExample{Polygon_repair/multipolygon.cpp} - -\subsection SubsectionPolygonRepair_WKTDraw Draw a multipolygon - -A multipolygon with holes can be visualized by calling the \link PkgPolygonRepairRef -CGAL::draw() \endlink function as shown in the following example. -This function opens a new window showing the given polygon. A call to this function -is blocking, that is the program continues as soon as the user closes the window. -Versions for polygons and polygons with holes also exist, cf. \link PkgDrawPolygon2 -CGAL::draw

() \endlink and \link PkgDrawPolygonWithHoles2 CGAL::draw() \endlink. - -The multipolygon with holes shown in this example is created using the well-known text -(WKT) reader, which can read and write multipolygons with holes. - -\cgalExample{Polygon_repair/draw_multipolygon.cpp} - -This function requires `CGAL_Qt5`, and is only available if the macro -`CGAL_USE_BASIC_VIEWER` is defined. Linking with the cmake target -`CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` and add the definition -`CGAL_USE_BASIC_VIEWER`. - -\cgalFigureBegin{draw_multipolygon, draw_multipolygon.png} -Result of the run of the draw_multipolygon program. A window shows the multipolygon -with holes and allows to navigate through the scene. -\cgalFigureEnd - \subsection SubsectionPolygonRepair_Repair Repairing a (multi)polygon It's possible to repair a polygon, polygon with holes or multipolygon with holes @@ -197,20 +153,19 @@ a hole. \cgalExample{Polygon_repair/repair_polygon_2.cpp} -\subsection SubsectionPolygonRepair_RepairHiddenApi Step by step repairing - -The following example shows to do the repair process step by step, including how -to extract the labeled triangulation, which is written as a GeoJSON file consisting -of the individual triangles with their labels. +\section SectionPolygonRepair_Performance Performance -\cgalFigureBegin{triangulation, triangulation.png} -(a) A multipolygon consisting of two polygons with one hole each, where one polygon -is inside the hole of the other (b) The labeled triangulation of the multipolygon -\cgalFigureEnd +\section SectionPolygonRepair_History History -\cgalExample{Polygon_repair/write_labeled_triangulation.cpp} +The polygon repair method as originally developed is described by Ledoux et al. +\cgalCite{ledoux2014triangulation} and implemented in the prepair software. +This package is a reimplementation of the method with a new approach to label +and reconstruct the multipolygons. It also incorporates improvements later +added to prepair, such as the application of the odd-even counting heuristic +to edges. -\section SectionPolygonRepair_Performance Performance +Ken Arroyo Ohori made a prototype version of this package for the Google Summer of +Code 2023 under the mentorship of Sébastien Loriot and Andreas Fabri. */ } /* namespace CGAL */ From 5c4e48e5bf310a5d46772475cf70e5126809bd35 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 24 Aug 2023 17:10:12 +0200 Subject: [PATCH 086/182] fix dependencies --- Polygon_repair/package_info/Polygon_repair/dependencies | 1 - Stream_support/package_info/Stream_support/dependencies | 1 - 2 files changed, 2 deletions(-) diff --git a/Polygon_repair/package_info/Polygon_repair/dependencies b/Polygon_repair/package_info/Polygon_repair/dependencies index f30877d02528..3678863c6925 100644 --- a/Polygon_repair/package_info/Polygon_repair/dependencies +++ b/Polygon_repair/package_info/Polygon_repair/dependencies @@ -5,7 +5,6 @@ Circulator Distance_2 Distance_3 Filtered_kernel -GraphicsView Hash_map Homogeneous_kernel Installation diff --git a/Stream_support/package_info/Stream_support/dependencies b/Stream_support/package_info/Stream_support/dependencies index 825609cbfe86..86fd53b13ace 100644 --- a/Stream_support/package_info/Stream_support/dependencies +++ b/Stream_support/package_info/Stream_support/dependencies @@ -7,7 +7,6 @@ Kernel_23 Modular_arithmetic Number_types Polygon -Polygon_repair Profiling_tools Property_map STL_Extension From 8192774070ac9205a89ba325fd258f8d907f288b Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 25 Aug 2023 11:19:20 +0200 Subject: [PATCH 087/182] info about multipolygons in polygon manual --- Polygon/doc/Polygon/Polygon.txt | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/Polygon/doc/Polygon/Polygon.txt b/Polygon/doc/Polygon/Polygon.txt index 9e50406194b3..284157f95ef7 100644 --- a/Polygon/doc/Polygon/Polygon.txt +++ b/Polygon/doc/Polygon/Polygon.txt @@ -37,6 +37,19 @@ points, but little more. Especially, computed values are not cached. That is, when the `Polygon_2::is_simple()` member function is called twice or more, the result is computed each time anew. +\section secPolygonWithHole Polygons with Holes and Multipolygons with Holes + +This package also provides classes to represent polygons with holes and multipolygons with holes. + +For polygons with holes, these are `Polygon_with_holes_2` and `General_polygon_with_holes_2`. They can store a polygon that represents +the outer boundary and a sequence of polygons that represent the holes. + +For multipolygons with holes, there is `Multipolygon_with_holes_2`. +It stores a sequence of polygons with holes. + +These classes do not add any semantic requirements on the simplicity +or orientation of their boundary polygons. + \section secPolygonExamples Examples \subsection subsecPolygon The Polygon Class @@ -46,6 +59,13 @@ some member functions. \cgalExample{Polygon/Polygon.cpp} +\subsection SubsectionPolygonRepair_Multipolygon The multipolygon with holes class + +The following example shows the creation of a multipolygon with holes and the traversal +of the polygons in it. + +\cgalExample{Polygon/multipolygon.cpp} + \cgalFigureBegin{polygon2_algo,pgn_algos.png} A polygon and some points \cgalFigureEnd @@ -95,15 +115,4 @@ Result of the run of the draw_polygon program. A window shows the polygon and al \cgalFigureEnd */ - -\section secPolygonWithHole Polygons with Holes - -This package also provides two classes to represent polygons with holes, -namely `Polygon_with_holes_2` and `General_polygon_with_holes_2`. They -can store a polygon that represents the outer boundary and a sequence -of polygons that represent the holes. - -These classes do not add any semantic requirements on the simplicity -or orientation of their boundary polygons. - } From 9ae9f54eeb3e694cef1fa2bed4547726c1bae51a Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 25 Aug 2023 11:26:17 +0200 Subject: [PATCH 088/182] remove old figs From 188188e1e70bf2ddc89a8c68d530747a01743652 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 25 Aug 2023 11:26:51 +0200 Subject: [PATCH 089/182] svg --- Polygon_repair/doc/Polygon_repair/Polygon_repair.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 39f44deed4e8..25c54989794b 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -50,7 +50,7 @@ are allowed to intersect tangentially at their common vertices. Note that a valid polygon with holes can also be represented as a valid multipolygon with holes (with only one polygon). -\cgalFigureBegin{multipolygons, multipolygons.png} +\cgalFigureBegin{multipolygons, multipolygons.svg} Valid: (a) polygon, (b-c) polygons with holes, (d-e) multipolygons with holes. (c) and (e) show cases where boundaries intersect tangentially at a single vertex. \cgalFigureEnd From f4c602144faa5d1c36041c5bf43dd3d8445628fd Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 25 Aug 2023 11:27:15 +0200 Subject: [PATCH 090/182] in/out will be in table --- Polygon_repair/doc/Polygon_repair/Polygon_repair.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 25c54989794b..137c3a40f3ff 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -87,7 +87,7 @@ according to what they represent (exterior, polygon interior or hole). then these are assembled into individual polygons with holes and put into a single multipolygon with holes. -FIGURE +TABLE IN/OUT \subsection SubsectionPolygonRepair_Arrangement Arrangement @@ -145,12 +145,6 @@ It's possible to repair a polygon, polygon with holes or multipolygon with holes using the odd-even rule by calling the `repair_odd_even` function as shown in the following example. This function returns a repaired multipolygon with holes. -\cgalFigureBegin{bridge_edge, bridge_edge.png} -(a) Before repair: A polygon with a single loop that implicitly creates a hole -using a bridge edge (b) After repair: the same area represented as a polygon with -a hole. -\cgalFigureEnd - \cgalExample{Polygon_repair/repair_polygon_2.cpp} \section SectionPolygonRepair_Performance Performance From ca3ad80390adaaee2f97a4ca789562951993a4fe Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 25 Aug 2023 12:03:38 +0200 Subject: [PATCH 091/182] valid and invalid examples --- Polygon_repair/doc/Polygon_repair/Polygon_repair.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 137c3a40f3ff..bf89b53a1da4 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -50,12 +50,14 @@ are allowed to intersect tangentially at their common vertices. Note that a valid polygon with holes can also be represented as a valid multipolygon with holes (with only one polygon). -\cgalFigureBegin{multipolygons, multipolygons.svg} -Valid: (a) polygon, (b-c) polygons with holes, (d-e) multipolygons with holes. +\cgalFigureBegin{valid, valid.svg} +Valid: (a) polygon, (b-c) polygons with holes, and (d-e) multipolygons with holes. (c) and (e) show cases where boundaries intersect tangentially at a single vertex. \cgalFigureEnd -FIGURE with invalid +\cgalFigureBegin{invalid, invalid.svg} +Invalid: (a) self-intersecting polygon self-intersection, (b) self-touching polygon, (c-d) polygons with badly nested holes, (e) polygon with hole touching at edge, (f) polygon with hole that separates interior into two parts, (g) multipolygon with overlapping polygons, and (h) multipolygon with polygons that touch at an edge. +\cgalFigureEnd \subsection SubsectionPolygonRepair_Output Stricter Conditions for Output From fff924b5def5ab8a96ac7a891dc45e25b8562054 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 25 Aug 2023 15:57:14 +0200 Subject: [PATCH 092/182] in/out examples --- Polygon_repair/doc/Polygon_repair/Polygon_repair.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index bf89b53a1da4..5235a77243dc 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -89,7 +89,9 @@ according to what they represent (exterior, polygon interior or hole). then these are assembled into individual polygons with holes and put into a single multipolygon with holes. -TABLE IN/OUT +\cgalFigureBegin{inout, inout.svg} +Examples of polygons with holes (a-d) and multipolygons with holes (e-h) before (left) and after (right) being repaired. +\cgalFigureEnd \subsection SubsectionPolygonRepair_Arrangement Arrangement From db09bc96ce6933af2b49083f1b5361a309e75ba5 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 29 Aug 2023 17:07:52 +0200 Subject: [PATCH 093/182] some performance info --- .../doc/Polygon_repair/Polygon_repair.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 5235a77243dc..cd3969ba832e 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -153,10 +153,24 @@ following example. This function returns a repaired multipolygon with holes. \section SectionPolygonRepair_Performance Performance +The method can repair large invalid polygons of millions of vertices in a few +seconds as long as the number of intersections between line segments is limited. +This is a realistic assumption with many invalid data sets, which only have +relatively minor issues involving a small number of their vertices/edges. +However, it is worth noting that there can be a potentially quadratic number of +intersection between edges in the worst case, leading to much worse performance +since all of these intersections need to be calculated in the overlay. + +| Polygon | Vertices | Holes | Time | +| :----: | :----: | :----: | | +| ![ ](Corine180927.jpg) | 101973 | 298 | 0.652 sec | +| ![ ](Corine2018418.jpg) | 43925 | 125 | 0.190 sec | + \section SectionPolygonRepair_History History The polygon repair method as originally developed is described by Ledoux et al. -\cgalCite{ledoux2014triangulation} and implemented in the prepair software. +\cgalCite{ledoux2014triangulation} and implemented in the +prepair software. This package is a reimplementation of the method with a new approach to label and reconstruct the multipolygons. It also incorporates improvements later added to prepair, such as the application of the odd-even counting heuristic From 423156595803f263e1b29e41a70bfa63a0454e41 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 29 Aug 2023 17:37:10 +0200 Subject: [PATCH 094/182] detect kernel automatically --- Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index ac08e4ad0ef3..2af593720ae9 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -80,7 +80,7 @@ class Polygon_repair { using Face_base = CGAL::Constrained_triangulation_face_base_2; using Face_base_with_repair_info = CGAL::Triangulation_face_base_with_repair_info_2; using Triangulation_data_structure = CGAL::Triangulation_data_structure_2; - using Tag = CGAL::Exact_predicates_tag; // assumed for now + using Tag = typename std::conditional::value, CGAL::Exact_predicates_tag, CGAL::Exact_intersections_tag>::type; using Constrained_Delaunay_triangulation = CGAL::Constrained_Delaunay_triangulation_2; using Triangulation = Triangulation_with_odd_even_constraints_2; From 69a01c7eed8a1d97c1a2800773560082463661ed Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 30 Aug 2023 13:27:02 +0200 Subject: [PATCH 095/182] unique_edges should be in class, clear all variables --- .../include/CGAL/Polygon_repair/Polygon_repair.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 2af593720ae9..9281bad46d97 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -124,8 +124,6 @@ class Polygon_repair { // Add edges of the polygon to the triangulation void add_to_triangulation_odd_even(const Polygon_2& polygon) { - std::unordered_set, - boost::hash>> unique_edges; // Get unique edges for (auto const& edge: polygon.edges()) { @@ -167,8 +165,6 @@ class Polygon_repair { // Add edges of the polygon to the triangulation void add_to_triangulation_odd_even(const Polygon_with_holes_2& polygon) { - std::unordered_set, - boost::hash>> unique_edges; // Get unique edges for (auto const& edge: polygon.outer_boundary().edges()) { @@ -219,8 +215,6 @@ class Polygon_repair { // Add edges of the polygon to the triangulation void add_to_triangulation_odd_even(const Multipolygon_with_holes_2& multipolygon) { - std::unordered_set, - boost::hash>> unique_edges; // Get unique edges for (auto const& polygon: multipolygon.polygons()) { @@ -439,6 +433,11 @@ class Polygon_repair { // Erases the triangulation. void clear() { t.clear(); + unique_edges.clear(); + mp.clear(); + number_of_polygons = 0; + number_of_holes = 0; + search_start = Triangulation::Face_handle(); } /// @} @@ -459,6 +458,8 @@ class Polygon_repair { protected: Triangulation t; + std::unordered_set, + boost::hash>> unique_edges; Multipolygon_with_holes_2 mp; int number_of_polygons, number_of_holes; typename Triangulation::Face_handle search_start; From 79edf301c950bd27bd4c3930389026da1ce117e0 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 30 Aug 2023 13:27:11 +0200 Subject: [PATCH 096/182] explain counting --- Polygon_repair/doc/Polygon_repair/Polygon_repair.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index cd3969ba832e..f950d5630d67 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -174,7 +174,7 @@ The polygon repair method as originally developed is described by Ledoux et al. This package is a reimplementation of the method with a new approach to label and reconstruct the multipolygons. It also incorporates improvements later added to prepair, such as the application of the odd-even counting heuristic -to edges. +to edges, which enables correct counting even on partially overlapping edges. Ken Arroyo Ohori made a prototype version of this package for the Google Summer of Code 2023 under the mentorship of Sébastien Loriot and Andreas Fabri. From d174f6a44502e3f2e203631e0df1ea461d98278d Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 30 Aug 2023 13:27:23 +0200 Subject: [PATCH 097/182] doc formatting --- Polygon_repair/doc/Polygon_repair/Polygon_repair.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index f950d5630d67..6547a97d482f 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -56,7 +56,10 @@ Valid: (a) polygon, (b-c) polygons with holes, and (d-e) multipolygons with hole \cgalFigureEnd \cgalFigureBegin{invalid, invalid.svg} -Invalid: (a) self-intersecting polygon self-intersection, (b) self-touching polygon, (c-d) polygons with badly nested holes, (e) polygon with hole touching at edge, (f) polygon with hole that separates interior into two parts, (g) multipolygon with overlapping polygons, and (h) multipolygon with polygons that touch at an edge. +Invalid: (a) self-intersecting polygon self-intersection, (b) self-touching polygon, +(c-d) polygons with badly nested holes, (e) polygon with hole touching at edge, +(f) polygon with hole that separates interior into two parts, (g) multipolygon +with overlapping polygons, and (h) multipolygon with polygons that touch at an edge. \cgalFigureEnd \subsection SubsectionPolygonRepair_Output Stricter Conditions for Output @@ -90,7 +93,8 @@ then these are assembled into individual polygons with holes and put into a single multipolygon with holes. \cgalFigureBegin{inout, inout.svg} -Examples of polygons with holes (a-d) and multipolygons with holes (e-h) before (left) and after (right) being repaired. +Examples of polygons with holes (a-d) and multipolygons with holes +(e-h) before (left) and after (right) being repaired. \cgalFigureEnd \subsection SubsectionPolygonRepair_Arrangement Arrangement From f2cb4edce86319031cc5ed2ce32ec96f6ec1a10e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 30 Aug 2023 18:37:30 +0200 Subject: [PATCH 098/182] draft (multi)polygon validation --- .../CGAL/Polygon_repair/Polygon_repair.h | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 9281bad46d97..e14673dcb613 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -83,6 +83,7 @@ class Polygon_repair { using Tag = typename std::conditional::value, CGAL::Exact_predicates_tag, CGAL::Exact_intersections_tag>::type; using Constrained_Delaunay_triangulation = CGAL::Constrained_Delaunay_triangulation_2; using Triangulation = Triangulation_with_odd_even_constraints_2; + using Validation_triangulation = CGAL::Constrained_triangulation_2; struct Polygon_less { using Polygon_2 = CGAL::Polygon_2; @@ -429,6 +430,110 @@ class Polygon_repair { mp.add_polygon(polygon); } } + + // Validation + bool is_valid(const Polygon_2& polygon) { + Validation_triangulation vt; + + // Intersections between edges + for (auto const& edge: polygon.edges()) { + if (edge.source() == edge.target()) { + std::cout << "Invalid: duplicate vertices" << std::endl; + return false; + } try { + vt.insert_constraint(edge.source(), edge.target()); + } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { + std::cout << "Invalid: intersecting edges" << std::endl; + return false; + } + } + + // Connected interior with no holes + for (auto const face: t.all_face_handles()) { + face->label() = 0; + face->processed() = false; + } std::list to_check; + std::list to_check_added_by; + label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior + int regions = 0, holes = 0; + while (!to_check.empty()) { + if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check_added_by.front() < 0) { + label_region(to_check.front(), regions+1, to_check, to_check_added_by); + ++regions; + } else { + label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + ++holes; + } + } to_check.pop_front(); + to_check_added_by.pop_front(); + } if (regions > 1) { + std::cout << "Invalid: disconnected interior" << std::endl; + return false; + } if (holes > 0) { + std::cout << "Invalid: hole(s)" << std::endl; + return false; + } + + return true; + } + + bool is_valid(const Polygon_with_holes_2& polygon) { + Validation_triangulation vt; + + // Intersections between edges of outer boundary + for (auto const& edge: polygon.outer_boundary().edges()) { + if (edge.source() == edge.target()) { + std::cout << "Invalid: duplicate vertices" << std::endl; + return false; + } try { + vt.insert_constraint(edge.source(), edge.target()); + } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { + std::cout << "Invalid: intersecting edges" << std::endl; + return false; + } + } + + // Connected interior with no holes + for (auto const face: t.all_face_handles()) { + face->label() = 0; + face->processed() = false; + } std::list to_check; + std::list to_check_added_by; + label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior + int regions = 0, holes = 0; + while (!to_check.empty()) { + if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check_added_by.front() < 0) { + label_region(to_check.front(), regions+1, to_check, to_check_added_by); + ++regions; + } else { + label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + ++holes; + } + } to_check.pop_front(); + to_check_added_by.pop_front(); + } if (regions > 1) { + std::cout << "Invalid: disconnected interior" << std::endl; + return false; + } if (holes > 0) { + std::cout << "Invalid: hole(s)" << std::endl; + return false; + } + + // Hole nesting + for (auto const& hole: polygon.holes()) { + for (auto const& vertex: hole.vertices()) { + + } + } + + return true; + } + + bool is_valid(const Multipolygon_with_holes_2& multipolygon) { + return true; + } // Erases the triangulation. void clear() { From d5f0f7748d76486af9861d201ecca0afcc18b87b Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 30 Aug 2023 18:38:06 +0200 Subject: [PATCH 099/182] missed a part --- .../CGAL/Polygon_repair/Polygon_repair.h | 162 +++++++++++++++++- 1 file changed, 155 insertions(+), 7 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index e14673dcb613..342f557e3f9f 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -83,7 +83,8 @@ class Polygon_repair { using Tag = typename std::conditional::value, CGAL::Exact_predicates_tag, CGAL::Exact_intersections_tag>::type; using Constrained_Delaunay_triangulation = CGAL::Constrained_Delaunay_triangulation_2; using Triangulation = Triangulation_with_odd_even_constraints_2; - using Validation_triangulation = CGAL::Constrained_triangulation_2; + using Validation_tag = CGAL::No_constraint_intersection_tag; + using Validation_triangulation = CGAL::Constrained_triangulation_2; struct Polygon_less { using Polygon_2 = CGAL::Polygon_2; @@ -467,6 +468,9 @@ class Polygon_repair { } } to_check.pop_front(); to_check_added_by.pop_front(); + } if (regions < 1) { + std::cout << "Invalid: no interior" << std::endl; + return false; } if (regions > 1) { std::cout << "Invalid: disconnected interior" << std::endl; return false; @@ -484,17 +488,17 @@ class Polygon_repair { // Intersections between edges of outer boundary for (auto const& edge: polygon.outer_boundary().edges()) { if (edge.source() == edge.target()) { - std::cout << "Invalid: duplicate vertices" << std::endl; + std::cout << "Invalid: duplicate vertices (outer boundary)" << std::endl; return false; } try { vt.insert_constraint(edge.source(), edge.target()); } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { - std::cout << "Invalid: intersecting edges" << std::endl; + std::cout << "Invalid: intersecting edges (outer boundary)" << std::endl; return false; } } - // Connected interior with no holes + // Connected interior ignoring holes for (auto const face: t.all_face_handles()) { face->label() = 0; face->processed() = false; @@ -513,25 +517,169 @@ class Polygon_repair { } } to_check.pop_front(); to_check_added_by.pop_front(); + } if (regions < 1) { + std::cout << "Invalid: no interior (outer boundary)" << std::endl; + return false; } if (regions > 1) { - std::cout << "Invalid: disconnected interior" << std::endl; + std::cout << "Invalid: disconnected interior (outer boundary)" << std::endl; return false; } if (holes > 0) { - std::cout << "Invalid: hole(s)" << std::endl; + std::cout << "Invalid: hole(s) formed by outer boundary" << std::endl; return false; } // Hole nesting for (auto const& hole: polygon.holes()) { for (auto const& vertex: hole.vertices()) { - + typename Validation_triangulation::Locate_type lt; + int li; + typename Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); + if (lt == Validation_triangulation::Locate_type::FACE && f->label() != 1) { + std::cout << "Invalid: hole outside outer boundary" << std::endl; + return false; + } + } for (auto const& edge: hole.edges()) { + if (edge.source() == edge.target()) { + std::cout << "Invalid: duplicate vertices (hole)" << std::endl; + return false; + } try { + vt.insert_constraint(edge.source(), edge.target()); + } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { + std::cout << "Invalid: intersecting edges (involving hole)" << std::endl; + return false; + } } + } for (auto const face: t.all_face_handles()) { + face->label() = 0; + face->processed() = false; + } to_check.clear(); + to_check_added_by.clear(); + label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior + regions = 0; + holes = 0; + while (!to_check.empty()) { + if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check_added_by.front() < 0) { + label_region(to_check.front(), regions+1, to_check, to_check_added_by); + ++regions; + } else { + label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + ++holes; + } + } to_check.pop_front(); + to_check_added_by.pop_front(); + } if (regions < 1) { + std::cout << "Invalid: no interior" << std::endl; + return false; + } if (regions > 1) { + std::cout << "Invalid: disconnected interior" << std::endl; + return false; + } if (holes != polygon.number_of_holes()) { + std::cout << "Invalid: hole(s) with disconnected interior" << std::endl; + return false; } return true; } bool is_valid(const Multipolygon_with_holes_2& multipolygon) { + Validation_triangulation vt; + + // Intersections between edges of outer boundary + for (auto const& polygon: multipolygon.polygons()) { + for (auto const& edge: polygon.outer_boundary().edges()) { + if (edge.source() == edge.target()) { + std::cout << "Invalid: duplicate vertices (outer boundary)" << std::endl; + return false; + } try { + vt.insert_constraint(edge.source(), edge.target()); + } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { + std::cout << "Invalid: intersecting edges (outer boundary)" << std::endl; + return false; + } + } + } + + // Connected interior ignoring holes + for (auto const face: t.all_face_handles()) { + face->label() = 0; + face->processed() = false; + } std::list to_check; + std::list to_check_added_by; + label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior + int regions = 0, holes = 0; + while (!to_check.empty()) { + if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check_added_by.front() < 0) { + label_region(to_check.front(), regions+1, to_check, to_check_added_by); + ++regions; + } else { + label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + ++holes; + } + } to_check.pop_front(); + to_check_added_by.pop_front(); + } if (regions != multipolygon.number_of_polygons()) { + std::cout << "Invalid: polygon(s) with disconnected interior (outer boundary)" << std::endl; + return false; + } if (holes > 0) { + std::cout << "Invalid: hole(s) formed by outer boundary" << std::endl; + return false; + } + + // Hole nesting + for (auto const& polygon: multipolygon.polygons()) { + for (auto const& hole: polygon.holes()) { + for (auto const& vertex: hole.vertices()) { + typename Validation_triangulation::Locate_type lt; + int li; + typename Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); + if (lt == Validation_triangulation::Locate_type::FACE && f->label() < 1) { + std::cout << "Invalid: hole outside outer boundary" << std::endl; + return false; + } + } for (auto const& edge: hole.edges()) { + if (edge.source() == edge.target()) { + std::cout << "Invalid: duplicate vertices (hole)" << std::endl; + return false; + } try { + vt.insert_constraint(edge.source(), edge.target()); + } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { + std::cout << "Invalid: intersecting edges (involving hole)" << std::endl; + return false; + } + } + } + } for (auto const face: t.all_face_handles()) { + face->label() = 0; + face->processed() = false; + } to_check.clear(); + to_check_added_by.clear(); + label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior + regions = 0; + holes = 0; + while (!to_check.empty()) { + if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check_added_by.front() < 0) { + label_region(to_check.front(), regions+1, to_check, to_check_added_by); + ++regions; + } else { + label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + ++holes; + } + } to_check.pop_front(); + to_check_added_by.pop_front(); + } if (regions != multipolygon.number_of_polygons()) { + std::cout << "Invalid: polygon(s) with disconnected interior (involving holes)" << std::endl; + return false; + } int total_holes = 0; + for (auto const& polygon: multipolygon.number_of_polygons()) { + total_holes += polygon.number_of_holes(); + } if (holes != total_holes) { + std::cout << "Invalid: hole(s) with disconnected interior" << std::endl; + return false; + } + return true; } From fdc5fa5fec4e953275f61d8c86db2c2ede4a0e4a Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 30 Aug 2023 18:41:20 +0200 Subject: [PATCH 100/182] trim whitespace --- .../CGAL/Polygon_repair/Polygon_repair.h | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 342f557e3f9f..a1a80a1aa633 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -431,11 +431,11 @@ class Polygon_repair { mp.add_polygon(polygon); } } - + // Validation bool is_valid(const Polygon_2& polygon) { Validation_triangulation vt; - + // Intersections between edges for (auto const& edge: polygon.edges()) { if (edge.source() == edge.target()) { @@ -448,7 +448,7 @@ class Polygon_repair { return false; } } - + // Connected interior with no holes for (auto const face: t.all_face_handles()) { face->label() = 0; @@ -478,13 +478,13 @@ class Polygon_repair { std::cout << "Invalid: hole(s)" << std::endl; return false; } - + return true; } - + bool is_valid(const Polygon_with_holes_2& polygon) { Validation_triangulation vt; - + // Intersections between edges of outer boundary for (auto const& edge: polygon.outer_boundary().edges()) { if (edge.source() == edge.target()) { @@ -497,7 +497,7 @@ class Polygon_repair { return false; } } - + // Connected interior ignoring holes for (auto const face: t.all_face_handles()) { face->label() = 0; @@ -527,7 +527,7 @@ class Polygon_repair { std::cout << "Invalid: hole(s) formed by outer boundary" << std::endl; return false; } - + // Hole nesting for (auto const& hole: polygon.holes()) { for (auto const& vertex: hole.vertices()) { @@ -578,13 +578,13 @@ class Polygon_repair { std::cout << "Invalid: hole(s) with disconnected interior" << std::endl; return false; } - + return true; } - + bool is_valid(const Multipolygon_with_holes_2& multipolygon) { Validation_triangulation vt; - + // Intersections between edges of outer boundary for (auto const& polygon: multipolygon.polygons()) { for (auto const& edge: polygon.outer_boundary().edges()) { @@ -599,7 +599,7 @@ class Polygon_repair { } } } - + // Connected interior ignoring holes for (auto const face: t.all_face_handles()) { face->label() = 0; @@ -626,7 +626,7 @@ class Polygon_repair { std::cout << "Invalid: hole(s) formed by outer boundary" << std::endl; return false; } - + // Hole nesting for (auto const& polygon: multipolygon.polygons()) { for (auto const& hole: polygon.holes()) { @@ -679,7 +679,7 @@ class Polygon_repair { std::cout << "Invalid: hole(s) with disconnected interior" << std::endl; return false; } - + return true; } From 6626b5205bc8162fac3dc6fabfd4bf4bd4d7f801 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 30 Aug 2023 21:25:39 +0200 Subject: [PATCH 101/182] better approach reusing existing functions + testing more cases --- .../CGAL/Polygon_repair/Polygon_repair.h | 250 +++++++----------- 1 file changed, 96 insertions(+), 154 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index a1a80a1aa633..cad6670b3645 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -434,71 +434,48 @@ class Polygon_repair { // Validation bool is_valid(const Polygon_2& polygon) { - Validation_triangulation vt; - - // Intersections between edges for (auto const& edge: polygon.edges()) { if (edge.source() == edge.target()) { std::cout << "Invalid: duplicate vertices" << std::endl; return false; - } try { - vt.insert_constraint(edge.source(), edge.target()); - } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { - std::cout << "Invalid: intersecting edges" << std::endl; - return false; } - } - - // Connected interior with no holes - for (auto const face: t.all_face_handles()) { - face->label() = 0; - face->processed() = false; - } std::list to_check; - std::list to_check_added_by; - label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior - int regions = 0, holes = 0; - while (!to_check.empty()) { - if (to_check.front()->label() == 0) { // label = 0 means not labelled yet - if (to_check_added_by.front() < 0) { - label_region(to_check.front(), regions+1, to_check, to_check_added_by); - ++regions; - } else { - label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); - ++holes; - } - } to_check.pop_front(); - to_check_added_by.pop_front(); - } if (regions < 1) { - std::cout << "Invalid: no interior" << std::endl; - return false; - } if (regions > 1) { - std::cout << "Invalid: disconnected interior" << std::endl; - return false; - } if (holes > 0) { - std::cout << "Invalid: hole(s)" << std::endl; + } if (!polygon.is_simple()) { + std::cout << "Invalid: not simple" << std::endl; return false; - } - - return true; + } return true; } bool is_valid(const Polygon_with_holes_2& polygon) { - Validation_triangulation vt; - // Intersections between edges of outer boundary + // Validate outer boundary for (auto const& edge: polygon.outer_boundary().edges()) { if (edge.source() == edge.target()) { - std::cout << "Invalid: duplicate vertices (outer boundary)" << std::endl; + std::cout << "Invalid: duplicate vertices in outer boundary" << std::endl; return false; - } try { - vt.insert_constraint(edge.source(), edge.target()); - } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { - std::cout << "Invalid: intersecting edges (outer boundary)" << std::endl; + } + } if (!polygon.outer_boundary().is_simple()) { + std::cout << "Invalid: outer boundary not simple" << std::endl; + return false; + } + + // Validate holes + for (auto const& hole: polygon.holes()) { + for (auto const& edge: hole.edges()) { + if (edge.source() == edge.target()) { + std::cout << "Invalid: duplicate vertices in hole" << std::endl; + return false; + } + } if (!hole.is_simple()) { + std::cout << "Invalid: hole not simple" << std::endl; return false; } } - // Connected interior ignoring holes + // Create triangulation of outer boundary + Validation_triangulation vt; + for (auto const& edge: polygon.outer_boundary().edges()) { + vt.insert_constraint(edge.source(), edge.target()); + } for (auto const face: t.all_face_handles()) { face->label() = 0; face->processed() = false; @@ -517,16 +494,7 @@ class Polygon_repair { } } to_check.pop_front(); to_check_added_by.pop_front(); - } if (regions < 1) { - std::cout << "Invalid: no interior (outer boundary)" << std::endl; - return false; - } if (regions > 1) { - std::cout << "Invalid: disconnected interior (outer boundary)" << std::endl; - return false; - } if (holes > 0) { - std::cout << "Invalid: hole(s) formed by outer boundary" << std::endl; - return false; - } + } CGAL_assertion(regions == 1 && holes == 0); // Hole nesting for (auto const& hole: polygon.holes()) { @@ -535,21 +503,22 @@ class Polygon_repair { int li; typename Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); if (lt == Validation_triangulation::Locate_type::FACE && f->label() != 1) { - std::cout << "Invalid: hole outside outer boundary" << std::endl; + std::cout << "Invalid: hole (partly) outside outer boundary" << std::endl; return false; } - } for (auto const& edge: hole.edges()) { - if (edge.source() == edge.target()) { - std::cout << "Invalid: duplicate vertices (hole)" << std::endl; - return false; - } try { + } + for (auto const& edge: hole.edges()) { + try { vt.insert_constraint(edge.source(), edge.target()); } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { - std::cout << "Invalid: intersecting edges (involving hole)" << std::endl; + std::cout << "Invalid: hole (partly) outside outer boundary" << std::endl; return false; } } - } for (auto const face: t.all_face_handles()) { + } + + // Connected interior + for (auto const face: t.all_face_handles()) { face->label() = 0; face->processed() = false; } to_check.clear(); @@ -568,116 +537,89 @@ class Polygon_repair { } } to_check.pop_front(); to_check_added_by.pop_front(); - } if (regions < 1) { - std::cout << "Invalid: no interior" << std::endl; - return false; - } if (regions > 1) { + } if (regions != 1) { std::cout << "Invalid: disconnected interior" << std::endl; return false; - } if (holes != polygon.number_of_holes()) { - std::cout << "Invalid: hole(s) with disconnected interior" << std::endl; - return false; - } + } CGAL_assertion(holes == polygon.number_of_holes()); return true; } bool is_valid(const Multipolygon_with_holes_2& multipolygon) { - Validation_triangulation vt; - // Intersections between edges of outer boundary + // Validate polygons for (auto const& polygon: multipolygon.polygons()) { - for (auto const& edge: polygon.outer_boundary().edges()) { - if (edge.source() == edge.target()) { - std::cout << "Invalid: duplicate vertices (outer boundary)" << std::endl; - return false; - } try { - vt.insert_constraint(edge.source(), edge.target()); - } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { - std::cout << "Invalid: intersecting edges (outer boundary)" << std::endl; - return false; - } - } + if (!is_valid(polygon)) return false; } - // Connected interior ignoring holes - for (auto const face: t.all_face_handles()) { - face->label() = 0; - face->processed() = false; - } std::list to_check; - std::list to_check_added_by; - label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior - int regions = 0, holes = 0; - while (!to_check.empty()) { - if (to_check.front()->label() == 0) { // label = 0 means not labelled yet - if (to_check_added_by.front() < 0) { - label_region(to_check.front(), regions+1, to_check, to_check_added_by); - ++regions; - } else { - label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); - ++holes; + Validation_triangulation vt; + typename Validation_triangulation::Locate_type lt; + int li; + for (auto const& polygon: multipolygon.polygons()) { + + + if (vt.number_of_triangles() > 0) { + + // Relabel + for (auto const face: t.all_face_handles()) { + face->label() = 0; + face->processed() = false; + } std::list to_check; + std::list to_check_added_by; + label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior + int regions = 0, holes = 0; + while (!to_check.empty()) { + if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check_added_by.front() < 0) { + label_region(to_check.front(), regions+1, to_check, to_check_added_by); + ++regions; + } else { + label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + ++holes; + } + } to_check.pop_front(); + to_check_added_by.pop_front(); } - } to_check.pop_front(); - to_check_added_by.pop_front(); - } if (regions != multipolygon.number_of_polygons()) { - std::cout << "Invalid: polygon(s) with disconnected interior (outer boundary)" << std::endl; - return false; - } if (holes > 0) { - std::cout << "Invalid: hole(s) formed by outer boundary" << std::endl; - return false; - } - // Hole nesting - for (auto const& polygon: multipolygon.polygons()) { - for (auto const& hole: polygon.holes()) { - for (auto const& vertex: hole.vertices()) { - typename Validation_triangulation::Locate_type lt; - int li; + // Test vertices in labelled triangulation + for (auto const& vertex: polygon.outer_boundary().vertices()) { typename Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); - if (lt == Validation_triangulation::Locate_type::FACE && f->label() < 1) { - std::cout << "Invalid: hole outside outer boundary" << std::endl; + if (lt == Validation_triangulation::Locate_type::FACE && f->label() != -1) { + std::cout << "Invalid: (partly) overlapping polygons" << std::endl; return false; } - } for (auto const& edge: hole.edges()) { - if (edge.source() == edge.target()) { - std::cout << "Invalid: duplicate vertices (hole)" << std::endl; - return false; - } try { + } + for (auto const& hole: polygon.holes()) { + for (auto const& vertex: hole.vertices()) { + typename Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); + if (lt == Validation_triangulation::Locate_type::FACE && f->label() != -1) { + std::cout << "Invalid: (partly) overlapping polygons" << std::endl; + return false; + } + } + } + + } + + // Insert constraints while checking for intersections + for (auto const& edge: polygon.outer_boundary().edges()) { + try { + vt.insert_constraint(edge.source(), edge.target()); + } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { + std::cout << "Invalid: (partly) overlapping polygons" << std::endl; + return false; + } + } + for (auto const& hole: polygon.holes()) { + for (auto const& edge: hole.edges()) { + try { vt.insert_constraint(edge.source(), edge.target()); } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { - std::cout << "Invalid: intersecting edges (involving hole)" << std::endl; + std::cout << "Invalid: (partly) overlapping polygons" << std::endl; return false; } } } - } for (auto const face: t.all_face_handles()) { - face->label() = 0; - face->processed() = false; - } to_check.clear(); - to_check_added_by.clear(); - label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior - regions = 0; - holes = 0; - while (!to_check.empty()) { - if (to_check.front()->label() == 0) { // label = 0 means not labelled yet - if (to_check_added_by.front() < 0) { - label_region(to_check.front(), regions+1, to_check, to_check_added_by); - ++regions; - } else { - label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); - ++holes; - } - } to_check.pop_front(); - to_check_added_by.pop_front(); - } if (regions != multipolygon.number_of_polygons()) { - std::cout << "Invalid: polygon(s) with disconnected interior (involving holes)" << std::endl; - return false; - } int total_holes = 0; - for (auto const& polygon: multipolygon.number_of_polygons()) { - total_holes += polygon.number_of_holes(); - } if (holes != total_holes) { - std::cout << "Invalid: hole(s) with disconnected interior" << std::endl; - return false; } return true; From 448e611e7f61ebaf83c83139574bfc8aa1e61a11 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 30 Aug 2023 21:26:32 +0200 Subject: [PATCH 102/182] images for doc From 1b4ce1c96598f79b99639c0123da4aa120f78c31 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 31 Aug 2023 15:30:30 +0200 Subject: [PATCH 103/182] put is_valid outside, bugfixes --- .../CGAL/Polygon_repair/Polygon_repair.h | 388 +++++++++--------- 1 file changed, 195 insertions(+), 193 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index cad6670b3645..be6a006fe0c1 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -67,6 +67,201 @@ Multipolygon_with_holes_2 repair_odd_even(const Multip } return pr.multipolygon(); } +template +bool is_valid(const Polygon_2& polygon) { + for (auto const& edge: polygon.edges()) { + if (edge.source() == edge.target()) { + std::cout << "Invalid: duplicate vertices" << std::endl; + return false; + } + } if (!polygon.is_simple()) { + std::cout << "Invalid: not simple" << std::endl; + return false; + } return true; +} + +template +bool is_valid(const Polygon_with_holes_2& polygon) { + + // Validate outer boundary + for (auto const& edge: polygon.outer_boundary().edges()) { + if (edge.source() == edge.target()) { + std::cout << "Invalid: duplicate vertices in outer boundary" << std::endl; + return false; + } + } if (!polygon.outer_boundary().is_simple()) { + std::cout << "Invalid: outer boundary not simple" << std::endl; + return false; + } + + // Validate holes + for (auto const& hole: polygon.holes()) { + for (auto const& edge: hole.edges()) { + if (edge.source() == edge.target()) { + std::cout << "Invalid: duplicate vertices in hole" << std::endl; + return false; + } + } if (!hole.is_simple()) { + std::cout << "Invalid: hole not simple" << std::endl; + return false; + } + } + + // Create triangulation of outer boundary + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation vt; + for (auto const& edge: polygon.outer_boundary().edges()) { + vt.insert_constraint(edge.source(), edge.target()); + } + for (auto const face: vt.all_face_handles()) { + face->label() = 0; + face->processed() = false; + } std::list::Validation_triangulation::Face_handle> to_check; + std::list to_check_added_by; + label_region(vt.infinite_face(), -1, to_check, to_check_added_by); // exterior + int regions = 0, holes = 0; + while (!to_check.empty()) { + if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check_added_by.front() < 0) { + label_region(to_check.front(), regions+1, to_check, to_check_added_by); + ++regions; + } else { + label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + ++holes; + } + } to_check.pop_front(); + to_check_added_by.pop_front(); + } CGAL_assertion(regions == 1 && holes == 0); + + // Hole nesting + for (auto const& hole: polygon.holes()) { + for (auto const& vertex: hole.vertices()) { + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type lt; + int li; + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); + if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() != 1) { + std::cout << "Invalid: hole (partly) outside outer boundary" << std::endl; + return false; + } + } + for (auto const& edge: hole.edges()) { + try { + vt.insert_constraint(edge.source(), edge.target()); + } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { + std::cout << "Invalid: hole (partly) outside outer boundary" << std::endl; + return false; + } + } + } + + // Connected interior + for (auto const face: vt.all_face_handles()) { + face->label() = 0; + face->processed() = false; + } to_check.clear(); + to_check_added_by.clear(); + label_region(vt.infinite_face(), -1, to_check, to_check_added_by); // exterior + regions = 0; + holes = 0; + while (!to_check.empty()) { + if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check_added_by.front() < 0) { + label_region(to_check.front(), regions+1, to_check, to_check_added_by); + ++regions; + } else { + label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + ++holes; + } + } to_check.pop_front(); + to_check_added_by.pop_front(); + } if (regions != 1) { + std::cout << "Invalid: disconnected interior" << std::endl; + return false; + } CGAL_assertion(holes == polygon.number_of_holes()); + + return true; +} + +template +bool is_valid(const Multipolygon_with_holes_2& multipolygon) { + + // Validate polygons + for (auto const& polygon: multipolygon.polygons()) { + if (!is_valid(polygon)) return false; + } + + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation vt; + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type lt; + int li; + for (auto const& polygon: multipolygon.polygons()) { + + + if (vt.number_of_triangles() > 0) { + + // Relabel + for (auto const face: vt.all_face_handles()) { + face->label() = 0; + face->processed() = false; + } std::list::Validation_triangulation::Face_handle> to_check; + std::list to_check_added_by; + label_region(vt.infinite_face(), -1, to_check, to_check_added_by); // exterior + int regions = 0, holes = 0; + while (!to_check.empty()) { + if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check_added_by.front() < 0) { + label_region(to_check.front(), regions+1, to_check, to_check_added_by); + ++regions; + } else { + label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + ++holes; + } + } to_check.pop_front(); + to_check_added_by.pop_front(); + } + + // Test vertices in labelled triangulation + for (auto const& vertex: polygon.outer_boundary().vertices()) { + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); + if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() != -1) { + std::cout << "Invalid: (partly) overlapping polygons" << std::endl; + return false; + } + } + for (auto const& hole: polygon.holes()) { + for (auto const& vertex: hole.vertices()) { + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); + if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() != -1) { + std::cout << "Invalid: (partly) overlapping polygons" << std::endl; + return false; + } + } + } + + } + + // Insert constraints while checking for intersections + for (auto const& edge: polygon.outer_boundary().edges()) { + try { + vt.insert_constraint(edge.source(), edge.target()); + } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { + std::cout << "Invalid: (partly) overlapping polygons" << std::endl; + return false; + } + } + for (auto const& hole: polygon.holes()) { + for (auto const& edge: hole.edges()) { + try { + vt.insert_constraint(edge.source(), edge.target()); + } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { + std::cout << "Invalid: (partly) overlapping polygons" << std::endl; + return false; + } + } + } + } + + return true; +} + /*! \ingroup PkgPolygonRepairRef * * The class `Polygon_repair` builds on a constrained @@ -432,199 +627,6 @@ class Polygon_repair { } } - // Validation - bool is_valid(const Polygon_2& polygon) { - for (auto const& edge: polygon.edges()) { - if (edge.source() == edge.target()) { - std::cout << "Invalid: duplicate vertices" << std::endl; - return false; - } - } if (!polygon.is_simple()) { - std::cout << "Invalid: not simple" << std::endl; - return false; - } return true; - } - - bool is_valid(const Polygon_with_holes_2& polygon) { - - // Validate outer boundary - for (auto const& edge: polygon.outer_boundary().edges()) { - if (edge.source() == edge.target()) { - std::cout << "Invalid: duplicate vertices in outer boundary" << std::endl; - return false; - } - } if (!polygon.outer_boundary().is_simple()) { - std::cout << "Invalid: outer boundary not simple" << std::endl; - return false; - } - - // Validate holes - for (auto const& hole: polygon.holes()) { - for (auto const& edge: hole.edges()) { - if (edge.source() == edge.target()) { - std::cout << "Invalid: duplicate vertices in hole" << std::endl; - return false; - } - } if (!hole.is_simple()) { - std::cout << "Invalid: hole not simple" << std::endl; - return false; - } - } - - // Create triangulation of outer boundary - Validation_triangulation vt; - for (auto const& edge: polygon.outer_boundary().edges()) { - vt.insert_constraint(edge.source(), edge.target()); - } - for (auto const face: t.all_face_handles()) { - face->label() = 0; - face->processed() = false; - } std::list to_check; - std::list to_check_added_by; - label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior - int regions = 0, holes = 0; - while (!to_check.empty()) { - if (to_check.front()->label() == 0) { // label = 0 means not labelled yet - if (to_check_added_by.front() < 0) { - label_region(to_check.front(), regions+1, to_check, to_check_added_by); - ++regions; - } else { - label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); - ++holes; - } - } to_check.pop_front(); - to_check_added_by.pop_front(); - } CGAL_assertion(regions == 1 && holes == 0); - - // Hole nesting - for (auto const& hole: polygon.holes()) { - for (auto const& vertex: hole.vertices()) { - typename Validation_triangulation::Locate_type lt; - int li; - typename Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); - if (lt == Validation_triangulation::Locate_type::FACE && f->label() != 1) { - std::cout << "Invalid: hole (partly) outside outer boundary" << std::endl; - return false; - } - } - for (auto const& edge: hole.edges()) { - try { - vt.insert_constraint(edge.source(), edge.target()); - } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { - std::cout << "Invalid: hole (partly) outside outer boundary" << std::endl; - return false; - } - } - } - - // Connected interior - for (auto const face: t.all_face_handles()) { - face->label() = 0; - face->processed() = false; - } to_check.clear(); - to_check_added_by.clear(); - label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior - regions = 0; - holes = 0; - while (!to_check.empty()) { - if (to_check.front()->label() == 0) { // label = 0 means not labelled yet - if (to_check_added_by.front() < 0) { - label_region(to_check.front(), regions+1, to_check, to_check_added_by); - ++regions; - } else { - label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); - ++holes; - } - } to_check.pop_front(); - to_check_added_by.pop_front(); - } if (regions != 1) { - std::cout << "Invalid: disconnected interior" << std::endl; - return false; - } CGAL_assertion(holes == polygon.number_of_holes()); - - return true; - } - - bool is_valid(const Multipolygon_with_holes_2& multipolygon) { - - // Validate polygons - for (auto const& polygon: multipolygon.polygons()) { - if (!is_valid(polygon)) return false; - } - - Validation_triangulation vt; - typename Validation_triangulation::Locate_type lt; - int li; - for (auto const& polygon: multipolygon.polygons()) { - - - if (vt.number_of_triangles() > 0) { - - // Relabel - for (auto const face: t.all_face_handles()) { - face->label() = 0; - face->processed() = false; - } std::list to_check; - std::list to_check_added_by; - label_region(t.infinite_face(), -1, to_check, to_check_added_by); // exterior - int regions = 0, holes = 0; - while (!to_check.empty()) { - if (to_check.front()->label() == 0) { // label = 0 means not labelled yet - if (to_check_added_by.front() < 0) { - label_region(to_check.front(), regions+1, to_check, to_check_added_by); - ++regions; - } else { - label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); - ++holes; - } - } to_check.pop_front(); - to_check_added_by.pop_front(); - } - - // Test vertices in labelled triangulation - for (auto const& vertex: polygon.outer_boundary().vertices()) { - typename Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); - if (lt == Validation_triangulation::Locate_type::FACE && f->label() != -1) { - std::cout << "Invalid: (partly) overlapping polygons" << std::endl; - return false; - } - } - for (auto const& hole: polygon.holes()) { - for (auto const& vertex: hole.vertices()) { - typename Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); - if (lt == Validation_triangulation::Locate_type::FACE && f->label() != -1) { - std::cout << "Invalid: (partly) overlapping polygons" << std::endl; - return false; - } - } - } - - } - - // Insert constraints while checking for intersections - for (auto const& edge: polygon.outer_boundary().edges()) { - try { - vt.insert_constraint(edge.source(), edge.target()); - } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { - std::cout << "Invalid: (partly) overlapping polygons" << std::endl; - return false; - } - } - for (auto const& hole: polygon.holes()) { - for (auto const& edge: hole.edges()) { - try { - vt.insert_constraint(edge.source(), edge.target()); - } catch (typename Validation_triangulation::Intersection_of_constraints_exception ice) { - std::cout << "Invalid: (partly) overlapping polygons" << std::endl; - return false; - } - } - } - } - - return true; - } - // Erases the triangulation. void clear() { t.clear(); From bc16dda92fe75beacea9497eb9a4d01f292e12d4 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 31 Aug 2023 15:58:03 +0200 Subject: [PATCH 104/182] label region static, bugfixes --- .../CGAL/Polygon_repair/Polygon_repair.h | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index be6a006fe0c1..f618f618a81b 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -117,15 +117,15 @@ bool is_valid(const Polygon_with_holes_2& polygon) { face->processed() = false; } std::list::Validation_triangulation::Face_handle> to_check; std::list to_check_added_by; - label_region(vt.infinite_face(), -1, to_check, to_check_added_by); // exterior + CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior int regions = 0, holes = 0; while (!to_check.empty()) { if (to_check.front()->label() == 0) { // label = 0 means not labelled yet if (to_check_added_by.front() < 0) { - label_region(to_check.front(), regions+1, to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); ++regions; } else { - label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), -(holes+2), to_check, to_check_added_by); ++holes; } } to_check.pop_front(); @@ -159,16 +159,16 @@ bool is_valid(const Polygon_with_holes_2& polygon) { face->processed() = false; } to_check.clear(); to_check_added_by.clear(); - label_region(vt.infinite_face(), -1, to_check, to_check_added_by); // exterior + CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior regions = 0; holes = 0; while (!to_check.empty()) { if (to_check.front()->label() == 0) { // label = 0 means not labelled yet if (to_check_added_by.front() < 0) { - label_region(to_check.front(), regions+1, to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); ++regions; } else { - label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), -(holes+2), to_check, to_check_added_by); ++holes; } } to_check.pop_front(); @@ -195,7 +195,7 @@ bool is_valid(const Multipolygon_with_holes_2& multipo for (auto const& polygon: multipolygon.polygons()) { - if (vt.number_of_triangles() > 0) { + if (vt.number_of_faces() > 0) { // Relabel for (auto const face: vt.all_face_handles()) { @@ -203,15 +203,15 @@ bool is_valid(const Multipolygon_with_holes_2& multipo face->processed() = false; } std::list::Validation_triangulation::Face_handle> to_check; std::list to_check_added_by; - label_region(vt.infinite_face(), -1, to_check, to_check_added_by); // exterior + CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior int regions = 0, holes = 0; while (!to_check.empty()) { if (to_check.front()->label() == 0) { // label = 0 means not labelled yet if (to_check_added_by.front() < 0) { - label_region(to_check.front(), regions+1, to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); ++regions; } else { - label_region(to_check.front(), -(holes+2), to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), -(holes+2), to_check, to_check_added_by); ++holes; } } to_check.pop_front(); @@ -464,9 +464,10 @@ class Polygon_repair { // Label a region of adjacent triangles without passing through constraints // adjacent triangles that involve passing through constraints are added to to_check - void label_region(typename Triangulation::Face_handle face, int label, - std::list& to_check, - std::list& to_check_added_by) { + template + static void label_region(T tt, typename T::Face_handle face, int label, + std::list& to_check, + std::list& to_check_added_by) { // std::cout << "Labelling region with " << label << std::endl; std::list to_check_in_region; face->label() = label; @@ -475,7 +476,7 @@ class Polygon_repair { while (!to_check_in_region.empty()) { for (int neighbour = 0; neighbour < 3; ++neighbour) { - if (!t.is_constrained(typename Triangulation::Edge(to_check_in_region.front(), neighbour))) { + if (!tt.is_constrained(typename Triangulation::Edge(to_check_in_region.front(), neighbour))) { if (to_check_in_region.front()->neighbor(neighbour)->label() == 0) { // unlabelled to_check_in_region.front()->neighbor(neighbour)->label() = label; to_check_in_region.push_back(to_check_in_region.front()->neighbor(neighbour)); @@ -530,17 +531,17 @@ class Polygon_repair { // putting interior triangles adjacent to it in to_check std::list to_check; std::list to_check_added_by; - label_region(t.infinite_face(), -1, to_check, to_check_added_by); + label_region(t, t.infinite_face(), -1, to_check, to_check_added_by); // Label region of front element to_check list while (!to_check.empty()) { if (to_check.front()->label() == 0) { // label = 0 means not labelled yet if (to_check_added_by.front() < 0) { - label_region(to_check.front(), number_of_polygons+1, to_check, to_check_added_by); + label_region(t, to_check.front(), number_of_polygons+1, to_check, to_check_added_by); ++number_of_polygons; } else { - label_region(to_check.front(), -(number_of_holes+2), to_check, to_check_added_by); + label_region(t, to_check.front(), -(number_of_holes+2), to_check, to_check_added_by); ++number_of_holes; } } to_check.pop_front(); From e331136a5bcc9926f4b99d395a08960697358cbf Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 31 Aug 2023 16:05:29 +0200 Subject: [PATCH 105/182] polygons can be in any hole, not just exterior --- Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index f618f618a81b..6436db920391 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -221,7 +221,7 @@ bool is_valid(const Multipolygon_with_holes_2& multipo // Test vertices in labelled triangulation for (auto const& vertex: polygon.outer_boundary().vertices()) { typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); - if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() != -1) { + if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() > 0) { std::cout << "Invalid: (partly) overlapping polygons" << std::endl; return false; } @@ -229,7 +229,7 @@ bool is_valid(const Multipolygon_with_holes_2& multipo for (auto const& hole: polygon.holes()) { for (auto const& vertex: hole.vertices()) { typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); - if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() != -1) { + if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() > 0) { std::cout << "Invalid: (partly) overlapping polygons" << std::endl; return false; } From 2ab6ad84f35790e17fd8a6df3361ef7d6248ec7d Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 31 Aug 2023 16:23:37 +0200 Subject: [PATCH 106/182] some more checks --- .../CGAL/Polygon_repair/Polygon_repair.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 6436db920391..42bfa04fae2e 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -69,7 +69,10 @@ Multipolygon_with_holes_2 repair_odd_even(const Multip template bool is_valid(const Polygon_2& polygon) { - for (auto const& edge: polygon.edges()) { + if (polygon.vertices().size() < 3) { + std::cout << "Invalid: less than 3 vertices" << std::endl; + return false; + } for (auto const& edge: polygon.edges()) { if (edge.source() == edge.target()) { std::cout << "Invalid: duplicate vertices" << std::endl; return false; @@ -110,9 +113,16 @@ bool is_valid(const Polygon_with_holes_2& polygon) { // Create triangulation of outer boundary typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation vt; for (auto const& edge: polygon.outer_boundary().edges()) { - vt.insert_constraint(edge.source(), edge.target()); - } - for (auto const face: vt.all_face_handles()) { + try { + vt.insert_constraint(edge.source(), edge.target()); + } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { + std::cout << "Invalid: intersection in outer boundary" << std::endl; + return false; + } + } if (vt.number_of_faces() == 0) { + std::cout << "Invalid: no outer boundary" << std::endl; + return false; + } for (auto const face: vt.all_face_handles()) { face->label() = 0; face->processed() = false; } std::list::Validation_triangulation::Face_handle> to_check; From c402ba7de4a5d9c83786f00502ea0e50408f9112 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 31 Aug 2023 17:56:18 +0200 Subject: [PATCH 107/182] wkt validation --- .../test/Polygon_repair/validate_wkt.cpp | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Polygon_repair/test/Polygon_repair/validate_wkt.cpp diff --git a/Polygon_repair/test/Polygon_repair/validate_wkt.cpp b/Polygon_repair/test/Polygon_repair/validate_wkt.cpp new file mode 100644 index 000000000000..c4781315c624 --- /dev/null +++ b/Polygon_repair/test/Polygon_repair/validate_wkt.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_2 = Kernel::Point_2; +using Polygon_2 = CGAL::Polygon_2; +using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; +using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; + +int main(int argc, char* argv[]) { + +// std::string folder = "/Users/ken/Downloads/big polygons/"; + std::string folder = "/Users/ken/Versioned/cgal-public-dev/Polygon_repair/test/Polygon_repair/data/in"; + + for (const auto& file: std::filesystem::directory_iterator(folder)) { + if (file.path().filename().extension() != ".wkt") continue; + std::cout << "Testing " << file.path().filename() << "... "; + + // Read test file + std::string in; + std::getline(std::ifstream(file.path()), in); + + // Load test file + std::istringstream iss(in); + bool valid = true; + if (in.find("POLYGON") == 0) { + Polygon_with_holes_2 p; + if (in != "POLYGON()") { // maybe should be checked in WKT reader + CGAL::IO::read_polygon_WKT(iss, p); + valid = CGAL::Polygon_repair::is_valid(p); + } + } else if (in.find("MULTIPOLYGON") == 0) { + Multipolygon_with_holes_2 mp; + CGAL::IO::read_multi_polygon_WKT(iss, mp); + valid = CGAL::Polygon_repair::is_valid(mp); + } if (valid) std::cout << "Valid" << std::endl; + } + + return 0; +} From dc3e1950680d82dd8d9184d40e2824b8b9b481ab Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 1 Sep 2023 17:40:25 +0200 Subject: [PATCH 108/182] test for clipart files --- .../test/Polygon_repair/test_clipart.cpp | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Polygon_repair/test/Polygon_repair/test_clipart.cpp diff --git a/Polygon_repair/test/Polygon_repair/test_clipart.cpp b/Polygon_repair/test/Polygon_repair/test_clipart.cpp new file mode 100644 index 000000000000..98dff9742fe0 --- /dev/null +++ b/Polygon_repair/test/Polygon_repair/test_clipart.cpp @@ -0,0 +1,80 @@ +#include +#include +#include + +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_2 = Kernel::Point_2; +using Polygon_2 = CGAL::Polygon_2; +using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; +using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; + +int main(int argc, char* argv[]) { + + std::string folder = "/Users/ken/Downloads/repaired"; + + for (const auto& file: std::filesystem::directory_iterator(folder)) { + if (file.path().filename().extension() != ".svg") continue; + if (file.path().filename().stem() != "182377") continue; + std::cout << "Testing " << file.path().filename() << "... "; + + // Read test file and create multipolygon with outer boundaries + pugi::xml_document doc; + if (doc.load_file(file.path().string().c_str())) { + Multipolygon_with_holes_2 mp; + std::list holes; + for (auto child: doc.child("svg").children()) { + if (strcmp(child.name(), "polygon") == 0) { + Polygon_2 p; + std::string points(child.attribute("points").value()); + std::string color(child.attribute("fill").value()); + + std::istringstream polygonss(points); + std::string point; + while (polygonss >> point) { + std::istringstream pointss(point); + std::string coordinate; + double x, y; + getline(pointss, coordinate, ','); + x = std::stod(coordinate); + getline(pointss, coordinate); + y = std::stod(coordinate); +// std::cout << "(" << x << ", " << y << ")" << std::endl; + p.push_back(Point_2(x, y)); + } + + if (color == "black") { + mp.add_polygon(p); + } else { + holes.push_back(p); + } + } + } + + // Put holes in correct polygon + for (auto const& hole: holes) { + std::set matches; + for (auto const& vertex: hole.vertices()) { + for (std::size_t pn = 0; pn < mp.number_of_polygons(); ++pn) { + if (mp.polygons()[pn].outer_boundary().bounded_side(vertex) == CGAL::ON_BOUNDED_SIDE) { + matches.insert(pn); + } + } + } if (matches.size() == 1) { + std::cout << "Found match" << std::endl; + mp.polygons()[*matches.begin()].add_hole(hole); + } else { + std::cout << "Error: couldn't find polygon for hole" << std::endl; + } + } + + // Check validity + std::cout << CGAL::Polygon_repair::is_valid(mp) << std::endl; + } + } + + return 0; +} From e9fc58bd4946afe48d3ae9655cca3036885de3cb Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Sat, 2 Sep 2023 13:59:09 +0200 Subject: [PATCH 109/182] get rid of hashes for exact kernels --- .../CGAL/Polygon_repair/Polygon_repair.h | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 42bfa04fae2e..6c20923fb40b 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -15,7 +15,6 @@ #include -#include #include #include #include @@ -285,9 +284,19 @@ class Polygon_repair { using Face_base = CGAL::Constrained_triangulation_face_base_2; using Face_base_with_repair_info = CGAL::Triangulation_face_base_with_repair_info_2; using Triangulation_data_structure = CGAL::Triangulation_data_structure_2; - using Tag = typename std::conditional::value, CGAL::Exact_predicates_tag, CGAL::Exact_intersections_tag>::type; + using Tag = typename std::conditional::value, + CGAL::Exact_predicates_tag, + CGAL::Exact_intersections_tag>::type; using Constrained_Delaunay_triangulation = CGAL::Constrained_Delaunay_triangulation_2; using Triangulation = Triangulation_with_odd_even_constraints_2; + using Edge_map = typename std::conditional::value, + std::unordered_set, + boost::hash>>, + std::set>>::type; + using Vertex_map = typename std::conditional::value, + std::unordered_map, + std::map>::type; + using Validation_tag = CGAL::No_constraint_intersection_tag; using Validation_triangulation = CGAL::Constrained_triangulation_2; @@ -342,12 +351,12 @@ class Polygon_repair { } // Insert vertices - std::unordered_map vertices; + Vertex_map vertices; std::vector> edges_to_insert; edges_to_insert.reserve(unique_edges.size()); for (auto const& edge: unique_edges) { typename Triangulation::Vertex_handle first_vertex, second_vertex; - typename std::unordered_map::const_iterator found = vertices.find(edge.first); + typename Vertex_map::const_iterator found = vertices.find(edge.first); if (found == vertices.end()) { first_vertex = t.insert(edge.first, search_start); vertices[edge.first] = first_vertex; @@ -392,12 +401,12 @@ class Polygon_repair { } // Insert vertices - std::unordered_map vertices; + Vertex_map vertices; std::vector> edges_to_insert; edges_to_insert.reserve(unique_edges.size()); for (auto const& edge: unique_edges) { typename Triangulation::Vertex_handle first_vertex, second_vertex; - typename std::unordered_map::const_iterator found = vertices.find(edge.first); + typename Vertex_map::const_iterator found = vertices.find(edge.first); if (found == vertices.end()) { first_vertex = t.insert(edge.first, search_start); vertices[edge.first] = first_vertex; @@ -444,12 +453,12 @@ class Polygon_repair { } // Insert vertices - std::unordered_map vertices; + Vertex_map vertices; std::vector> edges_to_insert; edges_to_insert.reserve(unique_edges.size()); for (auto const& edge: unique_edges) { typename Triangulation::Vertex_handle first_vertex, second_vertex; - typename std::unordered_map::const_iterator found = vertices.find(edge.first); + typename Vertex_map::const_iterator found = vertices.find(edge.first); if (found == vertices.end()) { first_vertex = t.insert(edge.first, search_start); vertices[edge.first] = first_vertex; @@ -666,8 +675,7 @@ class Polygon_repair { protected: Triangulation t; - std::unordered_set, - boost::hash>> unique_edges; + Edge_map unique_edges; Multipolygon_with_holes_2 mp; int number_of_polygons, number_of_holes; typename Triangulation::Face_handle search_start; From 3386efda797e809d41aa66cc6968a3c867b79404 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Sat, 2 Sep 2023 14:15:09 +0200 Subject: [PATCH 110/182] test showing exact kernel --- .../test/Polygon_repair/exact_test.cpp | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Polygon_repair/test/Polygon_repair/exact_test.cpp diff --git a/Polygon_repair/test/Polygon_repair/exact_test.cpp b/Polygon_repair/test/Polygon_repair/exact_test.cpp new file mode 100644 index 000000000000..e0263867fa11 --- /dev/null +++ b/Polygon_repair/test/Polygon_repair/exact_test.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_exact_constructions_kernel; +using Point_2 = Kernel::Point_2; +using Polygon_2 = CGAL::Polygon_2; +using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; +using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; +using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; + +int main(int argc, char* argv[]) { + + std::string in = "POLYGON((0.03 0.02,0.97 0.01,0.99 0.96,0.04 0.98,0.03 0.02),(0.5 0.5,1.5 0.5,0.5 0.5,1.5 0.7,0.5 0.5,1.5 0.9,0.5 0.5,1.5 1.1,0.5 0.5,1.5 1.3,0.5 0.5,1.5 1.5,0.5 0.5,1.3 1.5,0.5 0.5,1.1 1.5,0.5 0.5,0.9 1.5,0.5 0.5,0.7 1.5,0.5 0.5,0.5 1.5,0.5 0.5,0.3 1.5,0.5 0.5,0.1 1.5,0.5 0.5,-0.1 1.5,0.5 0.5,-0.3 1.5,0.5 0.5,-0.5 1.5,0.5 0.5,-0.5 1.3,0.5 0.5,-0.5 1.1,0.5 0.5,-0.5 0.9,0.5 0.5,-0.5 0.9,0.5 0.5,-0.5 0.7,0.5 0.5,-0.5 0.5,0.5 0.5,-0.5 0.3,0.5 0.5,-0.5 0.1,0.5 0.5,-0.5 -0.1,0.5 0.5,-0.5 -0.3,0.5 0.5,-0.5 -0.5,0.5 0.5,-0.3 -0.5,0.5 0.5,-0.1 -0.5,0.5 0.5,0.1 -0.5,0.5 0.5,0.3 -0.5,0.5 0.5,0.5 -0.5,0.5 0.5,0.7 -0.5,0.5 0.5,0.9 -0.5,0.5 0.5,1.1 -0.5,0.5 0.5,1.3 -0.5,0.5 0.5,1.5 -0.5,0.5 0.5,1.5 -0.3,0.5 0.5,1.5 -0.1,0.5 0.5,1.5 0.1,0.5 0.5,1.5 0.3,0.5 0.5))"; + std::istringstream iss(in); + Multipolygon_with_holes_2 rmp; + + Polygon_with_holes_2 p; + CGAL::IO::read_polygon_WKT(iss, p); + CGAL::draw(p); + Polygon_repair pr; + for (auto const edge: p.outer_boundary().edges()) { + pr.triangulation().odd_even_insert_constraint(edge.source(), edge.target()); + } int spikes = 20; + for (auto const& hole: p.holes()) { + for (auto const edge: hole.edges()) { + if (spikes-- <= 0) break; + pr.triangulation().odd_even_insert_constraint(edge.source(), edge.target()); + } + } + pr.label_triangulation_odd_even(); + pr.reconstruct_multipolygon(); + rmp = CGAL::Polygon_repair::repair_odd_even(p); + std::ostringstream oss; + CGAL::IO::write_multi_polygon_WKT(oss, rmp); + std::string out = oss.str(); + std::cout << "\tin: " << in << std::endl; + std::cout << "\tout: " << out; + CGAL::draw(rmp); + + return 0; +} From a5cea61a3309c894bf1e763ae495b91a97cd2458 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Sat, 2 Sep 2023 15:03:36 +0200 Subject: [PATCH 111/182] exact_test needs qt too --- Polygon_repair/test/Polygon_repair/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_repair/test/Polygon_repair/CMakeLists.txt b/Polygon_repair/test/Polygon_repair/CMakeLists.txt index 858e342b24ab..cc6b07baefe6 100644 --- a/Polygon_repair/test/Polygon_repair/CMakeLists.txt +++ b/Polygon_repair/test/Polygon_repair/CMakeLists.txt @@ -17,4 +17,5 @@ endforeach() if(CGAL_Qt5_FOUND) target_link_libraries(draw_test_polygons PUBLIC CGAL::CGAL_Basic_viewer) + target_link_libraries(exact_test PUBLIC CGAL::CGAL_Basic_viewer) endif() \ No newline at end of file From fbf3e08a5f26e96ebb670832cf998b1ee23b89a9 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Sat, 2 Sep 2023 15:47:37 +0200 Subject: [PATCH 112/182] test_clipart not needed --- .../test/Polygon_repair/test_clipart.cpp | 80 ------------------- 1 file changed, 80 deletions(-) delete mode 100644 Polygon_repair/test/Polygon_repair/test_clipart.cpp diff --git a/Polygon_repair/test/Polygon_repair/test_clipart.cpp b/Polygon_repair/test/Polygon_repair/test_clipart.cpp deleted file mode 100644 index 98dff9742fe0..000000000000 --- a/Polygon_repair/test/Polygon_repair/test_clipart.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include - -#include -#include - -using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; -using Point_2 = Kernel::Point_2; -using Polygon_2 = CGAL::Polygon_2; -using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; -using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; -using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; - -int main(int argc, char* argv[]) { - - std::string folder = "/Users/ken/Downloads/repaired"; - - for (const auto& file: std::filesystem::directory_iterator(folder)) { - if (file.path().filename().extension() != ".svg") continue; - if (file.path().filename().stem() != "182377") continue; - std::cout << "Testing " << file.path().filename() << "... "; - - // Read test file and create multipolygon with outer boundaries - pugi::xml_document doc; - if (doc.load_file(file.path().string().c_str())) { - Multipolygon_with_holes_2 mp; - std::list holes; - for (auto child: doc.child("svg").children()) { - if (strcmp(child.name(), "polygon") == 0) { - Polygon_2 p; - std::string points(child.attribute("points").value()); - std::string color(child.attribute("fill").value()); - - std::istringstream polygonss(points); - std::string point; - while (polygonss >> point) { - std::istringstream pointss(point); - std::string coordinate; - double x, y; - getline(pointss, coordinate, ','); - x = std::stod(coordinate); - getline(pointss, coordinate); - y = std::stod(coordinate); -// std::cout << "(" << x << ", " << y << ")" << std::endl; - p.push_back(Point_2(x, y)); - } - - if (color == "black") { - mp.add_polygon(p); - } else { - holes.push_back(p); - } - } - } - - // Put holes in correct polygon - for (auto const& hole: holes) { - std::set matches; - for (auto const& vertex: hole.vertices()) { - for (std::size_t pn = 0; pn < mp.number_of_polygons(); ++pn) { - if (mp.polygons()[pn].outer_boundary().bounded_side(vertex) == CGAL::ON_BOUNDED_SIDE) { - matches.insert(pn); - } - } - } if (matches.size() == 1) { - std::cout << "Found match" << std::endl; - mp.polygons()[*matches.begin()].add_hole(hole); - } else { - std::cout << "Error: couldn't find polygon for hole" << std::endl; - } - } - - // Check validity - std::cout << CGAL::Polygon_repair::is_valid(mp) << std::endl; - } - } - - return 0; -} From 091511b9f7be019ddad21798ba346910643055c1 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Sat, 2 Sep 2023 15:56:01 +0200 Subject: [PATCH 113/182] test clipart files directly instead --- .../test/Polygon_repair/clipart.cpp | 57 +++++-------------- 1 file changed, 14 insertions(+), 43 deletions(-) diff --git a/Polygon_repair/test/Polygon_repair/clipart.cpp b/Polygon_repair/test/Polygon_repair/clipart.cpp index 68b9f86e001d..cc184ee781ef 100644 --- a/Polygon_repair/test/Polygon_repair/clipart.cpp +++ b/Polygon_repair/test/Polygon_repair/clipart.cpp @@ -22,24 +22,20 @@ void print_timer(clock_t start_time) { int main(int argc, char* argv[]) { -// std::string folder_in = "/Volumes/Toshiba/out_fix"; -// std::string folder_out = "/Volumes/Toshiba/repaired"; - std::string folder_in = "/Users/ken/Downloads/test"; - std::string folder_out = "/Users/ken/Downloads/test"; + std::string folder_in = "/Volumes/T7 Shield/out_fix"; + std::string folder_out = "/Volumes/T7 Shield/repaired"; double desired_width = 500.0; - int current = 0, how_many = 100000; clock_t start_time; for (const auto& file: std::filesystem::directory_iterator(folder_in)) { if (file.path().filename().extension() != ".obj") continue; std::cout << "Reading " << file.path().filename() << "..."; -// if (std::filesystem::exists(folder_out + "/" + std::string(file.path().stem()) + ".svg")) { -// std::cout << " skipped: already processed" << std::endl; -// continue; -// } + if (std::filesystem::exists(folder_out + "/" + std::string(file.path().stem()) + ".svg")) { + std::cout << " skipped: already processed" << std::endl; + continue; + } - start_time = clock(); Polygon_repair pr; std::vector vertices; std::vector> edges; @@ -61,11 +57,7 @@ int main(int argc, char* argv[]) { edges.push_back(std::make_pair(vertices[a-1], vertices[b-1])); } } ifs.close(); - std::cout << "Read and parsed file in "; - print_timer(start_time); - std::cout << std::endl; - start_time = clock(); std::unordered_set, boost::hash>> edges_to_insert; @@ -75,46 +67,26 @@ int main(int argc, char* argv[]) { std::make_pair(edge.first, edge.second) : std::make_pair(edge.second, edge.first); auto inserted = edges_to_insert.insert(pair); if (!inserted.second) edges_to_insert.erase(inserted.first); - } std::cout << "Generated unique edges in "; - print_timer(start_time); - std::cout << std::endl; + } - start_time = clock(); Polygon_repair::Triangulation::Face_handle search_start; for (auto const& edge: edges_to_insert) { Polygon_repair::Triangulation::Vertex_handle va = pr.triangulation().insert(edge.first, search_start); Polygon_repair::Triangulation::Vertex_handle vb = pr.triangulation().insert(edge.second, va->face()); // vb is likely close to va pr.triangulation().odd_even_insert_constraint(va, vb); search_start = vb->face(); - } std::cout << "Inserted constraints in "; - print_timer(start_time); - std::cout << std::endl; - - // std::cout << pr.triangulation().number_of_faces() << " faces in the triangulation" << std::endl; + } if (pr.triangulation().number_of_faces() > 0) { - start_time = clock(); pr.label_triangulation_odd_even(); - std::cout << "Labelled in "; - print_timer(start_time); - std::cout << std::endl; - - start_time = clock(); pr.reconstruct_multipolygon(); - std::cout << "Reconstructed multipolygon in "; - print_timer(start_time); - std::cout << std::endl; } Multipolygon_with_holes_2 mp = pr.multipolygon(); - // std::cout << mp << std::endl; - // std::cout << mp.number_of_polygons() << " polygons" << std::endl; - if (mp.number_of_polygons() > 0) { CGAL::Bbox_2 bbox = mp.polygons().front().bbox(); for (auto const& polygon: mp.polygons()) { bbox += polygon.outer_boundary().bbox(); - } // std::cout << bbox.xmin() << " " << bbox.xmax() << " " << bbox.ymin() << " " << bbox.ymax() << std::endl; - Kernel::Vector_2 translate(-bbox.xmin(), -bbox.ymin()); + } Kernel::Vector_2 translate(-bbox.xmin(), -bbox.ymin()); double scale = desired_width/(bbox.xmax()-bbox.xmin()); @@ -127,9 +99,6 @@ int main(int argc, char* argv[]) { for (auto const& vertex: polygon.outer_boundary()) { ofs << scale*(vertex.x()+translate.x()) << "," << scale*(vertex.y()+translate.y()) << " "; } ofs << "\" fill=\"black\"/>" << std::endl; - } - - for (auto const& polygon: mp.polygons()) { for (auto const& hole: polygon.holes()) { // std::cout << hole << std::endl; ofs << "\t"; ofs.close(); - std::cout << " ok" << std::endl; - } ++current; - if (current >= how_many) break; + if (CGAL::Polygon_repair::is_valid(mp)) { + std::cout << " ok" << std::endl; + } + } + } return 0; From 23c4e1098b275f5ab4fc4ebf0e61d754bd851f95 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Sat, 2 Sep 2023 16:22:39 +0200 Subject: [PATCH 114/182] remove default kernel --- Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 6c20923fb40b..addb665bc26f 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -276,8 +276,7 @@ bool is_valid(const Multipolygon_with_holes_2& multipo * The class `Polygon_repair` builds on a constrained * triangulation to remove the parts of constraints that overlap an even number of times */ -template > +template > class Polygon_repair { public: using Vertex_base = CGAL::Triangulation_vertex_base_2; From 0cf0131c1a4a7ebe6f6c866ac92532b946429aca Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 4 Sep 2023 11:58:44 +0200 Subject: [PATCH 115/182] update dependencies --- Polygon_repair/package_info/Polygon_repair/dependencies | 2 -- 1 file changed, 2 deletions(-) diff --git a/Polygon_repair/package_info/Polygon_repair/dependencies b/Polygon_repair/package_info/Polygon_repair/dependencies index 3678863c6925..107d9f6d0d96 100644 --- a/Polygon_repair/package_info/Polygon_repair/dependencies +++ b/Polygon_repair/package_info/Polygon_repair/dependencies @@ -6,13 +6,11 @@ Distance_2 Distance_3 Filtered_kernel Hash_map -Homogeneous_kernel Installation Intersections_2 Intersections_3 Interval_support Kernel_23 -Kernel_d Modular_arithmetic Number_types Polygon From 31ca1f1485c82c050e46903c11574f88b71dd374 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 6 Sep 2023 22:30:31 +0200 Subject: [PATCH 116/182] package details --- Polygon_repair/doc/Polygon_repair/PackageDescription.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt index 0f63f0844b7d..b9526d2d1320 100644 --- a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt +++ b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt @@ -24,9 +24,8 @@ \cgalPkgShortInfoBegin \cgalPkgSince{6.0} \cgalPkgDependsOn{\ref PkgPolygon2, \ref PkgTriangulation2} -\cgalPkgBib{cgal:x-x} +\cgalPkgBib{cgal:a-pr} \cgalPkgLicense{\ref licensesGPL "GPL"} -\cgalPkgDemo{DEMO 1,demo1.zip} \cgalPkgShortInfoEnd \cgalPkgDescriptionEnd From 015e2baf965856218be613f942845412dcd091d6 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 6 Sep 2023 22:31:04 +0200 Subject: [PATCH 117/182] repair is odd-even --- Polygon_repair/doc/Polygon_repair/PackageDescription.txt | 2 +- Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt index b9526d2d1320..0274c721cfa9 100644 --- a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt +++ b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt @@ -36,6 +36,6 @@ - `CGAL::Polygon_repair` \cgalCRPSection{Functions} -- `CGAL::Polygon_repair::repair()` +- `CGAL::Polygon_repair::repair_odd_even()` */ diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index addb665bc26f..aa74a09864f9 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -31,7 +31,7 @@ template class Polygon_repair; /// \ingroup PkgPolygonRepairFunctions -/// Repair a polygon without holes +/// Repair a polygon without holes using the odd-even heuristic template Multipolygon_with_holes_2 repair_odd_even(const Polygon_2& p) { CGAL::Polygon_repair::Polygon_repair pr; @@ -43,7 +43,7 @@ Multipolygon_with_holes_2 repair_odd_even(const Polygo } /// \ingroup PkgPolygonRepairFunctions -/// Repair a polygon with holes +/// Repair a polygon with holes using the odd-even heuristic template Multipolygon_with_holes_2 repair_odd_even(const Polygon_with_holes_2& p) { CGAL::Polygon_repair::Polygon_repair pr; @@ -55,7 +55,7 @@ Multipolygon_with_holes_2 repair_odd_even(const Polygo } /// \ingroup PkgPolygonRepairFunctions -/// Repair a multipolygon with holes +/// Repair a multipolygon with holes using the odd-even heuristic template Multipolygon_with_holes_2 repair_odd_even(const Multipolygon_with_holes_2& mp) { CGAL::Polygon_repair::Polygon_repair pr; From 12d3505942c756e90d5a447b2fbfa6e33ecbadc9 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 6 Sep 2023 22:31:24 +0200 Subject: [PATCH 118/182] remove undocumented classes --- Polygon_repair/doc/Polygon_repair/PackageDescription.txt | 3 --- .../include/CGAL/Polygon_repair/Polygon_repair.h | 5 ----- .../Triangulation_with_odd_even_constraints_2.h | 7 ------- 3 files changed, 15 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt index 0274c721cfa9..ce5b791ff5c3 100644 --- a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt +++ b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt @@ -32,9 +32,6 @@ \cgalClassifedRefPages -\cgalCRPSection{Classes} -- `CGAL::Polygon_repair` - \cgalCRPSection{Functions} - `CGAL::Polygon_repair::repair_odd_even()` diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index aa74a09864f9..91829fd271d5 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -271,11 +271,6 @@ bool is_valid(const Multipolygon_with_holes_2& multipo return true; } -/*! \ingroup PkgPolygonRepairRef - * - * The class `Polygon_repair` builds on a constrained - * triangulation to remove the parts of constraints that overlap an even number of times - */ template > class Polygon_repair { public: diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_with_odd_even_constraints_2.h index 9a693be3d94d..3d5dd2a77e47 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_with_odd_even_constraints_2.h @@ -17,13 +17,6 @@ namespace CGAL { -/*! \ingroup PkgPolygonRepairRef - * - * The class `Triangulation_with_odd_even_constraints_2` builds on a constrained - * triangulation to remove the parts of constraints that overlap an even number of times - * - * \tparam Triangulation_ must have support for constraints - */ template class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { public: From e06422aab5eaa723a4f14b6207f5b7becc5599d6 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 6 Sep 2023 22:31:31 +0200 Subject: [PATCH 119/182] logo draft From 35d56ae8603cc3073acd6478f6be52f1c71fe265 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 6 Sep 2023 22:31:45 +0200 Subject: [PATCH 120/182] todo for exact kernels --- Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 91829fd271d5..66ff45ba462b 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -283,6 +283,7 @@ class Polygon_repair { CGAL::Exact_intersections_tag>::type; using Constrained_Delaunay_triangulation = CGAL::Constrained_Delaunay_triangulation_2; using Triangulation = Triangulation_with_odd_even_constraints_2; + // TODO: Edge_map and Vertex_map use std::set and set::map with exact kernels since Point_2 can't be hashed otherwise using Edge_map = typename std::conditional::value, std::unordered_set, boost::hash>>, From 6a203906c60d91cf2c95e93a93b3426fa4dba56b Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 6 Sep 2023 22:32:22 +0200 Subject: [PATCH 121/182] svg logo for the future From d954161b79e95d006090faefad78559d7e347536 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 6 Sep 2023 22:32:40 +0200 Subject: [PATCH 122/182] capitalisation --- Polygon_repair/doc/Polygon_repair/Polygon_repair.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 6547a97d482f..85a71fdc0767 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -123,7 +123,7 @@ faces. Then, all other faces are labeled. For the odd-even heuristic, the label applied alternates between polygon interior and hole every time that an edge is passed. -\subsection SubsectionPolygonRepair_Reconstruction Reconstruction of the multipolygon +\subsection SubsectionPolygonRepair_Reconstruction Reconstruction of the Multipolygon The algorithm reconstructs the multipolygon boundary by boundary, obtaining counter-clockwise cycles for outer boundaries and clockwise cycles for inner @@ -147,7 +147,7 @@ with holes has zero holes and extract these if needed. \section SectionPolygonRepair_Examples Examples -\subsection SubsectionPolygonRepair_Repair Repairing a (multi)polygon +\subsection SubsectionPolygonRepair_Repair Repairing a (Multi)polygon It's possible to repair a polygon, polygon with holes or multipolygon with holes using the odd-even rule by calling the `repair_odd_even` function as shown in the From c1e1e72e7fb7e7713e61f79ec62adefc720551c2 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 6 Sep 2023 22:33:36 +0200 Subject: [PATCH 123/182] narrower figure From 6c9bc49d9f2f3fe3997f01a1e1cec45a45068975 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 7 Sep 2023 14:01:36 +0200 Subject: [PATCH 124/182] triangulation should be passed by reference --- Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 66ff45ba462b..aa49e1857b05 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -479,7 +479,7 @@ class Polygon_repair { // Label a region of adjacent triangles without passing through constraints // adjacent triangles that involve passing through constraints are added to to_check template - static void label_region(T tt, typename T::Face_handle face, int label, + static void label_region(T& tt, typename T::Face_handle face, int label, std::list& to_check, std::list& to_check_added_by) { // std::cout << "Labelling region with " << label << std::endl; From 52e91967d8a67d3491871d38c996c85da8f5ff4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 6 Oct 2023 11:11:40 +0200 Subject: [PATCH 125/182] use new macros --- Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h | 4 +++- Polygon/include/CGAL/Multipolygon_with_holes_2.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h index 1c315df5a6bb..8725c35a233a 100644 --- a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h @@ -7,7 +7,9 @@ * The concept requires the ability to store the polygons with holes * that the multipolygon is composed of. * - * \cgalHasModel `CGAL::Multipolygon_with_holes_2` + * \cgalHasModelsBegin + * \cgalHasModel{CGAL::Multipolygon_with_holes_2} + * \cgalHasModelsEnd */ class MultipolygonWithHoles_2 { diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h index d2744339c7ef..ede241a6779e 100644 --- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h +++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h @@ -28,7 +28,7 @@ namespace CGAL { * the types `Polygon_2` and `Polygon_with_holes_2`. * The latter is used to represent each polygon with holes. The former is converted to the latter. * - * \cgalModels `MultipolygonWithHoles_2` + * \cgalModels{MultipolygonWithHoles_2} */ template > From be2ccc2ee2a987c461ff303a72a2669ff3d60cbf Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 6 Oct 2023 10:59:46 +0100 Subject: [PATCH 126/182] typo --- Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h index 8725c35a233a..c39c76680da3 100644 --- a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h @@ -8,7 +8,7 @@ * that the multipolygon is composed of. * * \cgalHasModelsBegin - * \cgalHasModel{CGAL::Multipolygon_with_holes_2} + * \cgalHasModels{CGAL::Multipolygon_with_holes_2} * \cgalHasModelsEnd */ From 1416ddfd2d67574ae592bf0da63d7af221ef8178 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 6 Oct 2023 13:40:32 +0100 Subject: [PATCH 127/182] No --- .../doc/Polygon_repair/Polygon_repair.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 85a71fdc0767..4a875571280e 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -25,16 +25,16 @@ from those of inner boundaries. \section SectionPolygonRepair_Definitions Definitions -- A valid polygon (without holes) is a point set in \f$ \mathbb{R}^2\f$ +- A valid polygon (without holes) is a point set in \f$ \mathbb{R}^2\f$ that is bounded by a cycle of linear edges, which is known as its -outer boundary. This outer boundary should be simple, +outer boundary. This outer boundary should be simple, meaning that the interiors of its edges are pairwise disjoint and all of its vertices have a degree of two. It is thus topologically equivalent to a disk and is represented internally as the sequence of points at the common end points of the edges around its outer boundary. -- A valid polygon with holes is a point set in \f$ \mathbb{R}^2\f$ -that is bounded by one outer boundary and zero or more inner boundaries, +- A valid polygon with holes is a point set in \f$ \mathbb{R}^2\f$ +that is bounded by one outer boundary and zero or more inner boundaries, where each inner boundary represents a hole in the polygon. Considered independently, each boundary should be simple. The different boundaries of a polygon are allowed to intersect tangentially at their common vertices (with no common @@ -43,7 +43,7 @@ The interior of a polygon with holes should form a connected point set. Note that a valid polygon can also be represented as a valid polygon with holes (where the number of holes is zero). -- A valid multipolygon with holes is a point set in \f$ \mathbb{R}^2\f$ +- A valid multipolygon with holes is a point set in \f$ \mathbb{R}^2\f$ that is represented by a set of zero or more valid polygons with holes. The interiors of the polygons with holes should be pairwise disjoint, but they are allowed to intersect tangentially at their common vertices. Note that @@ -102,7 +102,7 @@ Examples of polygons with holes (a-d) and multipolygons with holes For the purposes of the repair operation, the input polygon, polygon with holes or multipolygon is merely used as a container of input line segments. These line segments are added to the arrangement as edges. Internally, this is done using -a constrained triangulation where they added as constraints. +a constrained triangulation where they are added as constraints. With the odd-even heuristic, only the edges that are present an odd number of times in the input will be edges in the final arrangement. @@ -149,9 +149,9 @@ with holes has zero holes and extract these if needed. \subsection SubsectionPolygonRepair_Repair Repairing a (Multi)polygon -It's possible to repair a polygon, polygon with holes or multipolygon with holes -using the odd-even rule by calling the `repair_odd_even` function as shown in the -following example. This function returns a repaired multipolygon with holes. +It is possible to repair a polygon, polygon with holes or multipolygon with holes +using the odd-even rule by calling the `Polygon_repair::repair_odd_even()` function +as shown in the following example. This function returns a repaired multipolygon with holes. \cgalExample{Polygon_repair/repair_polygon_2.cpp} From 455c6324b6d3adbf438de37431df8d426168f8bb Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 6 Oct 2023 13:46:59 +0100 Subject: [PATCH 128/182] labelled -> labeled --- .../include/CGAL/Polygon_repair/Polygon_repair.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index aa49e1857b05..a11ba0f35647 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -129,7 +129,7 @@ bool is_valid(const Polygon_with_holes_2& polygon) { CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior int regions = 0, holes = 0; while (!to_check.empty()) { - if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check.front()->label() == 0) { // label = 0 means not labeled yet if (to_check_added_by.front() < 0) { CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); ++regions; @@ -172,7 +172,7 @@ bool is_valid(const Polygon_with_holes_2& polygon) { regions = 0; holes = 0; while (!to_check.empty()) { - if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check.front()->label() == 0) { // label = 0 means not labeled yet if (to_check_added_by.front() < 0) { CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); ++regions; @@ -215,7 +215,7 @@ bool is_valid(const Multipolygon_with_holes_2& multipo CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior int regions = 0, holes = 0; while (!to_check.empty()) { - if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check.front()->label() == 0) { // label = 0 means not labeled yet if (to_check_added_by.front() < 0) { CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); ++regions; @@ -227,7 +227,7 @@ bool is_valid(const Multipolygon_with_holes_2& multipo to_check_added_by.pop_front(); } - // Test vertices in labelled triangulation + // Test vertices in labeled triangulation for (auto const& vertex: polygon.outer_boundary().vertices()) { typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() > 0) { @@ -491,7 +491,7 @@ class Polygon_repair { while (!to_check_in_region.empty()) { for (int neighbour = 0; neighbour < 3; ++neighbour) { if (!tt.is_constrained(typename Triangulation::Edge(to_check_in_region.front(), neighbour))) { - if (to_check_in_region.front()->neighbor(neighbour)->label() == 0) { // unlabelled + if (to_check_in_region.front()->neighbor(neighbour)->label() == 0) { // unlabeled to_check_in_region.front()->neighbor(neighbour)->label() = label; to_check_in_region.push_back(to_check_in_region.front()->neighbor(neighbour)); to_check_in_region.front()->neighbor(neighbour)->processed() = true; @@ -550,7 +550,7 @@ class Polygon_repair { // Label region of front element to_check list while (!to_check.empty()) { - if (to_check.front()->label() == 0) { // label = 0 means not labelled yet + if (to_check.front()->label() == 0) { // label = 0 means not labeled yet if (to_check_added_by.front() < 0) { label_region(t, to_check.front(), number_of_polygons+1, to_check, to_check_added_by); ++number_of_polygons; From 4f9dd85aaa1a328ed536c607f733c5b430b61d72 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 6 Oct 2023 14:04:02 +0100 Subject: [PATCH 129/182] PolygonContainer -> Container --- .../CGAL/Polygon_repair/Polygon_repair.h | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index a11ba0f35647..5264913eb03f 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -27,14 +27,14 @@ namespace CGAL { namespace Polygon_repair { -template +template class Polygon_repair; /// \ingroup PkgPolygonRepairFunctions /// Repair a polygon without holes using the odd-even heuristic -template -Multipolygon_with_holes_2 repair_odd_even(const Polygon_2& p) { - CGAL::Polygon_repair::Polygon_repair pr; +template +Multipolygon_with_holes_2 repair_odd_even(const Polygon_2& p) { + CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_odd_even(p); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation_odd_even(); @@ -44,9 +44,9 @@ Multipolygon_with_holes_2 repair_odd_even(const Polygo /// \ingroup PkgPolygonRepairFunctions /// Repair a polygon with holes using the odd-even heuristic -template -Multipolygon_with_holes_2 repair_odd_even(const Polygon_with_holes_2& p) { - CGAL::Polygon_repair::Polygon_repair pr; +template +Multipolygon_with_holes_2 repair_odd_even(const Polygon_with_holes_2& p) { + CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_odd_even(p); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation_odd_even(); @@ -56,9 +56,9 @@ Multipolygon_with_holes_2 repair_odd_even(const Polygo /// \ingroup PkgPolygonRepairFunctions /// Repair a multipolygon with holes using the odd-even heuristic -template -Multipolygon_with_holes_2 repair_odd_even(const Multipolygon_with_holes_2& mp) { - CGAL::Polygon_repair::Polygon_repair pr; +template +Multipolygon_with_holes_2 repair_odd_even(const Multipolygon_with_holes_2& mp) { + CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_odd_even(mp); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation_odd_even(); @@ -66,8 +66,8 @@ Multipolygon_with_holes_2 repair_odd_even(const Multip } return pr.multipolygon(); } -template -bool is_valid(const Polygon_2& polygon) { +template +bool is_valid(const Polygon_2& polygon) { if (polygon.vertices().size() < 3) { std::cout << "Invalid: less than 3 vertices" << std::endl; return false; @@ -82,8 +82,8 @@ bool is_valid(const Polygon_2& polygon) { } return true; } -template -bool is_valid(const Polygon_with_holes_2& polygon) { +template +bool is_valid(const Polygon_with_holes_2& polygon) { // Validate outer boundary for (auto const& edge: polygon.outer_boundary().edges()) { @@ -110,11 +110,11 @@ bool is_valid(const Polygon_with_holes_2& polygon) { } // Create triangulation of outer boundary - typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation vt; + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation vt; for (auto const& edge: polygon.outer_boundary().edges()) { try { vt.insert_constraint(edge.source(), edge.target()); - } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { + } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { std::cout << "Invalid: intersection in outer boundary" << std::endl; return false; } @@ -124,17 +124,17 @@ bool is_valid(const Polygon_with_holes_2& polygon) { } for (auto const face: vt.all_face_handles()) { face->label() = 0; face->processed() = false; - } std::list::Validation_triangulation::Face_handle> to_check; + } std::list::Validation_triangulation::Face_handle> to_check; std::list to_check_added_by; - CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior + CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior int regions = 0, holes = 0; while (!to_check.empty()) { if (to_check.front()->label() == 0) { // label = 0 means not labeled yet if (to_check_added_by.front() < 0) { - CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); ++regions; } else { - CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), -(holes+2), to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), -(holes+2), to_check, to_check_added_by); ++holes; } } to_check.pop_front(); @@ -144,10 +144,10 @@ bool is_valid(const Polygon_with_holes_2& polygon) { // Hole nesting for (auto const& hole: polygon.holes()) { for (auto const& vertex: hole.vertices()) { - typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type lt; + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type lt; int li; - typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); - if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() != 1) { + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); + if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() != 1) { std::cout << "Invalid: hole (partly) outside outer boundary" << std::endl; return false; } @@ -155,7 +155,7 @@ bool is_valid(const Polygon_with_holes_2& polygon) { for (auto const& edge: hole.edges()) { try { vt.insert_constraint(edge.source(), edge.target()); - } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { + } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { std::cout << "Invalid: hole (partly) outside outer boundary" << std::endl; return false; } @@ -168,16 +168,16 @@ bool is_valid(const Polygon_with_holes_2& polygon) { face->processed() = false; } to_check.clear(); to_check_added_by.clear(); - CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior + CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior regions = 0; holes = 0; while (!to_check.empty()) { if (to_check.front()->label() == 0) { // label = 0 means not labeled yet if (to_check_added_by.front() < 0) { - CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); ++regions; } else { - CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), -(holes+2), to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), -(holes+2), to_check, to_check_added_by); ++holes; } } to_check.pop_front(); @@ -190,16 +190,16 @@ bool is_valid(const Polygon_with_holes_2& polygon) { return true; } -template -bool is_valid(const Multipolygon_with_holes_2& multipolygon) { +template +bool is_valid(const Multipolygon_with_holes_2& multipolygon) { // Validate polygons for (auto const& polygon: multipolygon.polygons()) { if (!is_valid(polygon)) return false; } - typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation vt; - typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type lt; + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation vt; + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type lt; int li; for (auto const& polygon: multipolygon.polygons()) { @@ -210,17 +210,17 @@ bool is_valid(const Multipolygon_with_holes_2& multipo for (auto const face: vt.all_face_handles()) { face->label() = 0; face->processed() = false; - } std::list::Validation_triangulation::Face_handle> to_check; + } std::list::Validation_triangulation::Face_handle> to_check; std::list to_check_added_by; - CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior + CGAL::Polygon_repair::Polygon_repair::label_region(vt, vt.infinite_face(), -1, to_check, to_check_added_by); // exterior int regions = 0, holes = 0; while (!to_check.empty()) { if (to_check.front()->label() == 0) { // label = 0 means not labeled yet if (to_check_added_by.front() < 0) { - CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), regions+1, to_check, to_check_added_by); ++regions; } else { - CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), -(holes+2), to_check, to_check_added_by); + CGAL::Polygon_repair::Polygon_repair::label_region(vt, to_check.front(), -(holes+2), to_check, to_check_added_by); ++holes; } } to_check.pop_front(); @@ -229,16 +229,16 @@ bool is_valid(const Multipolygon_with_holes_2& multipo // Test vertices in labeled triangulation for (auto const& vertex: polygon.outer_boundary().vertices()) { - typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); - if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() > 0) { + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); + if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() > 0) { std::cout << "Invalid: (partly) overlapping polygons" << std::endl; return false; } } for (auto const& hole: polygon.holes()) { for (auto const& vertex: hole.vertices()) { - typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); - if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() > 0) { + typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Face_handle f = vt.locate(vertex, lt, li); + if (lt == CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type::FACE && f->label() > 0) { std::cout << "Invalid: (partly) overlapping polygons" << std::endl; return false; } @@ -251,7 +251,7 @@ bool is_valid(const Multipolygon_with_holes_2& multipo for (auto const& edge: polygon.outer_boundary().edges()) { try { vt.insert_constraint(edge.source(), edge.target()); - } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { + } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { std::cout << "Invalid: (partly) overlapping polygons" << std::endl; return false; } @@ -260,7 +260,7 @@ bool is_valid(const Multipolygon_with_holes_2& multipo for (auto const& edge: hole.edges()) { try { vt.insert_constraint(edge.source(), edge.target()); - } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { + } catch (typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Intersection_of_constraints_exception ice) { std::cout << "Invalid: (partly) overlapping polygons" << std::endl; return false; } @@ -271,7 +271,7 @@ bool is_valid(const Multipolygon_with_holes_2& multipo return true; } -template > +template > class Polygon_repair { public: using Vertex_base = CGAL::Triangulation_vertex_base_2; @@ -296,7 +296,7 @@ class Polygon_repair { using Validation_triangulation = CGAL::Constrained_triangulation_2; struct Polygon_less { - using Polygon_2 = CGAL::Polygon_2; + using Polygon_2 = CGAL::Polygon_2; bool operator()(const Polygon_2& pa, const Polygon_2& pb) const { typename Polygon_2::Vertex_iterator va = pa.vertices_begin(); typename Polygon_2::Vertex_iterator vb = pb.vertices_begin(); @@ -311,7 +311,7 @@ class Polygon_repair { }; struct Polygon_with_holes_less { - using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; + using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; Polygon_less pl; bool operator()(const Polygon_with_holes_2& pa, const Polygon_with_holes_2& pb) const { if (pl(pa.outer_boundary(), pb.outer_boundary())) return true; @@ -334,7 +334,7 @@ class Polygon_repair { /// @{ // Add edges of the polygon to the triangulation - void add_to_triangulation_odd_even(const Polygon_2& polygon) { + void add_to_triangulation_odd_even(const Polygon_2& polygon) { // Get unique edges for (auto const& edge: polygon.edges()) { @@ -375,7 +375,7 @@ class Polygon_repair { } // Add edges of the polygon to the triangulation - void add_to_triangulation_odd_even(const Polygon_with_holes_2& polygon) { + void add_to_triangulation_odd_even(const Polygon_with_holes_2& polygon) { // Get unique edges for (auto const& edge: polygon.outer_boundary().edges()) { @@ -425,7 +425,7 @@ class Polygon_repair { } // Add edges of the polygon to the triangulation - void add_to_triangulation_odd_even(const Multipolygon_with_holes_2& multipolygon) { + void add_to_triangulation_odd_even(const Multipolygon_with_holes_2& multipolygon) { // Get unique edges for (auto const& polygon: multipolygon.polygons()) { @@ -602,8 +602,8 @@ class Polygon_repair { // Reconstruct multipolygon based on the triangles labeled as inside the polygon void reconstruct_multipolygon() { mp.clear(); - std::vector> polygons; // outer boundaries - std::vector, Polygon_less>> holes; // holes are ordered (per polygon) + std::vector> polygons; // outer boundaries + std::vector, Polygon_less>> holes; // holes are ordered (per polygon) polygons.resize(number_of_polygons); holes.resize(number_of_polygons); @@ -621,7 +621,7 @@ class Polygon_repair { reconstruct_ring(ring, face, opposite_vertex); // Put ring in polygons - Polygon_2 polygon(ring.begin(), ring.end()); + Polygon_2 polygon(ring.begin(), ring.end()); // std::cout << "Reconstructed ring for polygon " << face->label() << " with ccw? " << (polygon.orientation() == CGAL::COUNTERCLOCKWISE) << std::endl; if (polygon.orientation() == CGAL::COUNTERCLOCKWISE) { polygons[face->label()-1] = polygon; @@ -632,9 +632,9 @@ class Polygon_repair { } // Create polygons with holes and put in multipolygon - std::set, Polygon_with_holes_less> ordered_polygons; + std::set, Polygon_with_holes_less> ordered_polygons; for (int i = 0; i < polygons.size(); ++i) { - ordered_polygons.insert(Polygon_with_holes_2(polygons[i], holes[i].begin(), holes[i].end())); + ordered_polygons.insert(Polygon_with_holes_2(polygons[i], holes[i].begin(), holes[i].end())); } for (auto const& polygon: ordered_polygons) { // std::cout << "Adding polygon " << polygon << std::endl; @@ -661,7 +661,7 @@ class Polygon_repair { return t; } - Multipolygon_with_holes_2 multipolygon() { + Multipolygon_with_holes_2 multipolygon() { return mp; } @@ -671,7 +671,7 @@ class Polygon_repair { protected: Triangulation t; Edge_map unique_edges; - Multipolygon_with_holes_2 mp; + Multipolygon_with_holes_2 mp; int number_of_polygons, number_of_holes; typename Triangulation::Face_handle search_start; }; From 55c564558f8eb1cb7c82d2bb0bc07619b01e24e3 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 6 Oct 2023 14:15:02 +0100 Subject: [PATCH 130/182] Move code to internal folder/namespace --- .../include/CGAL/Polygon_repair/Polygon_repair.h | 8 ++++---- .../Triangulation_face_base_with_repair_info_2.h | 4 ++++ .../Triangulation_with_odd_even_constraints_2.h | 4 ++++ 3 files changed, 12 insertions(+), 4 deletions(-) rename Polygon_repair/include/CGAL/Polygon_repair/{ => internal}/Triangulation_face_base_with_repair_info_2.h (94%) rename Polygon_repair/include/CGAL/Polygon_repair/{ => internal}/Triangulation_with_odd_even_constraints_2.h (97%) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 5264913eb03f..e703ce7e842b 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -20,8 +20,8 @@ #include #include -#include -#include +#include +#include namespace CGAL { @@ -276,13 +276,13 @@ class Polygon_repair { public: using Vertex_base = CGAL::Triangulation_vertex_base_2; using Face_base = CGAL::Constrained_triangulation_face_base_2; - using Face_base_with_repair_info = CGAL::Triangulation_face_base_with_repair_info_2; + using Face_base_with_repair_info = internal::Triangulation_face_base_with_repair_info_2; using Triangulation_data_structure = CGAL::Triangulation_data_structure_2; using Tag = typename std::conditional::value, CGAL::Exact_predicates_tag, CGAL::Exact_intersections_tag>::type; using Constrained_Delaunay_triangulation = CGAL::Constrained_Delaunay_triangulation_2; - using Triangulation = Triangulation_with_odd_even_constraints_2; + using Triangulation = internal::Triangulation_with_odd_even_constraints_2; // TODO: Edge_map and Vertex_map use std::set and set::map with exact kernels since Point_2 can't be hashed otherwise using Edge_map = typename std::conditional::value, std::unordered_set, diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_face_base_with_repair_info_2.h b/Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_face_base_with_repair_info_2.h similarity index 94% rename from Polygon_repair/include/CGAL/Polygon_repair/Triangulation_face_base_with_repair_info_2.h rename to Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_face_base_with_repair_info_2.h index 61389d4e33ee..0f1482795486 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_face_base_with_repair_info_2.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_face_base_with_repair_info_2.h @@ -17,6 +17,8 @@ #include namespace CGAL { +namespace Polygon_repair { +namespace internal { template > class Triangulation_face_base_with_repair_info_2 : public FaceBase { @@ -47,6 +49,8 @@ class Triangulation_face_base_with_repair_info_2 : public FaceBase { int& label() { return _label; } }; +} // namespace internal +} // namespace Polygon_repair } //namespace CGAL #endif // CGAL_TRIANGULATION_WITH_REPAIR_INFO_2_H diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_with_odd_even_constraints_2.h similarity index 97% rename from Polygon_repair/include/CGAL/Polygon_repair/Triangulation_with_odd_even_constraints_2.h rename to Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_with_odd_even_constraints_2.h index 3d5dd2a77e47..563527a48fb1 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_with_odd_even_constraints_2.h @@ -16,6 +16,8 @@ #include namespace CGAL { +namespace Polygon_repair { +namespace internal { template class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { @@ -122,6 +124,8 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { } }; +} // namespace internal +} // namespace Polygon_repair } // namespace CGAL #endif // CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H From 2f9535d769b99df77a2834276d144c9d6efa0fa4 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 6 Oct 2023 14:40:32 +0100 Subject: [PATCH 131/182] no concepts, export->insert in a stream, capitalize --- Polygon/doc/Polygon/Polygon.txt | 2 +- Polygon/include/CGAL/Multipolygon_with_holes_2.h | 10 +++++----- .../doc/Polygon_repair/PackageDescription.txt | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Polygon/doc/Polygon/Polygon.txt b/Polygon/doc/Polygon/Polygon.txt index 284157f95ef7..6383cdad10cc 100644 --- a/Polygon/doc/Polygon/Polygon.txt +++ b/Polygon/doc/Polygon/Polygon.txt @@ -59,7 +59,7 @@ some member functions. \cgalExample{Polygon/Polygon.cpp} -\subsection SubsectionPolygonRepair_Multipolygon The multipolygon with holes class +\subsection SubsectionPolygonRepair_Multipolygon The Multipolygon with Holes Class The following example shows the creation of a multipolygon with holes and the traversal of the polygons in it. diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h index ede241a6779e..55162b50df16 100644 --- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h +++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h @@ -92,7 +92,7 @@ class Multipolygon_with_holes_2 { }; /*! -exports a multipolygon with holes to the output stream `os`. +inserts a multipolygon with holes to the output stream `os`. An \ascii and a binary format exist. The format can be selected with the \cgal modifiers for streams, `set_ascii_mode()` and `set_binary_mode()`, @@ -100,11 +100,11 @@ respectively. The modifier `set_pretty_mode()` can be used to allow for (a few) structuring comments in the output. Otherwise, the output would be free of comments. The default for writing is \ascii without comments. -The number of polygons is exported followed by the polygons. For each polygon, -the number of points of the outer boundary is exported followed by the +The number of polygons is written followed by the polygons. For each polygon, +the number of points of the outer boundary is written followed by the points themselves in counterclockwise order. Then, the number of holes -is exported, and for each hole, the number of points on its outer -boundary is exported followed by the points themselves in clockwise +is written, and for each hole, the number of points on its outer +boundary is written followed by the points themselves in clockwise order. \relates Multipolygon_with_holes_2 diff --git a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt index ce5b791ff5c3..e622d0f23b25 100644 --- a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt +++ b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt @@ -2,8 +2,8 @@ /// \defgroup PkgPolygonRepairRef 2D Polygon Repair Reference -/// \defgroup PkgPolygonRepairConcepts Concepts -/// \ingroup PkgPolygonRepairRef +// \defgroup PkgPolygonRepairConcepts Concepts +// \ingroup PkgPolygonRepairRef /// \defgroup PkgPolygonRepairFunctions Functions /// \ingroup PkgPolygonRepairRef From be6fa67a6b1f851e7401f2603418506b3ce0ef88 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 10 Oct 2023 18:39:15 -0600 Subject: [PATCH 132/182] 120x120 logo From cc04b10659da0a37ea8f5e898894c3072af930da Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 17 Oct 2023 09:02:43 +0100 Subject: [PATCH 133/182] remove non-author of one file --- Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index e703ce7e842b..6c67b602a43c 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -8,7 +8,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Ken Arroyo Ohori -// Guillaume Damiand #ifndef CGAL_POLYGON_REPAIR_H #define CGAL_POLYGON_REPAIR_H From 9f5a217200adf5c54551c3a00b8de474381e62cf Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 17 Oct 2023 09:25:07 +0100 Subject: [PATCH 134/182] fix ingroup --- Polygon/include/CGAL/Multipolygon_with_holes_2.h | 2 +- Polygon/include/CGAL/Polygon_with_holes_2.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h index 55162b50df16..7421f20c0048 100644 --- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h +++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h @@ -21,7 +21,7 @@ namespace CGAL { -/*! \ingroup PkgPolygonRepairRef +/*! \ingroup PkgPolygon2Ref * * The class `Multipolygon_with_holes_2` models the concept `MultipolygonWithHoles_2`. * It is parameterized with two types (`Kernel` and `Container`) that are used to instantiate diff --git a/Polygon/include/CGAL/Polygon_with_holes_2.h b/Polygon/include/CGAL/Polygon_with_holes_2.h index e41104c943a9..23eb826e9b2a 100644 --- a/Polygon/include/CGAL/Polygon_with_holes_2.h +++ b/Polygon/include/CGAL/Polygon_with_holes_2.h @@ -30,8 +30,8 @@ namespace CGAL { The class `Polygon_with_holes_2` models the concept `GeneralPolygonWithHoles_2`. It represents a linear polygon with holes. It is parameterized with two types (`Kernel` and `Container`) that are used to instantiate -the type `Polygon_2`. The latter is used to -represents the outer boundary and the boundary of the holes (if any exist). +the type `Polygon_2`. This poygon type is used to +represent the outer boundary and the boundary of the holes (if any exist). \cgalModels{GeneralPolygonWithHoles_2} From 4b9544dcc481f0db99e04612adbafab299e54848 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 17 Oct 2023 10:25:02 +0100 Subject: [PATCH 135/182] Fix doc of the parameters of the multipolygon --- Polygon/doc/Polygon/PackageDescription.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon/doc/Polygon/PackageDescription.txt b/Polygon/doc/Polygon/PackageDescription.txt index 4e36dd32906c..8083eb8e15b5 100644 --- a/Polygon/doc/Polygon/PackageDescription.txt +++ b/Polygon/doc/Polygon/PackageDescription.txt @@ -54,7 +54,7 @@ - `CGAL::Polygon_2` - `CGAL::Polygon_with_holes_2` - `CGAL::General_polygon_with_holes_2` -- `CGAL::Multipolygon_with_holes_2` +- `CGAL::Multipolygon_with_holes_2` \cgalCRPSection{Global Functions} - `CGAL::area_2()` From 1fb664a471548af2ef96b37171bb96d7f4c526c6 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 17 Oct 2023 11:36:26 +0100 Subject: [PATCH 136/182] Document Size --- Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h | 3 +++ Polygon/include/CGAL/Multipolygon_with_holes_2.h | 1 + 2 files changed, 4 insertions(+) diff --git a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h index c39c76680da3..6e5f4e4c9559 100644 --- a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h @@ -29,6 +29,9 @@ typedef unspecified_type Polygon_const_iterator; //! range type for iterating over holes. typedef unspecified_type Polygons_container; +//! size type +typedef unsigned int Size; + /// @} /// \name Creation diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h index 7421f20c0048..1d154419bd7d 100644 --- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h +++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h @@ -51,6 +51,7 @@ class Multipolygon_with_holes_2 { using Polygon_iterator = typename Polygons_container::iterator; using Polygon_const_iterator = typename Polygons_container::const_iterator; + /// the size type using Size = unsigned int; /*! %Default constructor. */ From f06f1024a67c92aaa65b4406570d5618801d7155 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 17 Oct 2023 11:48:43 +0100 Subject: [PATCH 137/182] holes -> polygons --- Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h | 2 +- Polygon_repair/doc/Polygon_repair/Polygon_repair.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h index 6e5f4e4c9559..6d4d2d948cf0 100644 --- a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h @@ -26,7 +26,7 @@ typedef unspecified_type Polygon_with_holes_2; */ typedef unspecified_type Polygon_const_iterator; -//! range type for iterating over holes. +//! range type for iterating over the polygons. typedef unspecified_type Polygons_container; //! size type diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 4a875571280e..e2ded1de8745 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -20,7 +20,7 @@ Different arrangement and labelling heuristics are possible, but currently only the odd-even heuristic is implemented in the package. This heuristic results in areas that are alternately assigned as polygon interiors and exterior/holes each time that an input edge is passed. -It doesn't distinguish between edges that are part of outer boundaries +It does not distinguish between edges that are part of outer boundaries from those of inner boundaries. \section SectionPolygonRepair_Definitions Definitions From 950ed67a9b46096fe5c76ef57b9a6767ff6eb9a6 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 17 Oct 2023 11:50:37 +0100 Subject: [PATCH 138/182] remove sentence about ability to store --- Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h index 6d4d2d948cf0..687683d76ffa 100644 --- a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h @@ -4,8 +4,6 @@ * \cgalRefines{CopyConstructible,Assignable,DefaultConstructible} * * A model of this concept represents a multipolygon with holes. - * The concept requires the ability to store the polygons with holes - * that the multipolygon is composed of. * * \cgalHasModelsBegin * \cgalHasModels{CGAL::Multipolygon_with_holes_2} From d760c408a7567ce5656ff5209f7fea3c0a62a7d9 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 17 Oct 2023 14:08:33 +0100 Subject: [PATCH 139/182] Be precise --- .../Concepts/MultiPolygonWithHoles_2.h | 34 ++++++++--------- .../CGAL/General_polygon_with_holes_2.h | 4 +- .../include/CGAL/Multipolygon_with_holes_2.h | 38 +++++++++---------- .../CGAL/draw_multipolygon_with_holes_2.h | 8 ++-- .../Polygon_repair/repair_polygon_2.cpp | 4 +- .../CGAL/Polygon_repair/Polygon_repair.h | 4 +- .../test/Polygon_repair/clipart.cpp | 8 ++-- .../Polygon_repair/repair_polygon_2_test.cpp | 2 +- .../write_repaired_polygons.cpp | 26 ++++++------- Stream_support/include/CGAL/IO/WKT.h | 4 +- 10 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h index 687683d76ffa..917e6f91052e 100644 --- a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h +++ b/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h @@ -19,13 +19,13 @@ class MultipolygonWithHoles_2 { //! the polygon type used to represent each polygon with holes of the multipolygon. typedef unspecified_type Polygon_with_holes_2; -/*! a bidirectional iterator over the polygons. +/*! a bidirectional iterator over the polygons with holes. * Its value type is `Polygon_with_holes_2`. */ -typedef unspecified_type Polygon_const_iterator; +typedef unspecified_type Polygon_with_holes_const_iterator; -//! range type for iterating over the polygons. -typedef unspecified_type Polygons_container; +//! range type for iterating over polygons with holes. +typedef unspecified_type Polygon_with_holes_container; //! size type typedef unsigned int Size; @@ -35,7 +35,7 @@ typedef unsigned int Size; /// \name Creation /// @{ -/*! constructs a multipolygon using a range of polygons. +/*! constructs a multipolygon using a range of polygons with holes. */ template MultipolygonWithHoles_2(InputIterator begin, InputIterator end); @@ -45,41 +45,41 @@ MultipolygonWithHoles_2(InputIterator begin, InputIterator end); /// \name Predicates /// @{ -/*! returns the number of polygons. +/*! returns the number of polygons with holes. */ -Size number_of_polygons(); +Size number_of_polygons_wih_holes(); /// @} /// \name Access Functions /// @{ -/*! returns the begin iterator of the polygons. +/*! returns the begin iterator of the polygons with holes. */ -Polygon_const_iterator polygons_begin() const; +Polygon_with_holes_const_iterator polygons_with_holes_begin() const; -/*! returns the past-the-end iterator of the polygons. +/*! returns the past-the-end iterator of the polygons with holes. */ -Polygon_const_iterator polygons_end() const; +Polygon_with_holes_const_iterator polygons_with_holes_end() const; -/*! returns the range of polygons. +/*! returns the range of polygons with holes. */ -const Polygons_container& polygons() const; +const Polygon_with_holes_container& polygons_with_holes() const; /// @} /// \name Modifiers /// @{ -/*! adds a given polygon to the multipolygon. +/*! adds a given polygon with holes to the multipolygon. */ -void add_polygon(const Polygon_with_holes_2& polygon); +void add_polygon_with_holes(const Polygon_with_holes_2& polygon); /*! erases the specified polygon. */ -void erase_polygon(Polygon_iterator pit); +void erase_polygon_with_holes(Polygon_iterator pit); -/*! removes all the polygons. +/*! removes all the polygons with holes. */ void clear(); diff --git a/Polygon/include/CGAL/General_polygon_with_holes_2.h b/Polygon/include/CGAL/General_polygon_with_holes_2.h index 42173fc2ad6f..bb19fcf99436 100644 --- a/Polygon/include/CGAL/General_polygon_with_holes_2.h +++ b/Polygon/include/CGAL/General_polygon_with_holes_2.h @@ -28,8 +28,8 @@ namespace CGAL { * * The class `General_polygon_with_holes_2` models the concept * `GeneralPolygonWithHoles_2`. It represents a general polygon with holes. - * It is parameterized with a type `Polygon` used to define the exposed - * type `Polygon_2`. This type represents the outer boundary of the general + * It is parameterized with a type `Polygon_` used to define the exposed + * type `%Polygon_2`. This type represents the outer boundary of the general * polygon and each hole. * * \tparam Polygon_ must have input and output operators. diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h index 1d154419bd7d..3fb93f903be7 100644 --- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h +++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h @@ -46,10 +46,10 @@ class Multipolygon_with_holes_2 { /// @} - using Polygons_container = std::deque; + using Polygon_with_holes_container = std::deque; - using Polygon_iterator = typename Polygons_container::iterator; - using Polygon_const_iterator = typename Polygons_container::const_iterator; + using Polygon_with_holes_iterator = typename Polygon_with_holes_container::iterator; + using Polygon_with_holes_const_iterator = typename Polygon_with_holes_container::const_iterator; /// the size type using Size = unsigned int; @@ -64,32 +64,32 @@ class Multipolygon_with_holes_2 { m_polygons(p_begin, p_end) {} - Polygons_container& polygons() { return m_polygons; } + Polygon_with_holes_container& polygons_with_holes() { return m_polygons; } - const Polygons_container& polygons() const { return m_polygons; } + const Polygon_with_holes_container& polygons_with_holes() const { return m_polygons; } - Polygon_iterator polygons_begin() { return m_polygons.begin(); } + Polygon_with_holes_iterator polygons_with_holes_begin() { return m_polygons.begin(); } - Polygon_iterator polygons_end() { return m_polygons.end(); } + Polygon_with_holes_iterator polygons_with_holes_end() { return m_polygons.end(); } - Polygon_const_iterator polygons_begin() const { return m_polygons.begin(); } + Polygon_with_holes_const_iterator polygons_with_holes_begin() const { return m_polygons.begin(); } - Polygon_const_iterator polygons_end() const { return m_polygons.end(); } + Polygon_with_holes_const_iterator polygons_with_holes_end() const { return m_polygons.end(); } void add_polygon(const Polygon_2& pgn) { m_polygons.push_back(Polygon_with_holes_2(pgn)); } - void add_polygon(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); } + void add_polygon_with_holes(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); } - void add_polygon(Polygon_with_holes_2&& pgn) { m_polygons.emplace_back(std::move(pgn)); } + void add_polygon_with_holes(Polygon_with_holes_2&& pgn) { m_polygons.emplace_back(std::move(pgn)); } - void erase_polygon(Polygon_iterator pit) { m_polygons.erase(pit); } + void erase_polygon_with_holes(Polygon_with_holes_iterator pit) { m_polygons.erase(pit); } void clear() { m_polygons.clear(); } - Size number_of_polygons() const { return static_cast(m_polygons.size()); } + Size number_of_polygons_with_holes() const { return static_cast(m_polygons.size()); } protected: - Polygons_container m_polygons; + Polygon_with_holes_container m_polygons; }; /*! @@ -113,26 +113,26 @@ order. template std::ostream& operator<<(std::ostream& os, const Multipolygon_with_holes_2& mp) { - typename Multipolygon_with_holes_2::Polygon_const_iterator i; + typename Multipolygon_with_holes_2::Polygon_with_holes_const_iterator i; switch(IO::get_mode(os)) { case IO::ASCII : os << mp.number_of_polygons() << ' '; - for (i = mp.polygons_begin(); i != mp.polygons_end(); ++i) { + for (i = mp.polygon_with_holes_begin(); i != mp.polygon_with_holes_end(); ++i) { os << *i << ' '; } return os; case IO::BINARY : - os << mp.number_of_polygons(); - for (i = mp.polygons_begin(); i != mp.polygons_end(); ++i) { + os << mp.number_of_polygons_with_holes(); + for (i = mp.polygons_with_holes_begin(); i != mp.polygons_with_holes_end(); ++i) { os << *i ; } return os; default: os << "Multipolygon_with_holes_2(" << std::endl; - for (i = mp.polygons_begin(); i != mp.polygons_end(); ++i) { + for (i = mp.polygons_with_holes_begin(); i != mp.polygons_with_holes_end(); ++i) { os << " " << *i << std::endl; } diff --git a/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h b/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h index 814723411c7a..d9e311b6af25 100644 --- a/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h +++ b/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h @@ -69,7 +69,7 @@ class Mpwh_2_basic_viewer_qt : public Basic_viewer_qt { const char* title = "Basic Multipolygon_with_holes_2 Viewer") : Base(parent, title, true, true, true, false, false), m_mpwh(mpwh) { - if (mpwh.number_of_polygons() == 0) return; + if (mpwh.number_of_polygons_with_holes() == 0) return; // mimic the computation of Camera::pixelGLRatio() auto bbox = bounding_box(); @@ -99,8 +99,8 @@ class Mpwh_2_basic_viewer_qt : public Basic_viewer_qt { */ CGAL::Bbox_2 bounding_box() { Bbox_2 bbox; - if (m_mpwh.number_of_polygons() > 0) bbox = m_mpwh.polygons().front().outer_boundary().bbox(); - for (auto const& pwh: m_mpwh.polygons()) { + if (m_mpwh.number_of_polygons_with_holes() > 0) bbox = m_mpwh.polygons_with_holes().front().outer_boundary().bbox(); + for (auto const& pwh: m_mpwh.polygons_with_holes()) { bbox += pwh.outer_boundary().bbox(); } return bbox; @@ -111,7 +111,7 @@ class Mpwh_2_basic_viewer_qt : public Basic_viewer_qt { void add_elements() { clear(); - for (auto const& p: m_mpwh.polygons()) { + for (auto const& p: m_mpwh.polygons_with_holes()) { CGAL::IO::Color c(rand()%255,rand()%255,rand()%255); face_begin(c); diff --git a/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp index c8a91fb0c1b7..ed48aabf5933 100644 --- a/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp +++ b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp @@ -17,10 +17,10 @@ int main(int argc, char* argv[]) { CGAL::IO::read_polygon_WKT(in, pin); Multipolygon_with_holes_2 mp = CGAL::Polygon_repair::repair_odd_even(pin); - if (mp.number_of_polygons() > 1) { + if (mp.number_of_polygons_with_holes() > 1) { CGAL::IO::write_multi_polygon_WKT(std::cout, mp); } else { - CGAL::IO::write_polygon_WKT(std::cout, mp.polygons()[0]); + CGAL::IO::write_polygon_WKT(std::cout, mp.polygons_with_holes()[0]); } return 0; diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 6c67b602a43c..81e1090af03b 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -427,7 +427,7 @@ class Polygon_repair { void add_to_triangulation_odd_even(const Multipolygon_with_holes_2& multipolygon) { // Get unique edges - for (auto const& polygon: multipolygon.polygons()) { + for (auto const& polygon: multipolygon.polygons_with_holes()) { for (auto const& edge: polygon.outer_boundary().edges()) { if (edge.source() == edge.target()) continue; std::pair pair = (edge.source() < edge.target())? @@ -637,7 +637,7 @@ class Polygon_repair { } for (auto const& polygon: ordered_polygons) { // std::cout << "Adding polygon " << polygon << std::endl; - mp.add_polygon(polygon); + mp.add_polygon_with_holes(polygon); } } diff --git a/Polygon_repair/test/Polygon_repair/clipart.cpp b/Polygon_repair/test/Polygon_repair/clipart.cpp index cc184ee781ef..b5337840fd88 100644 --- a/Polygon_repair/test/Polygon_repair/clipart.cpp +++ b/Polygon_repair/test/Polygon_repair/clipart.cpp @@ -82,9 +82,9 @@ int main(int argc, char* argv[]) { pr.reconstruct_multipolygon(); } Multipolygon_with_holes_2 mp = pr.multipolygon(); - if (mp.number_of_polygons() > 0) { - CGAL::Bbox_2 bbox = mp.polygons().front().bbox(); - for (auto const& polygon: mp.polygons()) { + if (mp.number_of_polygons_with_holes() > 0) { + CGAL::Bbox_2 bbox = mp.polygons_with_holes().front().bbox(); + for (auto const& polygon: mp.polygons_with_holes()) { bbox += polygon.outer_boundary().bbox(); } Kernel::Vector_2 translate(-bbox.xmin(), -bbox.ymin()); double scale = desired_width/(bbox.xmax()-bbox.xmin()); @@ -93,7 +93,7 @@ int main(int argc, char* argv[]) { std::ofstream ofs(folder_out + "/" + std::string(file.path().stem()) + ".svg"); ofs << "" << std::endl; - for (auto const& polygon: mp.polygons()) { + for (auto const& polygon: mp.polygons_with_holes()) { // std::cout << polygon << std::endl; ofs << "\t 0) ofs << ","; + if (rmp.polygons_with_holes()[i].number_of_holes() > 0) ofs << ","; ofs << std::endl; - for (int j = 0; j < rmp.polygons()[i].holes().size(); ++j) { + for (int j = 0; j < rmp.polygons_with_holes()[i].holes().size(); ++j) { ofs << "\t\t\t[" << std::endl; - for (int k = 0; k < rmp.polygons()[i].holes()[j].size(); ++k) { - ofs << "\t\t\t\t[" << rmp.polygons()[i].holes()[j][k].x() << - ", " << rmp.polygons()[i].holes()[j][k].y() << "]"; - if (k < rmp.polygons()[i].holes()[j].size()-1) ofs << ","; + for (int k = 0; k < rmp.polygons_with_holes()[i].holes()[j].size(); ++k) { + ofs << "\t\t\t\t[" << rmp.polygons_with_holes()[i].holes()[j][k].x() << + ", " << rmp.polygons_with_holes()[i].holes()[j][k].y() << "]"; + if (k < rmp.polygons_with_holes()[i].holes()[j].size()-1) ofs << ","; ofs << std::endl; } ofs << "\t\t\t]"; - if (j < rmp.polygons()[i].holes().size()-1) ofs << ","; + if (j < rmp.polygons_with_holes()[i].holes().size()-1) ofs << ","; ofs << std::endl; } ofs << "\t\t]"; - if (i < rmp.polygons().size()-1) ofs << ","; + if (i < rmp.polygons_with_holes().size()-1) ofs << ","; ofs << std::endl; } ofs << "\t]" << std::endl; ofs << "}" << std::endl; diff --git a/Stream_support/include/CGAL/IO/WKT.h b/Stream_support/include/CGAL/IO/WKT.h index ef8c7dee1f0e..f558c90aea28 100644 --- a/Stream_support/include/CGAL/IO/WKT.h +++ b/Stream_support/include/CGAL/IO/WKT.h @@ -351,7 +351,7 @@ template bool read_multi_polygon_WKT(std::istream& in, Multipolygon_with_holes_2& mp) { - return read_multi_polygon_WKT(in, mp.polygons()); + return read_multi_polygon_WKT(in, mp.polygons_with_holes()); } @@ -359,7 +359,7 @@ template std::ostream& write_multi_polygon_WKT(std::ostream& out, Multipolygon_with_holes_2& mp) { - return write_multi_polygon_WKT(out, mp.polygons()); + return write_multi_polygon_WKT(out, mp.polygons_with_holes()); } //! \ingroup PkgStreamSupportIoFuncsWKT From 6d51db7d975fb9595ab931996e2f407fb5ff4252 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 17 Oct 2023 14:10:12 +0100 Subject: [PATCH 140/182] Change filename --- .../{MultiPolygonWithHoles_2.h => MultipolygonWithHoles_2.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Polygon/doc/Polygon/Concepts/{MultiPolygonWithHoles_2.h => MultipolygonWithHoles_2.h} (100%) diff --git a/Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h b/Polygon/doc/Polygon/Concepts/MultipolygonWithHoles_2.h similarity index 100% rename from Polygon/doc/Polygon/Concepts/MultiPolygonWithHoles_2.h rename to Polygon/doc/Polygon/Concepts/MultipolygonWithHoles_2.h From f1c14d5ad7f91d7b2282e31ad171055c642bd46d Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 17 Oct 2023 14:16:46 +0100 Subject: [PATCH 141/182] fix example --- Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp | 1 + Polygon/examples/Polygon/multipolygon.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp b/Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp index 5db6ececb9ee..db7927c8ba5d 100644 --- a/Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp +++ b/Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include diff --git a/Polygon/examples/Polygon/multipolygon.cpp b/Polygon/examples/Polygon/multipolygon.cpp index b98a6fda3cfd..9699f916e99f 100644 --- a/Polygon/examples/Polygon/multipolygon.cpp +++ b/Polygon/examples/Polygon/multipolygon.cpp @@ -20,12 +20,12 @@ int main(int argc, char* argv[]) { Polygon_with_holes_2 p2(Polygon_2(p2_outer, p2_outer+4)); Multipolygon_with_holes_2 mp; - mp.add_polygon(p1); - mp.add_polygon(p2); + mp.add_polygon_with_holes(p1); + mp.add_polygon_with_holes(p2); for (auto const& p: mp.polygons()) { std::cout << p << std::endl; } return 0; -} \ No newline at end of file +} From 7ed78a0e15bac06222d0aff760375967038fd70d Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 25 Oct 2023 10:07:49 -0700 Subject: [PATCH 142/182] mark holes with red edges From 04264b5e89cc0fc8583f93d709b72dbb10683d99 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 16 Nov 2023 07:16:16 +0000 Subject: [PATCH 143/182] Add non const iterator in the doc --- .../Polygon/Concepts/MultipolygonWithHoles_2.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Polygon/doc/Polygon/Concepts/MultipolygonWithHoles_2.h b/Polygon/doc/Polygon/Concepts/MultipolygonWithHoles_2.h index 917e6f91052e..0992dda022cd 100644 --- a/Polygon/doc/Polygon/Concepts/MultipolygonWithHoles_2.h +++ b/Polygon/doc/Polygon/Concepts/MultipolygonWithHoles_2.h @@ -22,6 +22,11 @@ typedef unspecified_type Polygon_with_holes_2; /*! a bidirectional iterator over the polygons with holes. * Its value type is `Polygon_with_holes_2`. */ +typedef unspecified_type Polygon_with_holes_iterator; + +/*! a bidirectional const iterator over the polygons with holes. + * Its value type is `Polygon_with_holes_2`. + */ typedef unspecified_type Polygon_with_holes_const_iterator; //! range type for iterating over polygons with holes. @@ -54,6 +59,14 @@ Size number_of_polygons_wih_holes(); /// \name Access Functions /// @{ +/*! returns the begin iterator of the polygons with holes. + */ +Polygon_with_holes_iterator polygons_with_holes_begin(); + +/*! returns the past-the-end iterator of the polygons with holes. + */ + Polygon_with_holes_iterator polygons_with_holes_end(); + /*! returns the begin iterator of the polygons with holes. */ Polygon_with_holes_const_iterator polygons_with_holes_begin() const; @@ -77,7 +90,7 @@ void add_polygon_with_holes(const Polygon_with_holes_2& polygon); /*! erases the specified polygon. */ -void erase_polygon_with_holes(Polygon_iterator pit); +void erase_polygon_with_holes(Polygon_with_holes_const_iterator pit); /*! removes all the polygons with holes. */ From 43bf7ed6d24894e69d82843a33ac77772b30354c Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 4 Jan 2024 17:32:52 +0000 Subject: [PATCH 144/182] no concepts in this package --- Polygon_repair/doc/Polygon_repair/PackageDescription.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt index e622d0f23b25..74c33e961e1e 100644 --- a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt +++ b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt @@ -2,9 +2,6 @@ /// \defgroup PkgPolygonRepairRef 2D Polygon Repair Reference -// \defgroup PkgPolygonRepairConcepts Concepts -// \ingroup PkgPolygonRepairRef - /// \defgroup PkgPolygonRepairFunctions Functions /// \ingroup PkgPolygonRepairRef From ef6765474a711986d726afaa10801ac542a478c7 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 4 Jan 2024 18:00:10 +0000 Subject: [PATCH 145/182] Ken did more than prototyping --- Polygon_repair/doc/Polygon_repair/Polygon_repair.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index e2ded1de8745..7f3b427b48bf 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -180,7 +180,7 @@ and reconstruct the multipolygons. It also incorporates improvements later added to prepair, such as the application of the odd-even counting heuristic to edges, which enables correct counting even on partially overlapping edges. -Ken Arroyo Ohori made a prototype version of this package for the Google Summer of +Ken Arroyo Ohori developed this package during the Google Summer of Code 2023 under the mentorship of Sébastien Loriot and Andreas Fabri. */ From d1f19a7055c1674daf146e1d6eb33dd313c220ed Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 4 Jan 2024 18:13:34 +0000 Subject: [PATCH 146/182] Add to CHANGES.md --- Installation/CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 8ee04d38577d..aeb04c624779 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -23,6 +23,11 @@ Release date: October 2023 #### Envelopes of Surfaces in 3D - ** Breaking change**: Construct_projected_boundary_2 in `EnvelopeTraits_3` is now using `std::variant` instead of `Object` +### [Polygon Repair](https://doc.cgal.org/6.0/Manual/packages.html#PkgPolygonRepair) (new package) + +- This package provides functions to repair polygons, polygons with holes, and multipolygons with holes + using the odd-even heuristic. + ### [Combinatorial Maps](https://doc.cgal.org/6.0/Manual/packages.html#PkgCombinatorialMaps) and [Generalized Maps](https://doc.cgal.org/6.0/Manual/packages.html#PkgGeneralizedMaps) - Added the function `insert_cell_1_between_two_cells_2()` to the `GenericMap` concept, which enables users to insert an edge between two different faces in order to create faces with holes. From be89ad28bd03244a472cd0b43246600d19888d13 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 5 Jan 2024 10:02:11 +0000 Subject: [PATCH 147/182] Qt5 -> Qt6 --- Polygon_repair/test/Polygon_repair/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon_repair/test/Polygon_repair/CMakeLists.txt b/Polygon_repair/test/Polygon_repair/CMakeLists.txt index cc6b07baefe6..6075ee3222ba 100644 --- a/Polygon_repair/test/Polygon_repair/CMakeLists.txt +++ b/Polygon_repair/test/Polygon_repair/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1...3.23) project(Polygon_repair_Tests) -find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) +find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt6) # create a target per cppfile file( @@ -15,7 +15,7 @@ foreach(cppfile ${cppfiles}) create_single_source_cgal_program("${cppfile}") endforeach() -if(CGAL_Qt5_FOUND) +if(CGAL_Qt6_FOUND) target_link_libraries(draw_test_polygons PUBLIC CGAL::CGAL_Basic_viewer) target_link_libraries(exact_test PUBLIC CGAL::CGAL_Basic_viewer) -endif() \ No newline at end of file +endif() From 6edfffe313a3517c8187d0b5ea470be00e4364da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 5 Jan 2024 11:20:13 +0100 Subject: [PATCH 148/182] update doc to qt6 --- Polygon/include/CGAL/draw_multipolygon_with_holes_2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h b/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h index d9e311b6af25..909b4b29da82 100644 --- a/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h +++ b/Polygon/include/CGAL/draw_multipolygon_with_holes_2.h @@ -29,9 +29,9 @@ namespace CGAL { * opens a new window and draws `aph`, an instance of the * `CGAL::Multipolygon_with_holes_2` class. A call to this function is blocking, that * is the program continues as soon as the user closes the window. This function - * requires `CGAL_Qt5`, and is only available if the macro + * requires `CGAL_Qt6`, and is only available if the macro * `CGAL_USE_BASIC_VIEWER` is defined. Linking with the cmake target - * `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` and add the definition + * `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt6` and add the definition * `CGAL_USE_BASIC_VIEWER`. * \tparam PH an instance of the `CGAL::Multipolygon_with_holes_2` class. * \param aph the multipolygon with holes to draw. From c5a186b9039455224eea093273a4e3e25e4a6b81 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 18 Jan 2024 10:56:22 +0000 Subject: [PATCH 149/182] Add Even_odd_rule --- .../doc/Polygon_repair/Polygon_repair.txt | 13 ++-- .../Polygon_repair/repair_polygon_2.cpp | 2 +- .../CGAL/Polygon_repair/Polygon_repair.h | 61 ++++++++++++------- ...iangulation_with_even_odd_constraints_2.h} | 32 +++++----- .../test/Polygon_repair/clipart.cpp | 4 +- .../Polygon_repair/draw_test_polygons.cpp | 4 +- .../test/Polygon_repair/exact_test.cpp | 8 +-- .../Polygon_repair/repair_polygon_2_test.cpp | 6 +- .../test/Polygon_repair/validate_wkt.cpp | 1 + .../write_labeled_triangulation.cpp | 4 +- .../write_repaired_polygons.cpp | 4 +- 11 files changed, 78 insertions(+), 61 deletions(-) rename Polygon_repair/include/CGAL/Polygon_repair/internal/{Triangulation_with_odd_even_constraints_2.h => Triangulation_with_even_odd_constraints_2.h} (82%) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 7f3b427b48bf..54edf8f9898b 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -17,7 +17,7 @@ or hole), and reconstructs the polygon(s) represented by the arrangement. The method returns valid output stored in a multipolygon with holes. Different arrangement and labelling heuristics are possible, but -currently only the odd-even heuristic is implemented in the package. +currently only the even-odd heuristic is implemented in the package. This heuristic results in areas that are alternately assigned as polygon interiors and exterior/holes each time that an input edge is passed. It does not distinguish between edges that are part of outer boundaries @@ -104,14 +104,14 @@ or multipolygon is merely used as a container of input line segments. These line segments are added to the arrangement as edges. Internally, this is done using a constrained triangulation where they are added as constraints. -With the odd-even heuristic, only the edges that are present an odd number of +With the even-odd heuristic, only the edges that are present an odd number of times in the input will be edges in the final arrangement. When these edges are only partially overlapping, only the parts that overlap an odd number of times will be edges in the final arrangement. This procedure is done in two steps: 1. preprocessing to eliminate identical edges that are present an even number of times, and 2. adding edges incrementally -while applying an odd-even counting mechanism, which erases existing (parts of) +while applying an even-odd counting mechanism, which erases existing (parts of) edges when new overlapping ones are added. \subsection SubsectionPolygonRepair_Labeling Labeling @@ -120,7 +120,7 @@ First, the polygon exterior is labeled. For this, all of the faces that can be accessed from the exterior without passing through an edge are labeled as exterior faces. -Then, all other faces are labeled. For the odd-even heuristic, the label applied +Then, all other faces are labeled. For the even-odd heuristic, the label applied alternates between polygon interior and hole every time that an edge is passed. \subsection SubsectionPolygonRepair_Reconstruction Reconstruction of the Multipolygon @@ -150,7 +150,8 @@ with holes has zero holes and extract these if needed. \subsection SubsectionPolygonRepair_Repair Repairing a (Multi)polygon It is possible to repair a polygon, polygon with holes or multipolygon with holes -using the odd-even rule by calling the `Polygon_repair::repair_odd_even()` function +using the even-odd rule by calling the `Polygon_repair::repair()` function +giving as second argument the `Polygon_repair::Even_odd_rule` as shown in the following example. This function returns a repaired multipolygon with holes. \cgalExample{Polygon_repair/repair_polygon_2.cpp} @@ -177,7 +178,7 @@ The polygon repair method as originally developed is described by Ledoux et al. prepair software. This package is a reimplementation of the method with a new approach to label and reconstruct the multipolygons. It also incorporates improvements later -added to prepair, such as the application of the odd-even counting heuristic +added to prepair, such as the application of the even-odd counting heuristic to edges, which enables correct counting even on partially overlapping edges. Ken Arroyo Ohori developed this package during the Google Summer of diff --git a/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp index ed48aabf5933..f2f9d3302357 100644 --- a/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp +++ b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp @@ -16,7 +16,7 @@ int main(int argc, char* argv[]) { Polygon_with_holes_2 pin; CGAL::IO::read_polygon_WKT(in, pin); - Multipolygon_with_holes_2 mp = CGAL::Polygon_repair::repair_odd_even(pin); + Multipolygon_with_holes_2 mp = CGAL::Polygon_repair::repair(pin, CGAL::Polygon_repair::Even_odd_rule()); if (mp.number_of_polygons_with_holes() > 1) { CGAL::IO::write_multi_polygon_WKT(std::cout, mp); } else { diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 81e1090af03b..8010387d4ea1 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -18,9 +18,10 @@ #include #include #include +#include #include -#include +#include namespace CGAL { @@ -30,37 +31,55 @@ template class Polygon_repair; /// \ingroup PkgPolygonRepairFunctions -/// Repair a polygon without holes using the odd-even heuristic +/// Repair a polygon without holes using +template +Multipolygon_with_holes_2 repair(const Polygon_2& , Rule rule) { + CGAL_assertion(false); // rule not implemented + return Multipolygon_with_holes_2(); + } + template -Multipolygon_with_holes_2 repair_odd_even(const Polygon_2& p) { +Multipolygon_with_holes_2 repair(const Polygon_2& p, Even_odd_rule) { CGAL::Polygon_repair::Polygon_repair pr; - pr.add_to_triangulation_odd_even(p); + pr.add_to_triangulation_even_odd(p); if (pr.triangulation().number_of_faces() > 0) { - pr.label_triangulation_odd_even(); + pr.label_triangulation_even_odd(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } /// \ingroup PkgPolygonRepairFunctions -/// Repair a polygon with holes using the odd-even heuristic +/// Repair a polygon with holes +template +Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p, Rule rule) { + CGAL_assertion(false); // rule not implemented + return Multipolygon_with_holes_2(); +} + template -Multipolygon_with_holes_2 repair_odd_even(const Polygon_with_holes_2& p) { +Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p, Even_odd_rule) { CGAL::Polygon_repair::Polygon_repair pr; - pr.add_to_triangulation_odd_even(p); + pr.add_to_triangulation_even_odd(p); if (pr.triangulation().number_of_faces() > 0) { - pr.label_triangulation_odd_even(); + pr.label_triangulation_even_odd(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } /// \ingroup PkgPolygonRepairFunctions -/// Repair a multipolygon with holes using the odd-even heuristic +/// Repair a multipolygon with holes +template +Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& mp, Rule rule) { + CGAL_assertion(false); // rule not implemented + return Multipolygon_with_holes_2(); +} + template -Multipolygon_with_holes_2 repair_odd_even(const Multipolygon_with_holes_2& mp) { +Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& mp, Even_odd_rule) { CGAL::Polygon_repair::Polygon_repair pr; - pr.add_to_triangulation_odd_even(mp); + pr.add_to_triangulation_even_odd(mp); if (pr.triangulation().number_of_faces() > 0) { - pr.label_triangulation_odd_even(); + pr.label_triangulation_even_odd(); pr.reconstruct_multipolygon(); } return pr.multipolygon(); } @@ -281,7 +300,7 @@ class Polygon_repair { CGAL::Exact_predicates_tag, CGAL::Exact_intersections_tag>::type; using Constrained_Delaunay_triangulation = CGAL::Constrained_Delaunay_triangulation_2; - using Triangulation = internal::Triangulation_with_odd_even_constraints_2; + using Triangulation = internal::Triangulation_with_even_odd_constraints_2; // TODO: Edge_map and Vertex_map use std::set and set::map with exact kernels since Point_2 can't be hashed otherwise using Edge_map = typename std::conditional::value, std::unordered_set, @@ -333,7 +352,7 @@ class Polygon_repair { /// @{ // Add edges of the polygon to the triangulation - void add_to_triangulation_odd_even(const Polygon_2& polygon) { + void add_to_triangulation_even_odd(const Polygon_2& polygon) { // Get unique edges for (auto const& edge: polygon.edges()) { @@ -369,12 +388,12 @@ class Polygon_repair { // Insert edges for (auto const& edge: edges_to_insert) { - t.odd_even_insert_constraint(edge.first, edge.second); + t.even_odd_insert_constraint(edge.first, edge.second); } } // Add edges of the polygon to the triangulation - void add_to_triangulation_odd_even(const Polygon_with_holes_2& polygon) { + void add_to_triangulation_even_odd(const Polygon_with_holes_2& polygon) { // Get unique edges for (auto const& edge: polygon.outer_boundary().edges()) { @@ -419,12 +438,12 @@ class Polygon_repair { // Insert edges for (auto const& edge: edges_to_insert) { - t.odd_even_insert_constraint(edge.first, edge.second); + t.even_odd_insert_constraint(edge.first, edge.second); } } // Add edges of the polygon to the triangulation - void add_to_triangulation_odd_even(const Multipolygon_with_holes_2& multipolygon) { + void add_to_triangulation_even_odd(const Multipolygon_with_holes_2& multipolygon) { // Get unique edges for (auto const& polygon: multipolygon.polygons_with_holes()) { @@ -471,7 +490,7 @@ class Polygon_repair { // Insert edges for (auto const& edge: edges_to_insert) { - t.odd_even_insert_constraint(edge.first, edge.second); + t.even_odd_insert_constraint(edge.first, edge.second); } } @@ -507,7 +526,7 @@ class Polygon_repair { } // Label triangles in triangulation - void label_triangulation_odd_even() { + void label_triangulation_even_odd() { // Simplify collinear edges (gets rid of order dependency) for (auto vertex: t.all_vertex_handles()) { diff --git a/Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_with_odd_even_constraints_2.h b/Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_with_even_odd_constraints_2.h similarity index 82% rename from Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_with_odd_even_constraints_2.h rename to Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_with_even_odd_constraints_2.h index 563527a48fb1..e75be739e613 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_with_odd_even_constraints_2.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/internal/Triangulation_with_even_odd_constraints_2.h @@ -9,8 +9,8 @@ // // Author(s) : Ken Arroyo Ohori -#ifndef CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H -#define CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H +#ifndef CGAL_TRIANGULATION_WITH_EVEN_ODD_CONSTRAINTS_2_H +#define CGAL_TRIANGULATION_WITH_EVEN_ODD_CONSTRAINTS_2_H #include #include @@ -20,11 +20,8 @@ namespace Polygon_repair { namespace internal { template -class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { +class Triangulation_with_even_odd_constraints_2 : public Triangulation_ { public: - /// \name Definition - - /// @{ using Base_triangulation = Triangulation_; using Point = typename Triangulation_::Point; using Edge = typename Triangulation_::Edge; @@ -33,13 +30,12 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { using List_edges = typename Triangulation_::List_edges; using List_faces = typename Triangulation_::List_faces; using All_faces_iterator = typename Triangulation_::All_faces_iterator; - /// @} class Interior_tester { - const Triangulation_with_odd_even_constraints_2 *t; + const Triangulation_with_even_odd_constraints_2 *t; public: Interior_tester() {} - Interior_tester(const Triangulation_with_odd_even_constraints_2 *tr) : t(tr) {} + Interior_tester(const Triangulation_with_even_odd_constraints_2 *tr) : t(tr) {} bool operator()(const All_faces_iterator & fit) const { return fit->label() < 1; @@ -66,7 +62,7 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { } // Add constraint from va to vb using the odd-even rule - void odd_even_insert_constraint(Vertex_handle va, Vertex_handle vb) { + void even_odd_insert_constraint(Vertex_handle va, Vertex_handle vb) { // Degenerate edge if (va == vb) return; @@ -80,7 +76,7 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { if (Base_triangulation::is_constrained(Edge(incident_face, opposite_vertex))) { Base_triangulation::remove_constrained_edge(incident_face, opposite_vertex); } else Base_triangulation::mark_constraint(incident_face, opposite_vertex); - if (vc != vb) odd_even_insert_constraint(vc, vb); // process edges along [vc, vb] + if (vc != vb) even_odd_insert_constraint(vc, vb); // process edges along [vc, vb] return; } @@ -90,24 +86,24 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { Vertex_handle intersection; if (Base_triangulation::find_intersected_faces(va, vb, intersected_faces, conflict_boundary_ab, conflict_boundary_ba, intersection)) { if (intersection != va && intersection != vb) { - odd_even_insert_constraint(va, intersection); - odd_even_insert_constraint(intersection, vb); - } else odd_even_insert_constraint(va, vb); + even_odd_insert_constraint(va, intersection); + even_odd_insert_constraint(intersection, vb); + } else even_odd_insert_constraint(va, vb); return; } // Otherwise Base_triangulation::triangulate_hole(intersected_faces, conflict_boundary_ab, conflict_boundary_ba); if (intersection != vb) { - odd_even_insert_constraint(intersection, vb); + even_odd_insert_constraint(intersection, vb); } } // Add constraint from pa to pb using the odd-even rule - void odd_even_insert_constraint(Point pa, Point pb) { + void even_odd_insert_constraint(Point pa, Point pb) { Vertex_handle va = insert(pa); Vertex_handle vb = insert(pb, va->face()); // vb is likely close to va - odd_even_insert_constraint(va, vb); + even_odd_insert_constraint(va, vb); } // Starts at an arbitrary interior face @@ -128,4 +124,4 @@ class Triangulation_with_odd_even_constraints_2 : public Triangulation_ { } // namespace Polygon_repair } // namespace CGAL -#endif // CGAL_TRIANGULATION_WITH_ODD_EVEN_CONSTRAINTS_2_H +#endif // CGAL_TRIANGULATION_WITH_EVEN_ODD_CONSTRAINTS_2_H diff --git a/Polygon_repair/test/Polygon_repair/clipart.cpp b/Polygon_repair/test/Polygon_repair/clipart.cpp index b5337840fd88..3760c477f732 100644 --- a/Polygon_repair/test/Polygon_repair/clipart.cpp +++ b/Polygon_repair/test/Polygon_repair/clipart.cpp @@ -73,12 +73,12 @@ int main(int argc, char* argv[]) { for (auto const& edge: edges_to_insert) { Polygon_repair::Triangulation::Vertex_handle va = pr.triangulation().insert(edge.first, search_start); Polygon_repair::Triangulation::Vertex_handle vb = pr.triangulation().insert(edge.second, va->face()); // vb is likely close to va - pr.triangulation().odd_even_insert_constraint(va, vb); + pr.triangulation().even_odd_insert_constraint(va, vb); search_start = vb->face(); } if (pr.triangulation().number_of_faces() > 0) { - pr.label_triangulation_odd_even(); + pr.label_triangulation_even_odd(); pr.reconstruct_multipolygon(); } Multipolygon_with_holes_2 mp = pr.multipolygon(); diff --git a/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp b/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp index db22777f457a..ed312122c767 100644 --- a/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp +++ b/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp @@ -35,12 +35,12 @@ int main(int argc, char* argv[]) { if (in != "POLYGON()") { // maybe should be checked in WKT reader CGAL::IO::read_polygon_WKT(iss, p); } CGAL::draw(p); - rmp = CGAL::Polygon_repair::repair_odd_even(p); + rmp = CGAL::Polygon_repair::repair(p, CGAL::Polygon_repair::Even_odd_rule()); } else if (in.find("MULTIPOLYGON") == 0) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); CGAL::draw(mp); - rmp = CGAL::Polygon_repair::repair_odd_even(mp); + rmp = CGAL::Polygon_repair::repair(mp, CGAL::Polygon_repair::Even_odd_rule()); } std::ostringstream oss; CGAL::IO::write_multi_polygon_WKT(oss, rmp); std::string out = oss.str(); diff --git a/Polygon_repair/test/Polygon_repair/exact_test.cpp b/Polygon_repair/test/Polygon_repair/exact_test.cpp index e0263867fa11..bfa34ab36c97 100644 --- a/Polygon_repair/test/Polygon_repair/exact_test.cpp +++ b/Polygon_repair/test/Polygon_repair/exact_test.cpp @@ -28,17 +28,17 @@ int main(int argc, char* argv[]) { CGAL::draw(p); Polygon_repair pr; for (auto const edge: p.outer_boundary().edges()) { - pr.triangulation().odd_even_insert_constraint(edge.source(), edge.target()); + pr.triangulation().even_odd_insert_constraint(edge.source(), edge.target()); } int spikes = 20; for (auto const& hole: p.holes()) { for (auto const edge: hole.edges()) { if (spikes-- <= 0) break; - pr.triangulation().odd_even_insert_constraint(edge.source(), edge.target()); + pr.triangulation().even_odd_insert_constraint(edge.source(), edge.target()); } } - pr.label_triangulation_odd_even(); + pr.label_triangulation_even_odd(); pr.reconstruct_multipolygon(); - rmp = CGAL::Polygon_repair::repair_odd_even(p); + rmp = CGAL::Polygon_repair::repair(p, CGAL::Polygon_repair::Even_odd_rule()); std::ostringstream oss; CGAL::IO::write_multi_polygon_WKT(oss, rmp); std::string out = oss.str(); diff --git a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp index b36caa502b0b..055e8c15a0b4 100644 --- a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp +++ b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp @@ -31,18 +31,18 @@ int main(int argc, char* argv[]) { Polygon_with_holes_2 p; if (in != "POLYGON()") { // maybe should be checked in WKT reader CGAL::IO::read_polygon_WKT(iss, p); - } rmp = CGAL::Polygon_repair::repair_odd_even(p); + } rmp = CGAL::Polygon_repair::repair(p, CGAL::Polygon_repair::Even_odd_rule()); } else if (in.find("MULTIPOLYGON") == 0) { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); - rmp = CGAL::Polygon_repair::repair_odd_even(mp); + rmp = CGAL::Polygon_repair::repair(mp, CGAL::Polygon_repair::Even_odd_rule()); } std::ostringstream oss; CGAL::IO::write_multi_polygon_WKT(oss, rmp); std::string out = oss.str(); // Read reference file std::string ref_path = "data/ref/"; - ref_path += file.path().filename(); + ref_path += file.path().filename().string(); std::ifstream ref_ifs(ref_path); if (ref_ifs.fail()) { std::cout << std::endl << "\tin: " << in << std::endl; diff --git a/Polygon_repair/test/Polygon_repair/validate_wkt.cpp b/Polygon_repair/test/Polygon_repair/validate_wkt.cpp index c4781315c624..ac92bfd9140e 100644 --- a/Polygon_repair/test/Polygon_repair/validate_wkt.cpp +++ b/Polygon_repair/test/Polygon_repair/validate_wkt.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include diff --git a/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp b/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp index 24837d7c14ad..92d33b2f70f4 100644 --- a/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp +++ b/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp @@ -20,8 +20,8 @@ int main(int argc, char* argv[]) { CGAL::IO::read_multi_polygon_WKT(ifs, mp); Polygon_repair pr; - pr.add_to_triangulation_odd_even(mp); - pr.label_triangulation_odd_even(); + pr.add_to_triangulation_even_odd(mp); + pr.label_triangulation_even_odd(); std::cout << "{" << std::endl; std::cout << "\t\"type\": \"FeatureCollection\"," << std::endl; diff --git a/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp b/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp index f326da10c423..183c64bbd384 100644 --- a/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp +++ b/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp @@ -28,8 +28,8 @@ int main(int argc, char* argv[]) { Polygon_with_holes_2 p; CGAL::IO::read_polygon_WKT(iss, p); Polygon_repair pr; - pr.add_to_triangulation_odd_even(p); - pr.label_triangulation_odd_even(); + pr.add_to_triangulation_even_odd(p); + pr.label_triangulation_even_odd(); pr.reconstruct_multipolygon(); Multipolygon_with_holes_2 rmp = pr.multipolygon(); std::ostringstream oss; From e8909924d59c69aed52d694f64e4acc12790bdc0 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 18 Jan 2024 11:09:36 +0000 Subject: [PATCH 150/182] Fix clipart.cpp --- Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h | 4 ++-- Polygon_repair/test/Polygon_repair/clipart.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 8010387d4ea1..8ff40ee27d5f 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -212,14 +212,14 @@ template bool is_valid(const Multipolygon_with_holes_2& multipolygon) { // Validate polygons - for (auto const& polygon: multipolygon.polygons()) { + for (auto const& polygon: multipolygon.polygons_with_holes()) { if (!is_valid(polygon)) return false; } typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation vt; typename CGAL::Polygon_repair::Polygon_repair::Validation_triangulation::Locate_type lt; int li; - for (auto const& polygon: multipolygon.polygons()) { + for (auto const& polygon: multipolygon.polygons_with_holes()) { if (vt.number_of_faces() > 0) { diff --git a/Polygon_repair/test/Polygon_repair/clipart.cpp b/Polygon_repair/test/Polygon_repair/clipart.cpp index 3760c477f732..94516d6e7649 100644 --- a/Polygon_repair/test/Polygon_repair/clipart.cpp +++ b/Polygon_repair/test/Polygon_repair/clipart.cpp @@ -31,7 +31,7 @@ int main(int argc, char* argv[]) { if (file.path().filename().extension() != ".obj") continue; std::cout << "Reading " << file.path().filename() << "..."; - if (std::filesystem::exists(folder_out + "/" + std::string(file.path().stem()) + ".svg")) { + if (std::filesystem::exists(folder_out + "/" + file.path().stem().string() + ".svg")) { std::cout << " skipped: already processed" << std::endl; continue; } @@ -90,7 +90,7 @@ int main(int argc, char* argv[]) { double scale = desired_width/(bbox.xmax()-bbox.xmin()); - std::ofstream ofs(folder_out + "/" + std::string(file.path().stem()) + ".svg"); + std::ofstream ofs(folder_out + "/" + file.path().stem().string() + ".svg"); ofs << "" << std::endl; for (auto const& polygon: mp.polygons_with_holes()) { From ef8d2747ce143fa90c8b583cfbd1ac3d2eaf2381 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 18 Jan 2024 11:18:14 +0000 Subject: [PATCH 151/182] Document the rule --- Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 8ff40ee27d5f..b3453d6146a4 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -27,8 +27,10 @@ namespace CGAL { namespace Polygon_repair { +#ifndef DOXYGEN_RUNNING template class Polygon_repair; +#endif /// \ingroup PkgPolygonRepairFunctions /// Repair a polygon without holes using @@ -289,6 +291,8 @@ bool is_valid(const Multipolygon_with_holes_2& multipolygon) return true; } +#ifndef DOXYGEN_RUNNING + template > class Polygon_repair { public: @@ -694,6 +698,8 @@ class Polygon_repair { typename Triangulation::Face_handle search_start; }; +#endif // DOXYGEN_RUNNING + } // namespace Polygon_repair } // namespace CGAL From 1d8b0171234c03a6821280966278de410b9ba10c Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 18 Jan 2024 11:27:55 +0000 Subject: [PATCH 152/182] Fix package description --- Polygon_repair/doc/Polygon_repair/PackageDescription.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt index 74c33e961e1e..6aeb0392d074 100644 --- a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt +++ b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt @@ -30,6 +30,8 @@ \cgalClassifedRefPages \cgalCRPSection{Functions} -- `CGAL::Polygon_repair::repair_odd_even()` +- `CGAL::Polygon_repair::repair()` +\cgalCRPSection{Simplification Rules} +- `CGAL::Polygon_repair::Even_odd_rule` */ From db6f210684e012a35e4d5191a258677d5ff545e0 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 18 Jan 2024 11:31:17 +0000 Subject: [PATCH 153/182] Fix one input path --- .../test/Polygon_repair/write_labeled_triangulation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp b/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp index 92d33b2f70f4..769b56420a19 100644 --- a/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp +++ b/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp @@ -14,7 +14,7 @@ using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; int main(int argc, char* argv[]) { - std::ifstream ifs("data/nesting-spike.wkt"); + std::ifstream ifs("data/in/nesting-spike.wkt"); Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(ifs, mp); From c21a988f3a8a21323b6c198c0dec508bee0a8de0 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 18 Jan 2024 12:03:20 +0000 Subject: [PATCH 154/182] Add the file --- .../CGAL/Polygon_repair/Even_odd_rule.h | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h b/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h new file mode 100644 index 000000000000..769ad2640388 --- /dev/null +++ b/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h @@ -0,0 +1,31 @@ +// Copyright (c) 2023 GeometryFactory. +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Ken Arroyo Ohori + +#ifndef CGAL_POLYGON_REPAIR_EVEN_ODD_RULE_H +#define CGAL_POLYGON_REPAIR_EVEN_ODD_RULE_H + +#include + +namespace CGAL { + +namespace Polygon_repair { + + /*! + \addtogroup PkgPolygonRepairRef + + */ + struct Even_odd_rule {}; + +} // namespace Polygon_repair + +} // namespace CGAL + +#endif // CGAL_POLYGON_REPAIR_EVEN_ODD_RULE_H From a0ad1829b83a9d3e86f793c0802d5313cd55d583 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 6 Feb 2024 14:39:24 +0000 Subject: [PATCH 155/182] Fixes after Guillaume's review --- .../doc/Polygon_repair/Polygon_repair.txt | 17 +++++++++-------- .../include/CGAL/Polygon_repair/Even_odd_rule.h | 1 + .../CGAL/Polygon_repair/Polygon_repair.h | 15 ++++++++++++--- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 54edf8f9898b..746f5874c75e 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -17,11 +17,12 @@ or hole), and reconstructs the polygon(s) represented by the arrangement. The method returns valid output stored in a multipolygon with holes. Different arrangement and labelling heuristics are possible, but -currently only the even-odd heuristic is implemented in the package. -This heuristic results in areas that are alternately assigned as polygon +currently only the even-odd rule is implemented in this package. +This rule results in areas that are alternately assigned as polygon interiors and exterior/holes each time that an input edge is passed. It does not distinguish between edges that are part of outer boundaries -from those of inner boundaries. +from those of inner boundaries. In a next version we will add the +winding number rule. \section SectionPolygonRepair_Definitions Definitions @@ -104,7 +105,7 @@ or multipolygon is merely used as a container of input line segments. These line segments are added to the arrangement as edges. Internally, this is done using a constrained triangulation where they are added as constraints. -With the even-odd heuristic, only the edges that are present an odd number of +With the even-odd rule, only the edges that are present an odd number of times in the input will be edges in the final arrangement. When these edges are only partially overlapping, only the parts that overlap an odd number of times will be edges in the final arrangement. @@ -120,7 +121,7 @@ First, the polygon exterior is labeled. For this, all of the faces that can be accessed from the exterior without passing through an edge are labeled as exterior faces. -Then, all other faces are labeled. For the even-odd heuristic, the label applied +Then, all other faces are labeled. For the even-odd rule, the label applied alternates between polygon interior and hole every time that an edge is passed. \subsection SubsectionPolygonRepair_Reconstruction Reconstruction of the Multipolygon @@ -175,14 +176,14 @@ since all of these intersections need to be calculated in the overlay. The polygon repair method as originally developed is described by Ledoux et al. \cgalCite{ledoux2014triangulation} and implemented in the -prepair software. +prepair software. This package is a reimplementation of the method with a new approach to label and reconstruct the multipolygons. It also incorporates improvements later -added to prepair, such as the application of the even-odd counting heuristic +added to prepair, such as the application of the even-odd counting heuristics to edges, which enables correct counting even on partially overlapping edges. Ken Arroyo Ohori developed this package during the Google Summer of -Code 2023 under the mentorship of Sébastien Loriot and Andreas Fabri. +Code 2023 mentored by Sébastien Loriot and Andreas Fabri. */ } /* namespace CGAL */ diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h b/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h index 769ad2640388..619d3b7fd8b9 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h @@ -21,6 +21,7 @@ namespace Polygon_repair { /*! \addtogroup PkgPolygonRepairRef + Tag class to select the even odd rule when calling `CGAL::Polygon_repair::repair()`. */ struct Even_odd_rule {}; diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index b3453d6146a4..4e12f0b11f0b 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -33,7 +33,10 @@ class Polygon_repair; #endif /// \ingroup PkgPolygonRepairFunctions -/// Repair a polygon without holes using +/// repairs a polygon without holes using the given rule +/// \tparam Kernel parameter of the input and output polygons +/// \tparam Container parameter of the input and output polygons +/// \tparam Rule must be `Even_odd_rule` template Multipolygon_with_holes_2 repair(const Polygon_2& , Rule rule) { CGAL_assertion(false); // rule not implemented @@ -51,7 +54,10 @@ Multipolygon_with_holes_2 repair(const Polygon_2 Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p, Rule rule) { CGAL_assertion(false); // rule not implemented @@ -69,7 +75,10 @@ Multipolygon_with_holes_2 repair(const Polygon_with_holes_2 Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& mp, Rule rule) { CGAL_assertion(false); // rule not implemented From 458c52eb7cbef00a517848b0dcbe4f915a4c6720 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 6 Feb 2024 15:03:52 +0000 Subject: [PATCH 156/182] Fixes after Guillaume's review --- Polygon_repair/doc/Polygon_repair/PackageDescription.txt | 5 +++-- Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt index 6aeb0392d074..0bd41658ad43 100644 --- a/Polygon_repair/doc/Polygon_repair/PackageDescription.txt +++ b/Polygon_repair/doc/Polygon_repair/PackageDescription.txt @@ -7,14 +7,15 @@ /*! \addtogroup PkgPolygonRepairRef -\todo check generated documentation \cgalPkgDescriptionBegin{2D Polygon Repair,PkgPolygonRepair} \cgalPkgPicture{Polygon_repair-small.png} \cgalPkgSummaryBegin \cgalPkgAuthors{Ken Arroyo Ohori} -\cgalPkgDesc{The package provides algorithms to repair 2D (multi)polygons. } +\cgalPkgDesc{This package provides algorithms to repair 2D polygons, polygons with holes, +and multipolygons with holes, by selecting faces of the arrangement of the input based on a selection rule. +Currently, only the even-odd rule is provided. } \cgalPkgManuals{Chapter_2D_Polygon_repair,PkgPolygonRepairRef} \cgalPkgSummaryEnd diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h b/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h index 619d3b7fd8b9..7c640bda7ab5 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h @@ -17,7 +17,7 @@ namespace CGAL { namespace Polygon_repair { - +/// @{ /*! \addtogroup PkgPolygonRepairRef @@ -25,6 +25,8 @@ namespace Polygon_repair { */ struct Even_odd_rule {}; +///@} + } // namespace Polygon_repair } // namespace CGAL From edc721e89433b3b51e84b30757c563c809b5153f Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 6 Feb 2024 15:49:49 +0000 Subject: [PATCH 157/182] wording --- .../include/CGAL/Polygon_repair/Polygon_repair.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h index 4e12f0b11f0b..cdeda55d4878 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h @@ -33,12 +33,12 @@ class Polygon_repair; #endif /// \ingroup PkgPolygonRepairFunctions -/// repairs a polygon without holes using the given rule +/// repairs polygon `p` using the given rule /// \tparam Kernel parameter of the input and output polygons /// \tparam Container parameter of the input and output polygons /// \tparam Rule must be `Even_odd_rule` template -Multipolygon_with_holes_2 repair(const Polygon_2& , Rule rule) { +Multipolygon_with_holes_2 repair(const Polygon_2& p , Rule rule) { CGAL_assertion(false); // rule not implemented return Multipolygon_with_holes_2(); } @@ -54,7 +54,7 @@ Multipolygon_with_holes_2 repair(const Polygon_2 repair(const Polygon_with_holes_2 -Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& mp, Rule rule) { +Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p, Rule rule) { CGAL_assertion(false); // rule not implemented return Multipolygon_with_holes_2(); } From 653bc3616ba29831f4e999f7aff258de7066cbf7 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 6 Feb 2024 16:04:41 +0000 Subject: [PATCH 158/182] wording --- Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h b/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h index 7c640bda7ab5..fc4351aa7dcd 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h @@ -17,10 +17,11 @@ namespace CGAL { namespace Polygon_repair { + +\addtogroup PkgPolygonRepairRef /// @{ - /*! - \addtogroup PkgPolygonRepairRef +/*! Tag class to select the even odd rule when calling `CGAL::Polygon_repair::repair()`. */ struct Even_odd_rule {}; From 5e0191494e75b5d6e3d6c855a2effe3678307218 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 6 Feb 2024 17:00:59 +0000 Subject: [PATCH 159/182] C++ comment doxygen command --- Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h b/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h index fc4351aa7dcd..b2dc51bfe369 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/Even_odd_rule.h @@ -18,7 +18,7 @@ namespace CGAL { namespace Polygon_repair { -\addtogroup PkgPolygonRepairRef +/// \addtogroup PkgPolygonRepairRef /// @{ /*! From 1c31cfdcbb0d77ddc65456f213da3d415c7be3c5 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 7 Feb 2024 11:04:52 +0000 Subject: [PATCH 160/182] Fix path --- Polygon_repair/test/Polygon_repair/validate_wkt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair/test/Polygon_repair/validate_wkt.cpp b/Polygon_repair/test/Polygon_repair/validate_wkt.cpp index ac92bfd9140e..a5584e6745cc 100644 --- a/Polygon_repair/test/Polygon_repair/validate_wkt.cpp +++ b/Polygon_repair/test/Polygon_repair/validate_wkt.cpp @@ -18,7 +18,7 @@ using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; int main(int argc, char* argv[]) { // std::string folder = "/Users/ken/Downloads/big polygons/"; - std::string folder = "/Users/ken/Versioned/cgal-public-dev/Polygon_repair/test/Polygon_repair/data/in"; + std::string folder = "data/in"; for (const auto& file: std::filesystem::directory_iterator(folder)) { if (file.path().filename().extension() != ".wkt") continue; From 5333c6f07292ab39d5abaa4cbfddbceafd21751e Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 7 Feb 2024 11:10:17 +0000 Subject: [PATCH 161/182] #define CGAL_NO_CDT_2_WARNING --- Polygon_repair/test/Polygon_repair/exact_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polygon_repair/test/Polygon_repair/exact_test.cpp b/Polygon_repair/test/Polygon_repair/exact_test.cpp index bfa34ab36c97..265c4b6fd751 100644 --- a/Polygon_repair/test/Polygon_repair/exact_test.cpp +++ b/Polygon_repair/test/Polygon_repair/exact_test.cpp @@ -1,3 +1,5 @@ +#define CGAL_NO_CDT_2_WARNING + #include #include #include From aa6ff65c02b1dabdf95c12ac0a6f4e1fcd118b27 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 7 Feb 2024 11:11:53 +0000 Subject: [PATCH 162/182] Change #include order to check dependencies --- .../test/Polygon_repair/repair_polygon_2_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp index 055e8c15a0b4..7150090da045 100644 --- a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp +++ b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp @@ -1,12 +1,12 @@ +#include +#include +#include + #include #include #include #include -#include -#include -#include - using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; using Point_2 = Kernel::Point_2; using Polygon_2 = CGAL::Polygon_2; From 80075364eba5c17613e2f70b29a70e68320d3e87 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 7 Feb 2024 12:03:42 +0000 Subject: [PATCH 163/182] Only compile some of the test cases so that we can have it in a testsuite --- .../test/Polygon_repair/CMakeLists.txt | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Polygon_repair/test/Polygon_repair/CMakeLists.txt b/Polygon_repair/test/Polygon_repair/CMakeLists.txt index 6075ee3222ba..faced1f88058 100644 --- a/Polygon_repair/test/Polygon_repair/CMakeLists.txt +++ b/Polygon_repair/test/Polygon_repair/CMakeLists.txt @@ -7,13 +7,17 @@ project(Polygon_repair_Tests) find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt6) # create a target per cppfile -file( - GLOB cppfiles - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) -foreach(cppfile ${cppfiles}) - create_single_source_cgal_program("${cppfile}") -endforeach() +#file( +# GLOB cppfiles +# RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} +# ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +#foreach(cppfile ${cppfiles}) +# create_single_source_cgal_program("${cppfile}") +#endforeach() + +create_single_source_cgal_program( "draw_test_polygons.cpp" ) +create_single_source_cgal_program( "exact_test.cpp") +create_single_source_cgal_program( "repair_polygon_2_test.cpp" ) if(CGAL_Qt6_FOUND) target_link_libraries(draw_test_polygons PUBLIC CGAL::CGAL_Basic_viewer) From 38c43ce2cbfd71e79328f37015ee46568e8dc147 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 23 Feb 2024 07:44:07 +0000 Subject: [PATCH 164/182] Fix multipolygon.cpp --- Polygon/examples/Polygon/multipolygon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon/examples/Polygon/multipolygon.cpp b/Polygon/examples/Polygon/multipolygon.cpp index 9699f916e99f..babf3def44d6 100644 --- a/Polygon/examples/Polygon/multipolygon.cpp +++ b/Polygon/examples/Polygon/multipolygon.cpp @@ -23,7 +23,7 @@ int main(int argc, char* argv[]) { mp.add_polygon_with_holes(p1); mp.add_polygon_with_holes(p2); - for (auto const& p: mp.polygons()) { + for (auto const& p: mp.polygons_with_holes()) { std::cout << p << std::endl; } From 25b084e146e1d19ecba08544e07ed464fa88ff94 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 23 Feb 2024 07:52:05 +0000 Subject: [PATCH 165/182] Fix operator<< for Multipolygon_with_holes --- Polygon/include/CGAL/Multipolygon_with_holes_2.h | 4 ++-- Stream_support/examples/Stream_support/Polygon_WKT.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h index 3fb93f903be7..7cabd2871fe2 100644 --- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h +++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h @@ -117,8 +117,8 @@ std::ostream& operator<<(std::ostream& os, switch(IO::get_mode(os)) { case IO::ASCII : - os << mp.number_of_polygons() << ' '; - for (i = mp.polygon_with_holes_begin(); i != mp.polygon_with_holes_end(); ++i) { + os << mp.number_of_polygons_with_holes() << ' '; + for (i = mp.polygons_with_holes_begin(); i != mp.polygons_with_holes_end(); ++i) { os << *i << ' '; } return os; diff --git a/Stream_support/examples/Stream_support/Polygon_WKT.cpp b/Stream_support/examples/Stream_support/Polygon_WKT.cpp index f725dcd37494..9bf7a37cf4bd 100644 --- a/Stream_support/examples/Stream_support/Polygon_WKT.cpp +++ b/Stream_support/examples/Stream_support/Polygon_WKT.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include From 2324d61af6a25abdcd53497ff9680a916310f889 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 4 Mar 2024 16:50:46 +0000 Subject: [PATCH 166/182] Rename header file --- Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp | 2 +- .../include/CGAL/Polygon_repair/{Polygon_repair.h => repair.h} | 0 Polygon_repair/test/Polygon_repair/clipart.cpp | 2 +- Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp | 2 +- Polygon_repair/test/Polygon_repair/exact_test.cpp | 2 +- Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp | 2 +- Polygon_repair/test/Polygon_repair/validate_wkt.cpp | 2 +- .../test/Polygon_repair/write_labeled_triangulation.cpp | 2 +- Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename Polygon_repair/include/CGAL/Polygon_repair/{Polygon_repair.h => repair.h} (100%) diff --git a/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp index f2f9d3302357..36e3ba74a764 100644 --- a/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp +++ b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; diff --git a/Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h similarity index 100% rename from Polygon_repair/include/CGAL/Polygon_repair/Polygon_repair.h rename to Polygon_repair/include/CGAL/Polygon_repair/repair.h diff --git a/Polygon_repair/test/Polygon_repair/clipart.cpp b/Polygon_repair/test/Polygon_repair/clipart.cpp index 94516d6e7649..013265e835b8 100644 --- a/Polygon_repair/test/Polygon_repair/clipart.cpp +++ b/Polygon_repair/test/Polygon_repair/clipart.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; diff --git a/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp b/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp index ed312122c767..7161506f952a 100644 --- a/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp +++ b/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include diff --git a/Polygon_repair/test/Polygon_repair/exact_test.cpp b/Polygon_repair/test/Polygon_repair/exact_test.cpp index 265c4b6fd751..4ed815ff9ad2 100644 --- a/Polygon_repair/test/Polygon_repair/exact_test.cpp +++ b/Polygon_repair/test/Polygon_repair/exact_test.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include diff --git a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp index 7150090da045..2758dd4aebdf 100644 --- a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp +++ b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/Polygon_repair/test/Polygon_repair/validate_wkt.cpp b/Polygon_repair/test/Polygon_repair/validate_wkt.cpp index a5584e6745cc..281da7542f27 100644 --- a/Polygon_repair/test/Polygon_repair/validate_wkt.cpp +++ b/Polygon_repair/test/Polygon_repair/validate_wkt.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; diff --git a/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp b/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp index 769b56420a19..24d542c7ce1f 100644 --- a/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp +++ b/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; diff --git a/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp b/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp index 183c64bbd384..604e04a0ec8d 100644 --- a/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp +++ b/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; From b0f4e7335842534ce05906786933a59518faa2ce Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 4 Mar 2024 19:48:25 +0000 Subject: [PATCH 167/182] Make the Even_odd_rule a default --- .../doc/Polygon_repair/Polygon_repair.txt | 1 - .../Polygon_repair/repair_polygon_2.cpp | 2 +- .../include/CGAL/Polygon_repair/repair.h | 33 +++++-------------- 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt index 746f5874c75e..26b6f6d62c70 100644 --- a/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt +++ b/Polygon_repair/doc/Polygon_repair/Polygon_repair.txt @@ -152,7 +152,6 @@ with holes has zero holes and extract these if needed. It is possible to repair a polygon, polygon with holes or multipolygon with holes using the even-odd rule by calling the `Polygon_repair::repair()` function -giving as second argument the `Polygon_repair::Even_odd_rule` as shown in the following example. This function returns a repaired multipolygon with holes. \cgalExample{Polygon_repair/repair_polygon_2.cpp} diff --git a/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp index 36e3ba74a764..9004d092abd2 100644 --- a/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp +++ b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp @@ -16,7 +16,7 @@ int main(int argc, char* argv[]) { Polygon_with_holes_2 pin; CGAL::IO::read_polygon_WKT(in, pin); - Multipolygon_with_holes_2 mp = CGAL::Polygon_repair::repair(pin, CGAL::Polygon_repair::Even_odd_rule()); + Multipolygon_with_holes_2 mp = CGAL::Polygon_repair::repair(pin); if (mp.number_of_polygons_with_holes() > 1) { CGAL::IO::write_multi_polygon_WKT(std::cout, mp); } else { diff --git a/Polygon_repair/include/CGAL/Polygon_repair/repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h index cdeda55d4878..29ea87a6272a 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/repair.h @@ -37,14 +37,9 @@ class Polygon_repair; /// \tparam Kernel parameter of the input and output polygons /// \tparam Container parameter of the input and output polygons /// \tparam Rule must be `Even_odd_rule` -template -Multipolygon_with_holes_2 repair(const Polygon_2& p , Rule rule) { - CGAL_assertion(false); // rule not implemented - return Multipolygon_with_holes_2(); - } - -template -Multipolygon_with_holes_2 repair(const Polygon_2& p, Even_odd_rule) { +template +Multipolygon_with_holes_2 repair(const Polygon_2& p , Rule rule = Rule()) +{ CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_even_odd(p); if (pr.triangulation().number_of_faces() > 0) { @@ -58,14 +53,9 @@ Multipolygon_with_holes_2 repair(const Polygon_2 -Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p, Rule rule) { - CGAL_assertion(false); // rule not implemented - return Multipolygon_with_holes_2(); -} - -template -Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p, Even_odd_rule) { +template +Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p, Rule rule = Rule()) +{ CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_even_odd(p); if (pr.triangulation().number_of_faces() > 0) { @@ -79,14 +69,9 @@ Multipolygon_with_holes_2 repair(const Polygon_with_holes_2 -Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p, Rule rule) { - CGAL_assertion(false); // rule not implemented - return Multipolygon_with_holes_2(); -} - -template -Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& mp, Even_odd_rule) { +template +Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p, Rule rule = Rule()) +{ CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_even_odd(mp); if (pr.triangulation().number_of_faces() > 0) { From 7edadee3c2a42d1b87c263c849a2b4f22484ea43 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 4 Mar 2024 20:16:35 +0000 Subject: [PATCH 168/182] fix code --- Polygon_repair/include/CGAL/Polygon_repair/repair.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h index 29ea87a6272a..c2c57426467b 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/repair.h @@ -73,7 +73,7 @@ template Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p, Rule rule = Rule()) { CGAL::Polygon_repair::Polygon_repair pr; - pr.add_to_triangulation_even_odd(mp); + pr.add_to_triangulation_even_odd(p); if (pr.triangulation().number_of_faces() > 0) { pr.label_triangulation_even_odd(); pr.reconstruct_multipolygon(); From 181cec68f4be0799c81aa3987ce8ea827ecac9cd Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 5 Mar 2024 07:16:44 +0000 Subject: [PATCH 169/182] conversion warning --- Polygon_repair/include/CGAL/Polygon_repair/repair.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h index c2c57426467b..d40fad299f45 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/repair.h @@ -649,7 +649,7 @@ class Polygon_repair { // Create polygons with holes and put in multipolygon std::set, Polygon_with_holes_less> ordered_polygons; - for (int i = 0; i < polygons.size(); ++i) { + for (std::size_t i = 0; i < polygons.size(); ++i) { ordered_polygons.insert(Polygon_with_holes_2(polygons[i], holes[i].begin(), holes[i].end())); } for (auto const& polygon: ordered_polygons) { From b13b01af997d914c5073590652f64e220257988f Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 6 Mar 2024 08:13:12 +0000 Subject: [PATCH 170/182] Remove argc, argv --- Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp | 2 +- Polygon/examples/Polygon/multipolygon.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp b/Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp index db7927c8ba5d..bda77eb63236 100644 --- a/Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp +++ b/Polygon/examples/Polygon/draw_multipolygon_with_holes.cpp @@ -9,7 +9,7 @@ using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; -int main(int argc, char* argv[]) { +int main() { std::string wkt = "MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0),(0.1 0.1,0.1 0.9,0.9 0.9,0.9 0.1,0.1 0.1)),((0.2 0.2,0.8 0.2,0.8 0.8,0.2 0.8,0.2 0.2),(0.3 0.3,0.3 0.7,0.7 0.7,0.7 0.3,0.3 0.3)))"; std::istringstream iss(wkt); Multipolygon_with_holes_2 mp; diff --git a/Polygon/examples/Polygon/multipolygon.cpp b/Polygon/examples/Polygon/multipolygon.cpp index babf3def44d6..31ce7d37401c 100644 --- a/Polygon/examples/Polygon/multipolygon.cpp +++ b/Polygon/examples/Polygon/multipolygon.cpp @@ -7,7 +7,7 @@ using Polygon_2 = CGAL::Polygon_2; using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; -int main(int argc, char* argv[]) { +int main() { Point_2 p1_outer[] = {Point_2(0,0), Point_2(1,0), Point_2(1,1), Point_2(0,1)}; Point_2 p1_inner[] = {Point_2(0.2,0.2), Point_2(0.8,0.2), Point_2(0.8,0.8), Point_2(0.2,0.8)}; From b9f3e351921db084cefb5846cb5658a43bbfefee Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 6 Mar 2024 08:36:36 +0000 Subject: [PATCH 171/182] Address warning and assert the Rule type --- .../examples/Polygon_repair/repair_polygon_2.cpp | 2 +- Polygon_repair/include/CGAL/Polygon_repair/repair.h | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp index 9004d092abd2..be6a011b4a0c 100644 --- a/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp +++ b/Polygon_repair/examples/Polygon_repair/repair_polygon_2.cpp @@ -11,7 +11,7 @@ using Polygon_2 = CGAL::Polygon_2; using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; -int main(int argc, char* argv[]) { +int main() { std::ifstream in("data/bridge-edge.wkt"); Polygon_with_holes_2 pin; CGAL::IO::read_polygon_WKT(in, pin); diff --git a/Polygon_repair/include/CGAL/Polygon_repair/repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h index d40fad299f45..523764ce508b 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/repair.h @@ -38,8 +38,9 @@ class Polygon_repair; /// \tparam Container parameter of the input and output polygons /// \tparam Rule must be `Even_odd_rule` template -Multipolygon_with_holes_2 repair(const Polygon_2& p , Rule rule = Rule()) +Multipolygon_with_holes_2 repair(const Polygon_2& p , Rule = Rule()) { + static_assert(std::is_same_v); CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_even_odd(p); if (pr.triangulation().number_of_faces() > 0) { @@ -54,8 +55,9 @@ Multipolygon_with_holes_2 repair(const Polygon_2 -Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p, Rule rule = Rule()) +Multipolygon_with_holes_2 repair(const Polygon_with_holes_2& p, Rule = Rule()) { + static_assert(std::is_same_v); CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_even_odd(p); if (pr.triangulation().number_of_faces() > 0) { @@ -70,8 +72,9 @@ Multipolygon_with_holes_2 repair(const Polygon_with_holes_2 -Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p, Rule rule = Rule()) +Multipolygon_with_holes_2 repair(const Multipolygon_with_holes_2& p, Rule = Rule()) { + static_assert(std::is_same_v); CGAL::Polygon_repair::Polygon_repair pr; pr.add_to_triangulation_even_odd(p); if (pr.triangulation().number_of_faces() > 0) { From 5e3cf4376ecf51a2e1682405431c8092ae818b68 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 8 Mar 2024 10:55:42 +0000 Subject: [PATCH 172/182] flush --- Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp index 2758dd4aebdf..4456cb88f1e5 100644 --- a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp +++ b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp @@ -59,8 +59,8 @@ int main(int argc, char* argv[]) { } else { std::cout << "fail" << std::endl; std::cout << "\tin: " << in << std::endl; - std::cout << "\tout: " << out; - std::cout << "\tref: " << ref; + std::cout << "\tout: " << out << std::flush; + std::cout << "\tref: " << ref << std::flush; } CGAL_assertion(ref == out); // Test orientations From 6744cc1dd66573041e3920bf7ec3e9adfe920da8 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 11 Mar 2024 16:40:30 +0100 Subject: [PATCH 173/182] Add operator==() for Multipolygon_wih_holes --- .../include/CGAL/Multipolygon_with_holes_2.h | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h index 7cabd2871fe2..50edf6d592d2 100644 --- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h +++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h @@ -92,6 +92,45 @@ class Multipolygon_with_holes_2 { Polygon_with_holes_container m_polygons; }; + +template +bool operator==(const Multipolygon_with_holes_2& p1, + const Multipolygon_with_holes_2& p2) +{ + typedef typename + Multipolygon_with_holes_2::Polygon_with_holes_const_iterator HCI; + typedef CGAL::Polygon_with_holes_2 Polygon_2; + if(&p1 == &p2) + return (true); + + if(p1.number_of_polygons_with_holes() != p2.number_of_polygons_with_holes()) + return (false); + + std::list tmp_list(p2.polygons_with_holes_begin(), p2.polygons_with_holes_end()); + + HCI i = p1.polygons_with_holes_begin(); + for(; i!= p1.polygons_with_holes_end(); ++i) + { + typename std::list::iterator j = + (std::find(tmp_list.begin(), tmp_list.end(), *i)); + + if(j == tmp_list.end()) + return (false); + + tmp_list.erase(j); + } + + + CGAL_assertion(tmp_list.empty()); + return (true); +} + +template +inline bool operator!=(const Multipolygon_with_holes_2& p1, + const Multipolygon_with_holes_2& p2) +{ + return (!(p1==p2)); +} /*! inserts a multipolygon with holes to the output stream `os`. From cf0c917b0234b6186631ef9b3b7b6f155ecb6ed2 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 12 Mar 2024 09:22:33 +0100 Subject: [PATCH 174/182] fix unused variables --- .../test/Polygon_repair/draw_test_polygons.cpp | 2 +- Polygon_repair/test/Polygon_repair/exact_test.cpp | 2 +- .../test/Polygon_repair/repair_polygon_2_test.cpp | 10 ++++++---- Polygon_repair/test/Polygon_repair/validate_wkt.cpp | 2 +- .../Polygon_repair/write_labeled_triangulation.cpp | 2 +- .../test/Polygon_repair/write_repaired_polygons.cpp | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp b/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp index 7161506f952a..a61e8f80531b 100644 --- a/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp +++ b/Polygon_repair/test/Polygon_repair/draw_test_polygons.cpp @@ -17,7 +17,7 @@ using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; -int main(int argc, char* argv[]) { +int main() { for (const auto& file: std::filesystem::directory_iterator("data/in")) { if (file.path().filename().extension() != ".wkt") continue; diff --git a/Polygon_repair/test/Polygon_repair/exact_test.cpp b/Polygon_repair/test/Polygon_repair/exact_test.cpp index 4ed815ff9ad2..4182f8faa061 100644 --- a/Polygon_repair/test/Polygon_repair/exact_test.cpp +++ b/Polygon_repair/test/Polygon_repair/exact_test.cpp @@ -19,7 +19,7 @@ using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; -int main(int argc, char* argv[]) { +int main() { std::string in = "POLYGON((0.03 0.02,0.97 0.01,0.99 0.96,0.04 0.98,0.03 0.02),(0.5 0.5,1.5 0.5,0.5 0.5,1.5 0.7,0.5 0.5,1.5 0.9,0.5 0.5,1.5 1.1,0.5 0.5,1.5 1.3,0.5 0.5,1.5 1.5,0.5 0.5,1.3 1.5,0.5 0.5,1.1 1.5,0.5 0.5,0.9 1.5,0.5 0.5,0.7 1.5,0.5 0.5,0.5 1.5,0.5 0.5,0.3 1.5,0.5 0.5,0.1 1.5,0.5 0.5,-0.1 1.5,0.5 0.5,-0.3 1.5,0.5 0.5,-0.5 1.5,0.5 0.5,-0.5 1.3,0.5 0.5,-0.5 1.1,0.5 0.5,-0.5 0.9,0.5 0.5,-0.5 0.9,0.5 0.5,-0.5 0.7,0.5 0.5,-0.5 0.5,0.5 0.5,-0.5 0.3,0.5 0.5,-0.5 0.1,0.5 0.5,-0.5 -0.1,0.5 0.5,-0.5 -0.3,0.5 0.5,-0.5 -0.5,0.5 0.5,-0.3 -0.5,0.5 0.5,-0.1 -0.5,0.5 0.5,0.1 -0.5,0.5 0.5,0.3 -0.5,0.5 0.5,0.5 -0.5,0.5 0.5,0.7 -0.5,0.5 0.5,0.9 -0.5,0.5 0.5,1.1 -0.5,0.5 0.5,1.3 -0.5,0.5 0.5,1.5 -0.5,0.5 0.5,1.5 -0.3,0.5 0.5,1.5 -0.1,0.5 0.5,1.5 0.1,0.5 0.5,1.5 0.3,0.5 0.5))"; std::istringstream iss(in); diff --git a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp index 4456cb88f1e5..72399b5c72e4 100644 --- a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp +++ b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; using Point_2 = Kernel::Point_2; @@ -14,7 +15,7 @@ using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; -int main(int argc, char* argv[]) { +int main(]) { for (const auto& file: std::filesystem::directory_iterator("data/in")) { if (file.path().filename().extension() != ".wkt") continue; @@ -61,13 +62,14 @@ int main(int argc, char* argv[]) { std::cout << "\tin: " << in << std::endl; std::cout << "\tout: " << out << std::flush; std::cout << "\tref: " << ref << std::flush; - } CGAL_assertion(ref == out); + } + assert(ref == out); // Test orientations for (auto const& polygon: rmp.polygons_with_holes()) { - CGAL_assertion(polygon.outer_boundary().orientation() == CGAL::COUNTERCLOCKWISE); + assertpolygon.outer_boundary().orientation() == CGAL::COUNTERCLOCKWISE); for (auto const &hole: polygon.holes()) { - CGAL_assertion(hole.orientation() == CGAL::CLOCKWISE); + assert(hole.orientation() == CGAL::CLOCKWISE); } } } diff --git a/Polygon_repair/test/Polygon_repair/validate_wkt.cpp b/Polygon_repair/test/Polygon_repair/validate_wkt.cpp index 281da7542f27..af560d376291 100644 --- a/Polygon_repair/test/Polygon_repair/validate_wkt.cpp +++ b/Polygon_repair/test/Polygon_repair/validate_wkt.cpp @@ -15,7 +15,7 @@ using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; -int main(int argc, char* argv[]) { +int main() { // std::string folder = "/Users/ken/Downloads/big polygons/"; std::string folder = "data/in"; diff --git a/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp b/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp index 24d542c7ce1f..5b21e141505a 100644 --- a/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp +++ b/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp @@ -12,7 +12,7 @@ using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; -int main(int argc, char* argv[]) { +int main() { std::ifstream ifs("data/in/nesting-spike.wkt"); diff --git a/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp b/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp index 604e04a0ec8d..e31996ae33eb 100644 --- a/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp +++ b/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp @@ -14,7 +14,7 @@ using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; -int main(int argc, char* argv[]) { +int main() { // std::ifstream ifs("/Users/ken/Downloads/180927.wkt"); // std::ofstream ofs("/Users/ken/Downloads/1.geojson"); From a3fab59c1764847566911537c39e563cb87b2570 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 12 Mar 2024 09:25:56 +0100 Subject: [PATCH 175/182] fix unused variables --- Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp index 72399b5c72e4..de36b0f08b7f 100644 --- a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp +++ b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp @@ -15,7 +15,7 @@ using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2; using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2; using Polygon_repair = CGAL::Polygon_repair::Polygon_repair; -int main(]) { +int main() { for (const auto& file: std::filesystem::directory_iterator("data/in")) { if (file.path().filename().extension() != ".wkt") continue; @@ -67,7 +67,7 @@ int main(]) { // Test orientations for (auto const& polygon: rmp.polygons_with_holes()) { - assertpolygon.outer_boundary().orientation() == CGAL::COUNTERCLOCKWISE); + assert(polygon.outer_boundary().orientation() == CGAL::COUNTERCLOCKWISE); for (auto const &hole: polygon.holes()) { assert(hole.orientation() == CGAL::CLOCKWISE); } From 511cc507aeec12ed7ad8e8b72286cebaecc098be Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 12 Mar 2024 15:26:10 +0100 Subject: [PATCH 176/182] Do not compare strings, and do a write/read back in order to round --- .../test/Polygon_repair/repair_polygon_2_test.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp index de36b0f08b7f..6b673faf6396 100644 --- a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp +++ b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp @@ -27,7 +27,7 @@ int main() { // Load test file and repair to create output std::istringstream iss(in); - Multipolygon_with_holes_2 rmp; + Multipolygon_with_holes_2 rmp, refmp; if (in.find("POLYGON") == 0) { Polygon_with_holes_2 p; if (in != "POLYGON()") { // maybe should be checked in WKT reader @@ -37,9 +37,11 @@ int main() { Multipolygon_with_holes_2 mp; CGAL::IO::read_multi_polygon_WKT(iss, mp); rmp = CGAL::Polygon_repair::repair(mp, CGAL::Polygon_repair::Even_odd_rule()); - } std::ostringstream oss; + } std::stringstream oss; CGAL::IO::write_multi_polygon_WKT(oss, rmp); std::string out = oss.str(); + rmp.clear(); + CGAL::IO::read_multi_polygon_WKT(oss, rmp); // Read reference file std::string ref_path = "data/ref/"; @@ -53,9 +55,11 @@ int main() { } std::string ref; std::getline(ref_ifs, ref); ref += "\n"; + std::stringstream refss(ref); + CGAL::IO::read_multi_polygon_WKT(refss, refmp); // Compare output with reference file - if (ref == out) { + if (rmp == refmp) { std::cout << "ok" << std::endl; } else { std::cout << "fail" << std::endl; @@ -63,7 +67,7 @@ int main() { std::cout << "\tout: " << out << std::flush; std::cout << "\tref: " << ref << std::flush; } - assert(ref == out); + assert(rmp == refmp); // Test orientations for (auto const& polygon: rmp.polygons_with_holes()) { From 79ec44651df6e81d6e178ba949c636a7fdfcc216 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 13 Mar 2024 16:02:57 +0100 Subject: [PATCH 177/182] Add #includes --- Polygon_repair/include/CGAL/Polygon_repair/repair.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Polygon_repair/include/CGAL/Polygon_repair/repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h index 523764ce508b..0188f1630fb1 100644 --- a/Polygon_repair/include/CGAL/Polygon_repair/repair.h +++ b/Polygon_repair/include/CGAL/Polygon_repair/repair.h @@ -14,6 +14,11 @@ #include +#include +#include +#include +#include + #include #include #include From b0ac1d1c19ef1f2e4b0a54d45db1b97b323e27e1 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 13 Mar 2024 16:33:38 +0100 Subject: [PATCH 178/182] Move files from test to benchmark --- Polygon_repair/{test => benchmark}/Polygon_repair/clipart.cpp | 0 .../{test => benchmark}/Polygon_repair/validate_wkt.cpp | 0 .../Polygon_repair/write_labeled_triangulation.cpp | 0 .../Polygon_repair/write_repaired_polygons.cpp | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename Polygon_repair/{test => benchmark}/Polygon_repair/clipart.cpp (100%) rename Polygon_repair/{test => benchmark}/Polygon_repair/validate_wkt.cpp (100%) rename Polygon_repair/{test => benchmark}/Polygon_repair/write_labeled_triangulation.cpp (100%) rename Polygon_repair/{test => benchmark}/Polygon_repair/write_repaired_polygons.cpp (100%) diff --git a/Polygon_repair/test/Polygon_repair/clipart.cpp b/Polygon_repair/benchmark/Polygon_repair/clipart.cpp similarity index 100% rename from Polygon_repair/test/Polygon_repair/clipart.cpp rename to Polygon_repair/benchmark/Polygon_repair/clipart.cpp diff --git a/Polygon_repair/test/Polygon_repair/validate_wkt.cpp b/Polygon_repair/benchmark/Polygon_repair/validate_wkt.cpp similarity index 100% rename from Polygon_repair/test/Polygon_repair/validate_wkt.cpp rename to Polygon_repair/benchmark/Polygon_repair/validate_wkt.cpp diff --git a/Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp b/Polygon_repair/benchmark/Polygon_repair/write_labeled_triangulation.cpp similarity index 100% rename from Polygon_repair/test/Polygon_repair/write_labeled_triangulation.cpp rename to Polygon_repair/benchmark/Polygon_repair/write_labeled_triangulation.cpp diff --git a/Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp b/Polygon_repair/benchmark/Polygon_repair/write_repaired_polygons.cpp similarity index 100% rename from Polygon_repair/test/Polygon_repair/write_repaired_polygons.cpp rename to Polygon_repair/benchmark/Polygon_repair/write_repaired_polygons.cpp From fcbf327b16a459735bfab7811c6b4a79c1ad207d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 13 Mar 2024 17:12:24 +0100 Subject: [PATCH 179/182] workaround absence of --- .../Polygon_repair/repair_polygon_2_test.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp index 6b673faf6396..3ca4f4225df7 100644 --- a/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp +++ b/Polygon_repair/test/Polygon_repair/repair_polygon_2_test.cpp @@ -3,6 +3,19 @@ #include #include + +// work around for old compilers (Apple clang < 11 for example) +#define HAS_FILESYSTEM 1 +#if (__has_include) +#if !__has_include() +#undef HAS_FILESYSTEM +#define HAS_FILESYSTEM 0 +#endif +#endif + + +#if HAS_FILESYSTEM + #include #include #include @@ -80,3 +93,13 @@ int main() { return 0; } + +#else + +int main() +{ + std::cout << "Warning: filesystem feature is not present on the system, nothing will be tested\n"; + return 0; +} + +#endif From 5331c7e7443e071d9cd0e3d00d84741d0b990c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 13 Mar 2024 17:59:08 +0100 Subject: [PATCH 180/182] move after definition of function used --- Stream_support/include/CGAL/IO/WKT.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Stream_support/include/CGAL/IO/WKT.h b/Stream_support/include/CGAL/IO/WKT.h index f558c90aea28..3a3eea129d64 100644 --- a/Stream_support/include/CGAL/IO/WKT.h +++ b/Stream_support/include/CGAL/IO/WKT.h @@ -355,13 +355,6 @@ bool read_multi_polygon_WKT(std::istream& in, } -template -std::ostream& write_multi_polygon_WKT(std::ostream& out, - Multipolygon_with_holes_2& mp) -{ - return write_multi_polygon_WKT(out, mp.polygons_with_holes()); -} - //! \ingroup PkgStreamSupportIoFuncsWKT //! //! \brief writes `point` into a WKT stream. @@ -465,6 +458,13 @@ std::ostream& write_multi_polygon_WKT(std::ostream& out, return out; } +template +std::ostream& write_multi_polygon_WKT(std::ostream& out, + Multipolygon_with_holes_2& mp) +{ + return write_multi_polygon_WKT(out, mp.polygons_with_holes()); +} + //! \ingroup PkgStreamSupportIoFuncsWKT //! //! \brief writes the content of `mls` into a WKT stream. From 151b343f3c80b5c23eebe3f4aa2be135069cb7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 21 Mar 2024 15:29:53 +0100 Subject: [PATCH 181/182] readd figs --- .../doc/Polygon_repair/fig/Corine180927.jpg | Bin 0 -> 49878 bytes .../doc/Polygon_repair/fig/Corine2018418.jpg | Bin 0 -> 76156 bytes .../fig/Polygon_repair-small.png | Bin 0 -> 17908 bytes .../fig/Polygon_repair-small.svg | 90 ++++++++ .../doc/Polygon_repair/fig/inout.svg | 214 ++++++++++++++++++ .../doc/Polygon_repair/fig/invalid.svg | 130 +++++++++++ .../doc/Polygon_repair/fig/valid.svg | 88 +++++++ 7 files changed, 522 insertions(+) create mode 100644 Polygon_repair/doc/Polygon_repair/fig/Corine180927.jpg create mode 100644 Polygon_repair/doc/Polygon_repair/fig/Corine2018418.jpg create mode 100644 Polygon_repair/doc/Polygon_repair/fig/Polygon_repair-small.png create mode 100644 Polygon_repair/doc/Polygon_repair/fig/Polygon_repair-small.svg create mode 100644 Polygon_repair/doc/Polygon_repair/fig/inout.svg create mode 100644 Polygon_repair/doc/Polygon_repair/fig/invalid.svg create mode 100644 Polygon_repair/doc/Polygon_repair/fig/valid.svg diff --git a/Polygon_repair/doc/Polygon_repair/fig/Corine180927.jpg b/Polygon_repair/doc/Polygon_repair/fig/Corine180927.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3748a819d2e5ef9e854ef4cff499b2ec338a2309 GIT binary patch literal 49878 zcmeFYbyOVBw=X(afZzo8;O?%$Ed=+#1Pd1222XG&cme?uBsde?A$Wig+y);k$b=aP zFoXf_VSocrFocir>edjGw%XR7Qzn8|e_=xrI_-}&%0A*uUZEf`4*umGy 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 literal 0 HcmV?d00001 diff --git a/Polygon_repair/doc/Polygon_repair/fig/Corine2018418.jpg b/Polygon_repair/doc/Polygon_repair/fig/Corine2018418.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aba0e3879a20c94ac90f32a72a97109871903ebe GIT binary patch literal 76156 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⪋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

  • bM;5!aOg#9}6I+mtQai2|>G?op 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 MWBY&W*xxh%1NEMr9RL6T literal 0 HcmV?d00001 diff --git a/Polygon_repair/doc/Polygon_repair/fig/Polygon_repair-small.png b/Polygon_repair/doc/Polygon_repair/fig/Polygon_repair-small.png new file mode 100644 index 0000000000000000000000000000000000000000..634b116b03e59a8bb7e8e9a405b55bc2185b6501 GIT binary patch literal 17908 zcmagF19+uPvnU!(Y}>YN8)!o%y zRbA)^MR^H0Xl!U8ARss?Nzw0sZ}-1%NN~U>mofVs5YRUR3l()|bvapXBRd;<17kZw z6MAClx(A~z`)`{DlkN6+D+<@PI|7IX2{0GI^ijP=bPLWW= z&e4RBjh>C3k(eKvkk`@Jl>57=_*Bw_|EnQ@-T&t%?gsY%CuBLf|8H~~n}3^zle3sB zfN}q^2>&*w|Lnj?#lzl&;k${Gor|N9iI^*ZdnErb?k``s6)oINtkp#=08DiPtOg%3 z6Eoxg3###dgNoQ$+c_!&wxJ22**}f`@{U`|#=y)(&BEB({J*LFH$c|J*6e>l{*KPt z&LU_&(1Q>l;TC4LCXR%Z(k|A7%$$S({xMShds{bi69C=+ zJ7XFC=cN8~kh~24Ya0LJ!T-=HfOh}-51^|6N{`{cv>xE$zx1YwEkId10<_|%3Bv>s z5OAOcU{Cz7y#NG6nc(tsTt-+3HB6w1agMQ6ED9ZYNxBe1(k3veR8V+=up(y58;qa+ znVQHZs99KOp?JCAGjI*ODkzUK&|K@hfSs(xiG`8aEX}F=buz1eA|2R@wc_BR7vH7tluSz6Wi9aof9pE%QsrOKBLHTw2+cu zkqWWJ1G-&#G88>@exxT$N5NejWrc;8)dS}k0lB4u1VZ)okj+!Qtd~J)@o}i}$=ic^ zvcqHEBe|^6_l?RIe5}nA(KJ&3Obc?zJ+pYFI$v+tSq2vD0R->iX~lSTu}W#I7_>QK z%009u($&O0lGvUs`H>Y`iMtSFnQjg$A8Zfj%hZX#FpojL~OAEBHISdT|UF z{Uezt$?Zq0pv&A@x(iJM>{&K~%U#&Zd)q(dLfMi7Q;p1{goe=?>6a{@8m4CPM3)cB z=nc%&_@ge|=zM@bY0a7ovrr}h_6^EjQo{)d2!7!28#tK;9tQ}B5J*Z?NX0$tGTY2s zSz@h)VYJIl#_>AY)bn~J9>^j-K1Yr{rjd*&Ud}bq`lsA=@`ErpqNL;ro^?A@D@NP; zPcn|tP0MSDRrO{vEp~E`oa5(Dfs_6$E~lf3s&uDkt==ymQ6v&ipt?6y@o(aJ^Ee}A zDa6VpN<}Y-lphro?p#DK6%_Uw`ZTy=NnfCnyhAMXoPpmQy4|^-uavhzyquD?OXG=^ zbBptieDZb}(yvVhzQjPn>YX1f@UyPNDuP_xO4oK`x|rb)V!+Sn&o4fWA-~R`w82+? zV(J^QIRNu!5$e(cUC^&reiFayk>1=8qC&q2xEFlb5!T{$SC1pLRe^=p(uF}1fmCWC zP>5b}>|Q#OeZjbPUh44y!`KgOUs8kc+7S=Xq`cl5tU!lcjMM$9tVV46Lt$J#DR>?) z&ISYy3OQ-5vJc-Zs?Pz!r$*%3lcJbQiB1+gTRrPQSQC8r$NQlCy42zi+zIBIm9Fo* z0&%TBP~19_m$seuzzd`Jx3x#&q1GL9SkXkS?7o~VGs-fW0`acou}}rz>{X>l@R8CJ zV?A4{Urp?o_QVq<5w8vg(FhK`#Zkq=Lfa&3v541;;hQz2eGHKY!HNZ9!io6Jvd~c? zcH#TNhiHHi=XZ7^rk_C=mtQk|W`8=qEBrZnsk8i!jxcfG;;9P0(}6sCV%|BP>@muf7fo}YA~YHUtW9mgZ#@xxy=Bs330`3*GYZE=U`_6*Fus&L0w)z2 zsmn24K4jAEdS8dWK@&f7U(R1H+ljjTFf(&A?Wv(lUHv&hRKddZQ^Q;2!At?uJJ(mD zM(4UolN1sMSR(0DxgUbP>6Bj#txl$d2orD=^6z-5cM|7cmlrXR+iV+rR`~ej9kWy5 z_&Tf+n6vBszE?ZVho^-;(%0zID_3Pe~W#4%D;ez~zu42PN+RbM0bgbqb5u!#hH1J@;FoT6C! zlEc^G#DdTwS?>0|#Y866gFodW@fUawhrfTtX_3_l?D3io40T_x^}cxYcHwPO+x~;T zl2}OCP>COpW4IGi!QL z%D0u%TiS9~piDKpMEw;BZ*4wp-`|9KC0j?XT2?xS8x4$IlGikzGJ?<~2~%MC>eWB@ z9HbhzD-yCN=kd`sV7-{^{x;!_vTTzv>ktS2lb3#Ni#&;D7m4C$j9%fF-%!O7wHc& z!4B|PbhZRdm1x;yDT7JitF%vkn+)zq)b9u7A4v;7;3IDvSfWMSKH(c?NDQ$B-HQR( zE_gNC7)Gux+goa5QXQC5KK-WJ38Y>78G0>X~O4D5Di%*{he{FGv8cpv=LswlnQ>vn#XWB^?W3Vo8eB&u03%vs8U~Nq!Z%;s@anUfj4!4NX7t zYvYpNPcZv=(@Lsg<8`_TN;}xFJ1)kJENTTjC8WFiX~To?pzJvC5kDsf{}FAVB#NH( zK}81@DhYE!!^0h+`_)O5dp2~f#QG80CI)%ioxoGRF8GVTL z(P*f(zRd>G0U2w059co6`f^rpZ&7jAN94voxQP|Ow0J&g6e*%Qd&=NLVPRvhAAN=k zmu=)#2Bebk4W8A(OhQXv9(2EfP)8oU6R1fV&e#_&A?R&-@uO)mHuL%9I>=KIuVpCc zF|kqz8F*ORoqWQr`d9J@UWbLxBdmZNjk)PnEN2jeqTHu15Df=$PHj#o#q2oc^GYts zP%xs`X$Q0>C9ZCufs2Pj(w;1tY5$9-5Yu}ep&J6 zc+(L-2OQf0L0dg|d({UM$Y&os!!S6M>a&!6r?@*1?#$-9bwGpVRLBP!0*f52gf4D= zU5>hJn&hFZ(HrY?X9`3jytC?n;Zk)b^J%h34NoAf1+vc%BeMJ@q7@os!(3;0419%y zyPcEd(0HS&DaR@A*J50a{S515$V^v^S;p+k>5_4Yp?fTPYiV50U~x8**G2-9 ze&*$9lIv968C@s_FPY5#(&o8yXqfZeHWuWYnv7gGLJ4p{MA1 zBmKwp)`o;qOE$B`WAB3kpR6`_K;eg;q5K1QXI82K1#Es@6_AS;_t=r-PvM_8_Sjoy zglbE_hY|_CuimgV_qi9m=NdTg%#%`lW+$W2;gB|GTkU)V;jy}9i4_0&X}K6Dn3OZCY;I+-4CX|*ojbJTI`l15O;F;MXIGyCgJ;);bB%0vMN?Yl_*(||M#MvAnW?|hX)AnFcTANpoha&D-XQ4ooV4M1$Ft%#-vMadBbAtVeNDUJVxqU#32wqiX+rP9of6@%K1hHJiNyUx~#d3PIz z9s1@sc1}~QMW@{2+}H7ziP&-ex(+*@3+MFmD$7$g=bEE&7SWPUHg{_9k>Zp^nLfp6 za=7a>d;62Yop+Vj0eFqo(=rob@0>fWzCfVykLtl$p)>66Qp*!s0$m5N(-=}d5HhH> zhqDsuIr{KVR6{$1EpA5>j+>`X;)+}vAZg3#d=A*n&-25|{5ltgNj%SnWt-p|cWLC? zpVJe%Eg=0Q_G#1E8_Z%+-(S|rbT+|A(aRnxJY03s>%h81pbEc5k5v1||@W{(#W?*$gV85sRdy>|xc!a7$} z+R!gZh=ZAWO)}XwFaNPGe)tMTY@X@q$Xg+y?@q%f|GS*fq*m9OxG?=>jYkBFNep^T z>eA_o>y;TbP7A^t)@F&akrqC;LWOEGz}_Qk3ISM{ z(*;$>kAdkjtI$canq&Llu%!5Eh^H8XdrCx@uxZix``(B1+NB%)MYW%Is&*h9C^Vj7 zgN3|d@4AV7S(rEvtjvqLf=v3`PH39+D*Pd{+ZE@0aEjVi`f93N-%XI%&ay|a5$c>T z$O}HQU#TyNzDH>%xNFO_+QCvq82D_V)SDpGu~>m~C?LUke4;br?rMk0*9>pm+HQDg zCZ>@4@;ik#PhFR)+Vq)IIhd(BV{^zN=g*5I+=0rcP8D^2%E_m=+gF~jgK5W{K5N;X zoM=XWGX7y%2LeF`Wv{0?h-&fZV@Nj3glE@NOKBT~|wZ6CRdjp$>{*iZoo+&Hz{5>v}{Z^oDfN+RE z@OP)M?%%|a;J-~h-OO}iiN1ZAg}XH?tM>QHG)i-vy(-v866 z2cYZ~CP~-6+GKL}5gBDcv^d41U9s*V zin`=5_XC$%NXDwRo7(E|Wg$N>rk+GvF0o;SkwJ3~b5@B&x|fk{GtmVL4#>Eh`nfJZ z0WyUwBku9s@e^^UcVmU;)+w9$K#9($0Q|Ro_ir(8zdJSfLkdO~>a5d*YK%qCkA1IB z$j5Hbgg4}Zcca%g*>O>KdtFX>R|ra#0}{2%yvk3SJcF6lR<5;z<&OK)1m^F^B9PBG zEAJeb)Mo~2uHUk`y*6;Ge$;s)?fKvsKGQ@zMD13m=c9XVakBwc*}|+c?|Y>z`$46t zl{;JRx;xNFz(kcy^<5)u6BJ-Cu5Xq!gbeX`_PR%-1pz+9ouOzn?ocYn_YH2t139?*$}>DC1U zjK93U?}>B%-Bhy?ez6pe_iGsHETgBeU{_1<8z&PNZSt}zsSd2{c~m_&pO@o-HWRmh zFOuhUr00rne&qfjHR>6U`6+L|KCrbb`)=@C<() z`45v0fr-^KZXwuVxSOOViF~^^x2$2j+p2W*b z*VnZ%aDQ-lzPhY^1%20x!7sBrW58bsb~+VF=~Mn-d|0V;Mf4g{%x`bdVuRfV?s+30&IuMZ3 zE>3|LyptY`X_wlqnlWDyBrP)-33ZNKNS$617s;UrnHX`)U6Re*!#x=ocvDZ)Mm3GN zeA-J-r9Au?Sqx)nZsQ@ZwZ4$Q$~Dq>w=fUcT!o%eLnpH06$V&{KUQ|a;ZJ_SK-1~6 z@KJ^afzNq4xOCa}lsyS3gM%X~W|ZGMmj?;d16hoIzWWI^7ghT;dq6pXB0^0?^ZNUQ`LNd*^`W%+YN;4 z>RS$wZ1C_b?9FywW@WfNwI~*?h^Q`lT59keFrO89htd^PdGjmwI zw|hX2CRG#R%nWvM@Q%N_P4Lou|0 zW8E0?eiJ8fH{L9DJ9D!x%0g`e3_dDV1d-?~0 zncAz)PY1j*7B)m|a_gnmFTm!%$35@^a{MSpXcAUucV%Pj+eW0U9(S{-bcTMvf2Tfk zDzkq1`Dba<-ze9ZCZ801<@PFoxm%V`q0`u-=XIf_cX{}knaY|sj#gdT^OgANI9X9C zSEA_*CrPdcR5R<60_Ds}ARxym9UE!t!W@CQqOr66T&uo9E#2e-tk=h>j}cM4nl_}1 z>#Ml68Pa3FrqgSO)UGlsq#^w)tBVd2O!#EU7^~JAWFxD(Z;3oGwc2OWG9*MCqUJ)n zr12_O5W5<_);StOW>_|_$q7UPTGg>rJyMX+*i#g&pbcU$-`|? zs@`ZoCvw&$o@AYV!(__lP(_Eb$L?9q>j~V=*%i#eh%JSDRzwUUc?g%b?9@*s1KFv$ zrPZnEQb<$rwnwL<3X4C{&j_J6f5u+X1!O=7g$zXkNkKr7B++1AsjEV3=CC#R+ysR- zB=x&=jb_7ZW}9c$hz6%^mIOf``y|4osZ=&#&D%i=ymqV+q9i#xHew!*?s>Kc!QIZ~-PXw?x1KLY9^0wnqZb-F-hKJN|$io7xsdJdPe?*axg zlDs{c=~X4O;L$2LST={D)THBSIF0Q>{pKV<(b0}q_Pw6~qr0TQV3;h9#~Bg`^hZqC zN@7=nuowl`BHqRHn_=*sE#+up&0$NlW`(DpQ)dS8;3g!vo74q&0mRK5V+PRqNVRXE z0JFg1*epM~M1>O0%hQ0o^f`Z%Wx*1_sbRe)$O?>^NqEl~7PsEmEfB2BaeGn_s#zxf z0l#e3C_s(ld)#uLiHYHjkk6k&@~ysnjZ5W*DzbQf3D#=kH+Rq>N&EVc)@*IE-dqd( ziG_P-YmWA-a@QKYPMry1gC!Xj+Oj^?>S`_wAK;fmzU4QP>0gotO(KB_z1TYVdc~%7EHYv;1PW>a5vk(7lc1f=JevgwHFav!GG1H~J7?x5=7CTf zxOnz%uq+lz2G}Ooh6Dkr4Ug40m)M-~%M(TdsSQUZ)K3Sjv+Q7Tx_TTE8+dX(v(mD1 z-tI_o%cC(3`Q|1oN^(zmlkA;6swE$IQ;lyLSL z$BIRd*>yfuZ!X%78!*B(3L;iVyj~~ccd3}*9<9_IzunuMh-L3zdcHfcClb0tzc+lt zd4cHP6IFme@EMV6Ai{ASi0s*4Dg%9kY;o;N0AZt$jx4j~Rj6~sp^B*4-vg?-e&xxW zE+%}!96qRpJQ{+}nm1Y`MKY7&aBQ~*|M2O$3`g^umP;HI@tp>Xh?g>mtD`Xc>&$|4 zUrSpNwRnQgyzy*q%nm*$p^_+@C~CF@EKNm47|WtTfv+`T9gJR+DZoSAlf07L`#ywn zrG*ALpDmowwO&BV`l68PHTc#Y&ZGqB!>(cu_cZ%R=e#fJE*pwo->no#p@XiSY3)?` zV2v!AQ7ZXLcCdpY{zUao3&RjKBnb}8aLJ;|6pF1(B>5I$J+2-z;=_zEB_q5ytA}Jq z6FjUubpK$7Gm`l1N*9ULHN18JB?4c2K12dT46r&m_sRD_<5zXqc+O{*o=w?Q6%@xM zU4RpvUlZ0UGUXD@5ZyQZElM7QqQtx_~y6DjK(CzTrK+M z5O;>-@;Vw?W+G3}&iZo@ha)ZCz*YQFyswt< z7!x~-o5wSnJ7OTbA(d(NX!%}C%@6+u9IZ;{XU_>8Y-G`G4-hljSRWXiH7n@q|aw+KO!2`OiX$jE);a+Qn2ZfJxZS4%K++Qge;&Hs!l=<31) zanFBElIn>>;hTzv^8WUyAoZ|ky?U?0jtd^0Rng9uiZW=&!gS$5o;ex|QEO_ziuNdA z*vpxl&=-?9s9oyqlNRfXZr}?s9GPPzKOwa@K(K4hfo>HCpWlm>-S2n4Zy zJ0Qbv;`*Rb@cv~`t^9>|am*dkR_AxTREC_vL+;dQk5(crU8ZWHw0gr;&OWaChh}(1 zx%A|q%Ezsa&Ik)R4k{WZ!q6ZqZV~=;^U#)==GTZy$w_ z-Tl+KKe&h4HWK}??LC>H1S}uCZig+CE&9Nzjt1VldvVHoi3c;^+%G-C z990A>j_h4oJEiJp%K@2geVs^;*`Y0T;t#w!B>W@eQS`C%Nh_WUYkiwLFn}^~ZIYxa z^+-}V<<;HHHc45Y$Jt5VJeEqF`XyNxyETA^`P7W<{D*gMAXQ$Q5gQ7b^vT&=#=!wo zS}t6C?0oxBdk|!6%P-KC1*v8z`o^P3DlvgNw`g69ZO)GFc_PCkp;hj(mTjNVwa;fD zGHX&?16!;OY9P{+jQdg}fibs71Fb2Sq9-gcBh16-S|bX(3egUy8owowaN2~t$`Tq4 zAr0>2le#JrU^`(cVsZt6JnsB%&#o?zlySS;TH+_l7tu|=2L%8J4m@Plbk161hi@|{ z9gGnSt6Vs{MVna;1Vtk-O)p^itGONj)bT-SyYup}QD_%aqMuRLM?LhezP3FZleNX+ zbzktcG*Mgdg~-d7bb!Huf1U(e4>B?Gk%DxGJDI&1QIS|l?MMjBz_(E}{ectqMl~IV zEwm(?ut(&}ugv1UEL2NVkz>8ugGn3Q*t22L{!!kh_{!?#=*d}I&yClUy)A3fe@*^@ z3rOBgZZ^<%@Y?WK5Gs5^iu+x|7mcmIJV=HNegZ-ziIlGl@Xg34zJ^Q(Fgau5cLuWWsQT(9t7ya_YD z9SM&Qgm-UK9_D2H82GIfuZ;JMFkmx44x5Gkg(D?~Yx>XNQI|S!ku)6-i{DA4275s_ zSr`i0wSD`--SPfZx)PY@);B)wbI%4;ARzqQzqJ63CNy$R5Z0XDuw{3HzRS{<+lNt& z-v%O6Gfi@`E_VYw@&ze>HNmVTcZCXzA)!5%b+$32xyHnXE;$!V-~&P~KgkLMA@2ff z=E@T?RvyG`Z(F(GtLdm!D)%ox5h6*7|R*A|&XMh%KcJ(R4UMJ~$Va8&IH#_+3+Dp-Kz)_Il9ARDTCVP9HcD zq?7ILR_odZ!c#IH3mec}wSYVLxWO4;?D%OY8qVNpH5ltF><%+gFx=g{5B+KU8TEjl zC!xRt%Pg~omn~dcxgb4`LtVnbQ9s@>QQlFFf~s!I787(n+PTr7XBd@78UO6LMhgq;b6sbR?<|{BaZt z#vgmL0Ck8zRuy!;W1E@{xed|gG(_B~(>pEKOQ)QQc*N2PYZoL`h=K?RVDl71Xf6tj zjE7nc>q*ouv-SI$KA+3*n$}T%!tV_%WkW8MN;Xn%lh~GkBz% z7IzaV=DPR6FcS#RdNO<4G2CRk8vr{ z?q~my`shUGZn`-sW)=1s*x;uN++1~ZERTvWi*r3q?BJTXQh`@P+{GCDsYE3Dq7fU- z2sCXoZRWSN9f7oI%&G|{0f@*A8@j_`R!Jj#xd(GG%}zum1N3Dih!_%}v?9_du(fi*$CKd(G-xSH!2$_?~;R5i{}3;`fDtVe}H+~OxU%jUD|AwX#UC^Pnc zfZ^}ysCQuvmF7?I7i~|2T0N815Xe2*7M)P>-2Js42f!ieFIo&3HL&PxHtbvkD=S^T zy?B}in5N~T#fY-qvd(s5i-Dz0pm#Gb{x?T6kfzP3!hD^?0CBf(MnMdl8t^+&3(|8% z9CO8|4u&ufvb$#v3R;KpCG-91bMWjrlm*po;nhAirno zo6jC@CZ3$>Ri0wXZwAIasE=ucDDBC5=WS=W+&Q7@kV2IJ8Sr+#nu;GXPQy}btTI@B z5y@KZw^pG)MZO{A*-it^qrz8ZCzr1Igrms~O<&Gs-2%=ZxBI6prIxHsW9}?W4`%pj z7^b%`%O^X=QaIaLlm{g&5-)uBQ1mL*zr;U4KhB{}Elzm@%Wbd{`z0t-l?c4Oi?Ucx zp}8A*h-?S@e_TU|kOoIIO1m@1I?-h|8 zxW>J!pOe8b2R%~V+`p=;AY#RT1fz;|GLuqZz80v`7DF6Dz|+uY@5YRHWtF3j((heX zsqp)^D{6W3_Xlt?xGD*%ipfvw953hE>gqMQW9R5!5JN4 zxZZ}ILr2Chd_&O|;#VtXT#Q$c6lzC`Z_9UbMkWpT>q05P zV>I3_G^Y#x8D!To08#pU-aqEfZW`UEYbRoJ>mBD|AXF>)4k+fV;?KnY^(%bQiMe%D zwBpD5uYj@glt3W`VL?EkcrVH&7RYz9biauYCJpDFZyKTC{UnqrR(jCxcu|{YD>LL) z1O|#rZ+2?D1OHdSZee%oL@osLqJ!naCG4UhsalghNvVmFaQLFcd(H(obH!)O>}%(< zqdRwh&Q{DC~#z3qjKhlLjpYN&o z@sd&Kb;s_K;^7f4-i&Aoa=Vyh(RrmCg@CHfE}ZQ)@g0vOZqF|gx6)c5CQnju#y@{+ ztItu4`l(6hXZ$JpW4{{ss`FtKm3rxZ>NC+)$K30&;?&q}O8iVqnc+3v$DT`88ypaR z+|5MkD8tFaTxoN}OHcmlJNd=+^9E2N8a^A4dE?p!Qv2&~Y!Xkhuxft9rn~K#^&6WN zBb-wN8X8a+%1t~t+a!>D z#a_9@kGC?`M{+Z<*b8{wO*|tdo?;G6^W}{0Rsuj~ITaMoI>epxTb|{)X}z_il=IQh zC=I7pb5f88nF{NHvg$LP-4#sV@1+#t!{KP?_ZysSXWoh^(gbpi%;1mICb;=DxZ+78tp+r2`3X!Z?6LMY~Aq~Wl_-ws5mBd{z3@y z+A^g4#%BM>PytMg2S{*G-nK_H5I*I0>49KmiqoU=c7i2g)kgsUk7;1`A?CHAuuxv; zD#+pa&~6XxA;iCRN|rw$77xK`5y?Wi8B4qKdW!HK(^MZEvq&$1ySuK23iWAUNXC2j zB^T0lT&VX2y1TiWb`7W3r(-HmjF$*jPxPkGEuY5PvWjVB2V`pu6`i0xN<^e?g#Xsp z|44Czy33F#(qoN65ea{|_KhIA)aUClWo@9KKx;emIykctgeU}ku4NyjB&gYJOlvrl z;ncd4&2T0&j61im##=lWDsKivY{1Q!3qJG?kZ81xCxj^dAEP7y=1nhwM9ZK~;d?lq z6wy+0XcSV{_}W24|M#Z{W6+m)?^hkz0WH?1^D+x&Ivu+m{q6vm`GrCpJypI1-J81nuvJo? zy+JY?`#w?~`#TVC3pv0GqxH@ud#JOu!}CxX7vo~!VPvtDE0(#z5f@1@lel5oRmcq1QZG(>{jq_HmcLs$92NvLF{P{_p{5W{lW2*M7b6^W66y70O``4)*5|VkJ@S zz`m-gd^FoQ)H>wu?E&e}Km^3IF8q^R>fgwXo>X+6c7U!%zzz?3FA8xvkO1=y%Z0~u4v|=DTOJ%oU z9&l$mT&-!O%07J5-^Xl2(qkF3G7)gqYX(ApUain0p}NmF)>{u0%LbESy)M*Jr+8x*n|iEFd)-> zGuCu8-T)$*ob7DxLMl0t>5;*se_70D{DT3!ch#5Lfd3hJhbuq=Bc|RQ$?7ziL4um7+F0cUER{y9 zj2p*v8Ng0w=QQ&QM{BF)Xh|v`axNAl-P@bVRc{s!Pn8_0zALCU!O-l=T07dNs#=%y z`1p=K6g3%%X?LAi&tpd9xR?rv(gB0+c2~4{Ep-iqPY{G%V!up3vC5~QYBhGOtqaGi z0ll(;V{670%>F2_-V%4Xj8oyDH`C41>!C9M(%nb^l#OyxW_JHlR)fa`f|y3k3` zH*>8^Ffo{d(vYh+Z*+E-gcpjb0S;op+CFGbhCXzp>UAQkxH29ezH4loz=xOSE+K-@ z5x`w>VcX1>ayrI9h;0gHqot{TT`nl*PpUi4AMId2*5Orb#?!HxTGb+jZFVModcGIE zALsdWFtTdYGJE7D;8Uq}=k39c}ujz+X}U{F*mBGO*To4Yslh$5bW`lT7i@ z_RVCkfIz@;X%T&7%X6 zlbIsJ-#VO{t)YL!Y|qfqm#_a?XaQp(w+GRsAA(3;Jbfu@iGtk`|9+#o1gj`wdCo-^ z27Ogh#)lG9o#QIU(_P&F^;kz6bMkO=@dP`iMqlC-ZxGaB9!(St+(<5M0Im z{Sr^goAqa#0=0KVpUGuX#-Tn_T&4s!raJOZ3SZI!Spy+IW)N`Brf>VW7&vd1Dazp& zvDELcgITdcI{Y@WCQW{xC%9iO*SgkL=6o_u)POq*5nbKO;CZ#;({3fwucr?dMUijj z^RP!F+jbUVFfCEvX#2birQ{(=bPf9xwHi28S+hU+WdU)mtD`2gDDa1elZC#BJ=IuL zbmhe~35`ut@-P7j|1cCSmQS(TWe`AZFe4jpmPU~M1~(sXH&?duulZBErg|gc6D3_e zCKJJA;|}n-qRAp@nNr({{32H#n7!P7RZ3%pr-tBHU7*#@fZf|YdqUKkRgR_0~ zKd-fpeN^}w`gk1Giz1#H5ItGSGx<#>tC%fB5pdvij2x4#hP+sq7G^E8A2G^)0BX%l^?J&pZd~MqFFu*enURx>IMDxNS;C9(ubw4woSI?y$RW)x!mxCwZ_3Xtx%UHL#Izb}C zwI*{mZ*sGPCntl-Sk+EXfTU!sFE2}8+a$920Eo|m8 zQ8&`+J&dqm6Bab=bpzZ4kiJG0@xu=$Up@Ps0yc_11a5P5*ZnNW_(O)9iTy7ez znkL=z4@7S7WEABblyS(TC;oT@X8!SIsOJfqMRWc4k`>+>ys20i3*Vf}jO0kOJg4e{ zXhtI#280CQLKh2n?Xx#5IOr35el*M{2jCt;R>yS)mZ;EV>H_;Sd@T-eG;hHEKyIC_ z!`I!36}q_c>WzJgiTrERObbULBaXCRkSu>CgE)DKD!!f?#1%J+{!R|!VeLJP< zBOAR6yRVebxNdLg{@fv$`<86H8t(mmA11+`KM-&sNVl<#Ov*MwT&!n7g+xRopIFW&PM#FBGOb`1*}1KY#s~7kkzri2vfrde6R`UWF`mr z0-)!`{Ez8^-3MzKiLxAiKb^qEW8Ux~OkdN9L4La#*sJ5Md&F@xS&kv)5`WsiI_&iC zF#G7ct2<&-U0uBFY%N5icxzy7_MJV1HcpRfLL*1M{6f5vpGShuvN+=u6ZIzRj{?T3ad>BQkq0T0HxN*yDiuVB^LVT zCHa?NCN2b;)Zw$=yu5W%_jVr;!9|d#>DRK;1z7C0$qbA%9Q#%)w{o9i*mCSg%wWh}+PCHf%>N=AQPEJT$SJIAa;uI| zzdhz{d3V*uvsQ08bgQpOHTq*_Uz?10`V4{`R|hC%)0eMIU1U=7$+ry)@_5XmV<>LF z#r@^-#m>a(uk^4!M6*m^(k3#^(&HoND|gKdFfVoC8@XgNED7mKyQ(y%-8@uAT0_*v zlUBf);4#p%B z7arYzVxc((HQ5f3<6A!7vTE*H~Ym@aRtQ8rhxP_*HGxfMf?_WKE+@{-9$RArl? zQ~JEBJdM(t++bjyQ-m|ZgZ9de&V4X`xI_w{9OCWh#HmreK#|4SlndkOct%@SYj7?+ zot;(!ua3%J#5hCWzNY47h9B2~rHBAZJTp-Ck!>?t)kupR+J!i=e|X0-q{@>}h5h8^ zWab%lx!ZK^tT!!h`}O$ei*M)P0HfX14_UG5t8@jCb0}(@58R*SiEN?7^ z-fze#iOp7TuuxU*CbWZ5iru4=(2>pJT%QG?_vbim`DE<~sWSp^fTMP$fq;0r{MFfn zBy8xPc5$`}31+Fu69tS1xVl7D(eX3n_NM^_>+H$S>ZKW=JSreTeM*v773u6AUO|Tm z%Z=h*m&(u$3M*MUgU6E@m@4x#uih8ye*gWgt3@86M26?(LY?XL4sg>bmtZRxV%TIp zAfp#pVEGq7%6CFE$`l)BsoQE>? zq(qC?l^TW-498s#Oc{T^nyDq;z0rGD_nTH4Q*&p90Ap<>Sx3HdB`0Y>vEaRG9PMdz zR@&8=9$@tPFCNXmj{lzk+5sj03G-QjT%AQ#;}>0unafI4Q~cQk?)&V4nTl}V)!aYl zC8kGOmtx2O{Ck^}(ShFFFllHtA3i&#pscQu=dQ9`KCds%mbLKCf#)bzzB)+H!Qb^V z;jc2Afi*8&Qu`rartPENO8(=QbOo8!FW_W9^u=_t)018O6kE;?R&B+I##Z>`=s}8= zuMOV$uOTk{wFI^fxw6}NWml%feAeA4snzoPg`cQv9=@VL(R7#{R#a{=ma)wuyZUDS zLgHD2|M>)lW(pL4=byivT1<-3KbtCb9>E;5`Mj#h zs`@vNZCXQp%dsw^T3=7`|KqYEf+^t&=ER&JPW&FW!Z-{41lS5k5ij1ryx3DDg~%Bw dmiK=t{vQH~upj`S%X + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Polygon_repair/doc/Polygon_repair/fig/inout.svg b/Polygon_repair/doc/Polygon_repair/fig/inout.svg new file mode 100644 index 000000000000..d04cd3d601c6 --- /dev/null +++ b/Polygon_repair/doc/Polygon_repair/fig/inout.svg @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (a) + + + + + + + (b) + + + + + + + (c) + + + + + + + (d) + + + + + + + (e) + + + + + + + (f) + + + + + + + (g) + + + + + + + (h) + + + + + + diff --git a/Polygon_repair/doc/Polygon_repair/fig/invalid.svg b/Polygon_repair/doc/Polygon_repair/fig/invalid.svg new file mode 100644 index 000000000000..28a48816f750 --- /dev/null +++ b/Polygon_repair/doc/Polygon_repair/fig/invalid.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + (b) + + + + + + + (a) + + + + + + + (c) + + + + + + + (f) + + + + + + + (g) + + + + + + + + + + + + + + + + + + (d) + + + + + + + + + + + + + + + (e) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (h) + + + + + + diff --git a/Polygon_repair/doc/Polygon_repair/fig/valid.svg b/Polygon_repair/doc/Polygon_repair/fig/valid.svg new file mode 100644 index 000000000000..524d308b323c --- /dev/null +++ b/Polygon_repair/doc/Polygon_repair/fig/valid.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (b) + + + + + + + (a) + + + + + + + (c) + + + + + + + (d) + + + + + + + (e) + + + + + + From 30c303ff7d2ccd5a51e6e84457149e0938c54c4a Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Thu, 21 Mar 2024 16:28:00 +0100 Subject: [PATCH 182/182] Update CHANGES.md --- Installation/CHANGES.md | 1 - 1 file changed, 1 deletion(-) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 7932846acc42..d84f8bad7e55 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -35,7 +35,6 @@ Release date: October 2023 - **Breaking change**: Construct_projected_boundary_2 in `EnvelopeTraits_3` is now using `std::variant` instead of `Object` - Passed the base class of `Env_plane_traits_3` as a template parameter with a default value (being the 2D arrangement linear traits). Similarly, passed the base class of `Env_triangle_traits_3` as a template parameter with a default value (being the 2D arrangement segment traits). ->>>>>>> cgal/master ### [Combinatorial Maps](https://doc.cgal.org/6.0/Manual/packages.html#PkgCombinatorialMaps) and [Generalized Maps](https://doc.cgal.org/6.0/Manual/packages.html#PkgGeneralizedMaps)