clipper.cc 135 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374
  1. /*******************************************************************************
  2. * *
  3. * Author : Angus Johnson * Version : 6.4.2 * Date : 27 February
  4. *2017 * Website :
  5. *http://www.angusj.com * Copyright :
  6. *Angus Johnson 2010-2017 *
  7. * *
  8. * License: * Use, modification & distribution is subject to Boost Software
  9. *License Ver 1. * http://www.boost.org/LICENSE_1_0.txt *
  10. * *
  11. * Attributions: * The code in this library is an extension of Bala Vatti's
  12. *clipping algorithm: * "A generic solution to polygon clipping" *
  13. * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
  14. * http://portal.acm.org/citation.cfm?id=129906 *
  15. * *
  16. * Computer graphics and geometric modeling: implementation and algorithms * By
  17. *Max K. Agoston *
  18. * Springer; 1 edition (January 4, 2005) *
  19. * http://books.google.com/books?q=vatti+clipping+agoston *
  20. * *
  21. * See also: * "Polygon Offsetting by Computing Winding Numbers" * Paper no.
  22. *DETC2005-85513 pp. 565-575 * ASME 2005
  23. *International Design Engineering Technical Conferences * and
  24. *Computers and Information in Engineering Conference (IDETC/CIE2005) *
  25. * September 24-28, 2005 , Long Beach, California, USA *
  26. * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
  27. * *
  28. *******************************************************************************/
  29. /*******************************************************************************
  30. * *
  31. * This is a translation of the Delphi Clipper library and the naming style *
  32. * used has retained a Delphi flavour. *
  33. * *
  34. *******************************************************************************/
  35. #include <algorithm>
  36. #include <cmath>
  37. #include <cstdlib>
  38. #include <cstring>
  39. #include <functional>
  40. #include <ostream>
  41. #include <stdexcept>
  42. #include <vector>
  43. #include "clipper.h"
  44. namespace ClipperLib {
  45. static double const pi = 3.141592653589793238;
  46. static double const two_pi = pi * 2;
  47. static double const def_arc_tolerance = 0.25;
  48. enum Direction { dRightToLeft, dLeftToRight };
  49. static int const Unassigned = -1; // edge not currently 'owning' a solution
  50. static int const Skip = -2; // edge that would otherwise close a path
  51. #define HORIZONTAL (-1.0E+40)
  52. #define TOLERANCE (1.0e-20)
  53. #define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
  54. struct TEdge {
  55. IntPoint Bot;
  56. IntPoint Curr; // current (updated for every new scanbeam)
  57. IntPoint Top;
  58. double Dx;
  59. PolyType PolyTyp;
  60. EdgeSide Side; // side only refers to current side of solution poly
  61. int WindDelta; // 1 or -1 depending on winding direction
  62. int WindCnt;
  63. int WindCnt2; // winding count of the opposite polytype
  64. int OutIdx;
  65. TEdge *Next;
  66. TEdge *Prev;
  67. TEdge *NextInLML;
  68. TEdge *NextInAEL;
  69. TEdge *PrevInAEL;
  70. TEdge *NextInSEL;
  71. TEdge *PrevInSEL;
  72. };
  73. struct IntersectNode {
  74. TEdge *Edge1;
  75. TEdge *Edge2;
  76. IntPoint Pt;
  77. };
  78. struct LocalMinimum {
  79. cInt Y;
  80. TEdge *LeftBound;
  81. TEdge *RightBound;
  82. };
  83. struct OutPt;
  84. // OutRec: contains a path in the clipping solution. Edges in the AEL will
  85. // carry a pointer to an OutRec when they are part of the clipping solution.
  86. struct OutRec {
  87. int Idx;
  88. bool IsHole;
  89. bool IsOpen;
  90. OutRec *FirstLeft; // see comments in clipper.pas
  91. PolyNode *PolyNd;
  92. OutPt *Pts;
  93. OutPt *BottomPt;
  94. };
  95. struct OutPt {
  96. int Idx;
  97. IntPoint Pt;
  98. OutPt *Next;
  99. OutPt *Prev;
  100. };
  101. struct Join {
  102. OutPt *OutPt1;
  103. OutPt *OutPt2;
  104. IntPoint OffPt;
  105. };
  106. struct LocMinSorter {
  107. inline bool operator()(const LocalMinimum &locMin1,
  108. const LocalMinimum &locMin2) {
  109. return locMin2.Y < locMin1.Y;
  110. }
  111. };
  112. //------------------------------------------------------------------------------
  113. //------------------------------------------------------------------------------
  114. inline cInt Round(double val) {
  115. if ((val < 0))
  116. return static_cast<cInt>(val - 0.5);
  117. else
  118. return static_cast<cInt>(val + 0.5);
  119. }
  120. //------------------------------------------------------------------------------
  121. inline cInt Abs(cInt val) { return val < 0 ? -val : val; }
  122. //------------------------------------------------------------------------------
  123. // PolyTree methods ...
  124. //------------------------------------------------------------------------------
  125. void PolyTree::Clear() {
  126. for (PolyNodes::size_type i = 0; i < AllNodes.size(); ++i)
  127. delete AllNodes[i];
  128. AllNodes.resize(0);
  129. Childs.resize(0);
  130. }
  131. //------------------------------------------------------------------------------
  132. PolyNode *PolyTree::GetFirst() const {
  133. if (!Childs.empty())
  134. return Childs[0];
  135. else
  136. return 0;
  137. }
  138. //------------------------------------------------------------------------------
  139. int PolyTree::Total() const {
  140. int result = (int)AllNodes.size();
  141. // with negative offsets, ignore the hidden outer polygon ...
  142. if (result > 0 && Childs[0] != AllNodes[0])
  143. result--;
  144. return result;
  145. }
  146. //------------------------------------------------------------------------------
  147. // PolyNode methods ...
  148. //------------------------------------------------------------------------------
  149. PolyNode::PolyNode() : Parent(0), Index(0), m_IsOpen(false) {}
  150. //------------------------------------------------------------------------------
  151. int PolyNode::ChildCount() const { return (int)Childs.size(); }
  152. //------------------------------------------------------------------------------
  153. void PolyNode::AddChild(PolyNode &child) {
  154. unsigned cnt = (unsigned)Childs.size();
  155. Childs.push_back(&child);
  156. child.Parent = this;
  157. child.Index = cnt;
  158. }
  159. //------------------------------------------------------------------------------
  160. PolyNode *PolyNode::GetNext() const {
  161. if (!Childs.empty())
  162. return Childs[0];
  163. else
  164. return GetNextSiblingUp();
  165. }
  166. //------------------------------------------------------------------------------
  167. PolyNode *PolyNode::GetNextSiblingUp() const {
  168. if (!Parent) // protects against PolyTree.GetNextSiblingUp()
  169. return 0;
  170. else if (Index == Parent->Childs.size() - 1)
  171. return Parent->GetNextSiblingUp();
  172. else
  173. return Parent->Childs[Index + 1];
  174. }
  175. //------------------------------------------------------------------------------
  176. bool PolyNode::IsHole() const {
  177. bool result = true;
  178. PolyNode *node = Parent;
  179. while (node) {
  180. result = !result;
  181. node = node->Parent;
  182. }
  183. return result;
  184. }
  185. //------------------------------------------------------------------------------
  186. bool PolyNode::IsOpen() const { return m_IsOpen; }
  187. //------------------------------------------------------------------------------
  188. #ifndef use_int32
  189. //------------------------------------------------------------------------------
  190. // Int128 class (enables safe math on signed 64bit integers)
  191. // eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1
  192. // Int128 val2((long64)9223372036854775807);
  193. // Int128 val3 = val1 * val2;
  194. // val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
  195. //------------------------------------------------------------------------------
  196. class Int128 {
  197. public:
  198. ulong64 lo;
  199. long64 hi;
  200. Int128(long64 _lo = 0) {
  201. lo = (ulong64)_lo;
  202. if (_lo < 0)
  203. hi = -1;
  204. else
  205. hi = 0;
  206. }
  207. Int128(const Int128 &val) : lo(val.lo), hi(val.hi) {}
  208. Int128(const long64 &_hi, const ulong64 &_lo) : lo(_lo), hi(_hi) {}
  209. Int128 &operator=(const long64 &val) {
  210. lo = (ulong64)val;
  211. if (val < 0)
  212. hi = -1;
  213. else
  214. hi = 0;
  215. return *this;
  216. }
  217. bool operator==(const Int128 &val) const {
  218. return (hi == val.hi && lo == val.lo);
  219. }
  220. bool operator!=(const Int128 &val) const { return !(*this == val); }
  221. bool operator>(const Int128 &val) const {
  222. if (hi != val.hi)
  223. return hi > val.hi;
  224. else
  225. return lo > val.lo;
  226. }
  227. bool operator<(const Int128 &val) const {
  228. if (hi != val.hi)
  229. return hi < val.hi;
  230. else
  231. return lo < val.lo;
  232. }
  233. bool operator>=(const Int128 &val) const { return !(*this < val); }
  234. bool operator<=(const Int128 &val) const { return !(*this > val); }
  235. Int128 &operator+=(const Int128 &rhs) {
  236. hi += rhs.hi;
  237. lo += rhs.lo;
  238. if (lo < rhs.lo)
  239. hi++;
  240. return *this;
  241. }
  242. Int128 operator+(const Int128 &rhs) const {
  243. Int128 result(*this);
  244. result += rhs;
  245. return result;
  246. }
  247. Int128 &operator-=(const Int128 &rhs) {
  248. *this += -rhs;
  249. return *this;
  250. }
  251. Int128 operator-(const Int128 &rhs) const {
  252. Int128 result(*this);
  253. result -= rhs;
  254. return result;
  255. }
  256. Int128 operator-() const // unary negation
  257. {
  258. if (lo == 0)
  259. return Int128(-hi, 0);
  260. else
  261. return Int128(~hi, ~lo + 1);
  262. }
  263. operator double() const {
  264. const double shift64 = 18446744073709551616.0; // 2^64
  265. if (hi < 0) {
  266. if (lo == 0)
  267. return (double)hi * shift64;
  268. else
  269. return -(double)(~lo + ~hi * shift64);
  270. } else
  271. return (double)(lo + hi * shift64);
  272. }
  273. };
  274. //------------------------------------------------------------------------------
  275. Int128 Int128Mul(long64 lhs, long64 rhs) {
  276. bool negate = (lhs < 0) != (rhs < 0);
  277. if (lhs < 0)
  278. lhs = -lhs;
  279. ulong64 int1Hi = ulong64(lhs) >> 32;
  280. ulong64 int1Lo = ulong64(lhs & 0xFFFFFFFF);
  281. if (rhs < 0)
  282. rhs = -rhs;
  283. ulong64 int2Hi = ulong64(rhs) >> 32;
  284. ulong64 int2Lo = ulong64(rhs & 0xFFFFFFFF);
  285. // nb: see comments in clipper.pas
  286. ulong64 a = int1Hi * int2Hi;
  287. ulong64 b = int1Lo * int2Lo;
  288. ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi;
  289. Int128 tmp;
  290. tmp.hi = long64(a + (c >> 32));
  291. tmp.lo = long64(c << 32);
  292. tmp.lo += long64(b);
  293. if (tmp.lo < b)
  294. tmp.hi++;
  295. if (negate)
  296. tmp = -tmp;
  297. return tmp;
  298. };
  299. #endif
  300. //------------------------------------------------------------------------------
  301. // Miscellaneous global functions
  302. //------------------------------------------------------------------------------
  303. bool Orientation(const Path &poly) { return Area(poly) >= 0; }
  304. //------------------------------------------------------------------------------
  305. double Area(const Path &poly) {
  306. int size = (int)poly.size();
  307. if (size < 3)
  308. return 0;
  309. double a = 0;
  310. for (int i = 0, j = size - 1; i < size; ++i) {
  311. a += ((double)poly[j].X + poly[i].X) * ((double)poly[j].Y - poly[i].Y);
  312. j = i;
  313. }
  314. return -a * 0.5;
  315. }
  316. //------------------------------------------------------------------------------
  317. double Area(const OutPt *op) {
  318. const OutPt *startOp = op;
  319. if (!op)
  320. return 0;
  321. double a = 0;
  322. do {
  323. a += (double)(op->Prev->Pt.X + op->Pt.X) *
  324. (double)(op->Prev->Pt.Y - op->Pt.Y);
  325. op = op->Next;
  326. } while (op != startOp);
  327. return a * 0.5;
  328. }
  329. //------------------------------------------------------------------------------
  330. double Area(const OutRec &outRec) { return Area(outRec.Pts); }
  331. //------------------------------------------------------------------------------
  332. bool PointIsVertex(const IntPoint &Pt, OutPt *pp) {
  333. OutPt *pp2 = pp;
  334. do {
  335. if (pp2->Pt == Pt)
  336. return true;
  337. pp2 = pp2->Next;
  338. } while (pp2 != pp);
  339. return false;
  340. }
  341. //------------------------------------------------------------------------------
  342. // See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann &
  343. // Agathos
  344. // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
  345. int PointInPolygon(const IntPoint &pt, const Path &path) {
  346. // returns 0 if false, +1 if true, -1 if pt ON polygon boundary
  347. int result = 0;
  348. size_t cnt = path.size();
  349. if (cnt < 3)
  350. return 0;
  351. IntPoint ip = path[0];
  352. for (size_t i = 1; i <= cnt; ++i) {
  353. IntPoint ipNext = (i == cnt ? path[0] : path[i]);
  354. if (ipNext.Y == pt.Y) {
  355. if ((ipNext.X == pt.X) ||
  356. (ip.Y == pt.Y && ((ipNext.X > pt.X) == (ip.X < pt.X))))
  357. return -1;
  358. }
  359. if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y)) {
  360. if (ip.X >= pt.X) {
  361. if (ipNext.X > pt.X)
  362. result = 1 - result;
  363. else {
  364. double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) -
  365. (double)(ipNext.X - pt.X) * (ip.Y - pt.Y);
  366. if (!d)
  367. return -1;
  368. if ((d > 0) == (ipNext.Y > ip.Y))
  369. result = 1 - result;
  370. }
  371. } else {
  372. if (ipNext.X > pt.X) {
  373. double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) -
  374. (double)(ipNext.X - pt.X) * (ip.Y - pt.Y);
  375. if (!d)
  376. return -1;
  377. if ((d > 0) == (ipNext.Y > ip.Y))
  378. result = 1 - result;
  379. }
  380. }
  381. }
  382. ip = ipNext;
  383. }
  384. return result;
  385. }
  386. //------------------------------------------------------------------------------
  387. int PointInPolygon(const IntPoint &pt, OutPt *op) {
  388. // returns 0 if false, +1 if true, -1 if pt ON polygon boundary
  389. int result = 0;
  390. OutPt *startOp = op;
  391. for (;;) {
  392. if (op->Next->Pt.Y == pt.Y) {
  393. if ((op->Next->Pt.X == pt.X) ||
  394. (op->Pt.Y == pt.Y && ((op->Next->Pt.X > pt.X) == (op->Pt.X < pt.X))))
  395. return -1;
  396. }
  397. if ((op->Pt.Y < pt.Y) != (op->Next->Pt.Y < pt.Y)) {
  398. if (op->Pt.X >= pt.X) {
  399. if (op->Next->Pt.X > pt.X)
  400. result = 1 - result;
  401. else {
  402. double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) -
  403. (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y);
  404. if (!d)
  405. return -1;
  406. if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y))
  407. result = 1 - result;
  408. }
  409. } else {
  410. if (op->Next->Pt.X > pt.X) {
  411. double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) -
  412. (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y);
  413. if (!d)
  414. return -1;
  415. if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y))
  416. result = 1 - result;
  417. }
  418. }
  419. }
  420. op = op->Next;
  421. if (startOp == op)
  422. break;
  423. }
  424. return result;
  425. }
  426. //------------------------------------------------------------------------------
  427. bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2) {
  428. OutPt *op = OutPt1;
  429. do {
  430. // nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon
  431. int res = PointInPolygon(op->Pt, OutPt2);
  432. if (res >= 0)
  433. return res > 0;
  434. op = op->Next;
  435. } while (op != OutPt1);
  436. return true;
  437. }
  438. //----------------------------------------------------------------------
  439. bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range) {
  440. #ifndef use_int32
  441. if (UseFullInt64Range)
  442. return Int128Mul(e1.Top.Y - e1.Bot.Y, e2.Top.X - e2.Bot.X) ==
  443. Int128Mul(e1.Top.X - e1.Bot.X, e2.Top.Y - e2.Bot.Y);
  444. else
  445. #endif
  446. return (e1.Top.Y - e1.Bot.Y) * (e2.Top.X - e2.Bot.X) ==
  447. (e1.Top.X - e1.Bot.X) * (e2.Top.Y - e2.Bot.Y);
  448. }
  449. //------------------------------------------------------------------------------
  450. bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, const IntPoint pt3,
  451. bool UseFullInt64Range) {
  452. #ifndef use_int32
  453. if (UseFullInt64Range)
  454. return Int128Mul(pt1.Y - pt2.Y, pt2.X - pt3.X) ==
  455. Int128Mul(pt1.X - pt2.X, pt2.Y - pt3.Y);
  456. else
  457. #endif
  458. return (pt1.Y - pt2.Y) * (pt2.X - pt3.X) ==
  459. (pt1.X - pt2.X) * (pt2.Y - pt3.Y);
  460. }
  461. //------------------------------------------------------------------------------
  462. bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, const IntPoint pt3,
  463. const IntPoint pt4, bool UseFullInt64Range) {
  464. #ifndef use_int32
  465. if (UseFullInt64Range)
  466. return Int128Mul(pt1.Y - pt2.Y, pt3.X - pt4.X) ==
  467. Int128Mul(pt1.X - pt2.X, pt3.Y - pt4.Y);
  468. else
  469. #endif
  470. return (pt1.Y - pt2.Y) * (pt3.X - pt4.X) ==
  471. (pt1.X - pt2.X) * (pt3.Y - pt4.Y);
  472. }
  473. //------------------------------------------------------------------------------
  474. inline bool IsHorizontal(TEdge &e) { return e.Dx == HORIZONTAL; }
  475. //------------------------------------------------------------------------------
  476. inline double GetDx(const IntPoint pt1, const IntPoint pt2) {
  477. return (pt1.Y == pt2.Y) ? HORIZONTAL
  478. : (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y);
  479. }
  480. //---------------------------------------------------------------------------
  481. inline void SetDx(TEdge &e) {
  482. cInt dy = (e.Top.Y - e.Bot.Y);
  483. if (dy == 0)
  484. e.Dx = HORIZONTAL;
  485. else
  486. e.Dx = (double)(e.Top.X - e.Bot.X) / dy;
  487. }
  488. //---------------------------------------------------------------------------
  489. inline void SwapSides(TEdge &Edge1, TEdge &Edge2) {
  490. EdgeSide Side = Edge1.Side;
  491. Edge1.Side = Edge2.Side;
  492. Edge2.Side = Side;
  493. }
  494. //------------------------------------------------------------------------------
  495. inline void SwapPolyIndexes(TEdge &Edge1, TEdge &Edge2) {
  496. int OutIdx = Edge1.OutIdx;
  497. Edge1.OutIdx = Edge2.OutIdx;
  498. Edge2.OutIdx = OutIdx;
  499. }
  500. //------------------------------------------------------------------------------
  501. inline cInt TopX(TEdge &edge, const cInt currentY) {
  502. return (currentY == edge.Top.Y)
  503. ? edge.Top.X
  504. : edge.Bot.X + Round(edge.Dx * (currentY - edge.Bot.Y));
  505. }
  506. //------------------------------------------------------------------------------
  507. void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip) {
  508. #ifdef use_xyz
  509. ip.Z = 0;
  510. #endif
  511. double b1, b2;
  512. if (Edge1.Dx == Edge2.Dx) {
  513. ip.Y = Edge1.Curr.Y;
  514. ip.X = TopX(Edge1, ip.Y);
  515. return;
  516. } else if (Edge1.Dx == 0) {
  517. ip.X = Edge1.Bot.X;
  518. if (IsHorizontal(Edge2))
  519. ip.Y = Edge2.Bot.Y;
  520. else {
  521. b2 = Edge2.Bot.Y - (Edge2.Bot.X / Edge2.Dx);
  522. ip.Y = Round(ip.X / Edge2.Dx + b2);
  523. }
  524. } else if (Edge2.Dx == 0) {
  525. ip.X = Edge2.Bot.X;
  526. if (IsHorizontal(Edge1))
  527. ip.Y = Edge1.Bot.Y;
  528. else {
  529. b1 = Edge1.Bot.Y - (Edge1.Bot.X / Edge1.Dx);
  530. ip.Y = Round(ip.X / Edge1.Dx + b1);
  531. }
  532. } else {
  533. b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx;
  534. b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx;
  535. double q = (b2 - b1) / (Edge1.Dx - Edge2.Dx);
  536. ip.Y = Round(q);
  537. if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx))
  538. ip.X = Round(Edge1.Dx * q + b1);
  539. else
  540. ip.X = Round(Edge2.Dx * q + b2);
  541. }
  542. if (ip.Y < Edge1.Top.Y || ip.Y < Edge2.Top.Y) {
  543. if (Edge1.Top.Y > Edge2.Top.Y)
  544. ip.Y = Edge1.Top.Y;
  545. else
  546. ip.Y = Edge2.Top.Y;
  547. if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx))
  548. ip.X = TopX(Edge1, ip.Y);
  549. else
  550. ip.X = TopX(Edge2, ip.Y);
  551. }
  552. // finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ...
  553. if (ip.Y > Edge1.Curr.Y) {
  554. ip.Y = Edge1.Curr.Y;
  555. // use the more vertical edge to derive X ...
  556. if (std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx))
  557. ip.X = TopX(Edge2, ip.Y);
  558. else
  559. ip.X = TopX(Edge1, ip.Y);
  560. }
  561. }
  562. //------------------------------------------------------------------------------
  563. void ReversePolyPtLinks(OutPt *pp) {
  564. if (!pp)
  565. return;
  566. OutPt *pp1, *pp2;
  567. pp1 = pp;
  568. do {
  569. pp2 = pp1->Next;
  570. pp1->Next = pp1->Prev;
  571. pp1->Prev = pp2;
  572. pp1 = pp2;
  573. } while (pp1 != pp);
  574. }
  575. //------------------------------------------------------------------------------
  576. void DisposeOutPts(OutPt *&pp) {
  577. if (pp == 0)
  578. return;
  579. pp->Prev->Next = 0;
  580. while (pp) {
  581. OutPt *tmpPp = pp;
  582. pp = pp->Next;
  583. delete tmpPp;
  584. }
  585. }
  586. //------------------------------------------------------------------------------
  587. inline void InitEdge(TEdge *e, TEdge *eNext, TEdge *ePrev, const IntPoint &Pt) {
  588. std::memset(e, int(0), sizeof(TEdge));
  589. e->Next = eNext;
  590. e->Prev = ePrev;
  591. e->Curr = Pt;
  592. e->OutIdx = Unassigned;
  593. }
  594. //------------------------------------------------------------------------------
  595. void InitEdge2(TEdge &e, PolyType Pt) {
  596. if (e.Curr.Y >= e.Next->Curr.Y) {
  597. e.Bot = e.Curr;
  598. e.Top = e.Next->Curr;
  599. } else {
  600. e.Top = e.Curr;
  601. e.Bot = e.Next->Curr;
  602. }
  603. SetDx(e);
  604. e.PolyTyp = Pt;
  605. }
  606. //------------------------------------------------------------------------------
  607. TEdge *RemoveEdge(TEdge *e) {
  608. // removes e from double_linked_list (but without removing from memory)
  609. e->Prev->Next = e->Next;
  610. e->Next->Prev = e->Prev;
  611. TEdge *result = e->Next;
  612. e->Prev = 0; // flag as removed (see ClipperBase.Clear)
  613. return result;
  614. }
  615. //------------------------------------------------------------------------------
  616. inline void ReverseHorizontal(TEdge &e) {
  617. // swap horizontal edges' Top and Bottom x's so they follow the natural
  618. // progression of the bounds - ie so their xbots will align with the
  619. // adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
  620. std::swap(e.Top.X, e.Bot.X);
  621. #ifdef use_xyz
  622. std::swap(e.Top.Z, e.Bot.Z);
  623. #endif
  624. }
  625. //------------------------------------------------------------------------------
  626. void SwapPoints(IntPoint &pt1, IntPoint &pt2) {
  627. IntPoint tmp = pt1;
  628. pt1 = pt2;
  629. pt2 = tmp;
  630. }
  631. //------------------------------------------------------------------------------
  632. bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a,
  633. IntPoint pt2b, IntPoint &pt1, IntPoint &pt2) {
  634. // precondition: segments are Collinear.
  635. if (Abs(pt1a.X - pt1b.X) > Abs(pt1a.Y - pt1b.Y)) {
  636. if (pt1a.X > pt1b.X)
  637. SwapPoints(pt1a, pt1b);
  638. if (pt2a.X > pt2b.X)
  639. SwapPoints(pt2a, pt2b);
  640. if (pt1a.X > pt2a.X)
  641. pt1 = pt1a;
  642. else
  643. pt1 = pt2a;
  644. if (pt1b.X < pt2b.X)
  645. pt2 = pt1b;
  646. else
  647. pt2 = pt2b;
  648. return pt1.X < pt2.X;
  649. } else {
  650. if (pt1a.Y < pt1b.Y)
  651. SwapPoints(pt1a, pt1b);
  652. if (pt2a.Y < pt2b.Y)
  653. SwapPoints(pt2a, pt2b);
  654. if (pt1a.Y < pt2a.Y)
  655. pt1 = pt1a;
  656. else
  657. pt1 = pt2a;
  658. if (pt1b.Y > pt2b.Y)
  659. pt2 = pt1b;
  660. else
  661. pt2 = pt2b;
  662. return pt1.Y > pt2.Y;
  663. }
  664. }
  665. //------------------------------------------------------------------------------
  666. bool FirstIsBottomPt(const OutPt *btmPt1, const OutPt *btmPt2) {
  667. OutPt *p = btmPt1->Prev;
  668. while ((p->Pt == btmPt1->Pt) && (p != btmPt1))
  669. p = p->Prev;
  670. double dx1p = std::fabs(GetDx(btmPt1->Pt, p->Pt));
  671. p = btmPt1->Next;
  672. while ((p->Pt == btmPt1->Pt) && (p != btmPt1))
  673. p = p->Next;
  674. double dx1n = std::fabs(GetDx(btmPt1->Pt, p->Pt));
  675. p = btmPt2->Prev;
  676. while ((p->Pt == btmPt2->Pt) && (p != btmPt2))
  677. p = p->Prev;
  678. double dx2p = std::fabs(GetDx(btmPt2->Pt, p->Pt));
  679. p = btmPt2->Next;
  680. while ((p->Pt == btmPt2->Pt) && (p != btmPt2))
  681. p = p->Next;
  682. double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt));
  683. if (std::max(dx1p, dx1n) == std::max(dx2p, dx2n) &&
  684. std::min(dx1p, dx1n) == std::min(dx2p, dx2n))
  685. return Area(btmPt1) > 0; // if otherwise identical use orientation
  686. else
  687. return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
  688. }
  689. //------------------------------------------------------------------------------
  690. OutPt *GetBottomPt(OutPt *pp) {
  691. OutPt *dups = 0;
  692. OutPt *p = pp->Next;
  693. while (p != pp) {
  694. if (p->Pt.Y > pp->Pt.Y) {
  695. pp = p;
  696. dups = 0;
  697. } else if (p->Pt.Y == pp->Pt.Y && p->Pt.X <= pp->Pt.X) {
  698. if (p->Pt.X < pp->Pt.X) {
  699. dups = 0;
  700. pp = p;
  701. } else {
  702. if (p->Next != pp && p->Prev != pp)
  703. dups = p;
  704. }
  705. }
  706. p = p->Next;
  707. }
  708. if (dups) {
  709. // there appears to be at least 2 vertices at BottomPt so ...
  710. while (dups != p) {
  711. if (!FirstIsBottomPt(p, dups))
  712. pp = dups;
  713. dups = dups->Next;
  714. while (dups->Pt != pp->Pt)
  715. dups = dups->Next;
  716. }
  717. }
  718. return pp;
  719. }
  720. //------------------------------------------------------------------------------
  721. bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1, const IntPoint pt2,
  722. const IntPoint pt3) {
  723. if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2))
  724. return false;
  725. else if (pt1.X != pt3.X)
  726. return (pt2.X > pt1.X) == (pt2.X < pt3.X);
  727. else
  728. return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y);
  729. }
  730. //------------------------------------------------------------------------------
  731. bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b) {
  732. if (seg1a > seg1b)
  733. std::swap(seg1a, seg1b);
  734. if (seg2a > seg2b)
  735. std::swap(seg2a, seg2b);
  736. return (seg1a < seg2b) && (seg2a < seg1b);
  737. }
  738. //------------------------------------------------------------------------------
  739. // ClipperBase class methods ...
  740. //------------------------------------------------------------------------------
  741. ClipperBase::ClipperBase() // constructor
  742. {
  743. m_CurrentLM = m_MinimaList.begin(); // begin() == end() here
  744. m_UseFullRange = false;
  745. }
  746. //------------------------------------------------------------------------------
  747. ClipperBase::~ClipperBase() // destructor
  748. {
  749. Clear();
  750. }
  751. //------------------------------------------------------------------------------
  752. void RangeTest(const IntPoint &Pt, bool &useFullRange) {
  753. if (useFullRange) {
  754. if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange)
  755. throw clipperException("Coordinate outside allowed range");
  756. } else if (Pt.X > loRange || Pt.Y > loRange || -Pt.X > loRange ||
  757. -Pt.Y > loRange) {
  758. useFullRange = true;
  759. RangeTest(Pt, useFullRange);
  760. }
  761. }
  762. //------------------------------------------------------------------------------
  763. TEdge *FindNextLocMin(TEdge *E) {
  764. for (;;) {
  765. while (E->Bot != E->Prev->Bot || E->Curr == E->Top)
  766. E = E->Next;
  767. if (!IsHorizontal(*E) && !IsHorizontal(*E->Prev))
  768. break;
  769. while (IsHorizontal(*E->Prev))
  770. E = E->Prev;
  771. TEdge *E2 = E;
  772. while (IsHorizontal(*E))
  773. E = E->Next;
  774. if (E->Top.Y == E->Prev->Bot.Y)
  775. continue; // ie just an intermediate horz.
  776. if (E2->Prev->Bot.X < E->Bot.X)
  777. E = E2;
  778. break;
  779. }
  780. return E;
  781. }
  782. //------------------------------------------------------------------------------
  783. TEdge *ClipperBase::ProcessBound(TEdge *E, bool NextIsForward) {
  784. TEdge *Result = E;
  785. TEdge *Horz = 0;
  786. if (E->OutIdx == Skip) {
  787. // if edges still remain in the current bound beyond the skip edge then
  788. // create another LocMin and call ProcessBound once more
  789. if (NextIsForward) {
  790. while (E->Top.Y == E->Next->Bot.Y)
  791. E = E->Next;
  792. // don't include top horizontals when parsing a bound a second time,
  793. // they will be contained in the opposite bound ...
  794. while (E != Result && IsHorizontal(*E))
  795. E = E->Prev;
  796. } else {
  797. while (E->Top.Y == E->Prev->Bot.Y)
  798. E = E->Prev;
  799. while (E != Result && IsHorizontal(*E))
  800. E = E->Next;
  801. }
  802. if (E == Result) {
  803. if (NextIsForward)
  804. Result = E->Next;
  805. else
  806. Result = E->Prev;
  807. } else {
  808. // there are more edges in the bound beyond result starting with E
  809. if (NextIsForward)
  810. E = Result->Next;
  811. else
  812. E = Result->Prev;
  813. MinimaList::value_type locMin;
  814. locMin.Y = E->Bot.Y;
  815. locMin.LeftBound = 0;
  816. locMin.RightBound = E;
  817. E->WindDelta = 0;
  818. Result = ProcessBound(E, NextIsForward);
  819. m_MinimaList.push_back(locMin);
  820. }
  821. return Result;
  822. }
  823. TEdge *EStart;
  824. if (IsHorizontal(*E)) {
  825. // We need to be careful with open paths because this may not be a
  826. // true local minima (ie E may be following a skip edge).
  827. // Also, consecutive horz. edges may start heading left before going right.
  828. if (NextIsForward)
  829. EStart = E->Prev;
  830. else
  831. EStart = E->Next;
  832. if (IsHorizontal(*EStart)) // ie an adjoining horizontal skip edge
  833. {
  834. if (EStart->Bot.X != E->Bot.X && EStart->Top.X != E->Bot.X)
  835. ReverseHorizontal(*E);
  836. } else if (EStart->Bot.X != E->Bot.X)
  837. ReverseHorizontal(*E);
  838. }
  839. EStart = E;
  840. if (NextIsForward) {
  841. while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip)
  842. Result = Result->Next;
  843. if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip) {
  844. // nb: at the top of a bound, horizontals are added to the bound
  845. // only when the preceding edge attaches to the horizontal's left vertex
  846. // unless a Skip edge is encountered when that becomes the top divide
  847. Horz = Result;
  848. while (IsHorizontal(*Horz->Prev))
  849. Horz = Horz->Prev;
  850. if (Horz->Prev->Top.X > Result->Next->Top.X)
  851. Result = Horz->Prev;
  852. }
  853. while (E != Result) {
  854. E->NextInLML = E->Next;
  855. if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X)
  856. ReverseHorizontal(*E);
  857. E = E->Next;
  858. }
  859. if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X)
  860. ReverseHorizontal(*E);
  861. Result = Result->Next; // move to the edge just beyond current bound
  862. } else {
  863. while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip)
  864. Result = Result->Prev;
  865. if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip) {
  866. Horz = Result;
  867. while (IsHorizontal(*Horz->Next))
  868. Horz = Horz->Next;
  869. if (Horz->Next->Top.X == Result->Prev->Top.X ||
  870. Horz->Next->Top.X > Result->Prev->Top.X)
  871. Result = Horz->Next;
  872. }
  873. while (E != Result) {
  874. E->NextInLML = E->Prev;
  875. if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
  876. ReverseHorizontal(*E);
  877. E = E->Prev;
  878. }
  879. if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
  880. ReverseHorizontal(*E);
  881. Result = Result->Prev; // move to the edge just beyond current bound
  882. }
  883. return Result;
  884. }
  885. //------------------------------------------------------------------------------
  886. bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) {
  887. #ifdef use_lines
  888. if (!Closed && PolyTyp == ptClip)
  889. throw clipperException("AddPath: Open paths must be subject.");
  890. #else
  891. if (!Closed)
  892. throw clipperException("AddPath: Open paths have been disabled.");
  893. #endif
  894. int highI = (int)pg.size() - 1;
  895. if (Closed)
  896. while (highI > 0 && (pg[highI] == pg[0]))
  897. --highI;
  898. while (highI > 0 && (pg[highI] == pg[highI - 1]))
  899. --highI;
  900. if ((Closed && highI < 2) || (!Closed && highI < 1))
  901. return false;
  902. // create a new edge array ...
  903. TEdge *edges = new TEdge[highI + 1];
  904. bool IsFlat = true;
  905. // 1. Basic (first) edge initialization ...
  906. try {
  907. edges[1].Curr = pg[1];
  908. RangeTest(pg[0], m_UseFullRange);
  909. RangeTest(pg[highI], m_UseFullRange);
  910. InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]);
  911. InitEdge(&edges[highI], &edges[0], &edges[highI - 1], pg[highI]);
  912. for (int i = highI - 1; i >= 1; --i) {
  913. RangeTest(pg[i], m_UseFullRange);
  914. InitEdge(&edges[i], &edges[i + 1], &edges[i - 1], pg[i]);
  915. }
  916. } catch (...) {
  917. delete[] edges;
  918. throw; // range test fails
  919. }
  920. TEdge *eStart = &edges[0];
  921. // 2. Remove duplicate vertices, and (when closed) collinear edges ...
  922. TEdge *E = eStart, *eLoopStop = eStart;
  923. for (;;) {
  924. // nb: allows matching start and end points when not Closed ...
  925. if (E->Curr == E->Next->Curr && (Closed || E->Next != eStart)) {
  926. if (E == E->Next)
  927. break;
  928. if (E == eStart)
  929. eStart = E->Next;
  930. E = RemoveEdge(E);
  931. eLoopStop = E;
  932. continue;
  933. }
  934. if (E->Prev == E->Next)
  935. break; // only two vertices
  936. else if (Closed &&
  937. SlopesEqual(E->Prev->Curr, E->Curr, E->Next->Curr,
  938. m_UseFullRange) &&
  939. (!m_PreserveCollinear ||
  940. !Pt2IsBetweenPt1AndPt3(E->Prev->Curr, E->Curr, E->Next->Curr))) {
  941. // Collinear edges are allowed for open paths but in closed paths
  942. // the default is to merge adjacent collinear edges into a single edge.
  943. // However, if the PreserveCollinear property is enabled, only overlapping
  944. // collinear edges (ie spikes) will be removed from closed paths.
  945. if (E == eStart)
  946. eStart = E->Next;
  947. E = RemoveEdge(E);
  948. E = E->Prev;
  949. eLoopStop = E;
  950. continue;
  951. }
  952. E = E->Next;
  953. if ((E == eLoopStop) || (!Closed && E->Next == eStart))
  954. break;
  955. }
  956. if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next))) {
  957. delete[] edges;
  958. return false;
  959. }
  960. if (!Closed) {
  961. m_HasOpenPaths = true;
  962. eStart->Prev->OutIdx = Skip;
  963. }
  964. // 3. Do second stage of edge initialization ...
  965. E = eStart;
  966. do {
  967. InitEdge2(*E, PolyTyp);
  968. E = E->Next;
  969. if (IsFlat && E->Curr.Y != eStart->Curr.Y)
  970. IsFlat = false;
  971. } while (E != eStart);
  972. // 4. Finally, add edge bounds to LocalMinima list ...
  973. // Totally flat paths must be handled differently when adding them
  974. // to LocalMinima list to avoid endless loops etc ...
  975. if (IsFlat) {
  976. if (Closed) {
  977. delete[] edges;
  978. return false;
  979. }
  980. E->Prev->OutIdx = Skip;
  981. MinimaList::value_type locMin;
  982. locMin.Y = E->Bot.Y;
  983. locMin.LeftBound = 0;
  984. locMin.RightBound = E;
  985. locMin.RightBound->Side = esRight;
  986. locMin.RightBound->WindDelta = 0;
  987. for (;;) {
  988. if (E->Bot.X != E->Prev->Top.X)
  989. ReverseHorizontal(*E);
  990. if (E->Next->OutIdx == Skip)
  991. break;
  992. E->NextInLML = E->Next;
  993. E = E->Next;
  994. }
  995. m_MinimaList.push_back(locMin);
  996. m_edges.push_back(edges);
  997. return true;
  998. }
  999. m_edges.push_back(edges);
  1000. bool leftBoundIsForward;
  1001. TEdge *EMin = 0;
  1002. // workaround to avoid an endless loop in the while loop below when
  1003. // open paths have matching start and end points ...
  1004. if (E->Prev->Bot == E->Prev->Top)
  1005. E = E->Next;
  1006. for (;;) {
  1007. E = FindNextLocMin(E);
  1008. if (E == EMin)
  1009. break;
  1010. else if (!EMin)
  1011. EMin = E;
  1012. // E and E.Prev now share a local minima (left aligned if horizontal).
  1013. // Compare their slopes to find which starts which bound ...
  1014. MinimaList::value_type locMin;
  1015. locMin.Y = E->Bot.Y;
  1016. if (E->Dx < E->Prev->Dx) {
  1017. locMin.LeftBound = E->Prev;
  1018. locMin.RightBound = E;
  1019. leftBoundIsForward = false; // Q.nextInLML = Q.prev
  1020. } else {
  1021. locMin.LeftBound = E;
  1022. locMin.RightBound = E->Prev;
  1023. leftBoundIsForward = true; // Q.nextInLML = Q.next
  1024. }
  1025. if (!Closed)
  1026. locMin.LeftBound->WindDelta = 0;
  1027. else if (locMin.LeftBound->Next == locMin.RightBound)
  1028. locMin.LeftBound->WindDelta = -1;
  1029. else
  1030. locMin.LeftBound->WindDelta = 1;
  1031. locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta;
  1032. E = ProcessBound(locMin.LeftBound, leftBoundIsForward);
  1033. if (E->OutIdx == Skip)
  1034. E = ProcessBound(E, leftBoundIsForward);
  1035. TEdge *E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward);
  1036. if (E2->OutIdx == Skip)
  1037. E2 = ProcessBound(E2, !leftBoundIsForward);
  1038. if (locMin.LeftBound->OutIdx == Skip)
  1039. locMin.LeftBound = 0;
  1040. else if (locMin.RightBound->OutIdx == Skip)
  1041. locMin.RightBound = 0;
  1042. m_MinimaList.push_back(locMin);
  1043. if (!leftBoundIsForward)
  1044. E = E2;
  1045. }
  1046. return true;
  1047. }
  1048. //------------------------------------------------------------------------------
  1049. bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed) {
  1050. bool result = false;
  1051. for (Paths::size_type i = 0; i < ppg.size(); ++i)
  1052. if (AddPath(ppg[i], PolyTyp, Closed))
  1053. result = true;
  1054. return result;
  1055. }
  1056. //------------------------------------------------------------------------------
  1057. void ClipperBase::Clear() {
  1058. DisposeLocalMinimaList();
  1059. for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) {
  1060. TEdge *edges = m_edges[i];
  1061. delete[] edges;
  1062. }
  1063. m_edges.clear();
  1064. m_UseFullRange = false;
  1065. m_HasOpenPaths = false;
  1066. }
  1067. //------------------------------------------------------------------------------
  1068. void ClipperBase::Reset() {
  1069. m_CurrentLM = m_MinimaList.begin();
  1070. if (m_CurrentLM == m_MinimaList.end())
  1071. return; // ie nothing to process
  1072. std::sort(m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter());
  1073. m_Scanbeam = ScanbeamList(); // clears/resets priority_queue
  1074. // reset all edges ...
  1075. for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end();
  1076. ++lm) {
  1077. InsertScanbeam(lm->Y);
  1078. TEdge *e = lm->LeftBound;
  1079. if (e) {
  1080. e->Curr = e->Bot;
  1081. e->Side = esLeft;
  1082. e->OutIdx = Unassigned;
  1083. }
  1084. e = lm->RightBound;
  1085. if (e) {
  1086. e->Curr = e->Bot;
  1087. e->Side = esRight;
  1088. e->OutIdx = Unassigned;
  1089. }
  1090. }
  1091. m_ActiveEdges = 0;
  1092. m_CurrentLM = m_MinimaList.begin();
  1093. }
  1094. //------------------------------------------------------------------------------
  1095. void ClipperBase::DisposeLocalMinimaList() {
  1096. m_MinimaList.clear();
  1097. m_CurrentLM = m_MinimaList.begin();
  1098. }
  1099. //------------------------------------------------------------------------------
  1100. bool ClipperBase::PopLocalMinima(cInt Y, const LocalMinimum *&locMin) {
  1101. if (m_CurrentLM == m_MinimaList.end() || (*m_CurrentLM).Y != Y)
  1102. return false;
  1103. locMin = &(*m_CurrentLM);
  1104. ++m_CurrentLM;
  1105. return true;
  1106. }
  1107. //------------------------------------------------------------------------------
  1108. IntRect ClipperBase::GetBounds() {
  1109. IntRect result;
  1110. MinimaList::iterator lm = m_MinimaList.begin();
  1111. if (lm == m_MinimaList.end()) {
  1112. result.left = result.top = result.right = result.bottom = 0;
  1113. return result;
  1114. }
  1115. result.left = lm->LeftBound->Bot.X;
  1116. result.top = lm->LeftBound->Bot.Y;
  1117. result.right = lm->LeftBound->Bot.X;
  1118. result.bottom = lm->LeftBound->Bot.Y;
  1119. while (lm != m_MinimaList.end()) {
  1120. // todo - needs fixing for open paths
  1121. result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y);
  1122. TEdge *e = lm->LeftBound;
  1123. for (;;) {
  1124. TEdge *bottomE = e;
  1125. while (e->NextInLML) {
  1126. if (e->Bot.X < result.left)
  1127. result.left = e->Bot.X;
  1128. if (e->Bot.X > result.right)
  1129. result.right = e->Bot.X;
  1130. e = e->NextInLML;
  1131. }
  1132. result.left = std::min(result.left, e->Bot.X);
  1133. result.right = std::max(result.right, e->Bot.X);
  1134. result.left = std::min(result.left, e->Top.X);
  1135. result.right = std::max(result.right, e->Top.X);
  1136. result.top = std::min(result.top, e->Top.Y);
  1137. if (bottomE == lm->LeftBound)
  1138. e = lm->RightBound;
  1139. else
  1140. break;
  1141. }
  1142. ++lm;
  1143. }
  1144. return result;
  1145. }
  1146. //------------------------------------------------------------------------------
  1147. void ClipperBase::InsertScanbeam(const cInt Y) { m_Scanbeam.push(Y); }
  1148. //------------------------------------------------------------------------------
  1149. bool ClipperBase::PopScanbeam(cInt &Y) {
  1150. if (m_Scanbeam.empty())
  1151. return false;
  1152. Y = m_Scanbeam.top();
  1153. m_Scanbeam.pop();
  1154. while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) {
  1155. m_Scanbeam.pop();
  1156. } // Pop duplicates.
  1157. return true;
  1158. }
  1159. //------------------------------------------------------------------------------
  1160. void ClipperBase::DisposeAllOutRecs() {
  1161. for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
  1162. DisposeOutRec(i);
  1163. m_PolyOuts.clear();
  1164. }
  1165. //------------------------------------------------------------------------------
  1166. void ClipperBase::DisposeOutRec(PolyOutList::size_type index) {
  1167. OutRec *outRec = m_PolyOuts[index];
  1168. if (outRec->Pts)
  1169. DisposeOutPts(outRec->Pts);
  1170. delete outRec;
  1171. m_PolyOuts[index] = 0;
  1172. }
  1173. //------------------------------------------------------------------------------
  1174. void ClipperBase::DeleteFromAEL(TEdge *e) {
  1175. TEdge *AelPrev = e->PrevInAEL;
  1176. TEdge *AelNext = e->NextInAEL;
  1177. if (!AelPrev && !AelNext && (e != m_ActiveEdges))
  1178. return; // already deleted
  1179. if (AelPrev)
  1180. AelPrev->NextInAEL = AelNext;
  1181. else
  1182. m_ActiveEdges = AelNext;
  1183. if (AelNext)
  1184. AelNext->PrevInAEL = AelPrev;
  1185. e->NextInAEL = 0;
  1186. e->PrevInAEL = 0;
  1187. }
  1188. //------------------------------------------------------------------------------
  1189. OutRec *ClipperBase::CreateOutRec() {
  1190. OutRec *result = new OutRec;
  1191. result->IsHole = false;
  1192. result->IsOpen = false;
  1193. result->FirstLeft = 0;
  1194. result->Pts = 0;
  1195. result->BottomPt = 0;
  1196. result->PolyNd = 0;
  1197. m_PolyOuts.push_back(result);
  1198. result->Idx = (int)m_PolyOuts.size() - 1;
  1199. return result;
  1200. }
  1201. //------------------------------------------------------------------------------
  1202. void ClipperBase::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2) {
  1203. // check that one or other edge hasn't already been removed from AEL ...
  1204. if (Edge1->NextInAEL == Edge1->PrevInAEL ||
  1205. Edge2->NextInAEL == Edge2->PrevInAEL)
  1206. return;
  1207. if (Edge1->NextInAEL == Edge2) {
  1208. TEdge *Next = Edge2->NextInAEL;
  1209. if (Next)
  1210. Next->PrevInAEL = Edge1;
  1211. TEdge *Prev = Edge1->PrevInAEL;
  1212. if (Prev)
  1213. Prev->NextInAEL = Edge2;
  1214. Edge2->PrevInAEL = Prev;
  1215. Edge2->NextInAEL = Edge1;
  1216. Edge1->PrevInAEL = Edge2;
  1217. Edge1->NextInAEL = Next;
  1218. } else if (Edge2->NextInAEL == Edge1) {
  1219. TEdge *Next = Edge1->NextInAEL;
  1220. if (Next)
  1221. Next->PrevInAEL = Edge2;
  1222. TEdge *Prev = Edge2->PrevInAEL;
  1223. if (Prev)
  1224. Prev->NextInAEL = Edge1;
  1225. Edge1->PrevInAEL = Prev;
  1226. Edge1->NextInAEL = Edge2;
  1227. Edge2->PrevInAEL = Edge1;
  1228. Edge2->NextInAEL = Next;
  1229. } else {
  1230. TEdge *Next = Edge1->NextInAEL;
  1231. TEdge *Prev = Edge1->PrevInAEL;
  1232. Edge1->NextInAEL = Edge2->NextInAEL;
  1233. if (Edge1->NextInAEL)
  1234. Edge1->NextInAEL->PrevInAEL = Edge1;
  1235. Edge1->PrevInAEL = Edge2->PrevInAEL;
  1236. if (Edge1->PrevInAEL)
  1237. Edge1->PrevInAEL->NextInAEL = Edge1;
  1238. Edge2->NextInAEL = Next;
  1239. if (Edge2->NextInAEL)
  1240. Edge2->NextInAEL->PrevInAEL = Edge2;
  1241. Edge2->PrevInAEL = Prev;
  1242. if (Edge2->PrevInAEL)
  1243. Edge2->PrevInAEL->NextInAEL = Edge2;
  1244. }
  1245. if (!Edge1->PrevInAEL)
  1246. m_ActiveEdges = Edge1;
  1247. else if (!Edge2->PrevInAEL)
  1248. m_ActiveEdges = Edge2;
  1249. }
  1250. //------------------------------------------------------------------------------
  1251. void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e) {
  1252. if (!e->NextInLML)
  1253. throw clipperException("UpdateEdgeIntoAEL: invalid call");
  1254. e->NextInLML->OutIdx = e->OutIdx;
  1255. TEdge *AelPrev = e->PrevInAEL;
  1256. TEdge *AelNext = e->NextInAEL;
  1257. if (AelPrev)
  1258. AelPrev->NextInAEL = e->NextInLML;
  1259. else
  1260. m_ActiveEdges = e->NextInLML;
  1261. if (AelNext)
  1262. AelNext->PrevInAEL = e->NextInLML;
  1263. e->NextInLML->Side = e->Side;
  1264. e->NextInLML->WindDelta = e->WindDelta;
  1265. e->NextInLML->WindCnt = e->WindCnt;
  1266. e->NextInLML->WindCnt2 = e->WindCnt2;
  1267. e = e->NextInLML;
  1268. e->Curr = e->Bot;
  1269. e->PrevInAEL = AelPrev;
  1270. e->NextInAEL = AelNext;
  1271. if (!IsHorizontal(*e))
  1272. InsertScanbeam(e->Top.Y);
  1273. }
  1274. //------------------------------------------------------------------------------
  1275. bool ClipperBase::LocalMinimaPending() {
  1276. return (m_CurrentLM != m_MinimaList.end());
  1277. }
  1278. //------------------------------------------------------------------------------
  1279. // TClipper methods ...
  1280. //------------------------------------------------------------------------------
  1281. Clipper::Clipper(int initOptions)
  1282. : ClipperBase() // constructor
  1283. {
  1284. m_ExecuteLocked = false;
  1285. m_UseFullRange = false;
  1286. m_ReverseOutput = ((initOptions & ioReverseSolution) != 0);
  1287. m_StrictSimple = ((initOptions & ioStrictlySimple) != 0);
  1288. m_PreserveCollinear = ((initOptions & ioPreserveCollinear) != 0);
  1289. m_HasOpenPaths = false;
  1290. #ifdef use_xyz
  1291. m_ZFill = 0;
  1292. #endif
  1293. }
  1294. //------------------------------------------------------------------------------
  1295. #ifdef use_xyz
  1296. void Clipper::ZFillFunction(ZFillCallback zFillFunc) { m_ZFill = zFillFunc; }
  1297. //------------------------------------------------------------------------------
  1298. #endif
  1299. bool Clipper::Execute(ClipType clipType, Paths &solution,
  1300. PolyFillType fillType) {
  1301. return Execute(clipType, solution, fillType, fillType);
  1302. }
  1303. //------------------------------------------------------------------------------
  1304. bool Clipper::Execute(ClipType clipType, PolyTree &polytree,
  1305. PolyFillType fillType) {
  1306. return Execute(clipType, polytree, fillType, fillType);
  1307. }
  1308. //------------------------------------------------------------------------------
  1309. bool Clipper::Execute(ClipType clipType, Paths &solution,
  1310. PolyFillType subjFillType, PolyFillType clipFillType) {
  1311. if (m_ExecuteLocked)
  1312. return false;
  1313. if (m_HasOpenPaths)
  1314. throw clipperException(
  1315. "Error: PolyTree struct is needed for open path clipping.");
  1316. m_ExecuteLocked = true;
  1317. solution.resize(0);
  1318. m_SubjFillType = subjFillType;
  1319. m_ClipFillType = clipFillType;
  1320. m_ClipType = clipType;
  1321. m_UsingPolyTree = false;
  1322. bool succeeded = ExecuteInternal();
  1323. if (succeeded)
  1324. BuildResult(solution);
  1325. DisposeAllOutRecs();
  1326. m_ExecuteLocked = false;
  1327. return succeeded;
  1328. }
  1329. //------------------------------------------------------------------------------
  1330. bool Clipper::Execute(ClipType clipType, PolyTree &polytree,
  1331. PolyFillType subjFillType, PolyFillType clipFillType) {
  1332. if (m_ExecuteLocked)
  1333. return false;
  1334. m_ExecuteLocked = true;
  1335. m_SubjFillType = subjFillType;
  1336. m_ClipFillType = clipFillType;
  1337. m_ClipType = clipType;
  1338. m_UsingPolyTree = true;
  1339. bool succeeded = ExecuteInternal();
  1340. if (succeeded)
  1341. BuildResult2(polytree);
  1342. DisposeAllOutRecs();
  1343. m_ExecuteLocked = false;
  1344. return succeeded;
  1345. }
  1346. //------------------------------------------------------------------------------
  1347. void Clipper::FixHoleLinkage(OutRec &outrec) {
  1348. // skip OutRecs that (a) contain outermost polygons or
  1349. //(b) already have the correct owner/child linkage ...
  1350. if (!outrec.FirstLeft ||
  1351. (outrec.IsHole != outrec.FirstLeft->IsHole && outrec.FirstLeft->Pts))
  1352. return;
  1353. OutRec *orfl = outrec.FirstLeft;
  1354. while (orfl && ((orfl->IsHole == outrec.IsHole) || !orfl->Pts))
  1355. orfl = orfl->FirstLeft;
  1356. outrec.FirstLeft = orfl;
  1357. }
  1358. //------------------------------------------------------------------------------
  1359. bool Clipper::ExecuteInternal() {
  1360. bool succeeded = true;
  1361. try {
  1362. Reset();
  1363. m_Maxima = MaximaList();
  1364. m_SortedEdges = 0;
  1365. succeeded = true;
  1366. cInt botY, topY;
  1367. if (!PopScanbeam(botY))
  1368. return false;
  1369. InsertLocalMinimaIntoAEL(botY);
  1370. while (PopScanbeam(topY) || LocalMinimaPending()) {
  1371. ProcessHorizontals();
  1372. ClearGhostJoins();
  1373. if (!ProcessIntersections(topY)) {
  1374. succeeded = false;
  1375. break;
  1376. }
  1377. ProcessEdgesAtTopOfScanbeam(topY);
  1378. botY = topY;
  1379. InsertLocalMinimaIntoAEL(botY);
  1380. }
  1381. } catch (...) {
  1382. succeeded = false;
  1383. }
  1384. if (succeeded) {
  1385. // fix orientations ...
  1386. for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) {
  1387. OutRec *outRec = m_PolyOuts[i];
  1388. if (!outRec->Pts || outRec->IsOpen)
  1389. continue;
  1390. if ((outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0))
  1391. ReversePolyPtLinks(outRec->Pts);
  1392. }
  1393. if (!m_Joins.empty())
  1394. JoinCommonEdges();
  1395. // unfortunately FixupOutPolygon() must be done after JoinCommonEdges()
  1396. for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) {
  1397. OutRec *outRec = m_PolyOuts[i];
  1398. if (!outRec->Pts)
  1399. continue;
  1400. if (outRec->IsOpen)
  1401. FixupOutPolyline(*outRec);
  1402. else
  1403. FixupOutPolygon(*outRec);
  1404. }
  1405. if (m_StrictSimple)
  1406. DoSimplePolygons();
  1407. }
  1408. ClearJoins();
  1409. ClearGhostJoins();
  1410. return succeeded;
  1411. }
  1412. //------------------------------------------------------------------------------
  1413. void Clipper::SetWindingCount(TEdge &edge) {
  1414. TEdge *e = edge.PrevInAEL;
  1415. // find the edge of the same polytype that immediately preceeds 'edge' in AEL
  1416. while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0)))
  1417. e = e->PrevInAEL;
  1418. if (!e) {
  1419. if (edge.WindDelta == 0) {
  1420. PolyFillType pft =
  1421. (edge.PolyTyp == ptSubject ? m_SubjFillType : m_ClipFillType);
  1422. edge.WindCnt = (pft == pftNegative ? -1 : 1);
  1423. } else
  1424. edge.WindCnt = edge.WindDelta;
  1425. edge.WindCnt2 = 0;
  1426. e = m_ActiveEdges; // ie get ready to calc WindCnt2
  1427. } else if (edge.WindDelta == 0 && m_ClipType != ctUnion) {
  1428. edge.WindCnt = 1;
  1429. edge.WindCnt2 = e->WindCnt2;
  1430. e = e->NextInAEL; // ie get ready to calc WindCnt2
  1431. } else if (IsEvenOddFillType(edge)) {
  1432. // EvenOdd filling ...
  1433. if (edge.WindDelta == 0) {
  1434. // are we inside a subj polygon ...
  1435. bool Inside = true;
  1436. TEdge *e2 = e->PrevInAEL;
  1437. while (e2) {
  1438. if (e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0)
  1439. Inside = !Inside;
  1440. e2 = e2->PrevInAEL;
  1441. }
  1442. edge.WindCnt = (Inside ? 0 : 1);
  1443. } else {
  1444. edge.WindCnt = edge.WindDelta;
  1445. }
  1446. edge.WindCnt2 = e->WindCnt2;
  1447. e = e->NextInAEL; // ie get ready to calc WindCnt2
  1448. } else {
  1449. // nonZero, Positive or Negative filling ...
  1450. if (e->WindCnt * e->WindDelta < 0) {
  1451. // prev edge is 'decreasing' WindCount (WC) toward zero
  1452. // so we're outside the previous polygon ...
  1453. if (Abs(e->WindCnt) > 1) {
  1454. // outside prev poly but still inside another.
  1455. // when reversing direction of prev poly use the same WC
  1456. if (e->WindDelta * edge.WindDelta < 0)
  1457. edge.WindCnt = e->WindCnt;
  1458. // otherwise continue to 'decrease' WC ...
  1459. else
  1460. edge.WindCnt = e->WindCnt + edge.WindDelta;
  1461. } else
  1462. // now outside all polys of same polytype so set own WC ...
  1463. edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta);
  1464. } else {
  1465. // prev edge is 'increasing' WindCount (WC) away from zero
  1466. // so we're inside the previous polygon ...
  1467. if (edge.WindDelta == 0)
  1468. edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1);
  1469. // if wind direction is reversing prev then use same WC
  1470. else if (e->WindDelta * edge.WindDelta < 0)
  1471. edge.WindCnt = e->WindCnt;
  1472. // otherwise add to WC ...
  1473. else
  1474. edge.WindCnt = e->WindCnt + edge.WindDelta;
  1475. }
  1476. edge.WindCnt2 = e->WindCnt2;
  1477. e = e->NextInAEL; // ie get ready to calc WindCnt2
  1478. }
  1479. // update WindCnt2 ...
  1480. if (IsEvenOddAltFillType(edge)) {
  1481. // EvenOdd filling ...
  1482. while (e != &edge) {
  1483. if (e->WindDelta != 0)
  1484. edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0);
  1485. e = e->NextInAEL;
  1486. }
  1487. } else {
  1488. // nonZero, Positive or Negative filling ...
  1489. while (e != &edge) {
  1490. edge.WindCnt2 += e->WindDelta;
  1491. e = e->NextInAEL;
  1492. }
  1493. }
  1494. }
  1495. //------------------------------------------------------------------------------
  1496. bool Clipper::IsEvenOddFillType(const TEdge &edge) const {
  1497. if (edge.PolyTyp == ptSubject)
  1498. return m_SubjFillType == pftEvenOdd;
  1499. else
  1500. return m_ClipFillType == pftEvenOdd;
  1501. }
  1502. //------------------------------------------------------------------------------
  1503. bool Clipper::IsEvenOddAltFillType(const TEdge &edge) const {
  1504. if (edge.PolyTyp == ptSubject)
  1505. return m_ClipFillType == pftEvenOdd;
  1506. else
  1507. return m_SubjFillType == pftEvenOdd;
  1508. }
  1509. //------------------------------------------------------------------------------
  1510. bool Clipper::IsContributing(const TEdge &edge) const {
  1511. PolyFillType pft, pft2;
  1512. if (edge.PolyTyp == ptSubject) {
  1513. pft = m_SubjFillType;
  1514. pft2 = m_ClipFillType;
  1515. } else {
  1516. pft = m_ClipFillType;
  1517. pft2 = m_SubjFillType;
  1518. }
  1519. switch (pft) {
  1520. case pftEvenOdd:
  1521. // return false if a subj line has been flagged as inside a subj polygon
  1522. if (edge.WindDelta == 0 && edge.WindCnt != 1)
  1523. return false;
  1524. break;
  1525. case pftNonZero:
  1526. if (Abs(edge.WindCnt) != 1)
  1527. return false;
  1528. break;
  1529. case pftPositive:
  1530. if (edge.WindCnt != 1)
  1531. return false;
  1532. break;
  1533. default: // pftNegative
  1534. if (edge.WindCnt != -1)
  1535. return false;
  1536. }
  1537. switch (m_ClipType) {
  1538. case ctIntersection:
  1539. switch (pft2) {
  1540. case pftEvenOdd:
  1541. case pftNonZero:
  1542. return (edge.WindCnt2 != 0);
  1543. case pftPositive:
  1544. return (edge.WindCnt2 > 0);
  1545. default:
  1546. return (edge.WindCnt2 < 0);
  1547. }
  1548. break;
  1549. case ctUnion:
  1550. switch (pft2) {
  1551. case pftEvenOdd:
  1552. case pftNonZero:
  1553. return (edge.WindCnt2 == 0);
  1554. case pftPositive:
  1555. return (edge.WindCnt2 <= 0);
  1556. default:
  1557. return (edge.WindCnt2 >= 0);
  1558. }
  1559. break;
  1560. case ctDifference:
  1561. if (edge.PolyTyp == ptSubject)
  1562. switch (pft2) {
  1563. case pftEvenOdd:
  1564. case pftNonZero:
  1565. return (edge.WindCnt2 == 0);
  1566. case pftPositive:
  1567. return (edge.WindCnt2 <= 0);
  1568. default:
  1569. return (edge.WindCnt2 >= 0);
  1570. }
  1571. else
  1572. switch (pft2) {
  1573. case pftEvenOdd:
  1574. case pftNonZero:
  1575. return (edge.WindCnt2 != 0);
  1576. case pftPositive:
  1577. return (edge.WindCnt2 > 0);
  1578. default:
  1579. return (edge.WindCnt2 < 0);
  1580. }
  1581. break;
  1582. case ctXor:
  1583. if (edge.WindDelta == 0) // XOr always contributing unless open
  1584. switch (pft2) {
  1585. case pftEvenOdd:
  1586. case pftNonZero:
  1587. return (edge.WindCnt2 == 0);
  1588. case pftPositive:
  1589. return (edge.WindCnt2 <= 0);
  1590. default:
  1591. return (edge.WindCnt2 >= 0);
  1592. }
  1593. else
  1594. return true;
  1595. break;
  1596. default:
  1597. return true;
  1598. }
  1599. }
  1600. //------------------------------------------------------------------------------
  1601. OutPt *Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) {
  1602. OutPt *result;
  1603. TEdge *e, *prevE;
  1604. if (IsHorizontal(*e2) || (e1->Dx > e2->Dx)) {
  1605. result = AddOutPt(e1, Pt);
  1606. e2->OutIdx = e1->OutIdx;
  1607. e1->Side = esLeft;
  1608. e2->Side = esRight;
  1609. e = e1;
  1610. if (e->PrevInAEL == e2)
  1611. prevE = e2->PrevInAEL;
  1612. else
  1613. prevE = e->PrevInAEL;
  1614. } else {
  1615. result = AddOutPt(e2, Pt);
  1616. e1->OutIdx = e2->OutIdx;
  1617. e1->Side = esRight;
  1618. e2->Side = esLeft;
  1619. e = e2;
  1620. if (e->PrevInAEL == e1)
  1621. prevE = e1->PrevInAEL;
  1622. else
  1623. prevE = e->PrevInAEL;
  1624. }
  1625. if (prevE && prevE->OutIdx >= 0 && prevE->Top.Y < Pt.Y && e->Top.Y < Pt.Y) {
  1626. cInt xPrev = TopX(*prevE, Pt.Y);
  1627. cInt xE = TopX(*e, Pt.Y);
  1628. if (xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0) &&
  1629. SlopesEqual(IntPoint(xPrev, Pt.Y), prevE->Top, IntPoint(xE, Pt.Y),
  1630. e->Top, m_UseFullRange)) {
  1631. OutPt *outPt = AddOutPt(prevE, Pt);
  1632. AddJoin(result, outPt, e->Top);
  1633. }
  1634. }
  1635. return result;
  1636. }
  1637. //------------------------------------------------------------------------------
  1638. void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) {
  1639. AddOutPt(e1, Pt);
  1640. if (e2->WindDelta == 0)
  1641. AddOutPt(e2, Pt);
  1642. if (e1->OutIdx == e2->OutIdx) {
  1643. e1->OutIdx = Unassigned;
  1644. e2->OutIdx = Unassigned;
  1645. } else if (e1->OutIdx < e2->OutIdx)
  1646. AppendPolygon(e1, e2);
  1647. else
  1648. AppendPolygon(e2, e1);
  1649. }
  1650. //------------------------------------------------------------------------------
  1651. void Clipper::AddEdgeToSEL(TEdge *edge) {
  1652. // SEL pointers in PEdge are reused to build a list of horizontal edges.
  1653. // However, we don't need to worry about order with horizontal edge
  1654. // processing.
  1655. if (!m_SortedEdges) {
  1656. m_SortedEdges = edge;
  1657. edge->PrevInSEL = 0;
  1658. edge->NextInSEL = 0;
  1659. } else {
  1660. edge->NextInSEL = m_SortedEdges;
  1661. edge->PrevInSEL = 0;
  1662. m_SortedEdges->PrevInSEL = edge;
  1663. m_SortedEdges = edge;
  1664. }
  1665. }
  1666. //------------------------------------------------------------------------------
  1667. bool Clipper::PopEdgeFromSEL(TEdge *&edge) {
  1668. if (!m_SortedEdges)
  1669. return false;
  1670. edge = m_SortedEdges;
  1671. DeleteFromSEL(m_SortedEdges);
  1672. return true;
  1673. }
  1674. //------------------------------------------------------------------------------
  1675. void Clipper::CopyAELToSEL() {
  1676. TEdge *e = m_ActiveEdges;
  1677. m_SortedEdges = e;
  1678. while (e) {
  1679. e->PrevInSEL = e->PrevInAEL;
  1680. e->NextInSEL = e->NextInAEL;
  1681. e = e->NextInAEL;
  1682. }
  1683. }
  1684. //------------------------------------------------------------------------------
  1685. void Clipper::AddJoin(OutPt *op1, OutPt *op2, const IntPoint OffPt) {
  1686. Join *j = new Join;
  1687. j->OutPt1 = op1;
  1688. j->OutPt2 = op2;
  1689. j->OffPt = OffPt;
  1690. m_Joins.push_back(j);
  1691. }
  1692. //------------------------------------------------------------------------------
  1693. void Clipper::ClearJoins() {
  1694. for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
  1695. delete m_Joins[i];
  1696. m_Joins.resize(0);
  1697. }
  1698. //------------------------------------------------------------------------------
  1699. void Clipper::ClearGhostJoins() {
  1700. for (JoinList::size_type i = 0; i < m_GhostJoins.size(); i++)
  1701. delete m_GhostJoins[i];
  1702. m_GhostJoins.resize(0);
  1703. }
  1704. //------------------------------------------------------------------------------
  1705. void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt) {
  1706. Join *j = new Join;
  1707. j->OutPt1 = op;
  1708. j->OutPt2 = 0;
  1709. j->OffPt = OffPt;
  1710. m_GhostJoins.push_back(j);
  1711. }
  1712. //------------------------------------------------------------------------------
  1713. void Clipper::InsertLocalMinimaIntoAEL(const cInt botY) {
  1714. const LocalMinimum *lm;
  1715. while (PopLocalMinima(botY, lm)) {
  1716. TEdge *lb = lm->LeftBound;
  1717. TEdge *rb = lm->RightBound;
  1718. OutPt *Op1 = 0;
  1719. if (!lb || !rb) {
  1720. // nb: don't insert LB into either AEL or SEL
  1721. InsertEdgeIntoAEL(rb, 0);
  1722. SetWindingCount(*rb);
  1723. if (IsContributing(*rb))
  1724. Op1 = AddOutPt(rb, rb->Bot);
  1725. //} else if (!rb) {
  1726. // InsertEdgeIntoAEL(lb, 0);
  1727. // SetWindingCount(*lb);
  1728. // if (IsContributing(*lb))
  1729. // Op1 = AddOutPt(lb, lb->Bot);
  1730. InsertScanbeam(lb->Top.Y);
  1731. } else {
  1732. InsertEdgeIntoAEL(lb, 0);
  1733. InsertEdgeIntoAEL(rb, lb);
  1734. SetWindingCount(*lb);
  1735. rb->WindCnt = lb->WindCnt;
  1736. rb->WindCnt2 = lb->WindCnt2;
  1737. if (IsContributing(*lb))
  1738. Op1 = AddLocalMinPoly(lb, rb, lb->Bot);
  1739. InsertScanbeam(lb->Top.Y);
  1740. }
  1741. if (rb) {
  1742. if (IsHorizontal(*rb)) {
  1743. AddEdgeToSEL(rb);
  1744. if (rb->NextInLML)
  1745. InsertScanbeam(rb->NextInLML->Top.Y);
  1746. } else
  1747. InsertScanbeam(rb->Top.Y);
  1748. }
  1749. if (!lb || !rb)
  1750. continue;
  1751. // if any output polygons share an edge, they'll need joining later ...
  1752. if (Op1 && IsHorizontal(*rb) && m_GhostJoins.size() > 0 &&
  1753. (rb->WindDelta != 0)) {
  1754. for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i) {
  1755. Join *jr = m_GhostJoins[i];
  1756. // if the horizontal Rb and a 'ghost' horizontal overlap, then convert
  1757. // the 'ghost' join to a real join ready for later ...
  1758. if (HorzSegmentsOverlap(jr->OutPt1->Pt.X, jr->OffPt.X, rb->Bot.X,
  1759. rb->Top.X))
  1760. AddJoin(jr->OutPt1, Op1, jr->OffPt);
  1761. }
  1762. }
  1763. if (lb->OutIdx >= 0 && lb->PrevInAEL &&
  1764. lb->PrevInAEL->Curr.X == lb->Bot.X && lb->PrevInAEL->OutIdx >= 0 &&
  1765. SlopesEqual(lb->PrevInAEL->Bot, lb->PrevInAEL->Top, lb->Curr, lb->Top,
  1766. m_UseFullRange) &&
  1767. (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0)) {
  1768. OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot);
  1769. AddJoin(Op1, Op2, lb->Top);
  1770. }
  1771. if (lb->NextInAEL != rb) {
  1772. if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 &&
  1773. SlopesEqual(rb->PrevInAEL->Curr, rb->PrevInAEL->Top, rb->Curr,
  1774. rb->Top, m_UseFullRange) &&
  1775. (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0)) {
  1776. OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot);
  1777. AddJoin(Op1, Op2, rb->Top);
  1778. }
  1779. TEdge *e = lb->NextInAEL;
  1780. if (e) {
  1781. while (e != rb) {
  1782. // nb: For calculating winding counts etc, IntersectEdges() assumes
  1783. // that param1 will be to the Right of param2 ABOVE the intersection
  1784. // ...
  1785. IntersectEdges(rb, e, lb->Curr); // order important here
  1786. e = e->NextInAEL;
  1787. }
  1788. }
  1789. }
  1790. }
  1791. }
  1792. //------------------------------------------------------------------------------
  1793. void Clipper::DeleteFromSEL(TEdge *e) {
  1794. TEdge *SelPrev = e->PrevInSEL;
  1795. TEdge *SelNext = e->NextInSEL;
  1796. if (!SelPrev && !SelNext && (e != m_SortedEdges))
  1797. return; // already deleted
  1798. if (SelPrev)
  1799. SelPrev->NextInSEL = SelNext;
  1800. else
  1801. m_SortedEdges = SelNext;
  1802. if (SelNext)
  1803. SelNext->PrevInSEL = SelPrev;
  1804. e->NextInSEL = 0;
  1805. e->PrevInSEL = 0;
  1806. }
  1807. //------------------------------------------------------------------------------
  1808. #ifdef use_xyz
  1809. void Clipper::SetZ(IntPoint &pt, TEdge &e1, TEdge &e2) {
  1810. if (pt.Z != 0 || !m_ZFill)
  1811. return;
  1812. else if (pt == e1.Bot)
  1813. pt.Z = e1.Bot.Z;
  1814. else if (pt == e1.Top)
  1815. pt.Z = e1.Top.Z;
  1816. else if (pt == e2.Bot)
  1817. pt.Z = e2.Bot.Z;
  1818. else if (pt == e2.Top)
  1819. pt.Z = e2.Top.Z;
  1820. else
  1821. (*m_ZFill)(e1.Bot, e1.Top, e2.Bot, e2.Top, pt);
  1822. }
  1823. //------------------------------------------------------------------------------
  1824. #endif
  1825. void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt) {
  1826. bool e1Contributing = (e1->OutIdx >= 0);
  1827. bool e2Contributing = (e2->OutIdx >= 0);
  1828. #ifdef use_xyz
  1829. SetZ(Pt, *e1, *e2);
  1830. #endif
  1831. #ifdef use_lines
  1832. // if either edge is on an OPEN path ...
  1833. if (e1->WindDelta == 0 || e2->WindDelta == 0) {
  1834. // ignore subject-subject open path intersections UNLESS they
  1835. // are both open paths, AND they are both 'contributing maximas' ...
  1836. if (e1->WindDelta == 0 && e2->WindDelta == 0)
  1837. return;
  1838. // if intersecting a subj line with a subj poly ...
  1839. else if (e1->PolyTyp == e2->PolyTyp && e1->WindDelta != e2->WindDelta &&
  1840. m_ClipType == ctUnion) {
  1841. if (e1->WindDelta == 0) {
  1842. if (e2Contributing) {
  1843. AddOutPt(e1, Pt);
  1844. if (e1Contributing)
  1845. e1->OutIdx = Unassigned;
  1846. }
  1847. } else {
  1848. if (e1Contributing) {
  1849. AddOutPt(e2, Pt);
  1850. if (e2Contributing)
  1851. e2->OutIdx = Unassigned;
  1852. }
  1853. }
  1854. } else if (e1->PolyTyp != e2->PolyTyp) {
  1855. // toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ...
  1856. if ((e1->WindDelta == 0) && abs(e2->WindCnt) == 1 &&
  1857. (m_ClipType != ctUnion || e2->WindCnt2 == 0)) {
  1858. AddOutPt(e1, Pt);
  1859. if (e1Contributing)
  1860. e1->OutIdx = Unassigned;
  1861. } else if ((e2->WindDelta == 0) && (abs(e1->WindCnt) == 1) &&
  1862. (m_ClipType != ctUnion || e1->WindCnt2 == 0)) {
  1863. AddOutPt(e2, Pt);
  1864. if (e2Contributing)
  1865. e2->OutIdx = Unassigned;
  1866. }
  1867. }
  1868. return;
  1869. }
  1870. #endif
  1871. // update winding counts...
  1872. // assumes that e1 will be to the Right of e2 ABOVE the intersection
  1873. if (e1->PolyTyp == e2->PolyTyp) {
  1874. if (IsEvenOddFillType(*e1)) {
  1875. int oldE1WindCnt = e1->WindCnt;
  1876. e1->WindCnt = e2->WindCnt;
  1877. e2->WindCnt = oldE1WindCnt;
  1878. } else {
  1879. if (e1->WindCnt + e2->WindDelta == 0)
  1880. e1->WindCnt = -e1->WindCnt;
  1881. else
  1882. e1->WindCnt += e2->WindDelta;
  1883. if (e2->WindCnt - e1->WindDelta == 0)
  1884. e2->WindCnt = -e2->WindCnt;
  1885. else
  1886. e2->WindCnt -= e1->WindDelta;
  1887. }
  1888. } else {
  1889. if (!IsEvenOddFillType(*e2))
  1890. e1->WindCnt2 += e2->WindDelta;
  1891. else
  1892. e1->WindCnt2 = (e1->WindCnt2 == 0) ? 1 : 0;
  1893. if (!IsEvenOddFillType(*e1))
  1894. e2->WindCnt2 -= e1->WindDelta;
  1895. else
  1896. e2->WindCnt2 = (e2->WindCnt2 == 0) ? 1 : 0;
  1897. }
  1898. PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
  1899. if (e1->PolyTyp == ptSubject) {
  1900. e1FillType = m_SubjFillType;
  1901. e1FillType2 = m_ClipFillType;
  1902. } else {
  1903. e1FillType = m_ClipFillType;
  1904. e1FillType2 = m_SubjFillType;
  1905. }
  1906. if (e2->PolyTyp == ptSubject) {
  1907. e2FillType = m_SubjFillType;
  1908. e2FillType2 = m_ClipFillType;
  1909. } else {
  1910. e2FillType = m_ClipFillType;
  1911. e2FillType2 = m_SubjFillType;
  1912. }
  1913. cInt e1Wc, e2Wc;
  1914. switch (e1FillType) {
  1915. case pftPositive:
  1916. e1Wc = e1->WindCnt;
  1917. break;
  1918. case pftNegative:
  1919. e1Wc = -e1->WindCnt;
  1920. break;
  1921. default:
  1922. e1Wc = Abs(e1->WindCnt);
  1923. }
  1924. switch (e2FillType) {
  1925. case pftPositive:
  1926. e2Wc = e2->WindCnt;
  1927. break;
  1928. case pftNegative:
  1929. e2Wc = -e2->WindCnt;
  1930. break;
  1931. default:
  1932. e2Wc = Abs(e2->WindCnt);
  1933. }
  1934. if (e1Contributing && e2Contributing) {
  1935. if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
  1936. (e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor)) {
  1937. AddLocalMaxPoly(e1, e2, Pt);
  1938. } else {
  1939. AddOutPt(e1, Pt);
  1940. AddOutPt(e2, Pt);
  1941. SwapSides(*e1, *e2);
  1942. SwapPolyIndexes(*e1, *e2);
  1943. }
  1944. } else if (e1Contributing) {
  1945. if (e2Wc == 0 || e2Wc == 1) {
  1946. AddOutPt(e1, Pt);
  1947. SwapSides(*e1, *e2);
  1948. SwapPolyIndexes(*e1, *e2);
  1949. }
  1950. } else if (e2Contributing) {
  1951. if (e1Wc == 0 || e1Wc == 1) {
  1952. AddOutPt(e2, Pt);
  1953. SwapSides(*e1, *e2);
  1954. SwapPolyIndexes(*e1, *e2);
  1955. }
  1956. } else if ((e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1)) {
  1957. // neither edge is currently contributing ...
  1958. cInt e1Wc2, e2Wc2;
  1959. switch (e1FillType2) {
  1960. case pftPositive:
  1961. e1Wc2 = e1->WindCnt2;
  1962. break;
  1963. case pftNegative:
  1964. e1Wc2 = -e1->WindCnt2;
  1965. break;
  1966. default:
  1967. e1Wc2 = Abs(e1->WindCnt2);
  1968. }
  1969. switch (e2FillType2) {
  1970. case pftPositive:
  1971. e2Wc2 = e2->WindCnt2;
  1972. break;
  1973. case pftNegative:
  1974. e2Wc2 = -e2->WindCnt2;
  1975. break;
  1976. default:
  1977. e2Wc2 = Abs(e2->WindCnt2);
  1978. }
  1979. if (e1->PolyTyp != e2->PolyTyp) {
  1980. AddLocalMinPoly(e1, e2, Pt);
  1981. } else if (e1Wc == 1 && e2Wc == 1)
  1982. switch (m_ClipType) {
  1983. case ctIntersection:
  1984. if (e1Wc2 > 0 && e2Wc2 > 0)
  1985. AddLocalMinPoly(e1, e2, Pt);
  1986. break;
  1987. case ctUnion:
  1988. if (e1Wc2 <= 0 && e2Wc2 <= 0)
  1989. AddLocalMinPoly(e1, e2, Pt);
  1990. break;
  1991. case ctDifference:
  1992. if (((e1->PolyTyp == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
  1993. ((e1->PolyTyp == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
  1994. AddLocalMinPoly(e1, e2, Pt);
  1995. break;
  1996. case ctXor:
  1997. AddLocalMinPoly(e1, e2, Pt);
  1998. }
  1999. else
  2000. SwapSides(*e1, *e2);
  2001. }
  2002. }
  2003. //------------------------------------------------------------------------------
  2004. void Clipper::SetHoleState(TEdge *e, OutRec *outrec) {
  2005. TEdge *e2 = e->PrevInAEL;
  2006. TEdge *eTmp = 0;
  2007. while (e2) {
  2008. if (e2->OutIdx >= 0 && e2->WindDelta != 0) {
  2009. if (!eTmp)
  2010. eTmp = e2;
  2011. else if (eTmp->OutIdx == e2->OutIdx)
  2012. eTmp = 0;
  2013. }
  2014. e2 = e2->PrevInAEL;
  2015. }
  2016. if (!eTmp) {
  2017. outrec->FirstLeft = 0;
  2018. outrec->IsHole = false;
  2019. } else {
  2020. outrec->FirstLeft = m_PolyOuts[eTmp->OutIdx];
  2021. outrec->IsHole = !outrec->FirstLeft->IsHole;
  2022. }
  2023. }
  2024. //------------------------------------------------------------------------------
  2025. OutRec *GetLowermostRec(OutRec *outRec1, OutRec *outRec2) {
  2026. // work out which polygon fragment has the correct hole state ...
  2027. if (!outRec1->BottomPt)
  2028. outRec1->BottomPt = GetBottomPt(outRec1->Pts);
  2029. if (!outRec2->BottomPt)
  2030. outRec2->BottomPt = GetBottomPt(outRec2->Pts);
  2031. OutPt *OutPt1 = outRec1->BottomPt;
  2032. OutPt *OutPt2 = outRec2->BottomPt;
  2033. if (OutPt1->Pt.Y > OutPt2->Pt.Y)
  2034. return outRec1;
  2035. else if (OutPt1->Pt.Y < OutPt2->Pt.Y)
  2036. return outRec2;
  2037. else if (OutPt1->Pt.X < OutPt2->Pt.X)
  2038. return outRec1;
  2039. else if (OutPt1->Pt.X > OutPt2->Pt.X)
  2040. return outRec2;
  2041. else if (OutPt1->Next == OutPt1)
  2042. return outRec2;
  2043. else if (OutPt2->Next == OutPt2)
  2044. return outRec1;
  2045. else if (FirstIsBottomPt(OutPt1, OutPt2))
  2046. return outRec1;
  2047. else
  2048. return outRec2;
  2049. }
  2050. //------------------------------------------------------------------------------
  2051. bool OutRec1RightOfOutRec2(OutRec *outRec1, OutRec *outRec2) {
  2052. do {
  2053. outRec1 = outRec1->FirstLeft;
  2054. if (outRec1 == outRec2)
  2055. return true;
  2056. } while (outRec1);
  2057. return false;
  2058. }
  2059. //------------------------------------------------------------------------------
  2060. OutRec *Clipper::GetOutRec(int Idx) {
  2061. OutRec *outrec = m_PolyOuts[Idx];
  2062. while (outrec != m_PolyOuts[outrec->Idx])
  2063. outrec = m_PolyOuts[outrec->Idx];
  2064. return outrec;
  2065. }
  2066. //------------------------------------------------------------------------------
  2067. void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) {
  2068. // get the start and ends of both output polygons ...
  2069. OutRec *outRec1 = m_PolyOuts[e1->OutIdx];
  2070. OutRec *outRec2 = m_PolyOuts[e2->OutIdx];
  2071. OutRec *holeStateRec;
  2072. if (OutRec1RightOfOutRec2(outRec1, outRec2))
  2073. holeStateRec = outRec2;
  2074. else if (OutRec1RightOfOutRec2(outRec2, outRec1))
  2075. holeStateRec = outRec1;
  2076. else
  2077. holeStateRec = GetLowermostRec(outRec1, outRec2);
  2078. // get the start and ends of both output polygons and
  2079. // join e2 poly onto e1 poly and delete pointers to e2 ...
  2080. OutPt *p1_lft = outRec1->Pts;
  2081. OutPt *p1_rt = p1_lft->Prev;
  2082. OutPt *p2_lft = outRec2->Pts;
  2083. OutPt *p2_rt = p2_lft->Prev;
  2084. // join e2 poly onto e1 poly and delete pointers to e2 ...
  2085. if (e1->Side == esLeft) {
  2086. if (e2->Side == esLeft) {
  2087. // z y x a b c
  2088. ReversePolyPtLinks(p2_lft);
  2089. p2_lft->Next = p1_lft;
  2090. p1_lft->Prev = p2_lft;
  2091. p1_rt->Next = p2_rt;
  2092. p2_rt->Prev = p1_rt;
  2093. outRec1->Pts = p2_rt;
  2094. } else {
  2095. // x y z a b c
  2096. p2_rt->Next = p1_lft;
  2097. p1_lft->Prev = p2_rt;
  2098. p2_lft->Prev = p1_rt;
  2099. p1_rt->Next = p2_lft;
  2100. outRec1->Pts = p2_lft;
  2101. }
  2102. } else {
  2103. if (e2->Side == esRight) {
  2104. // a b c z y x
  2105. ReversePolyPtLinks(p2_lft);
  2106. p1_rt->Next = p2_rt;
  2107. p2_rt->Prev = p1_rt;
  2108. p2_lft->Next = p1_lft;
  2109. p1_lft->Prev = p2_lft;
  2110. } else {
  2111. // a b c x y z
  2112. p1_rt->Next = p2_lft;
  2113. p2_lft->Prev = p1_rt;
  2114. p1_lft->Prev = p2_rt;
  2115. p2_rt->Next = p1_lft;
  2116. }
  2117. }
  2118. outRec1->BottomPt = 0;
  2119. if (holeStateRec == outRec2) {
  2120. if (outRec2->FirstLeft != outRec1)
  2121. outRec1->FirstLeft = outRec2->FirstLeft;
  2122. outRec1->IsHole = outRec2->IsHole;
  2123. }
  2124. outRec2->Pts = 0;
  2125. outRec2->BottomPt = 0;
  2126. outRec2->FirstLeft = outRec1;
  2127. int OKIdx = e1->OutIdx;
  2128. int ObsoleteIdx = e2->OutIdx;
  2129. e1->OutIdx =
  2130. Unassigned; // nb: safe because we only get here via AddLocalMaxPoly
  2131. e2->OutIdx = Unassigned;
  2132. TEdge *e = m_ActiveEdges;
  2133. while (e) {
  2134. if (e->OutIdx == ObsoleteIdx) {
  2135. e->OutIdx = OKIdx;
  2136. e->Side = e1->Side;
  2137. break;
  2138. }
  2139. e = e->NextInAEL;
  2140. }
  2141. outRec2->Idx = outRec1->Idx;
  2142. }
  2143. //------------------------------------------------------------------------------
  2144. OutPt *Clipper::AddOutPt(TEdge *e, const IntPoint &pt) {
  2145. if (e->OutIdx < 0) {
  2146. OutRec *outRec = CreateOutRec();
  2147. outRec->IsOpen = (e->WindDelta == 0);
  2148. OutPt *newOp = new OutPt;
  2149. outRec->Pts = newOp;
  2150. newOp->Idx = outRec->Idx;
  2151. newOp->Pt = pt;
  2152. newOp->Next = newOp;
  2153. newOp->Prev = newOp;
  2154. if (!outRec->IsOpen)
  2155. SetHoleState(e, outRec);
  2156. e->OutIdx = outRec->Idx;
  2157. return newOp;
  2158. } else {
  2159. OutRec *outRec = m_PolyOuts[e->OutIdx];
  2160. // OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most'
  2161. OutPt *op = outRec->Pts;
  2162. bool ToFront = (e->Side == esLeft);
  2163. if (ToFront && (pt == op->Pt))
  2164. return op;
  2165. else if (!ToFront && (pt == op->Prev->Pt))
  2166. return op->Prev;
  2167. OutPt *newOp = new OutPt;
  2168. newOp->Idx = outRec->Idx;
  2169. newOp->Pt = pt;
  2170. newOp->Next = op;
  2171. newOp->Prev = op->Prev;
  2172. newOp->Prev->Next = newOp;
  2173. op->Prev = newOp;
  2174. if (ToFront)
  2175. outRec->Pts = newOp;
  2176. return newOp;
  2177. }
  2178. }
  2179. //------------------------------------------------------------------------------
  2180. OutPt *Clipper::GetLastOutPt(TEdge *e) {
  2181. OutRec *outRec = m_PolyOuts[e->OutIdx];
  2182. if (e->Side == esLeft)
  2183. return outRec->Pts;
  2184. else
  2185. return outRec->Pts->Prev;
  2186. }
  2187. //------------------------------------------------------------------------------
  2188. void Clipper::ProcessHorizontals() {
  2189. TEdge *horzEdge;
  2190. while (PopEdgeFromSEL(horzEdge))
  2191. ProcessHorizontal(horzEdge);
  2192. }
  2193. //------------------------------------------------------------------------------
  2194. inline bool IsMinima(TEdge *e) {
  2195. return e && (e->Prev->NextInLML != e) && (e->Next->NextInLML != e);
  2196. }
  2197. //------------------------------------------------------------------------------
  2198. inline bool IsMaxima(TEdge *e, const cInt Y) {
  2199. return e && e->Top.Y == Y && !e->NextInLML;
  2200. }
  2201. //------------------------------------------------------------------------------
  2202. inline bool IsIntermediate(TEdge *e, const cInt Y) {
  2203. return e->Top.Y == Y && e->NextInLML;
  2204. }
  2205. //------------------------------------------------------------------------------
  2206. TEdge *GetMaximaPair(TEdge *e) {
  2207. if ((e->Next->Top == e->Top) && !e->Next->NextInLML)
  2208. return e->Next;
  2209. else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML)
  2210. return e->Prev;
  2211. else
  2212. return 0;
  2213. }
  2214. //------------------------------------------------------------------------------
  2215. TEdge *GetMaximaPairEx(TEdge *e) {
  2216. // as GetMaximaPair() but returns 0 if MaxPair isn't in AEL (unless it's
  2217. // horizontal)
  2218. TEdge *result = GetMaximaPair(e);
  2219. if (result &&
  2220. (result->OutIdx == Skip ||
  2221. (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result))))
  2222. return 0;
  2223. return result;
  2224. }
  2225. //------------------------------------------------------------------------------
  2226. void Clipper::SwapPositionsInSEL(TEdge *Edge1, TEdge *Edge2) {
  2227. if (!(Edge1->NextInSEL) && !(Edge1->PrevInSEL))
  2228. return;
  2229. if (!(Edge2->NextInSEL) && !(Edge2->PrevInSEL))
  2230. return;
  2231. if (Edge1->NextInSEL == Edge2) {
  2232. TEdge *Next = Edge2->NextInSEL;
  2233. if (Next)
  2234. Next->PrevInSEL = Edge1;
  2235. TEdge *Prev = Edge1->PrevInSEL;
  2236. if (Prev)
  2237. Prev->NextInSEL = Edge2;
  2238. Edge2->PrevInSEL = Prev;
  2239. Edge2->NextInSEL = Edge1;
  2240. Edge1->PrevInSEL = Edge2;
  2241. Edge1->NextInSEL = Next;
  2242. } else if (Edge2->NextInSEL == Edge1) {
  2243. TEdge *Next = Edge1->NextInSEL;
  2244. if (Next)
  2245. Next->PrevInSEL = Edge2;
  2246. TEdge *Prev = Edge2->PrevInSEL;
  2247. if (Prev)
  2248. Prev->NextInSEL = Edge1;
  2249. Edge1->PrevInSEL = Prev;
  2250. Edge1->NextInSEL = Edge2;
  2251. Edge2->PrevInSEL = Edge1;
  2252. Edge2->NextInSEL = Next;
  2253. } else {
  2254. TEdge *Next = Edge1->NextInSEL;
  2255. TEdge *Prev = Edge1->PrevInSEL;
  2256. Edge1->NextInSEL = Edge2->NextInSEL;
  2257. if (Edge1->NextInSEL)
  2258. Edge1->NextInSEL->PrevInSEL = Edge1;
  2259. Edge1->PrevInSEL = Edge2->PrevInSEL;
  2260. if (Edge1->PrevInSEL)
  2261. Edge1->PrevInSEL->NextInSEL = Edge1;
  2262. Edge2->NextInSEL = Next;
  2263. if (Edge2->NextInSEL)
  2264. Edge2->NextInSEL->PrevInSEL = Edge2;
  2265. Edge2->PrevInSEL = Prev;
  2266. if (Edge2->PrevInSEL)
  2267. Edge2->PrevInSEL->NextInSEL = Edge2;
  2268. }
  2269. if (!Edge1->PrevInSEL)
  2270. m_SortedEdges = Edge1;
  2271. else if (!Edge2->PrevInSEL)
  2272. m_SortedEdges = Edge2;
  2273. }
  2274. //------------------------------------------------------------------------------
  2275. TEdge *GetNextInAEL(TEdge *e, Direction dir) {
  2276. return dir == dLeftToRight ? e->NextInAEL : e->PrevInAEL;
  2277. }
  2278. //------------------------------------------------------------------------------
  2279. void GetHorzDirection(TEdge &HorzEdge, Direction &Dir, cInt &Left,
  2280. cInt &Right) {
  2281. if (HorzEdge.Bot.X < HorzEdge.Top.X) {
  2282. Left = HorzEdge.Bot.X;
  2283. Right = HorzEdge.Top.X;
  2284. Dir = dLeftToRight;
  2285. } else {
  2286. Left = HorzEdge.Top.X;
  2287. Right = HorzEdge.Bot.X;
  2288. Dir = dRightToLeft;
  2289. }
  2290. }
  2291. //------------------------------------------------------------------------
  2292. /*******************************************************************************
  2293. * Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or *
  2294. * Bottom of a scanbeam) are processed as if layered. The order in which HEs *
  2295. * are processed doesn't matter. HEs intersect with other HE Bot.Xs only [#] *
  2296. * (or they could intersect with Top.Xs only, ie EITHER Bot.Xs OR Top.Xs), * and
  2297. *with other non-horizontal edges [*]. Once these intersections are *
  2298. * processed, intermediate HEs then 'promote' the Edge above (NextInLML) into *
  2299. * the AEL. These 'promoted' edges may in turn intersect [%] with other HEs. *
  2300. *******************************************************************************/
  2301. void Clipper::ProcessHorizontal(TEdge *horzEdge) {
  2302. Direction dir;
  2303. cInt horzLeft, horzRight;
  2304. bool IsOpen = (horzEdge->WindDelta == 0);
  2305. GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
  2306. TEdge *eLastHorz = horzEdge, *eMaxPair = 0;
  2307. while (eLastHorz->NextInLML && IsHorizontal(*eLastHorz->NextInLML))
  2308. eLastHorz = eLastHorz->NextInLML;
  2309. if (!eLastHorz->NextInLML)
  2310. eMaxPair = GetMaximaPair(eLastHorz);
  2311. MaximaList::const_iterator maxIt;
  2312. MaximaList::const_reverse_iterator maxRit;
  2313. if (m_Maxima.size() > 0) {
  2314. // get the first maxima in range (X) ...
  2315. if (dir == dLeftToRight) {
  2316. maxIt = m_Maxima.begin();
  2317. while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.X)
  2318. ++maxIt;
  2319. if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.X)
  2320. maxIt = m_Maxima.end();
  2321. } else {
  2322. maxRit = m_Maxima.rbegin();
  2323. while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.X)
  2324. ++maxRit;
  2325. if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.X)
  2326. maxRit = m_Maxima.rend();
  2327. }
  2328. }
  2329. OutPt *op1 = 0;
  2330. for (;;) // loop through consec. horizontal edges
  2331. {
  2332. bool IsLastHorz = (horzEdge == eLastHorz);
  2333. TEdge *e = GetNextInAEL(horzEdge, dir);
  2334. while (e) {
  2335. // this code block inserts extra coords into horizontal edges (in output
  2336. // polygons) wherever maxima touch these horizontal edges. This helps
  2337. //'simplifying' polygons (ie if the Simplify property is set).
  2338. if (m_Maxima.size() > 0) {
  2339. if (dir == dLeftToRight) {
  2340. while (maxIt != m_Maxima.end() && *maxIt < e->Curr.X) {
  2341. if (horzEdge->OutIdx >= 0 && !IsOpen)
  2342. AddOutPt(horzEdge, IntPoint(*maxIt, horzEdge->Bot.Y));
  2343. ++maxIt;
  2344. }
  2345. } else {
  2346. while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.X) {
  2347. if (horzEdge->OutIdx >= 0 && !IsOpen)
  2348. AddOutPt(horzEdge, IntPoint(*maxRit, horzEdge->Bot.Y));
  2349. ++maxRit;
  2350. }
  2351. }
  2352. };
  2353. if ((dir == dLeftToRight && e->Curr.X > horzRight) ||
  2354. (dir == dRightToLeft && e->Curr.X < horzLeft))
  2355. break;
  2356. // Also break if we've got to the end of an intermediate horizontal edge
  2357. // ...
  2358. // nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
  2359. if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML &&
  2360. e->Dx < horzEdge->NextInLML->Dx)
  2361. break;
  2362. if (horzEdge->OutIdx >= 0 && !IsOpen) // note: may be done multiple times
  2363. {
  2364. #ifdef use_xyz
  2365. if (dir == dLeftToRight)
  2366. SetZ(e->Curr, *horzEdge, *e);
  2367. else
  2368. SetZ(e->Curr, *e, *horzEdge);
  2369. #endif
  2370. op1 = AddOutPt(horzEdge, e->Curr);
  2371. TEdge *eNextHorz = m_SortedEdges;
  2372. while (eNextHorz) {
  2373. if (eNextHorz->OutIdx >= 0 &&
  2374. HorzSegmentsOverlap(horzEdge->Bot.X, horzEdge->Top.X,
  2375. eNextHorz->Bot.X, eNextHorz->Top.X)) {
  2376. OutPt *op2 = GetLastOutPt(eNextHorz);
  2377. AddJoin(op2, op1, eNextHorz->Top);
  2378. }
  2379. eNextHorz = eNextHorz->NextInSEL;
  2380. }
  2381. AddGhostJoin(op1, horzEdge->Bot);
  2382. }
  2383. // OK, so far we're still in range of the horizontal Edge but make sure
  2384. // we're at the last of consec. horizontals when matching with eMaxPair
  2385. if (e == eMaxPair && IsLastHorz) {
  2386. if (horzEdge->OutIdx >= 0)
  2387. AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top);
  2388. DeleteFromAEL(horzEdge);
  2389. DeleteFromAEL(eMaxPair);
  2390. return;
  2391. }
  2392. if (dir == dLeftToRight) {
  2393. IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
  2394. IntersectEdges(horzEdge, e, Pt);
  2395. } else {
  2396. IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
  2397. IntersectEdges(e, horzEdge, Pt);
  2398. }
  2399. TEdge *eNext = GetNextInAEL(e, dir);
  2400. SwapPositionsInAEL(horzEdge, e);
  2401. e = eNext;
  2402. } // end while(e)
  2403. // Break out of loop if HorzEdge.NextInLML is not also horizontal ...
  2404. if (!horzEdge->NextInLML || !IsHorizontal(*horzEdge->NextInLML))
  2405. break;
  2406. UpdateEdgeIntoAEL(horzEdge);
  2407. if (horzEdge->OutIdx >= 0)
  2408. AddOutPt(horzEdge, horzEdge->Bot);
  2409. GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
  2410. } // end for (;;)
  2411. if (horzEdge->OutIdx >= 0 && !op1) {
  2412. op1 = GetLastOutPt(horzEdge);
  2413. TEdge *eNextHorz = m_SortedEdges;
  2414. while (eNextHorz) {
  2415. if (eNextHorz->OutIdx >= 0 &&
  2416. HorzSegmentsOverlap(horzEdge->Bot.X, horzEdge->Top.X,
  2417. eNextHorz->Bot.X, eNextHorz->Top.X)) {
  2418. OutPt *op2 = GetLastOutPt(eNextHorz);
  2419. AddJoin(op2, op1, eNextHorz->Top);
  2420. }
  2421. eNextHorz = eNextHorz->NextInSEL;
  2422. }
  2423. AddGhostJoin(op1, horzEdge->Top);
  2424. }
  2425. if (horzEdge->NextInLML) {
  2426. if (horzEdge->OutIdx >= 0) {
  2427. op1 = AddOutPt(horzEdge, horzEdge->Top);
  2428. UpdateEdgeIntoAEL(horzEdge);
  2429. if (horzEdge->WindDelta == 0)
  2430. return;
  2431. // nb: HorzEdge is no longer horizontal here
  2432. TEdge *ePrev = horzEdge->PrevInAEL;
  2433. TEdge *eNext = horzEdge->NextInAEL;
  2434. if (ePrev && ePrev->Curr.X == horzEdge->Bot.X &&
  2435. ePrev->Curr.Y == horzEdge->Bot.Y && ePrev->WindDelta != 0 &&
  2436. (ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
  2437. SlopesEqual(*horzEdge, *ePrev, m_UseFullRange))) {
  2438. OutPt *op2 = AddOutPt(ePrev, horzEdge->Bot);
  2439. AddJoin(op1, op2, horzEdge->Top);
  2440. } else if (eNext && eNext->Curr.X == horzEdge->Bot.X &&
  2441. eNext->Curr.Y == horzEdge->Bot.Y && eNext->WindDelta != 0 &&
  2442. eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y &&
  2443. SlopesEqual(*horzEdge, *eNext, m_UseFullRange)) {
  2444. OutPt *op2 = AddOutPt(eNext, horzEdge->Bot);
  2445. AddJoin(op1, op2, horzEdge->Top);
  2446. }
  2447. } else
  2448. UpdateEdgeIntoAEL(horzEdge);
  2449. } else {
  2450. if (horzEdge->OutIdx >= 0)
  2451. AddOutPt(horzEdge, horzEdge->Top);
  2452. DeleteFromAEL(horzEdge);
  2453. }
  2454. }
  2455. //------------------------------------------------------------------------------
  2456. bool Clipper::ProcessIntersections(const cInt topY) {
  2457. if (!m_ActiveEdges)
  2458. return true;
  2459. try {
  2460. BuildIntersectList(topY);
  2461. size_t IlSize = m_IntersectList.size();
  2462. if (IlSize == 0)
  2463. return true;
  2464. if (IlSize == 1 || FixupIntersectionOrder())
  2465. ProcessIntersectList();
  2466. else
  2467. return false;
  2468. } catch (...) {
  2469. m_SortedEdges = 0;
  2470. DisposeIntersectNodes();
  2471. throw clipperException("ProcessIntersections error");
  2472. }
  2473. m_SortedEdges = 0;
  2474. return true;
  2475. }
  2476. //------------------------------------------------------------------------------
  2477. void Clipper::DisposeIntersectNodes() {
  2478. for (size_t i = 0; i < m_IntersectList.size(); ++i)
  2479. delete m_IntersectList[i];
  2480. m_IntersectList.clear();
  2481. }
  2482. //------------------------------------------------------------------------------
  2483. void Clipper::BuildIntersectList(const cInt topY) {
  2484. if (!m_ActiveEdges)
  2485. return;
  2486. // prepare for sorting ...
  2487. TEdge *e = m_ActiveEdges;
  2488. m_SortedEdges = e;
  2489. while (e) {
  2490. e->PrevInSEL = e->PrevInAEL;
  2491. e->NextInSEL = e->NextInAEL;
  2492. e->Curr.X = TopX(*e, topY);
  2493. e = e->NextInAEL;
  2494. }
  2495. // bubblesort ...
  2496. bool isModified;
  2497. do {
  2498. isModified = false;
  2499. e = m_SortedEdges;
  2500. while (e->NextInSEL) {
  2501. TEdge *eNext = e->NextInSEL;
  2502. IntPoint Pt;
  2503. if (e->Curr.X > eNext->Curr.X) {
  2504. IntersectPoint(*e, *eNext, Pt);
  2505. if (Pt.Y < topY)
  2506. Pt = IntPoint(TopX(*e, topY), topY);
  2507. IntersectNode *newNode = new IntersectNode;
  2508. newNode->Edge1 = e;
  2509. newNode->Edge2 = eNext;
  2510. newNode->Pt = Pt;
  2511. m_IntersectList.push_back(newNode);
  2512. SwapPositionsInSEL(e, eNext);
  2513. isModified = true;
  2514. } else
  2515. e = eNext;
  2516. }
  2517. if (e->PrevInSEL)
  2518. e->PrevInSEL->NextInSEL = 0;
  2519. else
  2520. break;
  2521. } while (isModified);
  2522. m_SortedEdges = 0; // important
  2523. }
  2524. //------------------------------------------------------------------------------
  2525. void Clipper::ProcessIntersectList() {
  2526. for (size_t i = 0; i < m_IntersectList.size(); ++i) {
  2527. IntersectNode *iNode = m_IntersectList[i];
  2528. {
  2529. IntersectEdges(iNode->Edge1, iNode->Edge2, iNode->Pt);
  2530. SwapPositionsInAEL(iNode->Edge1, iNode->Edge2);
  2531. }
  2532. delete iNode;
  2533. }
  2534. m_IntersectList.clear();
  2535. }
  2536. //------------------------------------------------------------------------------
  2537. bool IntersectListSort(IntersectNode *node1, IntersectNode *node2) {
  2538. return node2->Pt.Y < node1->Pt.Y;
  2539. }
  2540. //------------------------------------------------------------------------------
  2541. inline bool EdgesAdjacent(const IntersectNode &inode) {
  2542. return (inode.Edge1->NextInSEL == inode.Edge2) ||
  2543. (inode.Edge1->PrevInSEL == inode.Edge2);
  2544. }
  2545. //------------------------------------------------------------------------------
  2546. bool Clipper::FixupIntersectionOrder() {
  2547. // pre-condition: intersections are sorted Bottom-most first.
  2548. // Now it's crucial that intersections are made only between adjacent edges,
  2549. // so to ensure this the order of intersections may need adjusting ...
  2550. CopyAELToSEL();
  2551. std::sort(m_IntersectList.begin(), m_IntersectList.end(), IntersectListSort);
  2552. size_t cnt = m_IntersectList.size();
  2553. for (size_t i = 0; i < cnt; ++i) {
  2554. if (!EdgesAdjacent(*m_IntersectList[i])) {
  2555. size_t j = i + 1;
  2556. while (j < cnt && !EdgesAdjacent(*m_IntersectList[j]))
  2557. j++;
  2558. if (j == cnt)
  2559. return false;
  2560. std::swap(m_IntersectList[i], m_IntersectList[j]);
  2561. }
  2562. SwapPositionsInSEL(m_IntersectList[i]->Edge1, m_IntersectList[i]->Edge2);
  2563. }
  2564. return true;
  2565. }
  2566. //------------------------------------------------------------------------------
  2567. void Clipper::DoMaxima(TEdge *e) {
  2568. TEdge *eMaxPair = GetMaximaPairEx(e);
  2569. if (!eMaxPair) {
  2570. if (e->OutIdx >= 0)
  2571. AddOutPt(e, e->Top);
  2572. DeleteFromAEL(e);
  2573. return;
  2574. }
  2575. TEdge *eNext = e->NextInAEL;
  2576. while (eNext && eNext != eMaxPair) {
  2577. IntersectEdges(e, eNext, e->Top);
  2578. SwapPositionsInAEL(e, eNext);
  2579. eNext = e->NextInAEL;
  2580. }
  2581. if (e->OutIdx == Unassigned && eMaxPair->OutIdx == Unassigned) {
  2582. DeleteFromAEL(e);
  2583. DeleteFromAEL(eMaxPair);
  2584. } else if (e->OutIdx >= 0 && eMaxPair->OutIdx >= 0) {
  2585. if (e->OutIdx >= 0)
  2586. AddLocalMaxPoly(e, eMaxPair, e->Top);
  2587. DeleteFromAEL(e);
  2588. DeleteFromAEL(eMaxPair);
  2589. }
  2590. #ifdef use_lines
  2591. else if (e->WindDelta == 0) {
  2592. if (e->OutIdx >= 0) {
  2593. AddOutPt(e, e->Top);
  2594. e->OutIdx = Unassigned;
  2595. }
  2596. DeleteFromAEL(e);
  2597. if (eMaxPair->OutIdx >= 0) {
  2598. AddOutPt(eMaxPair, e->Top);
  2599. eMaxPair->OutIdx = Unassigned;
  2600. }
  2601. DeleteFromAEL(eMaxPair);
  2602. }
  2603. #endif
  2604. else
  2605. throw clipperException("DoMaxima error");
  2606. }
  2607. //------------------------------------------------------------------------------
  2608. void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY) {
  2609. TEdge *e = m_ActiveEdges;
  2610. while (e) {
  2611. // 1. process maxima, treating them as if they're 'bent' horizontal edges,
  2612. // but exclude maxima with horizontal edges. nb: e can't be a horizontal.
  2613. bool IsMaximaEdge = IsMaxima(e, topY);
  2614. if (IsMaximaEdge) {
  2615. TEdge *eMaxPair = GetMaximaPairEx(e);
  2616. IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair));
  2617. }
  2618. if (IsMaximaEdge) {
  2619. if (m_StrictSimple)
  2620. m_Maxima.push_back(e->Top.X);
  2621. TEdge *ePrev = e->PrevInAEL;
  2622. DoMaxima(e);
  2623. if (!ePrev)
  2624. e = m_ActiveEdges;
  2625. else
  2626. e = ePrev->NextInAEL;
  2627. } else {
  2628. // 2. promote horizontal edges, otherwise update Curr.X and Curr.Y ...
  2629. if (IsIntermediate(e, topY) && IsHorizontal(*e->NextInLML)) {
  2630. UpdateEdgeIntoAEL(e);
  2631. if (e->OutIdx >= 0)
  2632. AddOutPt(e, e->Bot);
  2633. AddEdgeToSEL(e);
  2634. } else {
  2635. e->Curr.X = TopX(*e, topY);
  2636. e->Curr.Y = topY;
  2637. #ifdef use_xyz
  2638. e->Curr.Z =
  2639. topY == e->Top.Y ? e->Top.Z : (topY == e->Bot.Y ? e->Bot.Z : 0);
  2640. #endif
  2641. }
  2642. // When StrictlySimple and 'e' is being touched by another edge, then
  2643. // make sure both edges have a vertex here ...
  2644. if (m_StrictSimple) {
  2645. TEdge *ePrev = e->PrevInAEL;
  2646. if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev &&
  2647. (ePrev->OutIdx >= 0) && (ePrev->Curr.X == e->Curr.X) &&
  2648. (ePrev->WindDelta != 0)) {
  2649. IntPoint pt = e->Curr;
  2650. #ifdef use_xyz
  2651. SetZ(pt, *ePrev, *e);
  2652. #endif
  2653. OutPt *op = AddOutPt(ePrev, pt);
  2654. OutPt *op2 = AddOutPt(e, pt);
  2655. AddJoin(op, op2, pt); // StrictlySimple (type-3) join
  2656. }
  2657. }
  2658. e = e->NextInAEL;
  2659. }
  2660. }
  2661. // 3. Process horizontals at the Top of the scanbeam ...
  2662. m_Maxima.sort();
  2663. ProcessHorizontals();
  2664. m_Maxima.clear();
  2665. // 4. Promote intermediate vertices ...
  2666. e = m_ActiveEdges;
  2667. while (e) {
  2668. if (IsIntermediate(e, topY)) {
  2669. OutPt *op = 0;
  2670. if (e->OutIdx >= 0)
  2671. op = AddOutPt(e, e->Top);
  2672. UpdateEdgeIntoAEL(e);
  2673. // if output polygons share an edge, they'll need joining later ...
  2674. TEdge *ePrev = e->PrevInAEL;
  2675. TEdge *eNext = e->NextInAEL;
  2676. if (ePrev && ePrev->Curr.X == e->Bot.X && ePrev->Curr.Y == e->Bot.Y &&
  2677. op && ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
  2678. SlopesEqual(e->Curr, e->Top, ePrev->Curr, ePrev->Top,
  2679. m_UseFullRange) &&
  2680. (e->WindDelta != 0) && (ePrev->WindDelta != 0)) {
  2681. OutPt *op2 = AddOutPt(ePrev, e->Bot);
  2682. AddJoin(op, op2, e->Top);
  2683. } else if (eNext && eNext->Curr.X == e->Bot.X &&
  2684. eNext->Curr.Y == e->Bot.Y && op && eNext->OutIdx >= 0 &&
  2685. eNext->Curr.Y > eNext->Top.Y &&
  2686. SlopesEqual(e->Curr, e->Top, eNext->Curr, eNext->Top,
  2687. m_UseFullRange) &&
  2688. (e->WindDelta != 0) && (eNext->WindDelta != 0)) {
  2689. OutPt *op2 = AddOutPt(eNext, e->Bot);
  2690. AddJoin(op, op2, e->Top);
  2691. }
  2692. }
  2693. e = e->NextInAEL;
  2694. }
  2695. }
  2696. //------------------------------------------------------------------------------
  2697. void Clipper::FixupOutPolyline(OutRec &outrec) {
  2698. OutPt *pp = outrec.Pts;
  2699. OutPt *lastPP = pp->Prev;
  2700. while (pp != lastPP) {
  2701. pp = pp->Next;
  2702. if (pp->Pt == pp->Prev->Pt) {
  2703. if (pp == lastPP)
  2704. lastPP = pp->Prev;
  2705. OutPt *tmpPP = pp->Prev;
  2706. tmpPP->Next = pp->Next;
  2707. pp->Next->Prev = tmpPP;
  2708. delete pp;
  2709. pp = tmpPP;
  2710. }
  2711. }
  2712. if (pp == pp->Prev) {
  2713. DisposeOutPts(pp);
  2714. outrec.Pts = 0;
  2715. return;
  2716. }
  2717. }
  2718. //------------------------------------------------------------------------------
  2719. void Clipper::FixupOutPolygon(OutRec &outrec) {
  2720. // FixupOutPolygon() - removes duplicate points and simplifies consecutive
  2721. // parallel edges by removing the middle vertex.
  2722. OutPt *lastOK = 0;
  2723. outrec.BottomPt = 0;
  2724. OutPt *pp = outrec.Pts;
  2725. bool preserveCol = m_PreserveCollinear || m_StrictSimple;
  2726. for (;;) {
  2727. if (pp->Prev == pp || pp->Prev == pp->Next) {
  2728. DisposeOutPts(pp);
  2729. outrec.Pts = 0;
  2730. return;
  2731. }
  2732. // test for duplicate points and collinear edges ...
  2733. if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) ||
  2734. (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) &&
  2735. (!preserveCol ||
  2736. !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt)))) {
  2737. lastOK = 0;
  2738. OutPt *tmp = pp;
  2739. pp->Prev->Next = pp->Next;
  2740. pp->Next->Prev = pp->Prev;
  2741. pp = pp->Prev;
  2742. delete tmp;
  2743. } else if (pp == lastOK)
  2744. break;
  2745. else {
  2746. if (!lastOK)
  2747. lastOK = pp;
  2748. pp = pp->Next;
  2749. }
  2750. }
  2751. outrec.Pts = pp;
  2752. }
  2753. //------------------------------------------------------------------------------
  2754. int PointCount(OutPt *Pts) {
  2755. if (!Pts)
  2756. return 0;
  2757. int result = 0;
  2758. OutPt *p = Pts;
  2759. do {
  2760. result++;
  2761. p = p->Next;
  2762. } while (p != Pts);
  2763. return result;
  2764. }
  2765. //------------------------------------------------------------------------------
  2766. void Clipper::BuildResult(Paths &polys) {
  2767. polys.reserve(m_PolyOuts.size());
  2768. for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) {
  2769. if (!m_PolyOuts[i]->Pts)
  2770. continue;
  2771. Path pg;
  2772. OutPt *p = m_PolyOuts[i]->Pts->Prev;
  2773. int cnt = PointCount(p);
  2774. if (cnt < 2)
  2775. continue;
  2776. pg.reserve(cnt);
  2777. for (int i = 0; i < cnt; ++i) {
  2778. pg.push_back(p->Pt);
  2779. p = p->Prev;
  2780. }
  2781. polys.push_back(pg);
  2782. }
  2783. }
  2784. //------------------------------------------------------------------------------
  2785. void Clipper::BuildResult2(PolyTree &polytree) {
  2786. polytree.Clear();
  2787. polytree.AllNodes.reserve(m_PolyOuts.size());
  2788. // add each output polygon/contour to polytree ...
  2789. for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) {
  2790. OutRec *outRec = m_PolyOuts[i];
  2791. int cnt = PointCount(outRec->Pts);
  2792. if ((outRec->IsOpen && cnt < 2) || (!outRec->IsOpen && cnt < 3))
  2793. continue;
  2794. FixHoleLinkage(*outRec);
  2795. PolyNode *pn = new PolyNode();
  2796. // nb: polytree takes ownership of all the PolyNodes
  2797. polytree.AllNodes.push_back(pn);
  2798. outRec->PolyNd = pn;
  2799. pn->Parent = 0;
  2800. pn->Index = 0;
  2801. pn->Contour.reserve(cnt);
  2802. OutPt *op = outRec->Pts->Prev;
  2803. for (int j = 0; j < cnt; j++) {
  2804. pn->Contour.push_back(op->Pt);
  2805. op = op->Prev;
  2806. }
  2807. }
  2808. // fixup PolyNode links etc ...
  2809. polytree.Childs.reserve(m_PolyOuts.size());
  2810. for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) {
  2811. OutRec *outRec = m_PolyOuts[i];
  2812. if (!outRec->PolyNd)
  2813. continue;
  2814. if (outRec->IsOpen) {
  2815. outRec->PolyNd->m_IsOpen = true;
  2816. polytree.AddChild(*outRec->PolyNd);
  2817. } else if (outRec->FirstLeft && outRec->FirstLeft->PolyNd)
  2818. outRec->FirstLeft->PolyNd->AddChild(*outRec->PolyNd);
  2819. else
  2820. polytree.AddChild(*outRec->PolyNd);
  2821. }
  2822. }
  2823. //------------------------------------------------------------------------------
  2824. void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2) {
  2825. // just swap the contents (because fIntersectNodes is a single-linked-list)
  2826. IntersectNode inode = int1; // gets a copy of Int1
  2827. int1.Edge1 = int2.Edge1;
  2828. int1.Edge2 = int2.Edge2;
  2829. int1.Pt = int2.Pt;
  2830. int2.Edge1 = inode.Edge1;
  2831. int2.Edge2 = inode.Edge2;
  2832. int2.Pt = inode.Pt;
  2833. }
  2834. //------------------------------------------------------------------------------
  2835. inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2) {
  2836. if (e2.Curr.X == e1.Curr.X) {
  2837. if (e2.Top.Y > e1.Top.Y)
  2838. return e2.Top.X < TopX(e1, e2.Top.Y);
  2839. else
  2840. return e1.Top.X > TopX(e2, e1.Top.Y);
  2841. } else
  2842. return e2.Curr.X < e1.Curr.X;
  2843. }
  2844. //------------------------------------------------------------------------------
  2845. bool GetOverlap(const cInt a1, const cInt a2, const cInt b1, const cInt b2,
  2846. cInt &Left, cInt &Right) {
  2847. if (a1 < a2) {
  2848. if (b1 < b2) {
  2849. Left = std::max(a1, b1);
  2850. Right = std::min(a2, b2);
  2851. } else {
  2852. Left = std::max(a1, b2);
  2853. Right = std::min(a2, b1);
  2854. }
  2855. } else {
  2856. if (b1 < b2) {
  2857. Left = std::max(a2, b1);
  2858. Right = std::min(a1, b2);
  2859. } else {
  2860. Left = std::max(a2, b2);
  2861. Right = std::min(a1, b1);
  2862. }
  2863. }
  2864. return Left < Right;
  2865. }
  2866. //------------------------------------------------------------------------------
  2867. inline void UpdateOutPtIdxs(OutRec &outrec) {
  2868. OutPt *op = outrec.Pts;
  2869. do {
  2870. op->Idx = outrec.Idx;
  2871. op = op->Prev;
  2872. } while (op != outrec.Pts);
  2873. }
  2874. //------------------------------------------------------------------------------
  2875. void Clipper::InsertEdgeIntoAEL(TEdge *edge, TEdge *startEdge) {
  2876. if (!m_ActiveEdges) {
  2877. edge->PrevInAEL = 0;
  2878. edge->NextInAEL = 0;
  2879. m_ActiveEdges = edge;
  2880. } else if (!startEdge && E2InsertsBeforeE1(*m_ActiveEdges, *edge)) {
  2881. edge->PrevInAEL = 0;
  2882. edge->NextInAEL = m_ActiveEdges;
  2883. m_ActiveEdges->PrevInAEL = edge;
  2884. m_ActiveEdges = edge;
  2885. } else {
  2886. if (!startEdge)
  2887. startEdge = m_ActiveEdges;
  2888. while (startEdge->NextInAEL &&
  2889. !E2InsertsBeforeE1(*startEdge->NextInAEL, *edge))
  2890. startEdge = startEdge->NextInAEL;
  2891. edge->NextInAEL = startEdge->NextInAEL;
  2892. if (startEdge->NextInAEL)
  2893. startEdge->NextInAEL->PrevInAEL = edge;
  2894. edge->PrevInAEL = startEdge;
  2895. startEdge->NextInAEL = edge;
  2896. }
  2897. }
  2898. //----------------------------------------------------------------------
  2899. OutPt *DupOutPt(OutPt *outPt, bool InsertAfter) {
  2900. OutPt *result = new OutPt;
  2901. result->Pt = outPt->Pt;
  2902. result->Idx = outPt->Idx;
  2903. if (InsertAfter) {
  2904. result->Next = outPt->Next;
  2905. result->Prev = outPt;
  2906. outPt->Next->Prev = result;
  2907. outPt->Next = result;
  2908. } else {
  2909. result->Prev = outPt->Prev;
  2910. result->Next = outPt;
  2911. outPt->Prev->Next = result;
  2912. outPt->Prev = result;
  2913. }
  2914. return result;
  2915. }
  2916. //------------------------------------------------------------------------------
  2917. bool JoinHorz(OutPt *op1, OutPt *op1b, OutPt *op2, OutPt *op2b,
  2918. const IntPoint Pt, bool DiscardLeft) {
  2919. Direction Dir1 = (op1->Pt.X > op1b->Pt.X ? dRightToLeft : dLeftToRight);
  2920. Direction Dir2 = (op2->Pt.X > op2b->Pt.X ? dRightToLeft : dLeftToRight);
  2921. if (Dir1 == Dir2)
  2922. return false;
  2923. // When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we
  2924. // want Op1b to be on the Right. (And likewise with Op2 and Op2b.)
  2925. // So, to facilitate this while inserting Op1b and Op2b ...
  2926. // when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b,
  2927. // otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.)
  2928. if (Dir1 == dLeftToRight) {
  2929. while (op1->Next->Pt.X <= Pt.X && op1->Next->Pt.X >= op1->Pt.X &&
  2930. op1->Next->Pt.Y == Pt.Y)
  2931. op1 = op1->Next;
  2932. if (DiscardLeft && (op1->Pt.X != Pt.X))
  2933. op1 = op1->Next;
  2934. op1b = DupOutPt(op1, !DiscardLeft);
  2935. if (op1b->Pt != Pt) {
  2936. op1 = op1b;
  2937. op1->Pt = Pt;
  2938. op1b = DupOutPt(op1, !DiscardLeft);
  2939. }
  2940. } else {
  2941. while (op1->Next->Pt.X >= Pt.X && op1->Next->Pt.X <= op1->Pt.X &&
  2942. op1->Next->Pt.Y == Pt.Y)
  2943. op1 = op1->Next;
  2944. if (!DiscardLeft && (op1->Pt.X != Pt.X))
  2945. op1 = op1->Next;
  2946. op1b = DupOutPt(op1, DiscardLeft);
  2947. if (op1b->Pt != Pt) {
  2948. op1 = op1b;
  2949. op1->Pt = Pt;
  2950. op1b = DupOutPt(op1, DiscardLeft);
  2951. }
  2952. }
  2953. if (Dir2 == dLeftToRight) {
  2954. while (op2->Next->Pt.X <= Pt.X && op2->Next->Pt.X >= op2->Pt.X &&
  2955. op2->Next->Pt.Y == Pt.Y)
  2956. op2 = op2->Next;
  2957. if (DiscardLeft && (op2->Pt.X != Pt.X))
  2958. op2 = op2->Next;
  2959. op2b = DupOutPt(op2, !DiscardLeft);
  2960. if (op2b->Pt != Pt) {
  2961. op2 = op2b;
  2962. op2->Pt = Pt;
  2963. op2b = DupOutPt(op2, !DiscardLeft);
  2964. };
  2965. } else {
  2966. while (op2->Next->Pt.X >= Pt.X && op2->Next->Pt.X <= op2->Pt.X &&
  2967. op2->Next->Pt.Y == Pt.Y)
  2968. op2 = op2->Next;
  2969. if (!DiscardLeft && (op2->Pt.X != Pt.X))
  2970. op2 = op2->Next;
  2971. op2b = DupOutPt(op2, DiscardLeft);
  2972. if (op2b->Pt != Pt) {
  2973. op2 = op2b;
  2974. op2->Pt = Pt;
  2975. op2b = DupOutPt(op2, DiscardLeft);
  2976. };
  2977. };
  2978. if ((Dir1 == dLeftToRight) == DiscardLeft) {
  2979. op1->Prev = op2;
  2980. op2->Next = op1;
  2981. op1b->Next = op2b;
  2982. op2b->Prev = op1b;
  2983. } else {
  2984. op1->Next = op2;
  2985. op2->Prev = op1;
  2986. op1b->Prev = op2b;
  2987. op2b->Next = op1b;
  2988. }
  2989. return true;
  2990. }
  2991. //------------------------------------------------------------------------------
  2992. bool Clipper::JoinPoints(Join *j, OutRec *outRec1, OutRec *outRec2) {
  2993. OutPt *op1 = j->OutPt1, *op1b;
  2994. OutPt *op2 = j->OutPt2, *op2b;
  2995. // There are 3 kinds of joins for output polygons ...
  2996. // 1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere
  2997. // along (horizontal) collinear edges (& Join.OffPt is on the same
  2998. // horizontal).
  2999. // 2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same
  3000. // location at the Bottom of the overlapping segment (& Join.OffPt is above).
  3001. // 3. StrictSimple joins where edges touch but are not collinear and where
  3002. // Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point.
  3003. bool isHorizontal = (j->OutPt1->Pt.Y == j->OffPt.Y);
  3004. if (isHorizontal && (j->OffPt == j->OutPt1->Pt) &&
  3005. (j->OffPt == j->OutPt2->Pt)) {
  3006. // Strictly Simple join ...
  3007. if (outRec1 != outRec2)
  3008. return false;
  3009. op1b = j->OutPt1->Next;
  3010. while (op1b != op1 && (op1b->Pt == j->OffPt))
  3011. op1b = op1b->Next;
  3012. bool reverse1 = (op1b->Pt.Y > j->OffPt.Y);
  3013. op2b = j->OutPt2->Next;
  3014. while (op2b != op2 && (op2b->Pt == j->OffPt))
  3015. op2b = op2b->Next;
  3016. bool reverse2 = (op2b->Pt.Y > j->OffPt.Y);
  3017. if (reverse1 == reverse2)
  3018. return false;
  3019. if (reverse1) {
  3020. op1b = DupOutPt(op1, false);
  3021. op2b = DupOutPt(op2, true);
  3022. op1->Prev = op2;
  3023. op2->Next = op1;
  3024. op1b->Next = op2b;
  3025. op2b->Prev = op1b;
  3026. j->OutPt1 = op1;
  3027. j->OutPt2 = op1b;
  3028. return true;
  3029. } else {
  3030. op1b = DupOutPt(op1, true);
  3031. op2b = DupOutPt(op2, false);
  3032. op1->Next = op2;
  3033. op2->Prev = op1;
  3034. op1b->Prev = op2b;
  3035. op2b->Next = op1b;
  3036. j->OutPt1 = op1;
  3037. j->OutPt2 = op1b;
  3038. return true;
  3039. }
  3040. } else if (isHorizontal) {
  3041. // treat horizontal joins differently to non-horizontal joins since with
  3042. // them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt
  3043. // may be anywhere along the horizontal edge.
  3044. op1b = op1;
  3045. while (op1->Prev->Pt.Y == op1->Pt.Y && op1->Prev != op1b &&
  3046. op1->Prev != op2)
  3047. op1 = op1->Prev;
  3048. while (op1b->Next->Pt.Y == op1b->Pt.Y && op1b->Next != op1 &&
  3049. op1b->Next != op2)
  3050. op1b = op1b->Next;
  3051. if (op1b->Next == op1 || op1b->Next == op2)
  3052. return false; // a flat 'polygon'
  3053. op2b = op2;
  3054. while (op2->Prev->Pt.Y == op2->Pt.Y && op2->Prev != op2b &&
  3055. op2->Prev != op1b)
  3056. op2 = op2->Prev;
  3057. while (op2b->Next->Pt.Y == op2b->Pt.Y && op2b->Next != op2 &&
  3058. op2b->Next != op1)
  3059. op2b = op2b->Next;
  3060. if (op2b->Next == op2 || op2b->Next == op1)
  3061. return false; // a flat 'polygon'
  3062. cInt Left, Right;
  3063. // Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges
  3064. if (!GetOverlap(op1->Pt.X, op1b->Pt.X, op2->Pt.X, op2b->Pt.X, Left, Right))
  3065. return false;
  3066. // DiscardLeftSide: when overlapping edges are joined, a spike will created
  3067. // which needs to be cleaned up. However, we don't want Op1 or Op2 caught up
  3068. // on the discard Side as either may still be needed for other joins ...
  3069. IntPoint Pt;
  3070. bool DiscardLeftSide;
  3071. if (op1->Pt.X >= Left && op1->Pt.X <= Right) {
  3072. Pt = op1->Pt;
  3073. DiscardLeftSide = (op1->Pt.X > op1b->Pt.X);
  3074. } else if (op2->Pt.X >= Left && op2->Pt.X <= Right) {
  3075. Pt = op2->Pt;
  3076. DiscardLeftSide = (op2->Pt.X > op2b->Pt.X);
  3077. } else if (op1b->Pt.X >= Left && op1b->Pt.X <= Right) {
  3078. Pt = op1b->Pt;
  3079. DiscardLeftSide = op1b->Pt.X > op1->Pt.X;
  3080. } else {
  3081. Pt = op2b->Pt;
  3082. DiscardLeftSide = (op2b->Pt.X > op2->Pt.X);
  3083. }
  3084. j->OutPt1 = op1;
  3085. j->OutPt2 = op2;
  3086. return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide);
  3087. } else {
  3088. // nb: For non-horizontal joins ...
  3089. // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y
  3090. // 2. Jr.OutPt1.Pt > Jr.OffPt.Y
  3091. // make sure the polygons are correctly oriented ...
  3092. op1b = op1->Next;
  3093. while ((op1b->Pt == op1->Pt) && (op1b != op1))
  3094. op1b = op1b->Next;
  3095. bool Reverse1 = ((op1b->Pt.Y > op1->Pt.Y) ||
  3096. !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange));
  3097. if (Reverse1) {
  3098. op1b = op1->Prev;
  3099. while ((op1b->Pt == op1->Pt) && (op1b != op1))
  3100. op1b = op1b->Prev;
  3101. if ((op1b->Pt.Y > op1->Pt.Y) ||
  3102. !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange))
  3103. return false;
  3104. };
  3105. op2b = op2->Next;
  3106. while ((op2b->Pt == op2->Pt) && (op2b != op2))
  3107. op2b = op2b->Next;
  3108. bool Reverse2 = ((op2b->Pt.Y > op2->Pt.Y) ||
  3109. !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange));
  3110. if (Reverse2) {
  3111. op2b = op2->Prev;
  3112. while ((op2b->Pt == op2->Pt) && (op2b != op2))
  3113. op2b = op2b->Prev;
  3114. if ((op2b->Pt.Y > op2->Pt.Y) ||
  3115. !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange))
  3116. return false;
  3117. }
  3118. if ((op1b == op1) || (op2b == op2) || (op1b == op2b) ||
  3119. ((outRec1 == outRec2) && (Reverse1 == Reverse2)))
  3120. return false;
  3121. if (Reverse1) {
  3122. op1b = DupOutPt(op1, false);
  3123. op2b = DupOutPt(op2, true);
  3124. op1->Prev = op2;
  3125. op2->Next = op1;
  3126. op1b->Next = op2b;
  3127. op2b->Prev = op1b;
  3128. j->OutPt1 = op1;
  3129. j->OutPt2 = op1b;
  3130. return true;
  3131. } else {
  3132. op1b = DupOutPt(op1, true);
  3133. op2b = DupOutPt(op2, false);
  3134. op1->Next = op2;
  3135. op2->Prev = op1;
  3136. op1b->Prev = op2b;
  3137. op2b->Next = op1b;
  3138. j->OutPt1 = op1;
  3139. j->OutPt2 = op1b;
  3140. return true;
  3141. }
  3142. }
  3143. }
  3144. //----------------------------------------------------------------------
  3145. static OutRec *ParseFirstLeft(OutRec *FirstLeft) {
  3146. while (FirstLeft && !FirstLeft->Pts)
  3147. FirstLeft = FirstLeft->FirstLeft;
  3148. return FirstLeft;
  3149. }
  3150. //------------------------------------------------------------------------------
  3151. void Clipper::FixupFirstLefts1(OutRec *OldOutRec, OutRec *NewOutRec) {
  3152. // tests if NewOutRec contains the polygon before reassigning FirstLeft
  3153. for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) {
  3154. OutRec *outRec = m_PolyOuts[i];
  3155. OutRec *firstLeft = ParseFirstLeft(outRec->FirstLeft);
  3156. if (outRec->Pts && firstLeft == OldOutRec) {
  3157. if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts))
  3158. outRec->FirstLeft = NewOutRec;
  3159. }
  3160. }
  3161. }
  3162. //----------------------------------------------------------------------
  3163. void Clipper::FixupFirstLefts2(OutRec *InnerOutRec, OutRec *OuterOutRec) {
  3164. // A polygon has split into two such that one is now the inner of the other.
  3165. // It's possible that these polygons now wrap around other polygons, so check
  3166. // every polygon that's also contained by OuterOutRec's FirstLeft container
  3167. //(including 0) to see if they've become inner to the new inner polygon ...
  3168. OutRec *orfl = OuterOutRec->FirstLeft;
  3169. for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) {
  3170. OutRec *outRec = m_PolyOuts[i];
  3171. if (!outRec->Pts || outRec == OuterOutRec || outRec == InnerOutRec)
  3172. continue;
  3173. OutRec *firstLeft = ParseFirstLeft(outRec->FirstLeft);
  3174. if (firstLeft != orfl && firstLeft != InnerOutRec &&
  3175. firstLeft != OuterOutRec)
  3176. continue;
  3177. if (Poly2ContainsPoly1(outRec->Pts, InnerOutRec->Pts))
  3178. outRec->FirstLeft = InnerOutRec;
  3179. else if (Poly2ContainsPoly1(outRec->Pts, OuterOutRec->Pts))
  3180. outRec->FirstLeft = OuterOutRec;
  3181. else if (outRec->FirstLeft == InnerOutRec ||
  3182. outRec->FirstLeft == OuterOutRec)
  3183. outRec->FirstLeft = orfl;
  3184. }
  3185. }
  3186. //----------------------------------------------------------------------
  3187. void Clipper::FixupFirstLefts3(OutRec *OldOutRec, OutRec *NewOutRec) {
  3188. // reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon
  3189. for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) {
  3190. OutRec *outRec = m_PolyOuts[i];
  3191. OutRec *firstLeft = ParseFirstLeft(outRec->FirstLeft);
  3192. if (outRec->Pts && firstLeft == OldOutRec)
  3193. outRec->FirstLeft = NewOutRec;
  3194. }
  3195. }
  3196. //----------------------------------------------------------------------
  3197. void Clipper::JoinCommonEdges() {
  3198. for (JoinList::size_type i = 0; i < m_Joins.size(); i++) {
  3199. Join *join = m_Joins[i];
  3200. OutRec *outRec1 = GetOutRec(join->OutPt1->Idx);
  3201. OutRec *outRec2 = GetOutRec(join->OutPt2->Idx);
  3202. if (!outRec1->Pts || !outRec2->Pts)
  3203. continue;
  3204. if (outRec1->IsOpen || outRec2->IsOpen)
  3205. continue;
  3206. // get the polygon fragment with the correct hole state (FirstLeft)
  3207. // before calling JoinPoints() ...
  3208. OutRec *holeStateRec;
  3209. if (outRec1 == outRec2)
  3210. holeStateRec = outRec1;
  3211. else if (OutRec1RightOfOutRec2(outRec1, outRec2))
  3212. holeStateRec = outRec2;
  3213. else if (OutRec1RightOfOutRec2(outRec2, outRec1))
  3214. holeStateRec = outRec1;
  3215. else
  3216. holeStateRec = GetLowermostRec(outRec1, outRec2);
  3217. if (!JoinPoints(join, outRec1, outRec2))
  3218. continue;
  3219. if (outRec1 == outRec2) {
  3220. // instead of joining two polygons, we've just created a new one by
  3221. // splitting one polygon into two.
  3222. outRec1->Pts = join->OutPt1;
  3223. outRec1->BottomPt = 0;
  3224. outRec2 = CreateOutRec();
  3225. outRec2->Pts = join->OutPt2;
  3226. // update all OutRec2.Pts Idx's ...
  3227. UpdateOutPtIdxs(*outRec2);
  3228. if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts)) {
  3229. // outRec1 contains outRec2 ...
  3230. outRec2->IsHole = !outRec1->IsHole;
  3231. outRec2->FirstLeft = outRec1;
  3232. if (m_UsingPolyTree)
  3233. FixupFirstLefts2(outRec2, outRec1);
  3234. if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0))
  3235. ReversePolyPtLinks(outRec2->Pts);
  3236. } else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts)) {
  3237. // outRec2 contains outRec1 ...
  3238. outRec2->IsHole = outRec1->IsHole;
  3239. outRec1->IsHole = !outRec2->IsHole;
  3240. outRec2->FirstLeft = outRec1->FirstLeft;
  3241. outRec1->FirstLeft = outRec2;
  3242. if (m_UsingPolyTree)
  3243. FixupFirstLefts2(outRec1, outRec2);
  3244. if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0))
  3245. ReversePolyPtLinks(outRec1->Pts);
  3246. } else {
  3247. // the 2 polygons are completely separate ...
  3248. outRec2->IsHole = outRec1->IsHole;
  3249. outRec2->FirstLeft = outRec1->FirstLeft;
  3250. // fixup FirstLeft pointers that may need reassigning to OutRec2
  3251. if (m_UsingPolyTree)
  3252. FixupFirstLefts1(outRec1, outRec2);
  3253. }
  3254. } else {
  3255. // joined 2 polygons together ...
  3256. outRec2->Pts = 0;
  3257. outRec2->BottomPt = 0;
  3258. outRec2->Idx = outRec1->Idx;
  3259. outRec1->IsHole = holeStateRec->IsHole;
  3260. if (holeStateRec == outRec2)
  3261. outRec1->FirstLeft = outRec2->FirstLeft;
  3262. outRec2->FirstLeft = outRec1;
  3263. if (m_UsingPolyTree)
  3264. FixupFirstLefts3(outRec2, outRec1);
  3265. }
  3266. }
  3267. }
  3268. //------------------------------------------------------------------------------
  3269. // ClipperOffset support functions ...
  3270. //------------------------------------------------------------------------------
  3271. DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2) {
  3272. if (pt2.X == pt1.X && pt2.Y == pt1.Y)
  3273. return DoublePoint(0, 0);
  3274. double Dx = (double)(pt2.X - pt1.X);
  3275. double dy = (double)(pt2.Y - pt1.Y);
  3276. double f = 1 * 1.0 / std::sqrt(Dx * Dx + dy * dy);
  3277. Dx *= f;
  3278. dy *= f;
  3279. return DoublePoint(dy, -Dx);
  3280. }
  3281. //------------------------------------------------------------------------------
  3282. // ClipperOffset class
  3283. //------------------------------------------------------------------------------
  3284. ClipperOffset::ClipperOffset(double miterLimit, double arcTolerance) {
  3285. this->MiterLimit = miterLimit;
  3286. this->ArcTolerance = arcTolerance;
  3287. m_lowest.X = -1;
  3288. }
  3289. //------------------------------------------------------------------------------
  3290. ClipperOffset::~ClipperOffset() { Clear(); }
  3291. //------------------------------------------------------------------------------
  3292. void ClipperOffset::Clear() {
  3293. for (int i = 0; i < m_polyNodes.ChildCount(); ++i)
  3294. delete m_polyNodes.Childs[i];
  3295. m_polyNodes.Childs.clear();
  3296. m_lowest.X = -1;
  3297. }
  3298. //------------------------------------------------------------------------------
  3299. void ClipperOffset::AddPath(const Path &path, JoinType joinType,
  3300. EndType endType) {
  3301. int highI = (int)path.size() - 1;
  3302. if (highI < 0)
  3303. return;
  3304. PolyNode *newNode = new PolyNode();
  3305. newNode->m_jointype = joinType;
  3306. newNode->m_endtype = endType;
  3307. // strip duplicate points from path and also get index to the lowest point ...
  3308. if (endType == etClosedLine || endType == etClosedPolygon)
  3309. while (highI > 0 && path[0] == path[highI])
  3310. highI--;
  3311. newNode->Contour.reserve(highI + 1);
  3312. newNode->Contour.push_back(path[0]);
  3313. int j = 0, k = 0;
  3314. for (int i = 1; i <= highI; i++)
  3315. if (newNode->Contour[j] != path[i]) {
  3316. j++;
  3317. newNode->Contour.push_back(path[i]);
  3318. if (path[i].Y > newNode->Contour[k].Y ||
  3319. (path[i].Y == newNode->Contour[k].Y &&
  3320. path[i].X < newNode->Contour[k].X))
  3321. k = j;
  3322. }
  3323. if (endType == etClosedPolygon && j < 2) {
  3324. delete newNode;
  3325. return;
  3326. }
  3327. m_polyNodes.AddChild(*newNode);
  3328. // if this path's lowest pt is lower than all the others then update m_lowest
  3329. if (endType != etClosedPolygon)
  3330. return;
  3331. if (m_lowest.X < 0)
  3332. m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k);
  3333. else {
  3334. IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y];
  3335. if (newNode->Contour[k].Y > ip.Y ||
  3336. (newNode->Contour[k].Y == ip.Y && newNode->Contour[k].X < ip.X))
  3337. m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k);
  3338. }
  3339. }
  3340. //------------------------------------------------------------------------------
  3341. void ClipperOffset::AddPaths(const Paths &paths, JoinType joinType,
  3342. EndType endType) {
  3343. for (Paths::size_type i = 0; i < paths.size(); ++i)
  3344. AddPath(paths[i], joinType, endType);
  3345. }
  3346. //------------------------------------------------------------------------------
  3347. void ClipperOffset::FixOrientations() {
  3348. // fixup orientations of all closed paths if the orientation of the
  3349. // closed path with the lowermost vertex is wrong ...
  3350. if (m_lowest.X >= 0 &&
  3351. !Orientation(m_polyNodes.Childs[(int)m_lowest.X]->Contour)) {
  3352. for (int i = 0; i < m_polyNodes.ChildCount(); ++i) {
  3353. PolyNode &node = *m_polyNodes.Childs[i];
  3354. if (node.m_endtype == etClosedPolygon ||
  3355. (node.m_endtype == etClosedLine && Orientation(node.Contour)))
  3356. ReversePath(node.Contour);
  3357. }
  3358. } else {
  3359. for (int i = 0; i < m_polyNodes.ChildCount(); ++i) {
  3360. PolyNode &node = *m_polyNodes.Childs[i];
  3361. if (node.m_endtype == etClosedLine && !Orientation(node.Contour))
  3362. ReversePath(node.Contour);
  3363. }
  3364. }
  3365. }
  3366. //------------------------------------------------------------------------------
  3367. void ClipperOffset::Execute(Paths &solution, double delta) {
  3368. solution.clear();
  3369. FixOrientations();
  3370. DoOffset(delta);
  3371. // now clean up 'corners' ...
  3372. Clipper clpr;
  3373. clpr.AddPaths(m_destPolys, ptSubject, true);
  3374. if (delta > 0) {
  3375. clpr.Execute(ctUnion, solution, pftPositive, pftPositive);
  3376. } else {
  3377. IntRect r = clpr.GetBounds();
  3378. Path outer(4);
  3379. outer[0] = IntPoint(r.left - 10, r.bottom + 10);
  3380. outer[1] = IntPoint(r.right + 10, r.bottom + 10);
  3381. outer[2] = IntPoint(r.right + 10, r.top - 10);
  3382. outer[3] = IntPoint(r.left - 10, r.top - 10);
  3383. clpr.AddPath(outer, ptSubject, true);
  3384. clpr.ReverseSolution(true);
  3385. clpr.Execute(ctUnion, solution, pftNegative, pftNegative);
  3386. if (solution.size() > 0)
  3387. solution.erase(solution.begin());
  3388. }
  3389. }
  3390. //------------------------------------------------------------------------------
  3391. void ClipperOffset::Execute(PolyTree &solution, double delta) {
  3392. solution.Clear();
  3393. FixOrientations();
  3394. DoOffset(delta);
  3395. // now clean up 'corners' ...
  3396. Clipper clpr;
  3397. clpr.AddPaths(m_destPolys, ptSubject, true);
  3398. if (delta > 0) {
  3399. clpr.Execute(ctUnion, solution, pftPositive, pftPositive);
  3400. } else {
  3401. IntRect r = clpr.GetBounds();
  3402. Path outer(4);
  3403. outer[0] = IntPoint(r.left - 10, r.bottom + 10);
  3404. outer[1] = IntPoint(r.right + 10, r.bottom + 10);
  3405. outer[2] = IntPoint(r.right + 10, r.top - 10);
  3406. outer[3] = IntPoint(r.left - 10, r.top - 10);
  3407. clpr.AddPath(outer, ptSubject, true);
  3408. clpr.ReverseSolution(true);
  3409. clpr.Execute(ctUnion, solution, pftNegative, pftNegative);
  3410. // remove the outer PolyNode rectangle ...
  3411. if (solution.ChildCount() == 1 && solution.Childs[0]->ChildCount() > 0) {
  3412. PolyNode *outerNode = solution.Childs[0];
  3413. solution.Childs.reserve(outerNode->ChildCount());
  3414. solution.Childs[0] = outerNode->Childs[0];
  3415. solution.Childs[0]->Parent = outerNode->Parent;
  3416. for (int i = 1; i < outerNode->ChildCount(); ++i)
  3417. solution.AddChild(*outerNode->Childs[i]);
  3418. } else
  3419. solution.Clear();
  3420. }
  3421. }
  3422. //------------------------------------------------------------------------------
  3423. void ClipperOffset::DoOffset(double delta) {
  3424. m_destPolys.clear();
  3425. m_delta = delta;
  3426. // if Zero offset, just copy any CLOSED polygons to m_p and return ...
  3427. if (NEAR_ZERO(delta)) {
  3428. m_destPolys.reserve(m_polyNodes.ChildCount());
  3429. for (int i = 0; i < m_polyNodes.ChildCount(); i++) {
  3430. PolyNode &node = *m_polyNodes.Childs[i];
  3431. if (node.m_endtype == etClosedPolygon)
  3432. m_destPolys.push_back(node.Contour);
  3433. }
  3434. return;
  3435. }
  3436. // see offset_triginometry3.svg in the documentation folder ...
  3437. if (MiterLimit > 2)
  3438. m_miterLim = 2 / (MiterLimit * MiterLimit);
  3439. else
  3440. m_miterLim = 0.5;
  3441. double y;
  3442. if (ArcTolerance <= 0.0)
  3443. y = def_arc_tolerance;
  3444. else if (ArcTolerance > std::fabs(delta) * def_arc_tolerance)
  3445. y = std::fabs(delta) * def_arc_tolerance;
  3446. else
  3447. y = ArcTolerance;
  3448. // see offset_triginometry2.svg in the documentation folder ...
  3449. double steps = pi / std::acos(1 - y / std::fabs(delta));
  3450. if (steps > std::fabs(delta) * pi)
  3451. steps = std::fabs(delta) * pi; // ie excessive precision check
  3452. m_sin = std::sin(two_pi / steps);
  3453. m_cos = std::cos(two_pi / steps);
  3454. m_StepsPerRad = steps / two_pi;
  3455. if (delta < 0.0)
  3456. m_sin = -m_sin;
  3457. m_destPolys.reserve(m_polyNodes.ChildCount() * 2);
  3458. for (int i = 0; i < m_polyNodes.ChildCount(); i++) {
  3459. PolyNode &node = *m_polyNodes.Childs[i];
  3460. m_srcPoly = node.Contour;
  3461. int len = (int)m_srcPoly.size();
  3462. if (len == 0 ||
  3463. (delta <= 0 && (len < 3 || node.m_endtype != etClosedPolygon)))
  3464. continue;
  3465. m_destPoly.clear();
  3466. if (len == 1) {
  3467. if (node.m_jointype == jtRound) {
  3468. double X = 1.0, Y = 0.0;
  3469. for (cInt j = 1; j <= steps; j++) {
  3470. m_destPoly.push_back(IntPoint(Round(m_srcPoly[0].X + X * delta),
  3471. Round(m_srcPoly[0].Y + Y * delta)));
  3472. double X2 = X;
  3473. X = X * m_cos - m_sin * Y;
  3474. Y = X2 * m_sin + Y * m_cos;
  3475. }
  3476. } else {
  3477. double X = -1.0, Y = -1.0;
  3478. for (int j = 0; j < 4; ++j) {
  3479. m_destPoly.push_back(IntPoint(Round(m_srcPoly[0].X + X * delta),
  3480. Round(m_srcPoly[0].Y + Y * delta)));
  3481. if (X < 0)
  3482. X = 1;
  3483. else if (Y < 0)
  3484. Y = 1;
  3485. else
  3486. X = -1;
  3487. }
  3488. }
  3489. m_destPolys.push_back(m_destPoly);
  3490. continue;
  3491. }
  3492. // build m_normals ...
  3493. m_normals.clear();
  3494. m_normals.reserve(len);
  3495. for (int j = 0; j < len - 1; ++j)
  3496. m_normals.push_back(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1]));
  3497. if (node.m_endtype == etClosedLine || node.m_endtype == etClosedPolygon)
  3498. m_normals.push_back(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0]));
  3499. else
  3500. m_normals.push_back(DoublePoint(m_normals[len - 2]));
  3501. if (node.m_endtype == etClosedPolygon) {
  3502. int k = len - 1;
  3503. for (int j = 0; j < len; ++j)
  3504. OffsetPoint(j, k, node.m_jointype);
  3505. m_destPolys.push_back(m_destPoly);
  3506. } else if (node.m_endtype == etClosedLine) {
  3507. int k = len - 1;
  3508. for (int j = 0; j < len; ++j)
  3509. OffsetPoint(j, k, node.m_jointype);
  3510. m_destPolys.push_back(m_destPoly);
  3511. m_destPoly.clear();
  3512. // re-build m_normals ...
  3513. DoublePoint n = m_normals[len - 1];
  3514. for (int j = len - 1; j > 0; j--)
  3515. m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y);
  3516. m_normals[0] = DoublePoint(-n.X, -n.Y);
  3517. k = 0;
  3518. for (int j = len - 1; j >= 0; j--)
  3519. OffsetPoint(j, k, node.m_jointype);
  3520. m_destPolys.push_back(m_destPoly);
  3521. } else {
  3522. int k = 0;
  3523. for (int j = 1; j < len - 1; ++j)
  3524. OffsetPoint(j, k, node.m_jointype);
  3525. IntPoint pt1;
  3526. if (node.m_endtype == etOpenButt) {
  3527. int j = len - 1;
  3528. pt1 = IntPoint((cInt)Round(m_srcPoly[j].X + m_normals[j].X * delta),
  3529. (cInt)Round(m_srcPoly[j].Y + m_normals[j].Y * delta));
  3530. m_destPoly.push_back(pt1);
  3531. pt1 = IntPoint((cInt)Round(m_srcPoly[j].X - m_normals[j].X * delta),
  3532. (cInt)Round(m_srcPoly[j].Y - m_normals[j].Y * delta));
  3533. m_destPoly.push_back(pt1);
  3534. } else {
  3535. int j = len - 1;
  3536. k = len - 2;
  3537. m_sinA = 0;
  3538. m_normals[j] = DoublePoint(-m_normals[j].X, -m_normals[j].Y);
  3539. if (node.m_endtype == etOpenSquare)
  3540. DoSquare(j, k);
  3541. else
  3542. DoRound(j, k);
  3543. }
  3544. // re-build m_normals ...
  3545. for (int j = len - 1; j > 0; j--)
  3546. m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y);
  3547. m_normals[0] = DoublePoint(-m_normals[1].X, -m_normals[1].Y);
  3548. k = len - 1;
  3549. for (int j = k - 1; j > 0; --j)
  3550. OffsetPoint(j, k, node.m_jointype);
  3551. if (node.m_endtype == etOpenButt) {
  3552. pt1 = IntPoint((cInt)Round(m_srcPoly[0].X - m_normals[0].X * delta),
  3553. (cInt)Round(m_srcPoly[0].Y - m_normals[0].Y * delta));
  3554. m_destPoly.push_back(pt1);
  3555. pt1 = IntPoint((cInt)Round(m_srcPoly[0].X + m_normals[0].X * delta),
  3556. (cInt)Round(m_srcPoly[0].Y + m_normals[0].Y * delta));
  3557. m_destPoly.push_back(pt1);
  3558. } else {
  3559. k = 1;
  3560. m_sinA = 0;
  3561. if (node.m_endtype == etOpenSquare)
  3562. DoSquare(0, 1);
  3563. else
  3564. DoRound(0, 1);
  3565. }
  3566. m_destPolys.push_back(m_destPoly);
  3567. }
  3568. }
  3569. }
  3570. //------------------------------------------------------------------------------
  3571. void ClipperOffset::OffsetPoint(int j, int &k, JoinType jointype) {
  3572. // cross product ...
  3573. m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y);
  3574. if (std::fabs(m_sinA * m_delta) < 1.0) {
  3575. // dot product ...
  3576. double cosA =
  3577. (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y);
  3578. if (cosA > 0) // angle => 0 degrees
  3579. {
  3580. m_destPoly.push_back(
  3581. IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
  3582. Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
  3583. return;
  3584. }
  3585. // else angle => 180 degrees
  3586. } else if (m_sinA > 1.0)
  3587. m_sinA = 1.0;
  3588. else if (m_sinA < -1.0)
  3589. m_sinA = -1.0;
  3590. if (m_sinA * m_delta < 0) {
  3591. m_destPoly.push_back(
  3592. IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
  3593. Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
  3594. m_destPoly.push_back(m_srcPoly[j]);
  3595. m_destPoly.push_back(
  3596. IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta),
  3597. Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta)));
  3598. } else
  3599. switch (jointype) {
  3600. case jtMiter: {
  3601. double r = 1 + (m_normals[j].X * m_normals[k].X +
  3602. m_normals[j].Y * m_normals[k].Y);
  3603. if (r >= m_miterLim)
  3604. DoMiter(j, k, r);
  3605. else
  3606. DoSquare(j, k);
  3607. break;
  3608. }
  3609. case jtSquare:
  3610. DoSquare(j, k);
  3611. break;
  3612. case jtRound:
  3613. DoRound(j, k);
  3614. break;
  3615. }
  3616. k = j;
  3617. }
  3618. //------------------------------------------------------------------------------
  3619. void ClipperOffset::DoSquare(int j, int k) {
  3620. double dx = std::tan(std::atan2(m_sinA, m_normals[k].X * m_normals[j].X +
  3621. m_normals[k].Y * m_normals[j].Y) /
  3622. 4);
  3623. m_destPoly.push_back(IntPoint(
  3624. Round(m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx)),
  3625. Round(m_srcPoly[j].Y +
  3626. m_delta * (m_normals[k].Y + m_normals[k].X * dx))));
  3627. m_destPoly.push_back(IntPoint(
  3628. Round(m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx)),
  3629. Round(m_srcPoly[j].Y +
  3630. m_delta * (m_normals[j].Y - m_normals[j].X * dx))));
  3631. }
  3632. //------------------------------------------------------------------------------
  3633. void ClipperOffset::DoMiter(int j, int k, double r) {
  3634. double q = m_delta / r;
  3635. m_destPoly.push_back(
  3636. IntPoint(Round(m_srcPoly[j].X + (m_normals[k].X + m_normals[j].X) * q),
  3637. Round(m_srcPoly[j].Y + (m_normals[k].Y + m_normals[j].Y) * q)));
  3638. }
  3639. //------------------------------------------------------------------------------
  3640. void ClipperOffset::DoRound(int j, int k) {
  3641. double a = std::atan2(m_sinA, m_normals[k].X * m_normals[j].X +
  3642. m_normals[k].Y * m_normals[j].Y);
  3643. int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1);
  3644. double X = m_normals[k].X, Y = m_normals[k].Y, X2;
  3645. for (int i = 0; i < steps; ++i) {
  3646. m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + X * m_delta),
  3647. Round(m_srcPoly[j].Y + Y * m_delta)));
  3648. X2 = X;
  3649. X = X * m_cos - m_sin * Y;
  3650. Y = X2 * m_sin + Y * m_cos;
  3651. }
  3652. m_destPoly.push_back(
  3653. IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta),
  3654. Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta)));
  3655. }
  3656. //------------------------------------------------------------------------------
  3657. // Miscellaneous public functions
  3658. //------------------------------------------------------------------------------
  3659. void Clipper::DoSimplePolygons() {
  3660. PolyOutList::size_type i = 0;
  3661. while (i < m_PolyOuts.size()) {
  3662. OutRec *outrec = m_PolyOuts[i++];
  3663. OutPt *op = outrec->Pts;
  3664. if (!op || outrec->IsOpen)
  3665. continue;
  3666. do // for each Pt in Polygon until duplicate found do ...
  3667. {
  3668. OutPt *op2 = op->Next;
  3669. while (op2 != outrec->Pts) {
  3670. if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op) {
  3671. // split the polygon into two ...
  3672. OutPt *op3 = op->Prev;
  3673. OutPt *op4 = op2->Prev;
  3674. op->Prev = op4;
  3675. op4->Next = op;
  3676. op2->Prev = op3;
  3677. op3->Next = op2;
  3678. outrec->Pts = op;
  3679. OutRec *outrec2 = CreateOutRec();
  3680. outrec2->Pts = op2;
  3681. UpdateOutPtIdxs(*outrec2);
  3682. if (Poly2ContainsPoly1(outrec2->Pts, outrec->Pts)) {
  3683. // OutRec2 is contained by OutRec1 ...
  3684. outrec2->IsHole = !outrec->IsHole;
  3685. outrec2->FirstLeft = outrec;
  3686. if (m_UsingPolyTree)
  3687. FixupFirstLefts2(outrec2, outrec);
  3688. } else if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts)) {
  3689. // OutRec1 is contained by OutRec2 ...
  3690. outrec2->IsHole = outrec->IsHole;
  3691. outrec->IsHole = !outrec2->IsHole;
  3692. outrec2->FirstLeft = outrec->FirstLeft;
  3693. outrec->FirstLeft = outrec2;
  3694. if (m_UsingPolyTree)
  3695. FixupFirstLefts2(outrec, outrec2);
  3696. } else {
  3697. // the 2 polygons are separate ...
  3698. outrec2->IsHole = outrec->IsHole;
  3699. outrec2->FirstLeft = outrec->FirstLeft;
  3700. if (m_UsingPolyTree)
  3701. FixupFirstLefts1(outrec, outrec2);
  3702. }
  3703. op2 = op; // ie get ready for the Next iteration
  3704. }
  3705. op2 = op2->Next;
  3706. }
  3707. op = op->Next;
  3708. } while (op != outrec->Pts);
  3709. }
  3710. }
  3711. //------------------------------------------------------------------------------
  3712. void ReversePath(Path &p) { std::reverse(p.begin(), p.end()); }
  3713. //------------------------------------------------------------------------------
  3714. void ReversePaths(Paths &p) {
  3715. for (Paths::size_type i = 0; i < p.size(); ++i)
  3716. ReversePath(p[i]);
  3717. }
  3718. //------------------------------------------------------------------------------
  3719. void SimplifyPolygon(const Path &in_poly, Paths &out_polys,
  3720. PolyFillType fillType) {
  3721. Clipper c;
  3722. c.StrictlySimple(true);
  3723. c.AddPath(in_poly, ptSubject, true);
  3724. c.Execute(ctUnion, out_polys, fillType, fillType);
  3725. }
  3726. //------------------------------------------------------------------------------
  3727. void SimplifyPolygons(const Paths &in_polys, Paths &out_polys,
  3728. PolyFillType fillType) {
  3729. Clipper c;
  3730. c.StrictlySimple(true);
  3731. c.AddPaths(in_polys, ptSubject, true);
  3732. c.Execute(ctUnion, out_polys, fillType, fillType);
  3733. }
  3734. //------------------------------------------------------------------------------
  3735. void SimplifyPolygons(Paths &polys, PolyFillType fillType) {
  3736. SimplifyPolygons(polys, polys, fillType);
  3737. }
  3738. //------------------------------------------------------------------------------
  3739. inline double DistanceSqrd(const IntPoint &pt1, const IntPoint &pt2) {
  3740. double Dx = ((double)pt1.X - pt2.X);
  3741. double dy = ((double)pt1.Y - pt2.Y);
  3742. return (Dx * Dx + dy * dy);
  3743. }
  3744. //------------------------------------------------------------------------------
  3745. double DistanceFromLineSqrd(const IntPoint &pt, const IntPoint &ln1,
  3746. const IntPoint &ln2) {
  3747. // The equation of a line in general form (Ax + By + C = 0)
  3748. // given 2 points (x�,y�) & (x�,y�) is ...
  3749. //(y� - y�)x + (x� - x�)y + (y� - y�)x� - (x� - x�)y� = 0
  3750. // A = (y� - y�); B = (x� - x�); C = (y� - y�)x� - (x� - x�)y�
  3751. // perpendicular distance of point (x�,y�) = (Ax� + By� + C)/Sqrt(A� + B�)
  3752. // see http://en.wikipedia.org/wiki/Perpendicular_distance
  3753. double A = double(ln1.Y - ln2.Y);
  3754. double B = double(ln2.X - ln1.X);
  3755. double C = A * ln1.X + B * ln1.Y;
  3756. C = A * pt.X + B * pt.Y - C;
  3757. return (C * C) / (A * A + B * B);
  3758. }
  3759. //---------------------------------------------------------------------------
  3760. bool SlopesNearCollinear(const IntPoint &pt1, const IntPoint &pt2,
  3761. const IntPoint &pt3, double distSqrd) {
  3762. // this function is more accurate when the point that's geometrically
  3763. // between the other 2 points is the one that's tested for distance.
  3764. // ie makes it more likely to pick up 'spikes' ...
  3765. if (Abs(pt1.X - pt2.X) > Abs(pt1.Y - pt2.Y)) {
  3766. if ((pt1.X > pt2.X) == (pt1.X < pt3.X))
  3767. return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
  3768. else if ((pt2.X > pt1.X) == (pt2.X < pt3.X))
  3769. return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
  3770. else
  3771. return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
  3772. } else {
  3773. if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y))
  3774. return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
  3775. else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y))
  3776. return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
  3777. else
  3778. return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
  3779. }
  3780. }
  3781. //------------------------------------------------------------------------------
  3782. bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd) {
  3783. double Dx = (double)pt1.X - pt2.X;
  3784. double dy = (double)pt1.Y - pt2.Y;
  3785. return ((Dx * Dx) + (dy * dy) <= distSqrd);
  3786. }
  3787. //------------------------------------------------------------------------------
  3788. OutPt *ExcludeOp(OutPt *op) {
  3789. OutPt *result = op->Prev;
  3790. result->Next = op->Next;
  3791. op->Next->Prev = result;
  3792. result->Idx = 0;
  3793. return result;
  3794. }
  3795. //------------------------------------------------------------------------------
  3796. void CleanPolygon(const Path &in_poly, Path &out_poly, double distance) {
  3797. // distance = proximity in units/pixels below which vertices
  3798. // will be stripped. Default ~= sqrt(2).
  3799. size_t size = in_poly.size();
  3800. if (size == 0) {
  3801. out_poly.clear();
  3802. return;
  3803. }
  3804. OutPt *outPts = new OutPt[size];
  3805. for (size_t i = 0; i < size; ++i) {
  3806. outPts[i].Pt = in_poly[i];
  3807. outPts[i].Next = &outPts[(i + 1) % size];
  3808. outPts[i].Next->Prev = &outPts[i];
  3809. outPts[i].Idx = 0;
  3810. }
  3811. double distSqrd = distance * distance;
  3812. OutPt *op = &outPts[0];
  3813. while (op->Idx == 0 && op->Next != op->Prev) {
  3814. if (PointsAreClose(op->Pt, op->Prev->Pt, distSqrd)) {
  3815. op = ExcludeOp(op);
  3816. size--;
  3817. } else if (PointsAreClose(op->Prev->Pt, op->Next->Pt, distSqrd)) {
  3818. ExcludeOp(op->Next);
  3819. op = ExcludeOp(op);
  3820. size -= 2;
  3821. } else if (SlopesNearCollinear(op->Prev->Pt, op->Pt, op->Next->Pt,
  3822. distSqrd)) {
  3823. op = ExcludeOp(op);
  3824. size--;
  3825. } else {
  3826. op->Idx = 1;
  3827. op = op->Next;
  3828. }
  3829. }
  3830. if (size < 3)
  3831. size = 0;
  3832. out_poly.resize(size);
  3833. for (size_t i = 0; i < size; ++i) {
  3834. out_poly[i] = op->Pt;
  3835. op = op->Next;
  3836. }
  3837. delete[] outPts;
  3838. }
  3839. //------------------------------------------------------------------------------
  3840. void CleanPolygon(Path &poly, double distance) {
  3841. CleanPolygon(poly, poly, distance);
  3842. }
  3843. //------------------------------------------------------------------------------
  3844. void CleanPolygons(const Paths &in_polys, Paths &out_polys, double distance) {
  3845. out_polys.resize(in_polys.size());
  3846. for (Paths::size_type i = 0; i < in_polys.size(); ++i)
  3847. CleanPolygon(in_polys[i], out_polys[i], distance);
  3848. }
  3849. //------------------------------------------------------------------------------
  3850. void CleanPolygons(Paths &polys, double distance) {
  3851. CleanPolygons(polys, polys, distance);
  3852. }
  3853. //------------------------------------------------------------------------------
  3854. void Minkowski(const Path &poly, const Path &path, Paths &solution, bool isSum,
  3855. bool isClosed) {
  3856. int delta = (isClosed ? 1 : 0);
  3857. size_t polyCnt = poly.size();
  3858. size_t pathCnt = path.size();
  3859. Paths pp;
  3860. pp.reserve(pathCnt);
  3861. if (isSum)
  3862. for (size_t i = 0; i < pathCnt; ++i) {
  3863. Path p;
  3864. p.reserve(polyCnt);
  3865. for (size_t j = 0; j < poly.size(); ++j)
  3866. p.push_back(IntPoint(path[i].X + poly[j].X, path[i].Y + poly[j].Y));
  3867. pp.push_back(p);
  3868. }
  3869. else
  3870. for (size_t i = 0; i < pathCnt; ++i) {
  3871. Path p;
  3872. p.reserve(polyCnt);
  3873. for (size_t j = 0; j < poly.size(); ++j)
  3874. p.push_back(IntPoint(path[i].X - poly[j].X, path[i].Y - poly[j].Y));
  3875. pp.push_back(p);
  3876. }
  3877. solution.clear();
  3878. solution.reserve((pathCnt + delta) * (polyCnt + 1));
  3879. for (size_t i = 0; i < pathCnt - 1 + delta; ++i)
  3880. for (size_t j = 0; j < polyCnt; ++j) {
  3881. Path quad;
  3882. quad.reserve(4);
  3883. quad.push_back(pp[i % pathCnt][j % polyCnt]);
  3884. quad.push_back(pp[(i + 1) % pathCnt][j % polyCnt]);
  3885. quad.push_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]);
  3886. quad.push_back(pp[i % pathCnt][(j + 1) % polyCnt]);
  3887. if (!Orientation(quad))
  3888. ReversePath(quad);
  3889. solution.push_back(quad);
  3890. }
  3891. }
  3892. //------------------------------------------------------------------------------
  3893. void MinkowskiSum(const Path &pattern, const Path &path, Paths &solution,
  3894. bool pathIsClosed) {
  3895. Minkowski(pattern, path, solution, true, pathIsClosed);
  3896. Clipper c;
  3897. c.AddPaths(solution, ptSubject, true);
  3898. c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
  3899. }
  3900. //------------------------------------------------------------------------------
  3901. void TranslatePath(const Path &input, Path &output, const IntPoint delta) {
  3902. // precondition: input != output
  3903. output.resize(input.size());
  3904. for (size_t i = 0; i < input.size(); ++i)
  3905. output[i] = IntPoint(input[i].X + delta.X, input[i].Y + delta.Y);
  3906. }
  3907. //------------------------------------------------------------------------------
  3908. void MinkowskiSum(const Path &pattern, const Paths &paths, Paths &solution,
  3909. bool pathIsClosed) {
  3910. Clipper c;
  3911. for (size_t i = 0; i < paths.size(); ++i) {
  3912. Paths tmp;
  3913. Minkowski(pattern, paths[i], tmp, true, pathIsClosed);
  3914. c.AddPaths(tmp, ptSubject, true);
  3915. if (pathIsClosed) {
  3916. Path tmp2;
  3917. TranslatePath(paths[i], tmp2, pattern[0]);
  3918. c.AddPath(tmp2, ptClip, true);
  3919. }
  3920. }
  3921. c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
  3922. }
  3923. //------------------------------------------------------------------------------
  3924. void MinkowskiDiff(const Path &poly1, const Path &poly2, Paths &solution) {
  3925. Minkowski(poly1, poly2, solution, false, true);
  3926. Clipper c;
  3927. c.AddPaths(solution, ptSubject, true);
  3928. c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
  3929. }
  3930. //------------------------------------------------------------------------------
  3931. enum NodeType { ntAny, ntOpen, ntClosed };
  3932. void AddPolyNodeToPaths(const PolyNode &polynode, NodeType nodetype,
  3933. Paths &paths) {
  3934. bool match = true;
  3935. if (nodetype == ntClosed)
  3936. match = !polynode.IsOpen();
  3937. else if (nodetype == ntOpen)
  3938. return;
  3939. if (!polynode.Contour.empty() && match)
  3940. paths.push_back(polynode.Contour);
  3941. for (int i = 0; i < polynode.ChildCount(); ++i)
  3942. AddPolyNodeToPaths(*polynode.Childs[i], nodetype, paths);
  3943. }
  3944. //------------------------------------------------------------------------------
  3945. void PolyTreeToPaths(const PolyTree &polytree, Paths &paths) {
  3946. paths.resize(0);
  3947. paths.reserve(polytree.Total());
  3948. AddPolyNodeToPaths(polytree, ntAny, paths);
  3949. }
  3950. //------------------------------------------------------------------------------
  3951. void ClosedPathsFromPolyTree(const PolyTree &polytree, Paths &paths) {
  3952. paths.resize(0);
  3953. paths.reserve(polytree.Total());
  3954. AddPolyNodeToPaths(polytree, ntClosed, paths);
  3955. }
  3956. //------------------------------------------------------------------------------
  3957. void OpenPathsFromPolyTree(PolyTree &polytree, Paths &paths) {
  3958. paths.resize(0);
  3959. paths.reserve(polytree.Total());
  3960. // Open paths are top level only, so ...
  3961. for (int i = 0; i < polytree.ChildCount(); ++i)
  3962. if (polytree.Childs[i]->IsOpen())
  3963. paths.push_back(polytree.Childs[i]->Contour);
  3964. }
  3965. //------------------------------------------------------------------------------
  3966. std::ostream &operator<<(std::ostream &s, const IntPoint &p) {
  3967. s << "(" << p.X << "," << p.Y << ")";
  3968. return s;
  3969. }
  3970. //------------------------------------------------------------------------------
  3971. std::ostream &operator<<(std::ostream &s, const Path &p) {
  3972. if (p.empty())
  3973. return s;
  3974. Path::size_type last = p.size() - 1;
  3975. for (Path::size_type i = 0; i < last; i++)
  3976. s << "(" << p[i].X << "," << p[i].Y << "), ";
  3977. s << "(" << p[last].X << "," << p[last].Y << ")\n";
  3978. return s;
  3979. }
  3980. //------------------------------------------------------------------------------
  3981. std::ostream &operator<<(std::ostream &s, const Paths &p) {
  3982. for (Paths::size_type i = 0; i < p.size(); i++)
  3983. s << p[i];
  3984. s << "\n";
  3985. return s;
  3986. }
  3987. //------------------------------------------------------------------------------
  3988. } // namespace ClipperLib