From 2c90136a04e01ff96f3b9b4ad3fcd554021d7b4f Mon Sep 17 00:00:00 2001 From: astridkbjorke Date: Mon, 16 Jan 2017 09:40:26 +0100 Subject: [PATCH] pre-proto - Adding clipper library version 6.4.0 to be used for polygon clipping --- CMakeLists.txt | 7 + ThirdParty/custom-clipper/CMakeLists.txt | 22 + .../custom-clipper/clipper/CMakeLists.txt | 21 + ThirdParty/custom-clipper/clipper/clipper.cpp | 4622 +++++++++++++++++ ThirdParty/custom-clipper/clipper/clipper.hpp | 404 ++ .../clipper/cpp_agg/agg_conv_clipper.h | 295 ++ .../clipper/cpp_agg/clipper_test.cpp | 574 ++ .../clipper/cpp_agg/clipper_test.exe | Bin 0 -> 240640 bytes .../clipper/cpp_agg/clipper_test.sln | 20 + .../clipper/cpp_agg/clipper_test.vcxproj | 114 + .../cpp_agg/clipper_test.vcxproj.filters | 118 + .../custom-clipper/clipper/cpp_agg/icon.res | Bin 0 -> 5556 bytes .../clipper/cpp_cairo/Cairo Resources.txt | 6 + .../clipper/cpp_cairo/cairo.sln | 20 + .../clipper/cpp_cairo/cairo.vcxproj | 93 + .../clipper/cpp_cairo/cairo_clipper.cpp | 134 + .../clipper/cpp_cairo/cairo_clipper.hpp | 59 + .../custom-clipper/clipper/cpp_cairo/main.cpp | 182 + .../cpp_console/clipper_console_demo.cpp | 461 ++ .../cpp_console/clipper_console_demo.exe | Bin 0 -> 74240 bytes .../cpp_console/clipper_console_demo.sln | 20 + .../cpp_console/clipper_console_demo.vcxproj | 92 + .../clipper/cpp_opengl/clipper_demo.exe | Bin 0 -> 307200 bytes .../clipper/cpp_opengl/clipper_demo.sln | 20 + .../clipper/cpp_opengl/clipper_demo.vcxproj | 98 + .../clipper/cpp_opengl/icon.res | Bin 0 -> 5556 bytes .../clipper/cpp_opengl/main.cpp | 621 +++ .../clipper/cpp_opengl/menu.res | Bin 0 -> 1364 bytes .../clipper/polyclipping.pc.cmakein | 13 + 29 files changed, 8016 insertions(+) create mode 100644 ThirdParty/custom-clipper/CMakeLists.txt create mode 100644 ThirdParty/custom-clipper/clipper/CMakeLists.txt create mode 100644 ThirdParty/custom-clipper/clipper/clipper.cpp create mode 100644 ThirdParty/custom-clipper/clipper/clipper.hpp create mode 100644 ThirdParty/custom-clipper/clipper/cpp_agg/agg_conv_clipper.h create mode 100644 ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.cpp create mode 100644 ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.exe create mode 100644 ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.sln create mode 100644 ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.vcxproj create mode 100644 ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.vcxproj.filters create mode 100644 ThirdParty/custom-clipper/clipper/cpp_agg/icon.res create mode 100644 ThirdParty/custom-clipper/clipper/cpp_cairo/Cairo Resources.txt create mode 100644 ThirdParty/custom-clipper/clipper/cpp_cairo/cairo.sln create mode 100644 ThirdParty/custom-clipper/clipper/cpp_cairo/cairo.vcxproj create mode 100644 ThirdParty/custom-clipper/clipper/cpp_cairo/cairo_clipper.cpp create mode 100644 ThirdParty/custom-clipper/clipper/cpp_cairo/cairo_clipper.hpp create mode 100644 ThirdParty/custom-clipper/clipper/cpp_cairo/main.cpp create mode 100644 ThirdParty/custom-clipper/clipper/cpp_console/clipper_console_demo.cpp create mode 100644 ThirdParty/custom-clipper/clipper/cpp_console/clipper_console_demo.exe create mode 100644 ThirdParty/custom-clipper/clipper/cpp_console/clipper_console_demo.sln create mode 100644 ThirdParty/custom-clipper/clipper/cpp_console/clipper_console_demo.vcxproj create mode 100644 ThirdParty/custom-clipper/clipper/cpp_opengl/clipper_demo.exe create mode 100644 ThirdParty/custom-clipper/clipper/cpp_opengl/clipper_demo.sln create mode 100644 ThirdParty/custom-clipper/clipper/cpp_opengl/clipper_demo.vcxproj create mode 100644 ThirdParty/custom-clipper/clipper/cpp_opengl/icon.res create mode 100644 ThirdParty/custom-clipper/clipper/cpp_opengl/main.cpp create mode 100644 ThirdParty/custom-clipper/clipper/cpp_opengl/menu.res create mode 100644 ThirdParty/custom-clipper/clipper/polyclipping.pc.cmakein diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bf1ff5e2f..c59594e2ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,6 +217,13 @@ add_subdirectory(ThirdParty/custom-opm-flowdiag-app) add_subdirectory(ThirdParty/NRLib) +################################################################################ +# clipper +################################################################################ + +add_subdirectory(ThirdParty/custom-clipper) + + ################################################################################ # Qt ################################################################################ diff --git a/ThirdParty/custom-clipper/CMakeLists.txt b/ThirdParty/custom-clipper/CMakeLists.txt new file mode 100644 index 0000000000..c4b5a02373 --- /dev/null +++ b/ThirdParty/custom-clipper/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required (VERSION 2.8) + +project (custom-clipper) + +include_directories( + clipper +) + +#include (opm-flowdiagnostics/CMakeLists_files.cmake) + +set(project_source_files + clipper.cpp +) + +foreach (file ${project_source_files} ) + list(APPEND project_source_files_complete_path "clipper/${file}" ) +endforeach() + +add_library(${PROJECT_NAME} + ${project_source_files_complete_path} +) + diff --git a/ThirdParty/custom-clipper/clipper/CMakeLists.txt b/ThirdParty/custom-clipper/clipper/CMakeLists.txt new file mode 100644 index 0000000000..f0ed7e8e16 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/CMakeLists.txt @@ -0,0 +1,21 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0) +PROJECT(polyclipping) + +SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Release type") +# The header name clipper.hpp is too generic, so install in a subdirectory +SET(CMAKE_INSTALL_INCDIR "${CMAKE_INSTALL_PREFIX}/include/polyclipping") +SET(CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") +SET(CMAKE_INSTALL_PKGCONFIGDIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig") +SET(PCFILE "${CMAKE_CURRENT_BINARY_DIR}/polyclipping.pc") + +SET(BUILD_SHARED_LIBS ON CACHE BOOL + "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)") +ADD_LIBRARY(polyclipping clipper.cpp) + +CONFIGURE_FILE (polyclipping.pc.cmakein "${PCFILE}" @ONLY) + +INSTALL (FILES clipper.hpp DESTINATION "${CMAKE_INSTALL_INCDIR}") +INSTALL (TARGETS polyclipping LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") +INSTALL (FILES "${PCFILE}" DESTINATION "${CMAKE_INSTALL_PKGCONFIGDIR}") + +SET_TARGET_PROPERTIES(polyclipping PROPERTIES VERSION 22.0.0 SOVERSION 22 ) diff --git a/ThirdParty/custom-clipper/clipper/clipper.cpp b/ThirdParty/custom-clipper/clipper/clipper.cpp new file mode 100644 index 0000000000..4993ba990f --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/clipper.cpp @@ -0,0 +1,4622 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 6.4.0 * +* Date : 2 July 2015 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2015 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Attributions: * +* The code in this library is an extension of Bala Vatti's clipping algorithm: * +* "A generic solution to polygon clipping" * +* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * +* http://portal.acm.org/citation.cfm?id=129906 * +* * +* Computer graphics and geometric modeling: implementation and algorithms * +* By Max K. Agoston * +* Springer; 1 edition (January 4, 2005) * +* http://books.google.com/books?q=vatti+clipping+agoston * +* * +* See also: * +* "Polygon Offsetting by Computing Winding Numbers" * +* Paper no. DETC2005-85513 pp. 565-575 * +* ASME 2005 International Design Engineering Technical Conferences * +* and Computers and Information in Engineering Conference (IDETC/CIE2005) * +* September 24-28, 2005 , Long Beach, California, USA * +* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * +* * +*******************************************************************************/ + +/******************************************************************************* +* * +* This is a translation of the Delphi Clipper library and the naming style * +* used has retained a Delphi flavour. * +* * +*******************************************************************************/ + +#include "clipper.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ClipperLib { + +static double const pi = 3.141592653589793238; +static double const two_pi = pi *2; +static double const def_arc_tolerance = 0.25; + +enum Direction { dRightToLeft, dLeftToRight }; + +static int const Unassigned = -1; //edge not currently 'owning' a solution +static int const Skip = -2; //edge that would otherwise close a path + +#define HORIZONTAL (-1.0E+40) +#define TOLERANCE (1.0e-20) +#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) + +struct TEdge { + IntPoint Bot; + IntPoint Curr; //current (updated for every new scanbeam) + IntPoint Top; + double Dx; + PolyType PolyTyp; + EdgeSide Side; //side only refers to current side of solution poly + int WindDelta; //1 or -1 depending on winding direction + int WindCnt; + int WindCnt2; //winding count of the opposite polytype + int OutIdx; + TEdge *Next; + TEdge *Prev; + TEdge *NextInLML; + TEdge *NextInAEL; + TEdge *PrevInAEL; + TEdge *NextInSEL; + TEdge *PrevInSEL; +}; + +struct IntersectNode { + TEdge *Edge1; + TEdge *Edge2; + IntPoint Pt; +}; + +struct LocalMinimum { + cInt Y; + TEdge *LeftBound; + TEdge *RightBound; +}; + +struct OutPt; + +//OutRec: contains a path in the clipping solution. Edges in the AEL will +//carry a pointer to an OutRec when they are part of the clipping solution. +struct OutRec { + int Idx; + bool IsHole; + bool IsOpen; + OutRec *FirstLeft; //see comments in clipper.pas + PolyNode *PolyNd; + OutPt *Pts; + OutPt *BottomPt; +}; + +struct OutPt { + int Idx; + IntPoint Pt; + OutPt *Next; + OutPt *Prev; +}; + +struct Join { + OutPt *OutPt1; + OutPt *OutPt2; + IntPoint OffPt; +}; + +struct LocMinSorter +{ + inline bool operator()(const LocalMinimum& locMin1, const LocalMinimum& locMin2) + { + return locMin2.Y < locMin1.Y; + } +}; + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +inline cInt Round(double val) +{ + if ((val < 0)) return static_cast(val - 0.5); + else return static_cast(val + 0.5); +} +//------------------------------------------------------------------------------ + +inline cInt Abs(cInt val) +{ + return val < 0 ? -val : val; +} + +//------------------------------------------------------------------------------ +// PolyTree methods ... +//------------------------------------------------------------------------------ + +void PolyTree::Clear() +{ + for (PolyNodes::size_type i = 0; i < AllNodes.size(); ++i) + delete AllNodes[i]; + AllNodes.resize(0); + Childs.resize(0); +} +//------------------------------------------------------------------------------ + +PolyNode* PolyTree::GetFirst() const +{ + if (!Childs.empty()) + return Childs[0]; + else + return 0; +} +//------------------------------------------------------------------------------ + +int PolyTree::Total() const +{ + int result = (int)AllNodes.size(); + //with negative offsets, ignore the hidden outer polygon ... + if (result > 0 && Childs[0] != AllNodes[0]) result--; + return result; +} + +//------------------------------------------------------------------------------ +// PolyNode methods ... +//------------------------------------------------------------------------------ + +PolyNode::PolyNode(): Childs(), Parent(0), Index(0), m_IsOpen(false) +{ +} +//------------------------------------------------------------------------------ + +int PolyNode::ChildCount() const +{ + return (int)Childs.size(); +} +//------------------------------------------------------------------------------ + +void PolyNode::AddChild(PolyNode& child) +{ + unsigned cnt = (unsigned)Childs.size(); + Childs.push_back(&child); + child.Parent = this; + child.Index = cnt; +} +//------------------------------------------------------------------------------ + +PolyNode* PolyNode::GetNext() const +{ + if (!Childs.empty()) + return Childs[0]; + else + return GetNextSiblingUp(); +} +//------------------------------------------------------------------------------ + +PolyNode* PolyNode::GetNextSiblingUp() const +{ + if (!Parent) //protects against PolyTree.GetNextSiblingUp() + return 0; + else if (Index == Parent->Childs.size() - 1) + return Parent->GetNextSiblingUp(); + else + return Parent->Childs[Index + 1]; +} +//------------------------------------------------------------------------------ + +bool PolyNode::IsHole() const +{ + bool result = true; + PolyNode* node = Parent; + while (node) + { + result = !result; + node = node->Parent; + } + return result; +} +//------------------------------------------------------------------------------ + +bool PolyNode::IsOpen() const +{ + return m_IsOpen; +} +//------------------------------------------------------------------------------ + +#ifndef use_int32 + +//------------------------------------------------------------------------------ +// Int128 class (enables safe math on signed 64bit integers) +// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1 +// Int128 val2((long64)9223372036854775807); +// Int128 val3 = val1 * val2; +// val3.AsString => "85070591730234615847396907784232501249" (8.5e+37) +//------------------------------------------------------------------------------ + +class Int128 +{ + public: + ulong64 lo; + long64 hi; + + Int128(long64 _lo = 0) + { + lo = (ulong64)_lo; + if (_lo < 0) hi = -1; else hi = 0; + } + + + Int128(const Int128 &val): lo(val.lo), hi(val.hi){} + + Int128(const long64& _hi, const ulong64& _lo): lo(_lo), hi(_hi){} + + Int128& operator = (const long64 &val) + { + lo = (ulong64)val; + if (val < 0) hi = -1; else hi = 0; + return *this; + } + + bool operator == (const Int128 &val) const + {return (hi == val.hi && lo == val.lo);} + + bool operator != (const Int128 &val) const + { return !(*this == val);} + + bool operator > (const Int128 &val) const + { + if (hi != val.hi) + return hi > val.hi; + else + return lo > val.lo; + } + + bool operator < (const Int128 &val) const + { + if (hi != val.hi) + return hi < val.hi; + else + return lo < val.lo; + } + + bool operator >= (const Int128 &val) const + { return !(*this < val);} + + bool operator <= (const Int128 &val) const + { return !(*this > val);} + + Int128& operator += (const Int128 &rhs) + { + hi += rhs.hi; + lo += rhs.lo; + if (lo < rhs.lo) hi++; + return *this; + } + + Int128 operator + (const Int128 &rhs) const + { + Int128 result(*this); + result+= rhs; + return result; + } + + Int128& operator -= (const Int128 &rhs) + { + *this += -rhs; + return *this; + } + + Int128 operator - (const Int128 &rhs) const + { + Int128 result(*this); + result -= rhs; + return result; + } + + Int128 operator-() const //unary negation + { + if (lo == 0) + return Int128(-hi, 0); + else + return Int128(~hi, ~lo + 1); + } + + operator double() const + { + const double shift64 = 18446744073709551616.0; //2^64 + if (hi < 0) + { + if (lo == 0) return (double)hi * shift64; + else return -(double)(~lo + ~hi * shift64); + } + else + return (double)(lo + hi * shift64); + } + +}; +//------------------------------------------------------------------------------ + +Int128 Int128Mul (long64 lhs, long64 rhs) +{ + bool negate = (lhs < 0) != (rhs < 0); + + if (lhs < 0) lhs = -lhs; + ulong64 int1Hi = ulong64(lhs) >> 32; + ulong64 int1Lo = ulong64(lhs & 0xFFFFFFFF); + + if (rhs < 0) rhs = -rhs; + ulong64 int2Hi = ulong64(rhs) >> 32; + ulong64 int2Lo = ulong64(rhs & 0xFFFFFFFF); + + //nb: see comments in clipper.pas + ulong64 a = int1Hi * int2Hi; + ulong64 b = int1Lo * int2Lo; + ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi; + + Int128 tmp; + tmp.hi = long64(a + (c >> 32)); + tmp.lo = long64(c << 32); + tmp.lo += long64(b); + if (tmp.lo < b) tmp.hi++; + if (negate) tmp = -tmp; + return tmp; +}; +#endif + +//------------------------------------------------------------------------------ +// Miscellaneous global functions +//------------------------------------------------------------------------------ + +bool Orientation(const Path &poly) +{ + return Area(poly) >= 0; +} +//------------------------------------------------------------------------------ + +double Area(const Path &poly) +{ + int size = (int)poly.size(); + if (size < 3) return 0; + + double a = 0; + for (int i = 0, j = size -1; i < size; ++i) + { + a += ((double)poly[j].X + poly[i].X) * ((double)poly[j].Y - poly[i].Y); + j = i; + } + return -a * 0.5; +} +//------------------------------------------------------------------------------ + +double Area(const OutPt *op) +{ + const OutPt *startOp = op; + if (!op) return 0; + double a = 0; + do { + a += (double)(op->Prev->Pt.X + op->Pt.X) * (double)(op->Prev->Pt.Y - op->Pt.Y); + op = op->Next; + } while (op != startOp); + return a * 0.5; +} +//------------------------------------------------------------------------------ + +double Area(const OutRec &outRec) +{ + return Area(outRec.Pts); +} +//------------------------------------------------------------------------------ + +bool PointIsVertex(const IntPoint &Pt, OutPt *pp) +{ + OutPt *pp2 = pp; + do + { + if (pp2->Pt == Pt) return true; + pp2 = pp2->Next; + } + while (pp2 != pp); + return false; +} +//------------------------------------------------------------------------------ + +//See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos +//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf +int PointInPolygon(const IntPoint &pt, const Path &path) +{ + //returns 0 if false, +1 if true, -1 if pt ON polygon boundary + int result = 0; + size_t cnt = path.size(); + if (cnt < 3) return 0; + IntPoint ip = path[0]; + for(size_t i = 1; i <= cnt; ++i) + { + IntPoint ipNext = (i == cnt ? path[0] : path[i]); + if (ipNext.Y == pt.Y) + { + if ((ipNext.X == pt.X) || (ip.Y == pt.Y && + ((ipNext.X > pt.X) == (ip.X < pt.X)))) return -1; + } + if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y)) + { + if (ip.X >= pt.X) + { + if (ipNext.X > pt.X) result = 1 - result; + else + { + double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - + (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; + } + } else + { + if (ipNext.X > pt.X) + { + double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - + (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; + } + } + } + ip = ipNext; + } + return result; +} +//------------------------------------------------------------------------------ + +int PointInPolygon (const IntPoint &pt, OutPt *op) +{ + //returns 0 if false, +1 if true, -1 if pt ON polygon boundary + int result = 0; + OutPt* startOp = op; + for(;;) + { + if (op->Next->Pt.Y == pt.Y) + { + if ((op->Next->Pt.X == pt.X) || (op->Pt.Y == pt.Y && + ((op->Next->Pt.X > pt.X) == (op->Pt.X < pt.X)))) return -1; + } + if ((op->Pt.Y < pt.Y) != (op->Next->Pt.Y < pt.Y)) + { + if (op->Pt.X >= pt.X) + { + if (op->Next->Pt.X > pt.X) result = 1 - result; + else + { + double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - + (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; + } + } else + { + if (op->Next->Pt.X > pt.X) + { + double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - + (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; + } + } + } + op = op->Next; + if (startOp == op) break; + } + return result; +} +//------------------------------------------------------------------------------ + +bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2) +{ + OutPt* op = OutPt1; + do + { + //nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon + int res = PointInPolygon(op->Pt, OutPt2); + if (res >= 0) return res > 0; + op = op->Next; + } + while (op != OutPt1); + return true; +} +//---------------------------------------------------------------------- + +bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range) +{ +#ifndef use_int32 + if (UseFullInt64Range) + return Int128Mul(e1.Top.Y - e1.Bot.Y, e2.Top.X - e2.Bot.X) == + Int128Mul(e1.Top.X - e1.Bot.X, e2.Top.Y - e2.Bot.Y); + else +#endif + return (e1.Top.Y - e1.Bot.Y) * (e2.Top.X - e2.Bot.X) == + (e1.Top.X - e1.Bot.X) * (e2.Top.Y - e2.Bot.Y); +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, + const IntPoint pt3, bool UseFullInt64Range) +{ +#ifndef use_int32 + if (UseFullInt64Range) + return Int128Mul(pt1.Y-pt2.Y, pt2.X-pt3.X) == Int128Mul(pt1.X-pt2.X, pt2.Y-pt3.Y); + else +#endif + return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y); +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, + const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range) +{ +#ifndef use_int32 + if (UseFullInt64Range) + return Int128Mul(pt1.Y-pt2.Y, pt3.X-pt4.X) == Int128Mul(pt1.X-pt2.X, pt3.Y-pt4.Y); + else +#endif + return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y); +} +//------------------------------------------------------------------------------ + +inline bool IsHorizontal(TEdge &e) +{ + return e.Dx == HORIZONTAL; +} +//------------------------------------------------------------------------------ + +inline double GetDx(const IntPoint pt1, const IntPoint pt2) +{ + return (pt1.Y == pt2.Y) ? + HORIZONTAL : (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y); +} +//--------------------------------------------------------------------------- + +inline void SetDx(TEdge &e) +{ + cInt dy = (e.Top.Y - e.Bot.Y); + if (dy == 0) e.Dx = HORIZONTAL; + else e.Dx = (double)(e.Top.X - e.Bot.X) / dy; +} +//--------------------------------------------------------------------------- + +inline void SwapSides(TEdge &Edge1, TEdge &Edge2) +{ + EdgeSide Side = Edge1.Side; + Edge1.Side = Edge2.Side; + Edge2.Side = Side; +} +//------------------------------------------------------------------------------ + +inline void SwapPolyIndexes(TEdge &Edge1, TEdge &Edge2) +{ + int OutIdx = Edge1.OutIdx; + Edge1.OutIdx = Edge2.OutIdx; + Edge2.OutIdx = OutIdx; +} +//------------------------------------------------------------------------------ + +inline cInt TopX(TEdge &edge, const cInt currentY) +{ + return ( currentY == edge.Top.Y ) ? + edge.Top.X : edge.Bot.X + Round(edge.Dx *(currentY - edge.Bot.Y)); +} +//------------------------------------------------------------------------------ + +void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip) +{ +#ifdef use_xyz + ip.Z = 0; +#endif + + double b1, b2; + if (Edge1.Dx == Edge2.Dx) + { + ip.Y = Edge1.Curr.Y; + ip.X = TopX(Edge1, ip.Y); + return; + } + else if (Edge1.Dx == 0) + { + ip.X = Edge1.Bot.X; + if (IsHorizontal(Edge2)) + ip.Y = Edge2.Bot.Y; + else + { + b2 = Edge2.Bot.Y - (Edge2.Bot.X / Edge2.Dx); + ip.Y = Round(ip.X / Edge2.Dx + b2); + } + } + else if (Edge2.Dx == 0) + { + ip.X = Edge2.Bot.X; + if (IsHorizontal(Edge1)) + ip.Y = Edge1.Bot.Y; + else + { + b1 = Edge1.Bot.Y - (Edge1.Bot.X / Edge1.Dx); + ip.Y = Round(ip.X / Edge1.Dx + b1); + } + } + else + { + b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx; + b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx; + double q = (b2-b1) / (Edge1.Dx - Edge2.Dx); + ip.Y = Round(q); + if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) + ip.X = Round(Edge1.Dx * q + b1); + else + ip.X = Round(Edge2.Dx * q + b2); + } + + if (ip.Y < Edge1.Top.Y || ip.Y < Edge2.Top.Y) + { + if (Edge1.Top.Y > Edge2.Top.Y) + ip.Y = Edge1.Top.Y; + else + ip.Y = Edge2.Top.Y; + if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) + ip.X = TopX(Edge1, ip.Y); + else + ip.X = TopX(Edge2, ip.Y); + } + //finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ... + if (ip.Y > Edge1.Curr.Y) + { + ip.Y = Edge1.Curr.Y; + //use the more vertical edge to derive X ... + if (std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx)) + ip.X = TopX(Edge2, ip.Y); else + ip.X = TopX(Edge1, ip.Y); + } +} +//------------------------------------------------------------------------------ + +void ReversePolyPtLinks(OutPt *pp) +{ + if (!pp) return; + OutPt *pp1, *pp2; + pp1 = pp; + do { + pp2 = pp1->Next; + pp1->Next = pp1->Prev; + pp1->Prev = pp2; + pp1 = pp2; + } while( pp1 != pp ); +} +//------------------------------------------------------------------------------ + +void DisposeOutPts(OutPt*& pp) +{ + if (pp == 0) return; + pp->Prev->Next = 0; + while( pp ) + { + OutPt *tmpPp = pp; + pp = pp->Next; + delete tmpPp; + } +} +//------------------------------------------------------------------------------ + +inline void InitEdge(TEdge* e, TEdge* eNext, TEdge* ePrev, const IntPoint& Pt) +{ + std::memset(e, 0, sizeof(TEdge)); + e->Next = eNext; + e->Prev = ePrev; + e->Curr = Pt; + e->OutIdx = Unassigned; +} +//------------------------------------------------------------------------------ + +void InitEdge2(TEdge& e, PolyType Pt) +{ + if (e.Curr.Y >= e.Next->Curr.Y) + { + e.Bot = e.Curr; + e.Top = e.Next->Curr; + } else + { + e.Top = e.Curr; + e.Bot = e.Next->Curr; + } + SetDx(e); + e.PolyTyp = Pt; +} +//------------------------------------------------------------------------------ + +TEdge* RemoveEdge(TEdge* e) +{ + //removes e from double_linked_list (but without removing from memory) + e->Prev->Next = e->Next; + e->Next->Prev = e->Prev; + TEdge* result = e->Next; + e->Prev = 0; //flag as removed (see ClipperBase.Clear) + return result; +} +//------------------------------------------------------------------------------ + +inline void ReverseHorizontal(TEdge &e) +{ + //swap horizontal edges' Top and Bottom x's so they follow the natural + //progression of the bounds - ie so their xbots will align with the + //adjoining lower edge. [Helpful in the ProcessHorizontal() method.] + std::swap(e.Top.X, e.Bot.X); +#ifdef use_xyz + std::swap(e.Top.Z, e.Bot.Z); +#endif +} +//------------------------------------------------------------------------------ + +void SwapPoints(IntPoint &pt1, IntPoint &pt2) +{ + IntPoint tmp = pt1; + pt1 = pt2; + pt2 = tmp; +} +//------------------------------------------------------------------------------ + +bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a, + IntPoint pt2b, IntPoint &pt1, IntPoint &pt2) +{ + //precondition: segments are Collinear. + if (Abs(pt1a.X - pt1b.X) > Abs(pt1a.Y - pt1b.Y)) + { + if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b); + if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b); + if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a; + if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b; + return pt1.X < pt2.X; + } else + { + if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b); + if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b); + if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a; + if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b; + return pt1.Y > pt2.Y; + } +} +//------------------------------------------------------------------------------ + +bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2) +{ + OutPt *p = btmPt1->Prev; + while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Prev; + double dx1p = std::fabs(GetDx(btmPt1->Pt, p->Pt)); + p = btmPt1->Next; + while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Next; + double dx1n = std::fabs(GetDx(btmPt1->Pt, p->Pt)); + + p = btmPt2->Prev; + while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Prev; + double dx2p = std::fabs(GetDx(btmPt2->Pt, p->Pt)); + p = btmPt2->Next; + while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next; + double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt)); + + if (std::max(dx1p, dx1n) == std::max(dx2p, dx2n) && + std::min(dx1p, dx1n) == std::min(dx2p, dx2n)) + return Area(btmPt1) > 0; //if otherwise identical use orientation + else + return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); +} +//------------------------------------------------------------------------------ + +OutPt* GetBottomPt(OutPt *pp) +{ + OutPt* dups = 0; + OutPt* p = pp->Next; + while (p != pp) + { + if (p->Pt.Y > pp->Pt.Y) + { + pp = p; + dups = 0; + } + else if (p->Pt.Y == pp->Pt.Y && p->Pt.X <= pp->Pt.X) + { + if (p->Pt.X < pp->Pt.X) + { + dups = 0; + pp = p; + } else + { + if (p->Next != pp && p->Prev != pp) dups = p; + } + } + p = p->Next; + } + if (dups) + { + //there appears to be at least 2 vertices at BottomPt so ... + while (dups != p) + { + if (!FirstIsBottomPt(p, dups)) pp = dups; + dups = dups->Next; + while (dups->Pt != pp->Pt) dups = dups->Next; + } + } + return pp; +} +//------------------------------------------------------------------------------ + +bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1, + const IntPoint pt2, const IntPoint pt3) +{ + if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) + return false; + else if (pt1.X != pt3.X) + return (pt2.X > pt1.X) == (pt2.X < pt3.X); + else + return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y); +} +//------------------------------------------------------------------------------ + +bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b) +{ + if (seg1a > seg1b) std::swap(seg1a, seg1b); + if (seg2a > seg2b) std::swap(seg2a, seg2b); + return (seg1a < seg2b) && (seg2a < seg1b); +} + +//------------------------------------------------------------------------------ +// ClipperBase class methods ... +//------------------------------------------------------------------------------ + +ClipperBase::ClipperBase() //constructor +{ + m_CurrentLM = m_MinimaList.begin(); //begin() == end() here + m_UseFullRange = false; +} +//------------------------------------------------------------------------------ + +ClipperBase::~ClipperBase() //destructor +{ + Clear(); +} +//------------------------------------------------------------------------------ + +void RangeTest(const IntPoint& Pt, bool& useFullRange) +{ + if (useFullRange) + { + if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange) + throw clipperException("Coordinate outside allowed range"); + } + else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange) + { + useFullRange = true; + RangeTest(Pt, useFullRange); + } +} +//------------------------------------------------------------------------------ + +TEdge* FindNextLocMin(TEdge* E) +{ + for (;;) + { + while (E->Bot != E->Prev->Bot || E->Curr == E->Top) E = E->Next; + if (!IsHorizontal(*E) && !IsHorizontal(*E->Prev)) break; + while (IsHorizontal(*E->Prev)) E = E->Prev; + TEdge* E2 = E; + while (IsHorizontal(*E)) E = E->Next; + if (E->Top.Y == E->Prev->Bot.Y) continue; //ie just an intermediate horz. + if (E2->Prev->Bot.X < E->Bot.X) E = E2; + break; + } + return E; +} +//------------------------------------------------------------------------------ + +TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward) +{ + TEdge *Result = E; + TEdge *Horz = 0; + + if (E->OutIdx == Skip) + { + //if edges still remain in the current bound beyond the skip edge then + //create another LocMin and call ProcessBound once more + if (NextIsForward) + { + while (E->Top.Y == E->Next->Bot.Y) E = E->Next; + //don't include top horizontals when parsing a bound a second time, + //they will be contained in the opposite bound ... + while (E != Result && IsHorizontal(*E)) E = E->Prev; + } + else + { + while (E->Top.Y == E->Prev->Bot.Y) E = E->Prev; + while (E != Result && IsHorizontal(*E)) E = E->Next; + } + + if (E == Result) + { + if (NextIsForward) Result = E->Next; + else Result = E->Prev; + } + else + { + //there are more edges in the bound beyond result starting with E + if (NextIsForward) + E = Result->Next; + else + E = Result->Prev; + MinimaList::value_type locMin; + locMin.Y = E->Bot.Y; + locMin.LeftBound = 0; + locMin.RightBound = E; + E->WindDelta = 0; + Result = ProcessBound(E, NextIsForward); + m_MinimaList.push_back(locMin); + } + return Result; + } + + TEdge *EStart; + + if (IsHorizontal(*E)) + { + //We need to be careful with open paths because this may not be a + //true local minima (ie E may be following a skip edge). + //Also, consecutive horz. edges may start heading left before going right. + if (NextIsForward) + EStart = E->Prev; + else + EStart = E->Next; + if (IsHorizontal(*EStart)) //ie an adjoining horizontal skip edge + { + if (EStart->Bot.X != E->Bot.X && EStart->Top.X != E->Bot.X) + ReverseHorizontal(*E); + } + else if (EStart->Bot.X != E->Bot.X) + ReverseHorizontal(*E); + } + + EStart = E; + if (NextIsForward) + { + while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip) + Result = Result->Next; + if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip) + { + //nb: at the top of a bound, horizontals are added to the bound + //only when the preceding edge attaches to the horizontal's left vertex + //unless a Skip edge is encountered when that becomes the top divide + Horz = Result; + while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev; + if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev; + } + while (E != Result) + { + E->NextInLML = E->Next; + if (IsHorizontal(*E) && E != EStart && + E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); + E = E->Next; + } + if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X) + ReverseHorizontal(*E); + Result = Result->Next; //move to the edge just beyond current bound + } else + { + while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip) + Result = Result->Prev; + if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip) + { + Horz = Result; + while (IsHorizontal(*Horz->Next)) Horz = Horz->Next; + if (Horz->Next->Top.X == Result->Prev->Top.X || + Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next; + } + + while (E != Result) + { + E->NextInLML = E->Prev; + if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X) + ReverseHorizontal(*E); + E = E->Prev; + } + if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X) + ReverseHorizontal(*E); + Result = Result->Prev; //move to the edge just beyond current bound + } + + return Result; +} +//------------------------------------------------------------------------------ + +bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) +{ +#ifdef use_lines + if (!Closed && PolyTyp == ptClip) + throw clipperException("AddPath: Open paths must be subject."); +#else + if (!Closed) + throw clipperException("AddPath: Open paths have been disabled."); +#endif + + int highI = (int)pg.size() -1; + if (Closed) while (highI > 0 && (pg[highI] == pg[0])) --highI; + while (highI > 0 && (pg[highI] == pg[highI -1])) --highI; + if ((Closed && highI < 2) || (!Closed && highI < 1)) return false; + + //create a new edge array ... + TEdge *edges = new TEdge [highI +1]; + + bool IsFlat = true; + //1. Basic (first) edge initialization ... + try + { + edges[1].Curr = pg[1]; + RangeTest(pg[0], m_UseFullRange); + RangeTest(pg[highI], m_UseFullRange); + InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]); + InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]); + for (int i = highI - 1; i >= 1; --i) + { + RangeTest(pg[i], m_UseFullRange); + InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]); + } + } + catch(...) + { + delete [] edges; + throw; //range test fails + } + TEdge *eStart = &edges[0]; + + //2. Remove duplicate vertices, and (when closed) collinear edges ... + TEdge *E = eStart, *eLoopStop = eStart; + for (;;) + { + //nb: allows matching start and end points when not Closed ... + if (E->Curr == E->Next->Curr && (Closed || E->Next != eStart)) + { + if (E == E->Next) break; + if (E == eStart) eStart = E->Next; + E = RemoveEdge(E); + eLoopStop = E; + continue; + } + if (E->Prev == E->Next) + break; //only two vertices + else if (Closed && + SlopesEqual(E->Prev->Curr, E->Curr, E->Next->Curr, m_UseFullRange) && + (!m_PreserveCollinear || + !Pt2IsBetweenPt1AndPt3(E->Prev->Curr, E->Curr, E->Next->Curr))) + { + //Collinear edges are allowed for open paths but in closed paths + //the default is to merge adjacent collinear edges into a single edge. + //However, if the PreserveCollinear property is enabled, only overlapping + //collinear edges (ie spikes) will be removed from closed paths. + if (E == eStart) eStart = E->Next; + E = RemoveEdge(E); + E = E->Prev; + eLoopStop = E; + continue; + } + E = E->Next; + if ((E == eLoopStop) || (!Closed && E->Next == eStart)) break; + } + + if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next))) + { + delete [] edges; + return false; + } + + if (!Closed) + { + m_HasOpenPaths = true; + eStart->Prev->OutIdx = Skip; + } + + //3. Do second stage of edge initialization ... + E = eStart; + do + { + InitEdge2(*E, PolyTyp); + E = E->Next; + if (IsFlat && E->Curr.Y != eStart->Curr.Y) IsFlat = false; + } + while (E != eStart); + + //4. Finally, add edge bounds to LocalMinima list ... + + //Totally flat paths must be handled differently when adding them + //to LocalMinima list to avoid endless loops etc ... + if (IsFlat) + { + if (Closed) + { + delete [] edges; + return false; + } + E->Prev->OutIdx = Skip; + MinimaList::value_type locMin; + locMin.Y = E->Bot.Y; + locMin.LeftBound = 0; + locMin.RightBound = E; + locMin.RightBound->Side = esRight; + locMin.RightBound->WindDelta = 0; + for (;;) + { + if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); + if (E->Next->OutIdx == Skip) break; + E->NextInLML = E->Next; + E = E->Next; + } + m_MinimaList.push_back(locMin); + m_edges.push_back(edges); + return true; + } + + m_edges.push_back(edges); + bool leftBoundIsForward; + TEdge* EMin = 0; + + //workaround to avoid an endless loop in the while loop below when + //open paths have matching start and end points ... + if (E->Prev->Bot == E->Prev->Top) E = E->Next; + + for (;;) + { + E = FindNextLocMin(E); + if (E == EMin) break; + else if (!EMin) EMin = E; + + //E and E.Prev now share a local minima (left aligned if horizontal). + //Compare their slopes to find which starts which bound ... + MinimaList::value_type locMin; + locMin.Y = E->Bot.Y; + if (E->Dx < E->Prev->Dx) + { + locMin.LeftBound = E->Prev; + locMin.RightBound = E; + leftBoundIsForward = false; //Q.nextInLML = Q.prev + } else + { + locMin.LeftBound = E; + locMin.RightBound = E->Prev; + leftBoundIsForward = true; //Q.nextInLML = Q.next + } + + if (!Closed) locMin.LeftBound->WindDelta = 0; + else if (locMin.LeftBound->Next == locMin.RightBound) + locMin.LeftBound->WindDelta = -1; + else locMin.LeftBound->WindDelta = 1; + locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta; + + E = ProcessBound(locMin.LeftBound, leftBoundIsForward); + if (E->OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward); + + TEdge* E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward); + if (E2->OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward); + + if (locMin.LeftBound->OutIdx == Skip) + locMin.LeftBound = 0; + else if (locMin.RightBound->OutIdx == Skip) + locMin.RightBound = 0; + m_MinimaList.push_back(locMin); + if (!leftBoundIsForward) E = E2; + } + return true; +} +//------------------------------------------------------------------------------ + +bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed) +{ + bool result = false; + for (Paths::size_type i = 0; i < ppg.size(); ++i) + if (AddPath(ppg[i], PolyTyp, Closed)) result = true; + return result; +} +//------------------------------------------------------------------------------ + +void ClipperBase::Clear() +{ + DisposeLocalMinimaList(); + for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) + { + TEdge* edges = m_edges[i]; + delete [] edges; + } + m_edges.clear(); + m_UseFullRange = false; + m_HasOpenPaths = false; +} +//------------------------------------------------------------------------------ + +void ClipperBase::Reset() +{ + m_CurrentLM = m_MinimaList.begin(); + if (m_CurrentLM == m_MinimaList.end()) return; //ie nothing to process + std::sort(m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter()); + + m_Scanbeam = ScanbeamList(); //clears/resets priority_queue + //reset all edges ... + for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm) + { + InsertScanbeam(lm->Y); + TEdge* e = lm->LeftBound; + if (e) + { + e->Curr = e->Bot; + e->Side = esLeft; + e->OutIdx = Unassigned; + } + + e = lm->RightBound; + if (e) + { + e->Curr = e->Bot; + e->Side = esRight; + e->OutIdx = Unassigned; + } + } + m_ActiveEdges = 0; + m_CurrentLM = m_MinimaList.begin(); +} +//------------------------------------------------------------------------------ + +void ClipperBase::DisposeLocalMinimaList() +{ + m_MinimaList.clear(); + m_CurrentLM = m_MinimaList.begin(); +} +//------------------------------------------------------------------------------ + +bool ClipperBase::PopLocalMinima(cInt Y, const LocalMinimum *&locMin) +{ + if (m_CurrentLM == m_MinimaList.end() || (*m_CurrentLM).Y != Y) return false; + locMin = &(*m_CurrentLM); + ++m_CurrentLM; + return true; +} +//------------------------------------------------------------------------------ + +IntRect ClipperBase::GetBounds() +{ + IntRect result; + MinimaList::iterator lm = m_MinimaList.begin(); + if (lm == m_MinimaList.end()) + { + result.left = result.top = result.right = result.bottom = 0; + return result; + } + result.left = lm->LeftBound->Bot.X; + result.top = lm->LeftBound->Bot.Y; + result.right = lm->LeftBound->Bot.X; + result.bottom = lm->LeftBound->Bot.Y; + while (lm != m_MinimaList.end()) + { + //todo - needs fixing for open paths + result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y); + TEdge* e = lm->LeftBound; + for (;;) { + TEdge* bottomE = e; + while (e->NextInLML) + { + if (e->Bot.X < result.left) result.left = e->Bot.X; + if (e->Bot.X > result.right) result.right = e->Bot.X; + e = e->NextInLML; + } + result.left = std::min(result.left, e->Bot.X); + result.right = std::max(result.right, e->Bot.X); + result.left = std::min(result.left, e->Top.X); + result.right = std::max(result.right, e->Top.X); + result.top = std::min(result.top, e->Top.Y); + if (bottomE == lm->LeftBound) e = lm->RightBound; + else break; + } + ++lm; + } + return result; +} +//------------------------------------------------------------------------------ + +void ClipperBase::InsertScanbeam(const cInt Y) +{ + m_Scanbeam.push(Y); +} +//------------------------------------------------------------------------------ + +bool ClipperBase::PopScanbeam(cInt &Y) +{ + if (m_Scanbeam.empty()) return false; + Y = m_Scanbeam.top(); + m_Scanbeam.pop(); + while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); } // Pop duplicates. + return true; +} +//------------------------------------------------------------------------------ + +void ClipperBase::DisposeAllOutRecs(){ + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + DisposeOutRec(i); + m_PolyOuts.clear(); +} +//------------------------------------------------------------------------------ + +void ClipperBase::DisposeOutRec(PolyOutList::size_type index) +{ + OutRec *outRec = m_PolyOuts[index]; + if (outRec->Pts) DisposeOutPts(outRec->Pts); + delete outRec; + m_PolyOuts[index] = 0; +} +//------------------------------------------------------------------------------ + +void ClipperBase::DeleteFromAEL(TEdge *e) +{ + TEdge* AelPrev = e->PrevInAEL; + TEdge* AelNext = e->NextInAEL; + if (!AelPrev && !AelNext && (e != m_ActiveEdges)) return; //already deleted + if (AelPrev) AelPrev->NextInAEL = AelNext; + else m_ActiveEdges = AelNext; + if (AelNext) AelNext->PrevInAEL = AelPrev; + e->NextInAEL = 0; + e->PrevInAEL = 0; +} +//------------------------------------------------------------------------------ + +OutRec* ClipperBase::CreateOutRec() +{ + OutRec* result = new OutRec; + result->IsHole = false; + result->IsOpen = false; + result->FirstLeft = 0; + result->Pts = 0; + result->BottomPt = 0; + result->PolyNd = 0; + m_PolyOuts.push_back(result); + result->Idx = (int)m_PolyOuts.size() - 1; + return result; +} +//------------------------------------------------------------------------------ + +void ClipperBase::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2) +{ + //check that one or other edge hasn't already been removed from AEL ... + if (Edge1->NextInAEL == Edge1->PrevInAEL || + Edge2->NextInAEL == Edge2->PrevInAEL) return; + + if (Edge1->NextInAEL == Edge2) + { + TEdge* Next = Edge2->NextInAEL; + if (Next) Next->PrevInAEL = Edge1; + TEdge* Prev = Edge1->PrevInAEL; + if (Prev) Prev->NextInAEL = Edge2; + Edge2->PrevInAEL = Prev; + Edge2->NextInAEL = Edge1; + Edge1->PrevInAEL = Edge2; + Edge1->NextInAEL = Next; + } + else if (Edge2->NextInAEL == Edge1) + { + TEdge* Next = Edge1->NextInAEL; + if (Next) Next->PrevInAEL = Edge2; + TEdge* Prev = Edge2->PrevInAEL; + if (Prev) Prev->NextInAEL = Edge1; + Edge1->PrevInAEL = Prev; + Edge1->NextInAEL = Edge2; + Edge2->PrevInAEL = Edge1; + Edge2->NextInAEL = Next; + } + else + { + TEdge* Next = Edge1->NextInAEL; + TEdge* Prev = Edge1->PrevInAEL; + Edge1->NextInAEL = Edge2->NextInAEL; + if (Edge1->NextInAEL) Edge1->NextInAEL->PrevInAEL = Edge1; + Edge1->PrevInAEL = Edge2->PrevInAEL; + if (Edge1->PrevInAEL) Edge1->PrevInAEL->NextInAEL = Edge1; + Edge2->NextInAEL = Next; + if (Edge2->NextInAEL) Edge2->NextInAEL->PrevInAEL = Edge2; + Edge2->PrevInAEL = Prev; + if (Edge2->PrevInAEL) Edge2->PrevInAEL->NextInAEL = Edge2; + } + + if (!Edge1->PrevInAEL) m_ActiveEdges = Edge1; + else if (!Edge2->PrevInAEL) m_ActiveEdges = Edge2; +} +//------------------------------------------------------------------------------ + +void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e) +{ + if (!e->NextInLML) + throw clipperException("UpdateEdgeIntoAEL: invalid call"); + + e->NextInLML->OutIdx = e->OutIdx; + TEdge* AelPrev = e->PrevInAEL; + TEdge* AelNext = e->NextInAEL; + if (AelPrev) AelPrev->NextInAEL = e->NextInLML; + else m_ActiveEdges = e->NextInLML; + if (AelNext) AelNext->PrevInAEL = e->NextInLML; + e->NextInLML->Side = e->Side; + e->NextInLML->WindDelta = e->WindDelta; + e->NextInLML->WindCnt = e->WindCnt; + e->NextInLML->WindCnt2 = e->WindCnt2; + e = e->NextInLML; + e->Curr = e->Bot; + e->PrevInAEL = AelPrev; + e->NextInAEL = AelNext; + if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y); +} +//------------------------------------------------------------------------------ + +bool ClipperBase::LocalMinimaPending() +{ + return (m_CurrentLM != m_MinimaList.end()); +} + +//------------------------------------------------------------------------------ +// TClipper methods ... +//------------------------------------------------------------------------------ + +Clipper::Clipper(int initOptions) : ClipperBase() //constructor +{ + m_ExecuteLocked = false; + m_UseFullRange = false; + m_ReverseOutput = ((initOptions & ioReverseSolution) != 0); + m_StrictSimple = ((initOptions & ioStrictlySimple) != 0); + m_PreserveCollinear = ((initOptions & ioPreserveCollinear) != 0); + m_HasOpenPaths = false; +#ifdef use_xyz + m_ZFill = 0; +#endif +} +//------------------------------------------------------------------------------ + +#ifdef use_xyz +void Clipper::ZFillFunction(ZFillCallback zFillFunc) +{ + m_ZFill = zFillFunc; +} +//------------------------------------------------------------------------------ +#endif + +bool Clipper::Execute(ClipType clipType, Paths &solution, PolyFillType fillType) +{ + return Execute(clipType, solution, fillType, fillType); +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, PolyTree &polytree, PolyFillType fillType) +{ + return Execute(clipType, polytree, fillType, fillType); +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, Paths &solution, + PolyFillType subjFillType, PolyFillType clipFillType) +{ + if( m_ExecuteLocked ) return false; + if (m_HasOpenPaths) + throw clipperException("Error: PolyTree struct is needed for open path clipping."); + m_ExecuteLocked = true; + solution.resize(0); + m_SubjFillType = subjFillType; + m_ClipFillType = clipFillType; + m_ClipType = clipType; + m_UsingPolyTree = false; + bool succeeded = ExecuteInternal(); + if (succeeded) BuildResult(solution); + DisposeAllOutRecs(); + m_ExecuteLocked = false; + return succeeded; +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, PolyTree& polytree, + PolyFillType subjFillType, PolyFillType clipFillType) +{ + if( m_ExecuteLocked ) return false; + m_ExecuteLocked = true; + m_SubjFillType = subjFillType; + m_ClipFillType = clipFillType; + m_ClipType = clipType; + m_UsingPolyTree = true; + bool succeeded = ExecuteInternal(); + if (succeeded) BuildResult2(polytree); + DisposeAllOutRecs(); + m_ExecuteLocked = false; + return succeeded; +} +//------------------------------------------------------------------------------ + +void Clipper::FixHoleLinkage(OutRec &outrec) +{ + //skip OutRecs that (a) contain outermost polygons or + //(b) already have the correct owner/child linkage ... + if (!outrec.FirstLeft || + (outrec.IsHole != outrec.FirstLeft->IsHole && + outrec.FirstLeft->Pts)) return; + + OutRec* orfl = outrec.FirstLeft; + while (orfl && ((orfl->IsHole == outrec.IsHole) || !orfl->Pts)) + orfl = orfl->FirstLeft; + outrec.FirstLeft = orfl; +} +//------------------------------------------------------------------------------ + +bool Clipper::ExecuteInternal() +{ + bool succeeded = true; + try { + Reset(); + m_Maxima = MaximaList(); + m_SortedEdges = 0; + + succeeded = true; + cInt botY, topY; + if (!PopScanbeam(botY)) return false; + InsertLocalMinimaIntoAEL(botY); + while (PopScanbeam(topY) || LocalMinimaPending()) + { + ProcessHorizontals(); + ClearGhostJoins(); + if (!ProcessIntersections(topY)) + { + succeeded = false; + break; + } + ProcessEdgesAtTopOfScanbeam(topY); + botY = topY; + InsertLocalMinimaIntoAEL(botY); + } + } + catch(...) + { + succeeded = false; + } + + if (succeeded) + { + //fix orientations ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec *outRec = m_PolyOuts[i]; + if (!outRec->Pts || outRec->IsOpen) continue; + if ((outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0)) + ReversePolyPtLinks(outRec->Pts); + } + + if (!m_Joins.empty()) JoinCommonEdges(); + + //unfortunately FixupOutPolygon() must be done after JoinCommonEdges() + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec *outRec = m_PolyOuts[i]; + if (!outRec->Pts) continue; + if (outRec->IsOpen) + FixupOutPolyline(*outRec); + else + FixupOutPolygon(*outRec); + } + + if (m_StrictSimple) DoSimplePolygons(); + } + + ClearJoins(); + ClearGhostJoins(); + return succeeded; +} +//------------------------------------------------------------------------------ + +void Clipper::SetWindingCount(TEdge &edge) +{ + TEdge *e = edge.PrevInAEL; + //find the edge of the same polytype that immediately preceeds 'edge' in AEL + while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL; + if (!e) + { + if (edge.WindDelta == 0) + { + PolyFillType pft = (edge.PolyTyp == ptSubject ? m_SubjFillType : m_ClipFillType); + edge.WindCnt = (pft == pftNegative ? -1 : 1); + } + else + edge.WindCnt = edge.WindDelta; + edge.WindCnt2 = 0; + e = m_ActiveEdges; //ie get ready to calc WindCnt2 + } + else if (edge.WindDelta == 0 && m_ClipType != ctUnion) + { + edge.WindCnt = 1; + edge.WindCnt2 = e->WindCnt2; + e = e->NextInAEL; //ie get ready to calc WindCnt2 + } + else if (IsEvenOddFillType(edge)) + { + //EvenOdd filling ... + if (edge.WindDelta == 0) + { + //are we inside a subj polygon ... + bool Inside = true; + TEdge *e2 = e->PrevInAEL; + while (e2) + { + if (e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0) + Inside = !Inside; + e2 = e2->PrevInAEL; + } + edge.WindCnt = (Inside ? 0 : 1); + } + else + { + edge.WindCnt = edge.WindDelta; + } + edge.WindCnt2 = e->WindCnt2; + e = e->NextInAEL; //ie get ready to calc WindCnt2 + } + else + { + //nonZero, Positive or Negative filling ... + if (e->WindCnt * e->WindDelta < 0) + { + //prev edge is 'decreasing' WindCount (WC) toward zero + //so we're outside the previous polygon ... + if (Abs(e->WindCnt) > 1) + { + //outside prev poly but still inside another. + //when reversing direction of prev poly use the same WC + if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; + //otherwise continue to 'decrease' WC ... + else edge.WindCnt = e->WindCnt + edge.WindDelta; + } + else + //now outside all polys of same polytype so set own WC ... + edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta); + } else + { + //prev edge is 'increasing' WindCount (WC) away from zero + //so we're inside the previous polygon ... + if (edge.WindDelta == 0) + edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1); + //if wind direction is reversing prev then use same WC + else if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; + //otherwise add to WC ... + else edge.WindCnt = e->WindCnt + edge.WindDelta; + } + edge.WindCnt2 = e->WindCnt2; + e = e->NextInAEL; //ie get ready to calc WindCnt2 + } + + //update WindCnt2 ... + if (IsEvenOddAltFillType(edge)) + { + //EvenOdd filling ... + while (e != &edge) + { + if (e->WindDelta != 0) + edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0); + e = e->NextInAEL; + } + } else + { + //nonZero, Positive or Negative filling ... + while ( e != &edge ) + { + edge.WindCnt2 += e->WindDelta; + e = e->NextInAEL; + } + } +} +//------------------------------------------------------------------------------ + +bool Clipper::IsEvenOddFillType(const TEdge& edge) const +{ + if (edge.PolyTyp == ptSubject) + return m_SubjFillType == pftEvenOdd; else + return m_ClipFillType == pftEvenOdd; +} +//------------------------------------------------------------------------------ + +bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const +{ + if (edge.PolyTyp == ptSubject) + return m_ClipFillType == pftEvenOdd; else + return m_SubjFillType == pftEvenOdd; +} +//------------------------------------------------------------------------------ + +bool Clipper::IsContributing(const TEdge& edge) const +{ + PolyFillType pft, pft2; + if (edge.PolyTyp == ptSubject) + { + pft = m_SubjFillType; + pft2 = m_ClipFillType; + } else + { + pft = m_ClipFillType; + pft2 = m_SubjFillType; + } + + switch(pft) + { + case pftEvenOdd: + //return false if a subj line has been flagged as inside a subj polygon + if (edge.WindDelta == 0 && edge.WindCnt != 1) return false; + break; + case pftNonZero: + if (Abs(edge.WindCnt) != 1) return false; + break; + case pftPositive: + if (edge.WindCnt != 1) return false; + break; + default: //pftNegative + if (edge.WindCnt != -1) return false; + } + + switch(m_ClipType) + { + case ctIntersection: + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 != 0); + case pftPositive: + return (edge.WindCnt2 > 0); + default: + return (edge.WindCnt2 < 0); + } + break; + case ctUnion: + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 == 0); + case pftPositive: + return (edge.WindCnt2 <= 0); + default: + return (edge.WindCnt2 >= 0); + } + break; + case ctDifference: + if (edge.PolyTyp == ptSubject) + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 == 0); + case pftPositive: + return (edge.WindCnt2 <= 0); + default: + return (edge.WindCnt2 >= 0); + } + else + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 != 0); + case pftPositive: + return (edge.WindCnt2 > 0); + default: + return (edge.WindCnt2 < 0); + } + break; + case ctXor: + if (edge.WindDelta == 0) //XOr always contributing unless open + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 == 0); + case pftPositive: + return (edge.WindCnt2 <= 0); + default: + return (edge.WindCnt2 >= 0); + } + else + return true; + break; + default: + return true; + } +} +//------------------------------------------------------------------------------ + +OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) +{ + OutPt* result; + TEdge *e, *prevE; + if (IsHorizontal(*e2) || ( e1->Dx > e2->Dx )) + { + result = AddOutPt(e1, Pt); + e2->OutIdx = e1->OutIdx; + e1->Side = esLeft; + e2->Side = esRight; + e = e1; + if (e->PrevInAEL == e2) + prevE = e2->PrevInAEL; + else + prevE = e->PrevInAEL; + } else + { + result = AddOutPt(e2, Pt); + e1->OutIdx = e2->OutIdx; + e1->Side = esRight; + e2->Side = esLeft; + e = e2; + if (e->PrevInAEL == e1) + prevE = e1->PrevInAEL; + else + prevE = e->PrevInAEL; + } + + if (prevE && prevE->OutIdx >= 0) + { + cInt xPrev = TopX(*prevE, Pt.Y); + cInt xE = TopX(*e, Pt.Y); + if (xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0) && + SlopesEqual(IntPoint(xPrev, Pt.Y), prevE->Top, IntPoint(xE, Pt.Y), e->Top, m_UseFullRange)) + { + OutPt* outPt = AddOutPt(prevE, Pt); + AddJoin(result, outPt, e->Top); + } + } + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) +{ + AddOutPt( e1, Pt ); + if (e2->WindDelta == 0) AddOutPt(e2, Pt); + if( e1->OutIdx == e2->OutIdx ) + { + e1->OutIdx = Unassigned; + e2->OutIdx = Unassigned; + } + else if (e1->OutIdx < e2->OutIdx) + AppendPolygon(e1, e2); + else + AppendPolygon(e2, e1); +} +//------------------------------------------------------------------------------ + +void Clipper::AddEdgeToSEL(TEdge *edge) +{ + //SEL pointers in PEdge are reused to build a list of horizontal edges. + //However, we don't need to worry about order with horizontal edge processing. + if( !m_SortedEdges ) + { + m_SortedEdges = edge; + edge->PrevInSEL = 0; + edge->NextInSEL = 0; + } + else + { + edge->NextInSEL = m_SortedEdges; + edge->PrevInSEL = 0; + m_SortedEdges->PrevInSEL = edge; + m_SortedEdges = edge; + } +} +//------------------------------------------------------------------------------ + +bool Clipper::PopEdgeFromSEL(TEdge *&edge) +{ + if (!m_SortedEdges) return false; + edge = m_SortedEdges; + DeleteFromSEL(m_SortedEdges); + return true; +} +//------------------------------------------------------------------------------ + +void Clipper::CopyAELToSEL() +{ + TEdge* e = m_ActiveEdges; + m_SortedEdges = e; + while ( e ) + { + e->PrevInSEL = e->PrevInAEL; + e->NextInSEL = e->NextInAEL; + e = e->NextInAEL; + } +} +//------------------------------------------------------------------------------ + +void Clipper::AddJoin(OutPt *op1, OutPt *op2, const IntPoint OffPt) +{ + Join* j = new Join; + j->OutPt1 = op1; + j->OutPt2 = op2; + j->OffPt = OffPt; + m_Joins.push_back(j); +} +//------------------------------------------------------------------------------ + +void Clipper::ClearJoins() +{ + for (JoinList::size_type i = 0; i < m_Joins.size(); i++) + delete m_Joins[i]; + m_Joins.resize(0); +} +//------------------------------------------------------------------------------ + +void Clipper::ClearGhostJoins() +{ + for (JoinList::size_type i = 0; i < m_GhostJoins.size(); i++) + delete m_GhostJoins[i]; + m_GhostJoins.resize(0); +} +//------------------------------------------------------------------------------ + +void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt) +{ + Join* j = new Join; + j->OutPt1 = op; + j->OutPt2 = 0; + j->OffPt = OffPt; + m_GhostJoins.push_back(j); +} +//------------------------------------------------------------------------------ + +void Clipper::InsertLocalMinimaIntoAEL(const cInt botY) +{ + const LocalMinimum *lm; + while (PopLocalMinima(botY, lm)) + { + TEdge* lb = lm->LeftBound; + TEdge* rb = lm->RightBound; + + OutPt *Op1 = 0; + if (!lb) + { + //nb: don't insert LB into either AEL or SEL + InsertEdgeIntoAEL(rb, 0); + SetWindingCount(*rb); + if (IsContributing(*rb)) + Op1 = AddOutPt(rb, rb->Bot); + } + else if (!rb) + { + InsertEdgeIntoAEL(lb, 0); + SetWindingCount(*lb); + if (IsContributing(*lb)) + Op1 = AddOutPt(lb, lb->Bot); + InsertScanbeam(lb->Top.Y); + } + else + { + InsertEdgeIntoAEL(lb, 0); + InsertEdgeIntoAEL(rb, lb); + SetWindingCount( *lb ); + rb->WindCnt = lb->WindCnt; + rb->WindCnt2 = lb->WindCnt2; + if (IsContributing(*lb)) + Op1 = AddLocalMinPoly(lb, rb, lb->Bot); + InsertScanbeam(lb->Top.Y); + } + + if (rb) + { + if (IsHorizontal(*rb)) + { + AddEdgeToSEL(rb); + if (rb->NextInLML) + InsertScanbeam(rb->NextInLML->Top.Y); + } + else InsertScanbeam( rb->Top.Y ); + } + + if (!lb || !rb) continue; + + //if any output polygons share an edge, they'll need joining later ... + if (Op1 && IsHorizontal(*rb) && + m_GhostJoins.size() > 0 && (rb->WindDelta != 0)) + { + for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i) + { + Join* jr = m_GhostJoins[i]; + //if the horizontal Rb and a 'ghost' horizontal overlap, then convert + //the 'ghost' join to a real join ready for later ... + if (HorzSegmentsOverlap(jr->OutPt1->Pt.X, jr->OffPt.X, rb->Bot.X, rb->Top.X)) + AddJoin(jr->OutPt1, Op1, jr->OffPt); + } + } + + if (lb->OutIdx >= 0 && lb->PrevInAEL && + lb->PrevInAEL->Curr.X == lb->Bot.X && + lb->PrevInAEL->OutIdx >= 0 && + SlopesEqual(lb->PrevInAEL->Bot, lb->PrevInAEL->Top, lb->Curr, lb->Top, m_UseFullRange) && + (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0)) + { + OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot); + AddJoin(Op1, Op2, lb->Top); + } + + if(lb->NextInAEL != rb) + { + + if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 && + SlopesEqual(rb->PrevInAEL->Curr, rb->PrevInAEL->Top, rb->Curr, rb->Top, m_UseFullRange) && + (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0)) + { + OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot); + AddJoin(Op1, Op2, rb->Top); + } + + TEdge* e = lb->NextInAEL; + if (e) + { + while( e != rb ) + { + //nb: For calculating winding counts etc, IntersectEdges() assumes + //that param1 will be to the Right of param2 ABOVE the intersection ... + IntersectEdges(rb , e , lb->Curr); //order important here + e = e->NextInAEL; + } + } + } + + } +} +//------------------------------------------------------------------------------ + +void Clipper::DeleteFromSEL(TEdge *e) +{ + TEdge* SelPrev = e->PrevInSEL; + TEdge* SelNext = e->NextInSEL; + if( !SelPrev && !SelNext && (e != m_SortedEdges) ) return; //already deleted + if( SelPrev ) SelPrev->NextInSEL = SelNext; + else m_SortedEdges = SelNext; + if( SelNext ) SelNext->PrevInSEL = SelPrev; + e->NextInSEL = 0; + e->PrevInSEL = 0; +} +//------------------------------------------------------------------------------ + +#ifdef use_xyz +void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2) +{ + if (pt.Z != 0 || !m_ZFill) return; + else if (pt == e1.Bot) pt.Z = e1.Bot.Z; + else if (pt == e1.Top) pt.Z = e1.Top.Z; + else if (pt == e2.Bot) pt.Z = e2.Bot.Z; + else if (pt == e2.Top) pt.Z = e2.Top.Z; + else (*m_ZFill)(e1.Bot, e1.Top, e2.Bot, e2.Top, pt); +} +//------------------------------------------------------------------------------ +#endif + +void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt) +{ + bool e1Contributing = ( e1->OutIdx >= 0 ); + bool e2Contributing = ( e2->OutIdx >= 0 ); + +#ifdef use_xyz + SetZ(Pt, *e1, *e2); +#endif + +#ifdef use_lines + //if either edge is on an OPEN path ... + if (e1->WindDelta == 0 || e2->WindDelta == 0) + { + //ignore subject-subject open path intersections UNLESS they + //are both open paths, AND they are both 'contributing maximas' ... + if (e1->WindDelta == 0 && e2->WindDelta == 0) return; + + //if intersecting a subj line with a subj poly ... + else if (e1->PolyTyp == e2->PolyTyp && + e1->WindDelta != e2->WindDelta && m_ClipType == ctUnion) + { + if (e1->WindDelta == 0) + { + if (e2Contributing) + { + AddOutPt(e1, Pt); + if (e1Contributing) e1->OutIdx = Unassigned; + } + } + else + { + if (e1Contributing) + { + AddOutPt(e2, Pt); + if (e2Contributing) e2->OutIdx = Unassigned; + } + } + } + else if (e1->PolyTyp != e2->PolyTyp) + { + //toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ... + if ((e1->WindDelta == 0) && abs(e2->WindCnt) == 1 && + (m_ClipType != ctUnion || e2->WindCnt2 == 0)) + { + AddOutPt(e1, Pt); + if (e1Contributing) e1->OutIdx = Unassigned; + } + else if ((e2->WindDelta == 0) && (abs(e1->WindCnt) == 1) && + (m_ClipType != ctUnion || e1->WindCnt2 == 0)) + { + AddOutPt(e2, Pt); + if (e2Contributing) e2->OutIdx = Unassigned; + } + } + return; + } +#endif + + //update winding counts... + //assumes that e1 will be to the Right of e2 ABOVE the intersection + if ( e1->PolyTyp == e2->PolyTyp ) + { + if ( IsEvenOddFillType( *e1) ) + { + int oldE1WindCnt = e1->WindCnt; + e1->WindCnt = e2->WindCnt; + e2->WindCnt = oldE1WindCnt; + } else + { + if (e1->WindCnt + e2->WindDelta == 0 ) e1->WindCnt = -e1->WindCnt; + else e1->WindCnt += e2->WindDelta; + if ( e2->WindCnt - e1->WindDelta == 0 ) e2->WindCnt = -e2->WindCnt; + else e2->WindCnt -= e1->WindDelta; + } + } else + { + if (!IsEvenOddFillType(*e2)) e1->WindCnt2 += e2->WindDelta; + else e1->WindCnt2 = ( e1->WindCnt2 == 0 ) ? 1 : 0; + if (!IsEvenOddFillType(*e1)) e2->WindCnt2 -= e1->WindDelta; + else e2->WindCnt2 = ( e2->WindCnt2 == 0 ) ? 1 : 0; + } + + PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; + if (e1->PolyTyp == ptSubject) + { + e1FillType = m_SubjFillType; + e1FillType2 = m_ClipFillType; + } else + { + e1FillType = m_ClipFillType; + e1FillType2 = m_SubjFillType; + } + if (e2->PolyTyp == ptSubject) + { + e2FillType = m_SubjFillType; + e2FillType2 = m_ClipFillType; + } else + { + e2FillType = m_ClipFillType; + e2FillType2 = m_SubjFillType; + } + + cInt e1Wc, e2Wc; + switch (e1FillType) + { + case pftPositive: e1Wc = e1->WindCnt; break; + case pftNegative: e1Wc = -e1->WindCnt; break; + default: e1Wc = Abs(e1->WindCnt); + } + switch(e2FillType) + { + case pftPositive: e2Wc = e2->WindCnt; break; + case pftNegative: e2Wc = -e2->WindCnt; break; + default: e2Wc = Abs(e2->WindCnt); + } + + if ( e1Contributing && e2Contributing ) + { + if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || + (e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) ) + { + AddLocalMaxPoly(e1, e2, Pt); + } + else + { + AddOutPt(e1, Pt); + AddOutPt(e2, Pt); + SwapSides( *e1 , *e2 ); + SwapPolyIndexes( *e1 , *e2 ); + } + } + else if ( e1Contributing ) + { + if (e2Wc == 0 || e2Wc == 1) + { + AddOutPt(e1, Pt); + SwapSides(*e1, *e2); + SwapPolyIndexes(*e1, *e2); + } + } + else if ( e2Contributing ) + { + if (e1Wc == 0 || e1Wc == 1) + { + AddOutPt(e2, Pt); + SwapSides(*e1, *e2); + SwapPolyIndexes(*e1, *e2); + } + } + else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1)) + { + //neither edge is currently contributing ... + + cInt e1Wc2, e2Wc2; + switch (e1FillType2) + { + case pftPositive: e1Wc2 = e1->WindCnt2; break; + case pftNegative : e1Wc2 = -e1->WindCnt2; break; + default: e1Wc2 = Abs(e1->WindCnt2); + } + switch (e2FillType2) + { + case pftPositive: e2Wc2 = e2->WindCnt2; break; + case pftNegative: e2Wc2 = -e2->WindCnt2; break; + default: e2Wc2 = Abs(e2->WindCnt2); + } + + if (e1->PolyTyp != e2->PolyTyp) + { + AddLocalMinPoly(e1, e2, Pt); + } + else if (e1Wc == 1 && e2Wc == 1) + switch( m_ClipType ) { + case ctIntersection: + if (e1Wc2 > 0 && e2Wc2 > 0) + AddLocalMinPoly(e1, e2, Pt); + break; + case ctUnion: + if ( e1Wc2 <= 0 && e2Wc2 <= 0 ) + AddLocalMinPoly(e1, e2, Pt); + break; + case ctDifference: + if (((e1->PolyTyp == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || + ((e1->PolyTyp == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) + AddLocalMinPoly(e1, e2, Pt); + break; + case ctXor: + AddLocalMinPoly(e1, e2, Pt); + } + else + SwapSides( *e1, *e2 ); + } +} +//------------------------------------------------------------------------------ + +void Clipper::SetHoleState(TEdge *e, OutRec *outrec) +{ + TEdge *e2 = e->PrevInAEL; + TEdge *eTmp = 0; + while (e2) + { + if (e2->OutIdx >= 0 && e2->WindDelta != 0) + { + if (!eTmp) eTmp = e2; + else if (eTmp->OutIdx == e2->OutIdx) eTmp = 0; + } + e2 = e2->PrevInAEL; + } + if (!eTmp) + { + outrec->FirstLeft = 0; + outrec->IsHole = false; + } + else + { + outrec->FirstLeft = m_PolyOuts[eTmp->OutIdx]; + outrec->IsHole = !outrec->FirstLeft->IsHole; + } +} +//------------------------------------------------------------------------------ + +OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2) +{ + //work out which polygon fragment has the correct hole state ... + if (!outRec1->BottomPt) + outRec1->BottomPt = GetBottomPt(outRec1->Pts); + if (!outRec2->BottomPt) + outRec2->BottomPt = GetBottomPt(outRec2->Pts); + OutPt *OutPt1 = outRec1->BottomPt; + OutPt *OutPt2 = outRec2->BottomPt; + if (OutPt1->Pt.Y > OutPt2->Pt.Y) return outRec1; + else if (OutPt1->Pt.Y < OutPt2->Pt.Y) return outRec2; + else if (OutPt1->Pt.X < OutPt2->Pt.X) return outRec1; + else if (OutPt1->Pt.X > OutPt2->Pt.X) return outRec2; + else if (OutPt1->Next == OutPt1) return outRec2; + else if (OutPt2->Next == OutPt2) return outRec1; + else if (FirstIsBottomPt(OutPt1, OutPt2)) return outRec1; + else return outRec2; +} +//------------------------------------------------------------------------------ + +bool OutRec1RightOfOutRec2(OutRec* outRec1, OutRec* outRec2) +{ + do + { + outRec1 = outRec1->FirstLeft; + if (outRec1 == outRec2) return true; + } while (outRec1); + return false; +} +//------------------------------------------------------------------------------ + +OutRec* Clipper::GetOutRec(int Idx) +{ + OutRec* outrec = m_PolyOuts[Idx]; + while (outrec != m_PolyOuts[outrec->Idx]) + outrec = m_PolyOuts[outrec->Idx]; + return outrec; +} +//------------------------------------------------------------------------------ + +void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) +{ + //get the start and ends of both output polygons ... + OutRec *outRec1 = m_PolyOuts[e1->OutIdx]; + OutRec *outRec2 = m_PolyOuts[e2->OutIdx]; + + OutRec *holeStateRec; + if (OutRec1RightOfOutRec2(outRec1, outRec2)) + holeStateRec = outRec2; + else if (OutRec1RightOfOutRec2(outRec2, outRec1)) + holeStateRec = outRec1; + else + holeStateRec = GetLowermostRec(outRec1, outRec2); + + //get the start and ends of both output polygons and + //join e2 poly onto e1 poly and delete pointers to e2 ... + + OutPt* p1_lft = outRec1->Pts; + OutPt* p1_rt = p1_lft->Prev; + OutPt* p2_lft = outRec2->Pts; + OutPt* p2_rt = p2_lft->Prev; + + //join e2 poly onto e1 poly and delete pointers to e2 ... + if( e1->Side == esLeft ) + { + if( e2->Side == esLeft ) + { + //z y x a b c + ReversePolyPtLinks(p2_lft); + p2_lft->Next = p1_lft; + p1_lft->Prev = p2_lft; + p1_rt->Next = p2_rt; + p2_rt->Prev = p1_rt; + outRec1->Pts = p2_rt; + } else + { + //x y z a b c + p2_rt->Next = p1_lft; + p1_lft->Prev = p2_rt; + p2_lft->Prev = p1_rt; + p1_rt->Next = p2_lft; + outRec1->Pts = p2_lft; + } + } else + { + if( e2->Side == esRight ) + { + //a b c z y x + ReversePolyPtLinks(p2_lft); + p1_rt->Next = p2_rt; + p2_rt->Prev = p1_rt; + p2_lft->Next = p1_lft; + p1_lft->Prev = p2_lft; + } else + { + //a b c x y z + p1_rt->Next = p2_lft; + p2_lft->Prev = p1_rt; + p1_lft->Prev = p2_rt; + p2_rt->Next = p1_lft; + } + } + + outRec1->BottomPt = 0; + if (holeStateRec == outRec2) + { + if (outRec2->FirstLeft != outRec1) + outRec1->FirstLeft = outRec2->FirstLeft; + outRec1->IsHole = outRec2->IsHole; + } + outRec2->Pts = 0; + outRec2->BottomPt = 0; + outRec2->FirstLeft = outRec1; + + int OKIdx = e1->OutIdx; + int ObsoleteIdx = e2->OutIdx; + + e1->OutIdx = Unassigned; //nb: safe because we only get here via AddLocalMaxPoly + e2->OutIdx = Unassigned; + + TEdge* e = m_ActiveEdges; + while( e ) + { + if( e->OutIdx == ObsoleteIdx ) + { + e->OutIdx = OKIdx; + e->Side = e1->Side; + break; + } + e = e->NextInAEL; + } + + outRec2->Idx = outRec1->Idx; +} +//------------------------------------------------------------------------------ + +OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt) +{ + if( e->OutIdx < 0 ) + { + OutRec *outRec = CreateOutRec(); + outRec->IsOpen = (e->WindDelta == 0); + OutPt* newOp = new OutPt; + outRec->Pts = newOp; + newOp->Idx = outRec->Idx; + newOp->Pt = pt; + newOp->Next = newOp; + newOp->Prev = newOp; + if (!outRec->IsOpen) + SetHoleState(e, outRec); + e->OutIdx = outRec->Idx; + return newOp; + } else + { + OutRec *outRec = m_PolyOuts[e->OutIdx]; + //OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most' + OutPt* op = outRec->Pts; + + bool ToFront = (e->Side == esLeft); + if (ToFront && (pt == op->Pt)) return op; + else if (!ToFront && (pt == op->Prev->Pt)) return op->Prev; + + OutPt* newOp = new OutPt; + newOp->Idx = outRec->Idx; + newOp->Pt = pt; + newOp->Next = op; + newOp->Prev = op->Prev; + newOp->Prev->Next = newOp; + op->Prev = newOp; + if (ToFront) outRec->Pts = newOp; + return newOp; + } +} +//------------------------------------------------------------------------------ + +OutPt* Clipper::GetLastOutPt(TEdge *e) +{ + OutRec *outRec = m_PolyOuts[e->OutIdx]; + if (e->Side == esLeft) + return outRec->Pts; + else + return outRec->Pts->Prev; +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessHorizontals() +{ + TEdge* horzEdge; + while (PopEdgeFromSEL(horzEdge)) + ProcessHorizontal(horzEdge); +} +//------------------------------------------------------------------------------ + +inline bool IsMinima(TEdge *e) +{ + return e && (e->Prev->NextInLML != e) && (e->Next->NextInLML != e); +} +//------------------------------------------------------------------------------ + +inline bool IsMaxima(TEdge *e, const cInt Y) +{ + return e && e->Top.Y == Y && !e->NextInLML; +} +//------------------------------------------------------------------------------ + +inline bool IsIntermediate(TEdge *e, const cInt Y) +{ + return e->Top.Y == Y && e->NextInLML; +} +//------------------------------------------------------------------------------ + +TEdge *GetMaximaPair(TEdge *e) +{ + if ((e->Next->Top == e->Top) && !e->Next->NextInLML) + return e->Next; + else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML) + return e->Prev; + else return 0; +} +//------------------------------------------------------------------------------ + +TEdge *GetMaximaPairEx(TEdge *e) +{ + //as GetMaximaPair() but returns 0 if MaxPair isn't in AEL (unless it's horizontal) + TEdge* result = GetMaximaPair(e); + if (result && (result->OutIdx == Skip || + (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result)))) return 0; + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::SwapPositionsInSEL(TEdge *Edge1, TEdge *Edge2) +{ + if( !( Edge1->NextInSEL ) && !( Edge1->PrevInSEL ) ) return; + if( !( Edge2->NextInSEL ) && !( Edge2->PrevInSEL ) ) return; + + if( Edge1->NextInSEL == Edge2 ) + { + TEdge* Next = Edge2->NextInSEL; + if( Next ) Next->PrevInSEL = Edge1; + TEdge* Prev = Edge1->PrevInSEL; + if( Prev ) Prev->NextInSEL = Edge2; + Edge2->PrevInSEL = Prev; + Edge2->NextInSEL = Edge1; + Edge1->PrevInSEL = Edge2; + Edge1->NextInSEL = Next; + } + else if( Edge2->NextInSEL == Edge1 ) + { + TEdge* Next = Edge1->NextInSEL; + if( Next ) Next->PrevInSEL = Edge2; + TEdge* Prev = Edge2->PrevInSEL; + if( Prev ) Prev->NextInSEL = Edge1; + Edge1->PrevInSEL = Prev; + Edge1->NextInSEL = Edge2; + Edge2->PrevInSEL = Edge1; + Edge2->NextInSEL = Next; + } + else + { + TEdge* Next = Edge1->NextInSEL; + TEdge* Prev = Edge1->PrevInSEL; + Edge1->NextInSEL = Edge2->NextInSEL; + if( Edge1->NextInSEL ) Edge1->NextInSEL->PrevInSEL = Edge1; + Edge1->PrevInSEL = Edge2->PrevInSEL; + if( Edge1->PrevInSEL ) Edge1->PrevInSEL->NextInSEL = Edge1; + Edge2->NextInSEL = Next; + if( Edge2->NextInSEL ) Edge2->NextInSEL->PrevInSEL = Edge2; + Edge2->PrevInSEL = Prev; + if( Edge2->PrevInSEL ) Edge2->PrevInSEL->NextInSEL = Edge2; + } + + if( !Edge1->PrevInSEL ) m_SortedEdges = Edge1; + else if( !Edge2->PrevInSEL ) m_SortedEdges = Edge2; +} +//------------------------------------------------------------------------------ + +TEdge* GetNextInAEL(TEdge *e, Direction dir) +{ + return dir == dLeftToRight ? e->NextInAEL : e->PrevInAEL; +} +//------------------------------------------------------------------------------ + +void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right) +{ + if (HorzEdge.Bot.X < HorzEdge.Top.X) + { + Left = HorzEdge.Bot.X; + Right = HorzEdge.Top.X; + Dir = dLeftToRight; + } else + { + Left = HorzEdge.Top.X; + Right = HorzEdge.Bot.X; + Dir = dRightToLeft; + } +} +//------------------------------------------------------------------------ + +/******************************************************************************* +* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or * +* Bottom of a scanbeam) are processed as if layered. The order in which HEs * +* are processed doesn't matter. HEs intersect with other HE Bot.Xs only [#] * +* (or they could intersect with Top.Xs only, ie EITHER Bot.Xs OR Top.Xs), * +* and with other non-horizontal edges [*]. Once these intersections are * +* processed, intermediate HEs then 'promote' the Edge above (NextInLML) into * +* the AEL. These 'promoted' edges may in turn intersect [%] with other HEs. * +*******************************************************************************/ + +void Clipper::ProcessHorizontal(TEdge *horzEdge) +{ + Direction dir; + cInt horzLeft, horzRight; + bool IsOpen = (horzEdge->WindDelta == 0); + + GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); + + TEdge* eLastHorz = horzEdge, *eMaxPair = 0; + while (eLastHorz->NextInLML && IsHorizontal(*eLastHorz->NextInLML)) + eLastHorz = eLastHorz->NextInLML; + if (!eLastHorz->NextInLML) + eMaxPair = GetMaximaPair(eLastHorz); + + MaximaList::const_iterator maxIt; + MaximaList::const_reverse_iterator maxRit; + if (m_Maxima.size() > 0) + { + //get the first maxima in range (X) ... + if (dir == dLeftToRight) + { + maxIt = m_Maxima.begin(); + while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.X) maxIt++; + if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.X) + maxIt = m_Maxima.end(); + } + else + { + maxRit = m_Maxima.rbegin(); + while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.X) maxRit++; + if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.X) + maxRit = m_Maxima.rend(); + } + } + + OutPt* op1 = 0; + + for (;;) //loop through consec. horizontal edges + { + + bool IsLastHorz = (horzEdge == eLastHorz); + TEdge* e = GetNextInAEL(horzEdge, dir); + while(e) + { + + //this code block inserts extra coords into horizontal edges (in output + //polygons) whereever maxima touch these horizontal edges. This helps + //'simplifying' polygons (ie if the Simplify property is set). + if (m_Maxima.size() > 0) + { + if (dir == dLeftToRight) + { + while (maxIt != m_Maxima.end() && *maxIt < e->Curr.X) + { + if (horzEdge->OutIdx >= 0 && !IsOpen) + AddOutPt(horzEdge, IntPoint(*maxIt, horzEdge->Bot.Y)); + maxIt++; + } + } + else + { + while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.X) + { + if (horzEdge->OutIdx >= 0 && !IsOpen) + AddOutPt(horzEdge, IntPoint(*maxRit, horzEdge->Bot.Y)); + maxRit++; + } + } + }; + + if ((dir == dLeftToRight && e->Curr.X > horzRight) || + (dir == dRightToLeft && e->Curr.X < horzLeft)) break; + + //Also break if we've got to the end of an intermediate horizontal edge ... + //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal. + if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML && + e->Dx < horzEdge->NextInLML->Dx) break; + + if (horzEdge->OutIdx >= 0 && !IsOpen) //note: may be done multiple times + { + op1 = AddOutPt(horzEdge, e->Curr); + TEdge* eNextHorz = m_SortedEdges; + while (eNextHorz) + { + if (eNextHorz->OutIdx >= 0 && + HorzSegmentsOverlap(horzEdge->Bot.X, + horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X)) + { + OutPt* op2 = GetLastOutPt(eNextHorz); + AddJoin(op2, op1, eNextHorz->Top); + } + eNextHorz = eNextHorz->NextInSEL; + } + AddGhostJoin(op1, horzEdge->Bot); + } + + //OK, so far we're still in range of the horizontal Edge but make sure + //we're at the last of consec. horizontals when matching with eMaxPair + if(e == eMaxPair && IsLastHorz) + { + if (horzEdge->OutIdx >= 0) + AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top); + DeleteFromAEL(horzEdge); + DeleteFromAEL(eMaxPair); + return; + } + + if(dir == dLeftToRight) + { + IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y); + IntersectEdges(horzEdge, e, Pt); + } + else + { + IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y); + IntersectEdges( e, horzEdge, Pt); + } + TEdge* eNext = GetNextInAEL(e, dir); + SwapPositionsInAEL( horzEdge, e ); + e = eNext; + } //end while(e) + + //Break out of loop if HorzEdge.NextInLML is not also horizontal ... + if (!horzEdge->NextInLML || !IsHorizontal(*horzEdge->NextInLML)) break; + + UpdateEdgeIntoAEL(horzEdge); + if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot); + GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); + + } //end for (;;) + + if (horzEdge->OutIdx >= 0 && !op1) + { + op1 = GetLastOutPt(horzEdge); + TEdge* eNextHorz = m_SortedEdges; + while (eNextHorz) + { + if (eNextHorz->OutIdx >= 0 && + HorzSegmentsOverlap(horzEdge->Bot.X, + horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X)) + { + OutPt* op2 = GetLastOutPt(eNextHorz); + AddJoin(op2, op1, eNextHorz->Top); + } + eNextHorz = eNextHorz->NextInSEL; + } + AddGhostJoin(op1, horzEdge->Top); + } + + if (horzEdge->NextInLML) + { + if(horzEdge->OutIdx >= 0) + { + op1 = AddOutPt( horzEdge, horzEdge->Top); + UpdateEdgeIntoAEL(horzEdge); + if (horzEdge->WindDelta == 0) return; + //nb: HorzEdge is no longer horizontal here + TEdge* ePrev = horzEdge->PrevInAEL; + TEdge* eNext = horzEdge->NextInAEL; + if (ePrev && ePrev->Curr.X == horzEdge->Bot.X && + ePrev->Curr.Y == horzEdge->Bot.Y && ePrev->WindDelta != 0 && + (ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y && + SlopesEqual(*horzEdge, *ePrev, m_UseFullRange))) + { + OutPt* op2 = AddOutPt(ePrev, horzEdge->Bot); + AddJoin(op1, op2, horzEdge->Top); + } + else if (eNext && eNext->Curr.X == horzEdge->Bot.X && + eNext->Curr.Y == horzEdge->Bot.Y && eNext->WindDelta != 0 && + eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y && + SlopesEqual(*horzEdge, *eNext, m_UseFullRange)) + { + OutPt* op2 = AddOutPt(eNext, horzEdge->Bot); + AddJoin(op1, op2, horzEdge->Top); + } + } + else + UpdateEdgeIntoAEL(horzEdge); + } + else + { + if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top); + DeleteFromAEL(horzEdge); + } +} +//------------------------------------------------------------------------------ + +bool Clipper::ProcessIntersections(const cInt topY) +{ + if( !m_ActiveEdges ) return true; + try { + BuildIntersectList(topY); + size_t IlSize = m_IntersectList.size(); + if (IlSize == 0) return true; + if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList(); + else return false; + } + catch(...) + { + m_SortedEdges = 0; + DisposeIntersectNodes(); + throw clipperException("ProcessIntersections error"); + } + m_SortedEdges = 0; + return true; +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeIntersectNodes() +{ + for (size_t i = 0; i < m_IntersectList.size(); ++i ) + delete m_IntersectList[i]; + m_IntersectList.clear(); +} +//------------------------------------------------------------------------------ + +void Clipper::BuildIntersectList(const cInt topY) +{ + if ( !m_ActiveEdges ) return; + + //prepare for sorting ... + TEdge* e = m_ActiveEdges; + m_SortedEdges = e; + while( e ) + { + e->PrevInSEL = e->PrevInAEL; + e->NextInSEL = e->NextInAEL; + e->Curr.X = TopX( *e, topY ); + e = e->NextInAEL; + } + + //bubblesort ... + bool isModified; + do + { + isModified = false; + e = m_SortedEdges; + while( e->NextInSEL ) + { + TEdge *eNext = e->NextInSEL; + IntPoint Pt; + if(e->Curr.X > eNext->Curr.X) + { + IntersectPoint(*e, *eNext, Pt); + if (Pt.Y < topY) Pt = IntPoint(TopX(*e, topY), topY); + IntersectNode * newNode = new IntersectNode; + newNode->Edge1 = e; + newNode->Edge2 = eNext; + newNode->Pt = Pt; + m_IntersectList.push_back(newNode); + + SwapPositionsInSEL(e, eNext); + isModified = true; + } + else + e = eNext; + } + if( e->PrevInSEL ) e->PrevInSEL->NextInSEL = 0; + else break; + } + while ( isModified ); + m_SortedEdges = 0; //important +} +//------------------------------------------------------------------------------ + + +void Clipper::ProcessIntersectList() +{ + for (size_t i = 0; i < m_IntersectList.size(); ++i) + { + IntersectNode* iNode = m_IntersectList[i]; + { + IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt); + SwapPositionsInAEL( iNode->Edge1 , iNode->Edge2 ); + } + delete iNode; + } + m_IntersectList.clear(); +} +//------------------------------------------------------------------------------ + +bool IntersectListSort(IntersectNode* node1, IntersectNode* node2) +{ + return node2->Pt.Y < node1->Pt.Y; +} +//------------------------------------------------------------------------------ + +inline bool EdgesAdjacent(const IntersectNode &inode) +{ + return (inode.Edge1->NextInSEL == inode.Edge2) || + (inode.Edge1->PrevInSEL == inode.Edge2); +} +//------------------------------------------------------------------------------ + +bool Clipper::FixupIntersectionOrder() +{ + //pre-condition: intersections are sorted Bottom-most first. + //Now it's crucial that intersections are made only between adjacent edges, + //so to ensure this the order of intersections may need adjusting ... + CopyAELToSEL(); + std::sort(m_IntersectList.begin(), m_IntersectList.end(), IntersectListSort); + size_t cnt = m_IntersectList.size(); + for (size_t i = 0; i < cnt; ++i) + { + if (!EdgesAdjacent(*m_IntersectList[i])) + { + size_t j = i + 1; + while (j < cnt && !EdgesAdjacent(*m_IntersectList[j])) j++; + if (j == cnt) return false; + std::swap(m_IntersectList[i], m_IntersectList[j]); + } + SwapPositionsInSEL(m_IntersectList[i]->Edge1, m_IntersectList[i]->Edge2); + } + return true; +} +//------------------------------------------------------------------------------ + +void Clipper::DoMaxima(TEdge *e) +{ + TEdge* eMaxPair = GetMaximaPairEx(e); + if (!eMaxPair) + { + if (e->OutIdx >= 0) + AddOutPt(e, e->Top); + DeleteFromAEL(e); + return; + } + + TEdge* eNext = e->NextInAEL; + while(eNext && eNext != eMaxPair) + { + IntersectEdges(e, eNext, e->Top); + SwapPositionsInAEL(e, eNext); + eNext = e->NextInAEL; + } + + if(e->OutIdx == Unassigned && eMaxPair->OutIdx == Unassigned) + { + DeleteFromAEL(e); + DeleteFromAEL(eMaxPair); + } + else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 ) + { + if (e->OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e->Top); + DeleteFromAEL(e); + DeleteFromAEL(eMaxPair); + } +#ifdef use_lines + else if (e->WindDelta == 0) + { + if (e->OutIdx >= 0) + { + AddOutPt(e, e->Top); + e->OutIdx = Unassigned; + } + DeleteFromAEL(e); + + if (eMaxPair->OutIdx >= 0) + { + AddOutPt(eMaxPair, e->Top); + eMaxPair->OutIdx = Unassigned; + } + DeleteFromAEL(eMaxPair); + } +#endif + else throw clipperException("DoMaxima error"); +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY) +{ + TEdge* e = m_ActiveEdges; + while( e ) + { + //1. process maxima, treating them as if they're 'bent' horizontal edges, + // but exclude maxima with horizontal edges. nb: e can't be a horizontal. + bool IsMaximaEdge = IsMaxima(e, topY); + + if(IsMaximaEdge) + { + TEdge* eMaxPair = GetMaximaPairEx(e); + IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair)); + } + + if(IsMaximaEdge) + { + if (m_StrictSimple) m_Maxima.push_back(e->Top.X); + TEdge* ePrev = e->PrevInAEL; + DoMaxima(e); + if( !ePrev ) e = m_ActiveEdges; + else e = ePrev->NextInAEL; + } + else + { + //2. promote horizontal edges, otherwise update Curr.X and Curr.Y ... + if (IsIntermediate(e, topY) && IsHorizontal(*e->NextInLML)) + { + UpdateEdgeIntoAEL(e); + if (e->OutIdx >= 0) + AddOutPt(e, e->Bot); + AddEdgeToSEL(e); + } + else + { + e->Curr.X = TopX( *e, topY ); + e->Curr.Y = topY; + } + + //When StrictlySimple and 'e' is being touched by another edge, then + //make sure both edges have a vertex here ... + if (m_StrictSimple) + { + TEdge* ePrev = e->PrevInAEL; + if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) && + (ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0)) + { + IntPoint pt = e->Curr; +#ifdef use_xyz + SetZ(pt, *ePrev, *e); +#endif + OutPt* op = AddOutPt(ePrev, pt); + OutPt* op2 = AddOutPt(e, pt); + AddJoin(op, op2, pt); //StrictlySimple (type-3) join + } + } + + e = e->NextInAEL; + } + } + + //3. Process horizontals at the Top of the scanbeam ... + m_Maxima.sort(); + ProcessHorizontals(); + m_Maxima.clear(); + + //4. Promote intermediate vertices ... + e = m_ActiveEdges; + while(e) + { + if(IsIntermediate(e, topY)) + { + OutPt* op = 0; + if( e->OutIdx >= 0 ) + op = AddOutPt(e, e->Top); + UpdateEdgeIntoAEL(e); + + //if output polygons share an edge, they'll need joining later ... + TEdge* ePrev = e->PrevInAEL; + TEdge* eNext = e->NextInAEL; + if (ePrev && ePrev->Curr.X == e->Bot.X && + ePrev->Curr.Y == e->Bot.Y && op && + ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y && + SlopesEqual(e->Curr, e->Top, ePrev->Curr, ePrev->Top, m_UseFullRange) && + (e->WindDelta != 0) && (ePrev->WindDelta != 0)) + { + OutPt* op2 = AddOutPt(ePrev, e->Bot); + AddJoin(op, op2, e->Top); + } + else if (eNext && eNext->Curr.X == e->Bot.X && + eNext->Curr.Y == e->Bot.Y && op && + eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y && + SlopesEqual(e->Curr, e->Top, eNext->Curr, eNext->Top, m_UseFullRange) && + (e->WindDelta != 0) && (eNext->WindDelta != 0)) + { + OutPt* op2 = AddOutPt(eNext, e->Bot); + AddJoin(op, op2, e->Top); + } + } + e = e->NextInAEL; + } +} +//------------------------------------------------------------------------------ + +void Clipper::FixupOutPolyline(OutRec &outrec) +{ + OutPt *pp = outrec.Pts; + OutPt *lastPP = pp->Prev; + while (pp != lastPP) + { + pp = pp->Next; + if (pp->Pt == pp->Prev->Pt) + { + if (pp == lastPP) lastPP = pp->Prev; + OutPt *tmpPP = pp->Prev; + tmpPP->Next = pp->Next; + pp->Next->Prev = tmpPP; + delete pp; + pp = tmpPP; + } + } + + if (pp == pp->Prev) + { + DisposeOutPts(pp); + outrec.Pts = 0; + return; + } +} +//------------------------------------------------------------------------------ + +void Clipper::FixupOutPolygon(OutRec &outrec) +{ + //FixupOutPolygon() - removes duplicate points and simplifies consecutive + //parallel edges by removing the middle vertex. + OutPt *lastOK = 0; + outrec.BottomPt = 0; + OutPt *pp = outrec.Pts; + bool preserveCol = m_PreserveCollinear || m_StrictSimple; + + for (;;) + { + if (pp->Prev == pp || pp->Prev == pp->Next) + { + DisposeOutPts(pp); + outrec.Pts = 0; + return; + } + + //test for duplicate points and collinear edges ... + if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) || + (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) && + (!preserveCol || !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt)))) + { + lastOK = 0; + OutPt *tmp = pp; + pp->Prev->Next = pp->Next; + pp->Next->Prev = pp->Prev; + pp = pp->Prev; + delete tmp; + } + else if (pp == lastOK) break; + else + { + if (!lastOK) lastOK = pp; + pp = pp->Next; + } + } + outrec.Pts = pp; +} +//------------------------------------------------------------------------------ + +int PointCount(OutPt *Pts) +{ + if (!Pts) return 0; + int result = 0; + OutPt* p = Pts; + do + { + result++; + p = p->Next; + } + while (p != Pts); + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::BuildResult(Paths &polys) +{ + polys.reserve(m_PolyOuts.size()); + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + if (!m_PolyOuts[i]->Pts) continue; + Path pg; + OutPt* p = m_PolyOuts[i]->Pts->Prev; + int cnt = PointCount(p); + if (cnt < 2) continue; + pg.reserve(cnt); + for (int i = 0; i < cnt; ++i) + { + pg.push_back(p->Pt); + p = p->Prev; + } + polys.push_back(pg); + } +} +//------------------------------------------------------------------------------ + +void Clipper::BuildResult2(PolyTree& polytree) +{ + polytree.Clear(); + polytree.AllNodes.reserve(m_PolyOuts.size()); + //add each output polygon/contour to polytree ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) + { + OutRec* outRec = m_PolyOuts[i]; + int cnt = PointCount(outRec->Pts); + if ((outRec->IsOpen && cnt < 2) || (!outRec->IsOpen && cnt < 3)) continue; + FixHoleLinkage(*outRec); + PolyNode* pn = new PolyNode(); + //nb: polytree takes ownership of all the PolyNodes + polytree.AllNodes.push_back(pn); + outRec->PolyNd = pn; + pn->Parent = 0; + pn->Index = 0; + pn->Contour.reserve(cnt); + OutPt *op = outRec->Pts->Prev; + for (int j = 0; j < cnt; j++) + { + pn->Contour.push_back(op->Pt); + op = op->Prev; + } + } + + //fixup PolyNode links etc ... + polytree.Childs.reserve(m_PolyOuts.size()); + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) + { + OutRec* outRec = m_PolyOuts[i]; + if (!outRec->PolyNd) continue; + if (outRec->IsOpen) + { + outRec->PolyNd->m_IsOpen = true; + polytree.AddChild(*outRec->PolyNd); + } + else if (outRec->FirstLeft && outRec->FirstLeft->PolyNd) + outRec->FirstLeft->PolyNd->AddChild(*outRec->PolyNd); + else + polytree.AddChild(*outRec->PolyNd); + } +} +//------------------------------------------------------------------------------ + +void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2) +{ + //just swap the contents (because fIntersectNodes is a single-linked-list) + IntersectNode inode = int1; //gets a copy of Int1 + int1.Edge1 = int2.Edge1; + int1.Edge2 = int2.Edge2; + int1.Pt = int2.Pt; + int2.Edge1 = inode.Edge1; + int2.Edge2 = inode.Edge2; + int2.Pt = inode.Pt; +} +//------------------------------------------------------------------------------ + +inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2) +{ + if (e2.Curr.X == e1.Curr.X) + { + if (e2.Top.Y > e1.Top.Y) + return e2.Top.X < TopX(e1, e2.Top.Y); + else return e1.Top.X > TopX(e2, e1.Top.Y); + } + else return e2.Curr.X < e1.Curr.X; +} +//------------------------------------------------------------------------------ + +bool GetOverlap(const cInt a1, const cInt a2, const cInt b1, const cInt b2, + cInt& Left, cInt& Right) +{ + if (a1 < a2) + { + if (b1 < b2) {Left = std::max(a1,b1); Right = std::min(a2,b2);} + else {Left = std::max(a1,b2); Right = std::min(a2,b1);} + } + else + { + if (b1 < b2) {Left = std::max(a2,b1); Right = std::min(a1,b2);} + else {Left = std::max(a2,b2); Right = std::min(a1,b1);} + } + return Left < Right; +} +//------------------------------------------------------------------------------ + +inline void UpdateOutPtIdxs(OutRec& outrec) +{ + OutPt* op = outrec.Pts; + do + { + op->Idx = outrec.Idx; + op = op->Prev; + } + while(op != outrec.Pts); +} +//------------------------------------------------------------------------------ + +void Clipper::InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge) +{ + if(!m_ActiveEdges) + { + edge->PrevInAEL = 0; + edge->NextInAEL = 0; + m_ActiveEdges = edge; + } + else if(!startEdge && E2InsertsBeforeE1(*m_ActiveEdges, *edge)) + { + edge->PrevInAEL = 0; + edge->NextInAEL = m_ActiveEdges; + m_ActiveEdges->PrevInAEL = edge; + m_ActiveEdges = edge; + } + else + { + if(!startEdge) startEdge = m_ActiveEdges; + while(startEdge->NextInAEL && + !E2InsertsBeforeE1(*startEdge->NextInAEL , *edge)) + startEdge = startEdge->NextInAEL; + edge->NextInAEL = startEdge->NextInAEL; + if(startEdge->NextInAEL) startEdge->NextInAEL->PrevInAEL = edge; + edge->PrevInAEL = startEdge; + startEdge->NextInAEL = edge; + } +} +//---------------------------------------------------------------------- + +OutPt* DupOutPt(OutPt* outPt, bool InsertAfter) +{ + OutPt* result = new OutPt; + result->Pt = outPt->Pt; + result->Idx = outPt->Idx; + if (InsertAfter) + { + result->Next = outPt->Next; + result->Prev = outPt; + outPt->Next->Prev = result; + outPt->Next = result; + } + else + { + result->Prev = outPt->Prev; + result->Next = outPt; + outPt->Prev->Next = result; + outPt->Prev = result; + } + return result; +} +//------------------------------------------------------------------------------ + +bool JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b, + const IntPoint Pt, bool DiscardLeft) +{ + Direction Dir1 = (op1->Pt.X > op1b->Pt.X ? dRightToLeft : dLeftToRight); + Direction Dir2 = (op2->Pt.X > op2b->Pt.X ? dRightToLeft : dLeftToRight); + if (Dir1 == Dir2) return false; + + //When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we + //want Op1b to be on the Right. (And likewise with Op2 and Op2b.) + //So, to facilitate this while inserting Op1b and Op2b ... + //when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b, + //otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.) + if (Dir1 == dLeftToRight) + { + while (op1->Next->Pt.X <= Pt.X && + op1->Next->Pt.X >= op1->Pt.X && op1->Next->Pt.Y == Pt.Y) + op1 = op1->Next; + if (DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next; + op1b = DupOutPt(op1, !DiscardLeft); + if (op1b->Pt != Pt) + { + op1 = op1b; + op1->Pt = Pt; + op1b = DupOutPt(op1, !DiscardLeft); + } + } + else + { + while (op1->Next->Pt.X >= Pt.X && + op1->Next->Pt.X <= op1->Pt.X && op1->Next->Pt.Y == Pt.Y) + op1 = op1->Next; + if (!DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next; + op1b = DupOutPt(op1, DiscardLeft); + if (op1b->Pt != Pt) + { + op1 = op1b; + op1->Pt = Pt; + op1b = DupOutPt(op1, DiscardLeft); + } + } + + if (Dir2 == dLeftToRight) + { + while (op2->Next->Pt.X <= Pt.X && + op2->Next->Pt.X >= op2->Pt.X && op2->Next->Pt.Y == Pt.Y) + op2 = op2->Next; + if (DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next; + op2b = DupOutPt(op2, !DiscardLeft); + if (op2b->Pt != Pt) + { + op2 = op2b; + op2->Pt = Pt; + op2b = DupOutPt(op2, !DiscardLeft); + }; + } else + { + while (op2->Next->Pt.X >= Pt.X && + op2->Next->Pt.X <= op2->Pt.X && op2->Next->Pt.Y == Pt.Y) + op2 = op2->Next; + if (!DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next; + op2b = DupOutPt(op2, DiscardLeft); + if (op2b->Pt != Pt) + { + op2 = op2b; + op2->Pt = Pt; + op2b = DupOutPt(op2, DiscardLeft); + }; + }; + + if ((Dir1 == dLeftToRight) == DiscardLeft) + { + op1->Prev = op2; + op2->Next = op1; + op1b->Next = op2b; + op2b->Prev = op1b; + } + else + { + op1->Next = op2; + op2->Prev = op1; + op1b->Prev = op2b; + op2b->Next = op1b; + } + return true; +} +//------------------------------------------------------------------------------ + +bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2) +{ + OutPt *op1 = j->OutPt1, *op1b; + OutPt *op2 = j->OutPt2, *op2b; + + //There are 3 kinds of joins for output polygons ... + //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere + //along (horizontal) collinear edges (& Join.OffPt is on the same horizontal). + //2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same + //location at the Bottom of the overlapping segment (& Join.OffPt is above). + //3. StrictSimple joins where edges touch but are not collinear and where + //Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point. + bool isHorizontal = (j->OutPt1->Pt.Y == j->OffPt.Y); + + if (isHorizontal && (j->OffPt == j->OutPt1->Pt) && + (j->OffPt == j->OutPt2->Pt)) + { + //Strictly Simple join ... + if (outRec1 != outRec2) return false; + op1b = j->OutPt1->Next; + while (op1b != op1 && (op1b->Pt == j->OffPt)) + op1b = op1b->Next; + bool reverse1 = (op1b->Pt.Y > j->OffPt.Y); + op2b = j->OutPt2->Next; + while (op2b != op2 && (op2b->Pt == j->OffPt)) + op2b = op2b->Next; + bool reverse2 = (op2b->Pt.Y > j->OffPt.Y); + if (reverse1 == reverse2) return false; + if (reverse1) + { + op1b = DupOutPt(op1, false); + op2b = DupOutPt(op2, true); + op1->Prev = op2; + op2->Next = op1; + op1b->Next = op2b; + op2b->Prev = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } else + { + op1b = DupOutPt(op1, true); + op2b = DupOutPt(op2, false); + op1->Next = op2; + op2->Prev = op1; + op1b->Prev = op2b; + op2b->Next = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } + } + else if (isHorizontal) + { + //treat horizontal joins differently to non-horizontal joins since with + //them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt + //may be anywhere along the horizontal edge. + op1b = op1; + while (op1->Prev->Pt.Y == op1->Pt.Y && op1->Prev != op1b && op1->Prev != op2) + op1 = op1->Prev; + while (op1b->Next->Pt.Y == op1b->Pt.Y && op1b->Next != op1 && op1b->Next != op2) + op1b = op1b->Next; + if (op1b->Next == op1 || op1b->Next == op2) return false; //a flat 'polygon' + + op2b = op2; + while (op2->Prev->Pt.Y == op2->Pt.Y && op2->Prev != op2b && op2->Prev != op1b) + op2 = op2->Prev; + while (op2b->Next->Pt.Y == op2b->Pt.Y && op2b->Next != op2 && op2b->Next != op1) + op2b = op2b->Next; + if (op2b->Next == op2 || op2b->Next == op1) return false; //a flat 'polygon' + + cInt Left, Right; + //Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges + if (!GetOverlap(op1->Pt.X, op1b->Pt.X, op2->Pt.X, op2b->Pt.X, Left, Right)) + return false; + + //DiscardLeftSide: when overlapping edges are joined, a spike will created + //which needs to be cleaned up. However, we don't want Op1 or Op2 caught up + //on the discard Side as either may still be needed for other joins ... + IntPoint Pt; + bool DiscardLeftSide; + if (op1->Pt.X >= Left && op1->Pt.X <= Right) + { + Pt = op1->Pt; DiscardLeftSide = (op1->Pt.X > op1b->Pt.X); + } + else if (op2->Pt.X >= Left&& op2->Pt.X <= Right) + { + Pt = op2->Pt; DiscardLeftSide = (op2->Pt.X > op2b->Pt.X); + } + else if (op1b->Pt.X >= Left && op1b->Pt.X <= Right) + { + Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.X > op1->Pt.X; + } + else + { + Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.X > op2->Pt.X); + } + j->OutPt1 = op1; j->OutPt2 = op2; + return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide); + } else + { + //nb: For non-horizontal joins ... + // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y + // 2. Jr.OutPt1.Pt > Jr.OffPt.Y + + //make sure the polygons are correctly oriented ... + op1b = op1->Next; + while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Next; + bool Reverse1 = ((op1b->Pt.Y > op1->Pt.Y) || + !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)); + if (Reverse1) + { + op1b = op1->Prev; + while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Prev; + if ((op1b->Pt.Y > op1->Pt.Y) || + !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)) return false; + }; + op2b = op2->Next; + while ((op2b->Pt == op2->Pt) && (op2b != op2))op2b = op2b->Next; + bool Reverse2 = ((op2b->Pt.Y > op2->Pt.Y) || + !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)); + if (Reverse2) + { + op2b = op2->Prev; + while ((op2b->Pt == op2->Pt) && (op2b != op2)) op2b = op2b->Prev; + if ((op2b->Pt.Y > op2->Pt.Y) || + !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)) return false; + } + + if ((op1b == op1) || (op2b == op2) || (op1b == op2b) || + ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false; + + if (Reverse1) + { + op1b = DupOutPt(op1, false); + op2b = DupOutPt(op2, true); + op1->Prev = op2; + op2->Next = op1; + op1b->Next = op2b; + op2b->Prev = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } else + { + op1b = DupOutPt(op1, true); + op2b = DupOutPt(op2, false); + op1->Next = op2; + op2->Prev = op1; + op1b->Prev = op2b; + op2b->Next = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } + } +} +//---------------------------------------------------------------------- + +static OutRec* ParseFirstLeft(OutRec* FirstLeft) +{ + while (FirstLeft && !FirstLeft->Pts) + FirstLeft = FirstLeft->FirstLeft; + return FirstLeft; +} +//------------------------------------------------------------------------------ + +void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) +{ + //tests if NewOutRec contains the polygon before reassigning FirstLeft + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec* outRec = m_PolyOuts[i]; + OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft); + if (outRec->Pts && firstLeft == OldOutRec) + { + if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts)) + outRec->FirstLeft = NewOutRec; + } + } +} +//---------------------------------------------------------------------- + +void Clipper::FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec) +{ + //A polygon has split into two such that one is now the inner of the other. + //It's possible that these polygons now wrap around other polygons, so check + //every polygon that's also contained by OuterOutRec's FirstLeft container + //(including 0) to see if they've become inner to the new inner polygon ... + OutRec* orfl = OuterOutRec->FirstLeft; + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec* outRec = m_PolyOuts[i]; + + if (!outRec->Pts || outRec == OuterOutRec || outRec == InnerOutRec) + continue; + OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft); + if (firstLeft != orfl && firstLeft != InnerOutRec && firstLeft != OuterOutRec) + continue; + if (Poly2ContainsPoly1(outRec->Pts, InnerOutRec->Pts)) + outRec->FirstLeft = InnerOutRec; + else if (Poly2ContainsPoly1(outRec->Pts, OuterOutRec->Pts)) + outRec->FirstLeft = OuterOutRec; + else if (outRec->FirstLeft == InnerOutRec || outRec->FirstLeft == OuterOutRec) + outRec->FirstLeft = orfl; + } +} +//---------------------------------------------------------------------- +void Clipper::FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec) +{ + //reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec* outRec = m_PolyOuts[i]; + OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft); + if (outRec->Pts && outRec->FirstLeft == OldOutRec) + outRec->FirstLeft = NewOutRec; + } +} +//---------------------------------------------------------------------- + +void Clipper::JoinCommonEdges() +{ + for (JoinList::size_type i = 0; i < m_Joins.size(); i++) + { + Join* join = m_Joins[i]; + + OutRec *outRec1 = GetOutRec(join->OutPt1->Idx); + OutRec *outRec2 = GetOutRec(join->OutPt2->Idx); + + if (!outRec1->Pts || !outRec2->Pts) continue; + if (outRec1->IsOpen || outRec2->IsOpen) continue; + + //get the polygon fragment with the correct hole state (FirstLeft) + //before calling JoinPoints() ... + OutRec *holeStateRec; + if (outRec1 == outRec2) holeStateRec = outRec1; + else if (OutRec1RightOfOutRec2(outRec1, outRec2)) holeStateRec = outRec2; + else if (OutRec1RightOfOutRec2(outRec2, outRec1)) holeStateRec = outRec1; + else holeStateRec = GetLowermostRec(outRec1, outRec2); + + if (!JoinPoints(join, outRec1, outRec2)) continue; + + if (outRec1 == outRec2) + { + //instead of joining two polygons, we've just created a new one by + //splitting one polygon into two. + outRec1->Pts = join->OutPt1; + outRec1->BottomPt = 0; + outRec2 = CreateOutRec(); + outRec2->Pts = join->OutPt2; + + //update all OutRec2.Pts Idx's ... + UpdateOutPtIdxs(*outRec2); + + if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts)) + { + //outRec1 contains outRec2 ... + outRec2->IsHole = !outRec1->IsHole; + outRec2->FirstLeft = outRec1; + + if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); + + if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0)) + ReversePolyPtLinks(outRec2->Pts); + + } else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts)) + { + //outRec2 contains outRec1 ... + outRec2->IsHole = outRec1->IsHole; + outRec1->IsHole = !outRec2->IsHole; + outRec2->FirstLeft = outRec1->FirstLeft; + outRec1->FirstLeft = outRec2; + + if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2); + + if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0)) + ReversePolyPtLinks(outRec1->Pts); + } + else + { + //the 2 polygons are completely separate ... + outRec2->IsHole = outRec1->IsHole; + outRec2->FirstLeft = outRec1->FirstLeft; + + //fixup FirstLeft pointers that may need reassigning to OutRec2 + if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2); + } + + } else + { + //joined 2 polygons together ... + + outRec2->Pts = 0; + outRec2->BottomPt = 0; + outRec2->Idx = outRec1->Idx; + + outRec1->IsHole = holeStateRec->IsHole; + if (holeStateRec == outRec2) + outRec1->FirstLeft = outRec2->FirstLeft; + outRec2->FirstLeft = outRec1; + + if (m_UsingPolyTree) FixupFirstLefts3(outRec2, outRec1); + } + } +} + +//------------------------------------------------------------------------------ +// ClipperOffset support functions ... +//------------------------------------------------------------------------------ + +DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2) +{ + if(pt2.X == pt1.X && pt2.Y == pt1.Y) + return DoublePoint(0, 0); + + double Dx = (double)(pt2.X - pt1.X); + double dy = (double)(pt2.Y - pt1.Y); + double f = 1 *1.0/ std::sqrt( Dx*Dx + dy*dy ); + Dx *= f; + dy *= f; + return DoublePoint(dy, -Dx); +} + +//------------------------------------------------------------------------------ +// ClipperOffset class +//------------------------------------------------------------------------------ + +ClipperOffset::ClipperOffset(double miterLimit, double arcTolerance) +{ + this->MiterLimit = miterLimit; + this->ArcTolerance = arcTolerance; + m_lowest.X = -1; +} +//------------------------------------------------------------------------------ + +ClipperOffset::~ClipperOffset() +{ + Clear(); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::Clear() +{ + for (int i = 0; i < m_polyNodes.ChildCount(); ++i) + delete m_polyNodes.Childs[i]; + m_polyNodes.Childs.clear(); + m_lowest.X = -1; +} +//------------------------------------------------------------------------------ + +void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType) +{ + int highI = (int)path.size() - 1; + if (highI < 0) return; + PolyNode* newNode = new PolyNode(); + newNode->m_jointype = joinType; + newNode->m_endtype = endType; + + //strip duplicate points from path and also get index to the lowest point ... + if (endType == etClosedLine || endType == etClosedPolygon) + while (highI > 0 && path[0] == path[highI]) highI--; + newNode->Contour.reserve(highI + 1); + newNode->Contour.push_back(path[0]); + int j = 0, k = 0; + for (int i = 1; i <= highI; i++) + if (newNode->Contour[j] != path[i]) + { + j++; + newNode->Contour.push_back(path[i]); + if (path[i].Y > newNode->Contour[k].Y || + (path[i].Y == newNode->Contour[k].Y && + path[i].X < newNode->Contour[k].X)) k = j; + } + if (endType == etClosedPolygon && j < 2) + { + delete newNode; + return; + } + m_polyNodes.AddChild(*newNode); + + //if this path's lowest pt is lower than all the others then update m_lowest + if (endType != etClosedPolygon) return; + if (m_lowest.X < 0) + m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k); + else + { + IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y]; + if (newNode->Contour[k].Y > ip.Y || + (newNode->Contour[k].Y == ip.Y && + newNode->Contour[k].X < ip.X)) + m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k); + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::AddPaths(const Paths& paths, JoinType joinType, EndType endType) +{ + for (Paths::size_type i = 0; i < paths.size(); ++i) + AddPath(paths[i], joinType, endType); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::FixOrientations() +{ + //fixup orientations of all closed paths if the orientation of the + //closed path with the lowermost vertex is wrong ... + if (m_lowest.X >= 0 && + !Orientation(m_polyNodes.Childs[(int)m_lowest.X]->Contour)) + { + for (int i = 0; i < m_polyNodes.ChildCount(); ++i) + { + PolyNode& node = *m_polyNodes.Childs[i]; + if (node.m_endtype == etClosedPolygon || + (node.m_endtype == etClosedLine && Orientation(node.Contour))) + ReversePath(node.Contour); + } + } else + { + for (int i = 0; i < m_polyNodes.ChildCount(); ++i) + { + PolyNode& node = *m_polyNodes.Childs[i]; + if (node.m_endtype == etClosedLine && !Orientation(node.Contour)) + ReversePath(node.Contour); + } + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::Execute(Paths& solution, double delta) +{ + solution.clear(); + FixOrientations(); + DoOffset(delta); + + //now clean up 'corners' ... + Clipper clpr; + clpr.AddPaths(m_destPolys, ptSubject, true); + if (delta > 0) + { + clpr.Execute(ctUnion, solution, pftPositive, pftPositive); + } + else + { + IntRect r = clpr.GetBounds(); + Path outer(4); + outer[0] = IntPoint(r.left - 10, r.bottom + 10); + outer[1] = IntPoint(r.right + 10, r.bottom + 10); + outer[2] = IntPoint(r.right + 10, r.top - 10); + outer[3] = IntPoint(r.left - 10, r.top - 10); + + clpr.AddPath(outer, ptSubject, true); + clpr.ReverseSolution(true); + clpr.Execute(ctUnion, solution, pftNegative, pftNegative); + if (solution.size() > 0) solution.erase(solution.begin()); + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::Execute(PolyTree& solution, double delta) +{ + solution.Clear(); + FixOrientations(); + DoOffset(delta); + + //now clean up 'corners' ... + Clipper clpr; + clpr.AddPaths(m_destPolys, ptSubject, true); + if (delta > 0) + { + clpr.Execute(ctUnion, solution, pftPositive, pftPositive); + } + else + { + IntRect r = clpr.GetBounds(); + Path outer(4); + outer[0] = IntPoint(r.left - 10, r.bottom + 10); + outer[1] = IntPoint(r.right + 10, r.bottom + 10); + outer[2] = IntPoint(r.right + 10, r.top - 10); + outer[3] = IntPoint(r.left - 10, r.top - 10); + + clpr.AddPath(outer, ptSubject, true); + clpr.ReverseSolution(true); + clpr.Execute(ctUnion, solution, pftNegative, pftNegative); + //remove the outer PolyNode rectangle ... + if (solution.ChildCount() == 1 && solution.Childs[0]->ChildCount() > 0) + { + PolyNode* outerNode = solution.Childs[0]; + solution.Childs.reserve(outerNode->ChildCount()); + solution.Childs[0] = outerNode->Childs[0]; + solution.Childs[0]->Parent = outerNode->Parent; + for (int i = 1; i < outerNode->ChildCount(); ++i) + solution.AddChild(*outerNode->Childs[i]); + } + else + solution.Clear(); + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoOffset(double delta) +{ + m_destPolys.clear(); + m_delta = delta; + + //if Zero offset, just copy any CLOSED polygons to m_p and return ... + if (NEAR_ZERO(delta)) + { + m_destPolys.reserve(m_polyNodes.ChildCount()); + for (int i = 0; i < m_polyNodes.ChildCount(); i++) + { + PolyNode& node = *m_polyNodes.Childs[i]; + if (node.m_endtype == etClosedPolygon) + m_destPolys.push_back(node.Contour); + } + return; + } + + //see offset_triginometry3.svg in the documentation folder ... + if (MiterLimit > 2) m_miterLim = 2/(MiterLimit * MiterLimit); + else m_miterLim = 0.5; + + double y; + if (ArcTolerance <= 0.0) y = def_arc_tolerance; + else if (ArcTolerance > std::fabs(delta) * def_arc_tolerance) + y = std::fabs(delta) * def_arc_tolerance; + else y = ArcTolerance; + //see offset_triginometry2.svg in the documentation folder ... + double steps = pi / std::acos(1 - y / std::fabs(delta)); + if (steps > std::fabs(delta) * pi) + steps = std::fabs(delta) * pi; //ie excessive precision check + m_sin = std::sin(two_pi / steps); + m_cos = std::cos(two_pi / steps); + m_StepsPerRad = steps / two_pi; + if (delta < 0.0) m_sin = -m_sin; + + m_destPolys.reserve(m_polyNodes.ChildCount() * 2); + for (int i = 0; i < m_polyNodes.ChildCount(); i++) + { + PolyNode& node = *m_polyNodes.Childs[i]; + m_srcPoly = node.Contour; + + int len = (int)m_srcPoly.size(); + if (len == 0 || (delta <= 0 && (len < 3 || node.m_endtype != etClosedPolygon))) + continue; + + m_destPoly.clear(); + if (len == 1) + { + if (node.m_jointype == jtRound) + { + double X = 1.0, Y = 0.0; + for (cInt j = 1; j <= steps; j++) + { + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[0].X + X * delta), + Round(m_srcPoly[0].Y + Y * delta))); + double X2 = X; + X = X * m_cos - m_sin * Y; + Y = X2 * m_sin + Y * m_cos; + } + } + else + { + double X = -1.0, Y = -1.0; + for (int j = 0; j < 4; ++j) + { + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[0].X + X * delta), + Round(m_srcPoly[0].Y + Y * delta))); + if (X < 0) X = 1; + else if (Y < 0) Y = 1; + else X = -1; + } + } + m_destPolys.push_back(m_destPoly); + continue; + } + //build m_normals ... + m_normals.clear(); + m_normals.reserve(len); + for (int j = 0; j < len - 1; ++j) + m_normals.push_back(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1])); + if (node.m_endtype == etClosedLine || node.m_endtype == etClosedPolygon) + m_normals.push_back(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0])); + else + m_normals.push_back(DoublePoint(m_normals[len - 2])); + + if (node.m_endtype == etClosedPolygon) + { + int k = len - 1; + for (int j = 0; j < len; ++j) + OffsetPoint(j, k, node.m_jointype); + m_destPolys.push_back(m_destPoly); + } + else if (node.m_endtype == etClosedLine) + { + int k = len - 1; + for (int j = 0; j < len; ++j) + OffsetPoint(j, k, node.m_jointype); + m_destPolys.push_back(m_destPoly); + m_destPoly.clear(); + //re-build m_normals ... + DoublePoint n = m_normals[len -1]; + for (int j = len - 1; j > 0; j--) + m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); + m_normals[0] = DoublePoint(-n.X, -n.Y); + k = 0; + for (int j = len - 1; j >= 0; j--) + OffsetPoint(j, k, node.m_jointype); + m_destPolys.push_back(m_destPoly); + } + else + { + int k = 0; + for (int j = 1; j < len - 1; ++j) + OffsetPoint(j, k, node.m_jointype); + + IntPoint pt1; + if (node.m_endtype == etOpenButt) + { + int j = len - 1; + pt1 = IntPoint((cInt)Round(m_srcPoly[j].X + m_normals[j].X * + delta), (cInt)Round(m_srcPoly[j].Y + m_normals[j].Y * delta)); + m_destPoly.push_back(pt1); + pt1 = IntPoint((cInt)Round(m_srcPoly[j].X - m_normals[j].X * + delta), (cInt)Round(m_srcPoly[j].Y - m_normals[j].Y * delta)); + m_destPoly.push_back(pt1); + } + else + { + int j = len - 1; + k = len - 2; + m_sinA = 0; + m_normals[j] = DoublePoint(-m_normals[j].X, -m_normals[j].Y); + if (node.m_endtype == etOpenSquare) + DoSquare(j, k); + else + DoRound(j, k); + } + + //re-build m_normals ... + for (int j = len - 1; j > 0; j--) + m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); + m_normals[0] = DoublePoint(-m_normals[1].X, -m_normals[1].Y); + + k = len - 1; + for (int j = k - 1; j > 0; --j) OffsetPoint(j, k, node.m_jointype); + + if (node.m_endtype == etOpenButt) + { + pt1 = IntPoint((cInt)Round(m_srcPoly[0].X - m_normals[0].X * delta), + (cInt)Round(m_srcPoly[0].Y - m_normals[0].Y * delta)); + m_destPoly.push_back(pt1); + pt1 = IntPoint((cInt)Round(m_srcPoly[0].X + m_normals[0].X * delta), + (cInt)Round(m_srcPoly[0].Y + m_normals[0].Y * delta)); + m_destPoly.push_back(pt1); + } + else + { + k = 1; + m_sinA = 0; + if (node.m_endtype == etOpenSquare) + DoSquare(0, 1); + else + DoRound(0, 1); + } + m_destPolys.push_back(m_destPoly); + } + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype) +{ + //cross product ... + m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y); + if (std::fabs(m_sinA * m_delta) < 1.0) + { + //dot product ... + double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y ); + if (cosA > 0) // angle => 0 degrees + { + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta))); + return; + } + //else angle => 180 degrees + } + else if (m_sinA > 1.0) m_sinA = 1.0; + else if (m_sinA < -1.0) m_sinA = -1.0; + + if (m_sinA * m_delta < 0) + { + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta))); + m_destPoly.push_back(m_srcPoly[j]); + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); + } + else + switch (jointype) + { + case jtMiter: + { + double r = 1 + (m_normals[j].X * m_normals[k].X + + m_normals[j].Y * m_normals[k].Y); + if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k); + break; + } + case jtSquare: DoSquare(j, k); break; + case jtRound: DoRound(j, k); break; + } + k = j; +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoSquare(int j, int k) +{ + double dx = std::tan(std::atan2(m_sinA, + m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y) / 4); + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx)), + Round(m_srcPoly[j].Y + m_delta * (m_normals[k].Y + m_normals[k].X * dx)))); + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx)), + Round(m_srcPoly[j].Y + m_delta * (m_normals[j].Y - m_normals[j].X * dx)))); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoMiter(int j, int k, double r) +{ + double q = m_delta / r; + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + (m_normals[k].X + m_normals[j].X) * q), + Round(m_srcPoly[j].Y + (m_normals[k].Y + m_normals[j].Y) * q))); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoRound(int j, int k) +{ + double a = std::atan2(m_sinA, + m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y); + int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1); + + double X = m_normals[k].X, Y = m_normals[k].Y, X2; + for (int i = 0; i < steps; ++i) + { + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + X * m_delta), + Round(m_srcPoly[j].Y + Y * m_delta))); + X2 = X; + X = X * m_cos - m_sin * Y; + Y = X2 * m_sin + Y * m_cos; + } + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + m_normals[j].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); +} + +//------------------------------------------------------------------------------ +// Miscellaneous public functions +//------------------------------------------------------------------------------ + +void Clipper::DoSimplePolygons() +{ + PolyOutList::size_type i = 0; + while (i < m_PolyOuts.size()) + { + OutRec* outrec = m_PolyOuts[i++]; + OutPt* op = outrec->Pts; + if (!op || outrec->IsOpen) continue; + do //for each Pt in Polygon until duplicate found do ... + { + OutPt* op2 = op->Next; + while (op2 != outrec->Pts) + { + if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op) + { + //split the polygon into two ... + OutPt* op3 = op->Prev; + OutPt* op4 = op2->Prev; + op->Prev = op4; + op4->Next = op; + op2->Prev = op3; + op3->Next = op2; + + outrec->Pts = op; + OutRec* outrec2 = CreateOutRec(); + outrec2->Pts = op2; + UpdateOutPtIdxs(*outrec2); + if (Poly2ContainsPoly1(outrec2->Pts, outrec->Pts)) + { + //OutRec2 is contained by OutRec1 ... + outrec2->IsHole = !outrec->IsHole; + outrec2->FirstLeft = outrec; + if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec); + } + else + if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts)) + { + //OutRec1 is contained by OutRec2 ... + outrec2->IsHole = outrec->IsHole; + outrec->IsHole = !outrec2->IsHole; + outrec2->FirstLeft = outrec->FirstLeft; + outrec->FirstLeft = outrec2; + if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2); + } + else + { + //the 2 polygons are separate ... + outrec2->IsHole = outrec->IsHole; + outrec2->FirstLeft = outrec->FirstLeft; + if (m_UsingPolyTree) FixupFirstLefts1(outrec, outrec2); + } + op2 = op; //ie get ready for the Next iteration + } + op2 = op2->Next; + } + op = op->Next; + } + while (op != outrec->Pts); + } +} +//------------------------------------------------------------------------------ + +void ReversePath(Path& p) +{ + std::reverse(p.begin(), p.end()); +} +//------------------------------------------------------------------------------ + +void ReversePaths(Paths& p) +{ + for (Paths::size_type i = 0; i < p.size(); ++i) + ReversePath(p[i]); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType) +{ + Clipper c; + c.StrictlySimple(true); + c.AddPath(in_poly, ptSubject, true); + c.Execute(ctUnion, out_polys, fillType, fillType); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType) +{ + Clipper c; + c.StrictlySimple(true); + c.AddPaths(in_polys, ptSubject, true); + c.Execute(ctUnion, out_polys, fillType, fillType); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygons(Paths &polys, PolyFillType fillType) +{ + SimplifyPolygons(polys, polys, fillType); +} +//------------------------------------------------------------------------------ + +inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2) +{ + double Dx = ((double)pt1.X - pt2.X); + double dy = ((double)pt1.Y - pt2.Y); + return (Dx*Dx + dy*dy); +} +//------------------------------------------------------------------------------ + +double DistanceFromLineSqrd( + const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2) +{ + //The equation of a line in general form (Ax + By + C = 0) + //given 2 points (x¹,y¹) & (x²,y²) is ... + //(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0 + //A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹ + //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²) + //see http://en.wikipedia.org/wiki/Perpendicular_distance + double A = double(ln1.Y - ln2.Y); + double B = double(ln2.X - ln1.X); + double C = A * ln1.X + B * ln1.Y; + C = A * pt.X + B * pt.Y - C; + return (C * C) / (A * A + B * B); +} +//--------------------------------------------------------------------------- + +bool SlopesNearCollinear(const IntPoint& pt1, + const IntPoint& pt2, const IntPoint& pt3, double distSqrd) +{ + //this function is more accurate when the point that's geometrically + //between the other 2 points is the one that's tested for distance. + //ie makes it more likely to pick up 'spikes' ... + if (Abs(pt1.X - pt2.X) > Abs(pt1.Y - pt2.Y)) + { + if ((pt1.X > pt2.X) == (pt1.X < pt3.X)) + return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; + else if ((pt2.X > pt1.X) == (pt2.X < pt3.X)) + return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; + else + return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; + } + else + { + if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y)) + return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; + else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y)) + return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; + else + return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; + } +} +//------------------------------------------------------------------------------ + +bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd) +{ + double Dx = (double)pt1.X - pt2.X; + double dy = (double)pt1.Y - pt2.Y; + return ((Dx * Dx) + (dy * dy) <= distSqrd); +} +//------------------------------------------------------------------------------ + +OutPt* ExcludeOp(OutPt* op) +{ + OutPt* result = op->Prev; + result->Next = op->Next; + op->Next->Prev = result; + result->Idx = 0; + return result; +} +//------------------------------------------------------------------------------ + +void CleanPolygon(const Path& in_poly, Path& out_poly, double distance) +{ + //distance = proximity in units/pixels below which vertices + //will be stripped. Default ~= sqrt(2). + + size_t size = in_poly.size(); + + if (size == 0) + { + out_poly.clear(); + return; + } + + OutPt* outPts = new OutPt[size]; + for (size_t i = 0; i < size; ++i) + { + outPts[i].Pt = in_poly[i]; + outPts[i].Next = &outPts[(i + 1) % size]; + outPts[i].Next->Prev = &outPts[i]; + outPts[i].Idx = 0; + } + + double distSqrd = distance * distance; + OutPt* op = &outPts[0]; + while (op->Idx == 0 && op->Next != op->Prev) + { + if (PointsAreClose(op->Pt, op->Prev->Pt, distSqrd)) + { + op = ExcludeOp(op); + size--; + } + else if (PointsAreClose(op->Prev->Pt, op->Next->Pt, distSqrd)) + { + ExcludeOp(op->Next); + op = ExcludeOp(op); + size -= 2; + } + else if (SlopesNearCollinear(op->Prev->Pt, op->Pt, op->Next->Pt, distSqrd)) + { + op = ExcludeOp(op); + size--; + } + else + { + op->Idx = 1; + op = op->Next; + } + } + + if (size < 3) size = 0; + out_poly.resize(size); + for (size_t i = 0; i < size; ++i) + { + out_poly[i] = op->Pt; + op = op->Next; + } + delete [] outPts; +} +//------------------------------------------------------------------------------ + +void CleanPolygon(Path& poly, double distance) +{ + CleanPolygon(poly, poly, distance); +} +//------------------------------------------------------------------------------ + +void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance) +{ + out_polys.resize(in_polys.size()); + for (Paths::size_type i = 0; i < in_polys.size(); ++i) + CleanPolygon(in_polys[i], out_polys[i], distance); +} +//------------------------------------------------------------------------------ + +void CleanPolygons(Paths& polys, double distance) +{ + CleanPolygons(polys, polys, distance); +} +//------------------------------------------------------------------------------ + +void Minkowski(const Path& poly, const Path& path, + Paths& solution, bool isSum, bool isClosed) +{ + int delta = (isClosed ? 1 : 0); + size_t polyCnt = poly.size(); + size_t pathCnt = path.size(); + Paths pp; + pp.reserve(pathCnt); + if (isSum) + for (size_t i = 0; i < pathCnt; ++i) + { + Path p; + p.reserve(polyCnt); + for (size_t j = 0; j < poly.size(); ++j) + p.push_back(IntPoint(path[i].X + poly[j].X, path[i].Y + poly[j].Y)); + pp.push_back(p); + } + else + for (size_t i = 0; i < pathCnt; ++i) + { + Path p; + p.reserve(polyCnt); + for (size_t j = 0; j < poly.size(); ++j) + p.push_back(IntPoint(path[i].X - poly[j].X, path[i].Y - poly[j].Y)); + pp.push_back(p); + } + + solution.clear(); + solution.reserve((pathCnt + delta) * (polyCnt + 1)); + for (size_t i = 0; i < pathCnt - 1 + delta; ++i) + for (size_t j = 0; j < polyCnt; ++j) + { + Path quad; + quad.reserve(4); + quad.push_back(pp[i % pathCnt][j % polyCnt]); + quad.push_back(pp[(i + 1) % pathCnt][j % polyCnt]); + quad.push_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]); + quad.push_back(pp[i % pathCnt][(j + 1) % polyCnt]); + if (!Orientation(quad)) ReversePath(quad); + solution.push_back(quad); + } +} +//------------------------------------------------------------------------------ + +void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed) +{ + Minkowski(pattern, path, solution, true, pathIsClosed); + Clipper c; + c.AddPaths(solution, ptSubject, true); + c.Execute(ctUnion, solution, pftNonZero, pftNonZero); +} +//------------------------------------------------------------------------------ + +void TranslatePath(const Path& input, Path& output, const IntPoint delta) +{ + //precondition: input != output + output.resize(input.size()); + for (size_t i = 0; i < input.size(); ++i) + output[i] = IntPoint(input[i].X + delta.X, input[i].Y + delta.Y); +} +//------------------------------------------------------------------------------ + +void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed) +{ + Clipper c; + for (size_t i = 0; i < paths.size(); ++i) + { + Paths tmp; + Minkowski(pattern, paths[i], tmp, true, pathIsClosed); + c.AddPaths(tmp, ptSubject, true); + if (pathIsClosed) + { + Path tmp2; + TranslatePath(paths[i], tmp2, pattern[0]); + c.AddPath(tmp2, ptClip, true); + } + } + c.Execute(ctUnion, solution, pftNonZero, pftNonZero); +} +//------------------------------------------------------------------------------ + +void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution) +{ + Minkowski(poly1, poly2, solution, false, true); + Clipper c; + c.AddPaths(solution, ptSubject, true); + c.Execute(ctUnion, solution, pftNonZero, pftNonZero); +} +//------------------------------------------------------------------------------ + +enum NodeType {ntAny, ntOpen, ntClosed}; + +void AddPolyNodeToPaths(const PolyNode& polynode, NodeType nodetype, Paths& paths) +{ + bool match = true; + if (nodetype == ntClosed) match = !polynode.IsOpen(); + else if (nodetype == ntOpen) return; + + if (!polynode.Contour.empty() && match) + paths.push_back(polynode.Contour); + for (int i = 0; i < polynode.ChildCount(); ++i) + AddPolyNodeToPaths(*polynode.Childs[i], nodetype, paths); +} +//------------------------------------------------------------------------------ + +void PolyTreeToPaths(const PolyTree& polytree, Paths& paths) +{ + paths.resize(0); + paths.reserve(polytree.Total()); + AddPolyNodeToPaths(polytree, ntAny, paths); +} +//------------------------------------------------------------------------------ + +void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths) +{ + paths.resize(0); + paths.reserve(polytree.Total()); + AddPolyNodeToPaths(polytree, ntClosed, paths); +} +//------------------------------------------------------------------------------ + +void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths) +{ + paths.resize(0); + paths.reserve(polytree.Total()); + //Open paths are top level only, so ... + for (int i = 0; i < polytree.ChildCount(); ++i) + if (polytree.Childs[i]->IsOpen()) + paths.push_back(polytree.Childs[i]->Contour); +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, const IntPoint &p) +{ + s << "(" << p.X << "," << p.Y << ")"; + return s; +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, const Path &p) +{ + if (p.empty()) return s; + Path::size_type last = p.size() -1; + for (Path::size_type i = 0; i < last; i++) + s << "(" << p[i].X << "," << p[i].Y << "), "; + s << "(" << p[last].X << "," << p[last].Y << ")\n"; + return s; +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, const Paths &p) +{ + for (Paths::size_type i = 0; i < p.size(); i++) + s << p[i]; + s << "\n"; + return s; +} +//------------------------------------------------------------------------------ + +} //ClipperLib namespace diff --git a/ThirdParty/custom-clipper/clipper/clipper.hpp b/ThirdParty/custom-clipper/clipper/clipper.hpp new file mode 100644 index 0000000000..2472ac7708 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/clipper.hpp @@ -0,0 +1,404 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 6.4.0 * +* Date : 2 July 2015 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2015 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Attributions: * +* The code in this library is an extension of Bala Vatti's clipping algorithm: * +* "A generic solution to polygon clipping" * +* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * +* http://portal.acm.org/citation.cfm?id=129906 * +* * +* Computer graphics and geometric modeling: implementation and algorithms * +* By Max K. Agoston * +* Springer; 1 edition (January 4, 2005) * +* http://books.google.com/books?q=vatti+clipping+agoston * +* * +* See also: * +* "Polygon Offsetting by Computing Winding Numbers" * +* Paper no. DETC2005-85513 pp. 565-575 * +* ASME 2005 International Design Engineering Technical Conferences * +* and Computers and Information in Engineering Conference (IDETC/CIE2005) * +* September 24-28, 2005 , Long Beach, California, USA * +* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * +* * +*******************************************************************************/ + +#ifndef clipper_hpp +#define clipper_hpp + +#define CLIPPER_VERSION "6.2.6" + +//use_int32: When enabled 32bit ints are used instead of 64bit ints. This +//improve performance but coordinate values are limited to the range +/- 46340 +//#define use_int32 + +//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance. +//#define use_xyz + +//use_lines: Enables line clipping. Adds a very minor cost to performance. +#define use_lines + +//use_deprecated: Enables temporary support for the obsolete functions +//#define use_deprecated + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ClipperLib { + +enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; +enum PolyType { ptSubject, ptClip }; +//By far the most widely used winding rules for polygon filling are +//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) +//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) +//see http://glprogramming.com/red/chapter11.html +enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; + +#ifdef use_int32 + typedef int cInt; + static cInt const loRange = 0x7FFF; + static cInt const hiRange = 0x7FFF; +#else + typedef signed long long cInt; + static cInt const loRange = 0x3FFFFFFF; + static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; + typedef signed long long long64; //used by Int128 class + typedef unsigned long long ulong64; + +#endif + +struct IntPoint { + cInt X; + cInt Y; +#ifdef use_xyz + cInt Z; + IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {}; +#else + IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {}; +#endif + + friend inline bool operator== (const IntPoint& a, const IntPoint& b) + { + return a.X == b.X && a.Y == b.Y; + } + friend inline bool operator!= (const IntPoint& a, const IntPoint& b) + { + return a.X != b.X || a.Y != b.Y; + } +}; +//------------------------------------------------------------------------------ + +typedef std::vector< IntPoint > Path; +typedef std::vector< Path > Paths; + +inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;} +inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;} + +std::ostream& operator <<(std::ostream &s, const IntPoint &p); +std::ostream& operator <<(std::ostream &s, const Path &p); +std::ostream& operator <<(std::ostream &s, const Paths &p); + +struct DoublePoint +{ + double X; + double Y; + DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} + DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {} +}; +//------------------------------------------------------------------------------ + +#ifdef use_xyz +typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt); +#endif + +enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4}; +enum JoinType {jtSquare, jtRound, jtMiter}; +enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound}; + +class PolyNode; +typedef std::vector< PolyNode* > PolyNodes; + +class PolyNode +{ +public: + PolyNode(); + virtual ~PolyNode(){}; + Path Contour; + PolyNodes Childs; + PolyNode* Parent; + PolyNode* GetNext() const; + bool IsHole() const; + bool IsOpen() const; + int ChildCount() const; +private: + unsigned Index; //node index in Parent.Childs + bool m_IsOpen; + JoinType m_jointype; + EndType m_endtype; + PolyNode* GetNextSiblingUp() const; + void AddChild(PolyNode& child); + friend class Clipper; //to access Index + friend class ClipperOffset; +}; + +class PolyTree: public PolyNode +{ +public: + ~PolyTree(){Clear();}; + PolyNode* GetFirst() const; + void Clear(); + int Total() const; +private: + PolyNodes AllNodes; + friend class Clipper; //to access AllNodes +}; + +bool Orientation(const Path &poly); +double Area(const Path &poly); +int PointInPolygon(const IntPoint &pt, const Path &path); + +void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd); +void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd); +void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd); + +void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); +void CleanPolygon(Path& poly, double distance = 1.415); +void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415); +void CleanPolygons(Paths& polys, double distance = 1.415); + +void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed); +void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed); +void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution); + +void PolyTreeToPaths(const PolyTree& polytree, Paths& paths); +void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths); +void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths); + +void ReversePath(Path& p); +void ReversePaths(Paths& p); + +struct IntRect { cInt left; cInt top; cInt right; cInt bottom; }; + +//enums that are used internally ... +enum EdgeSide { esLeft = 1, esRight = 2}; + +//forward declarations (for stuff used internally) ... +struct TEdge; +struct IntersectNode; +struct LocalMinimum; +struct OutPt; +struct OutRec; +struct Join; + +typedef std::vector < OutRec* > PolyOutList; +typedef std::vector < TEdge* > EdgeList; +typedef std::vector < Join* > JoinList; +typedef std::vector < IntersectNode* > IntersectList; + +//------------------------------------------------------------------------------ + +//ClipperBase is the ancestor to the Clipper class. It should not be +//instantiated directly. This class simply abstracts the conversion of sets of +//polygon coordinates into edge objects that are stored in a LocalMinima list. +class ClipperBase +{ +public: + ClipperBase(); + virtual ~ClipperBase(); + virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed); + bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed); + virtual void Clear(); + IntRect GetBounds(); + bool PreserveCollinear() {return m_PreserveCollinear;}; + void PreserveCollinear(bool value) {m_PreserveCollinear = value;}; +protected: + void DisposeLocalMinimaList(); + TEdge* AddBoundsToLML(TEdge *e, bool IsClosed); + virtual void Reset(); + TEdge* ProcessBound(TEdge* E, bool IsClockwise); + void InsertScanbeam(const cInt Y); + bool PopScanbeam(cInt &Y); + bool LocalMinimaPending(); + bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin); + OutRec* CreateOutRec(); + void DisposeAllOutRecs(); + void DisposeOutRec(PolyOutList::size_type index); + void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); + void DeleteFromAEL(TEdge *e); + void UpdateEdgeIntoAEL(TEdge *&e); + + typedef std::vector MinimaList; + MinimaList::iterator m_CurrentLM; + MinimaList m_MinimaList; + + bool m_UseFullRange; + EdgeList m_edges; + bool m_PreserveCollinear; + bool m_HasOpenPaths; + PolyOutList m_PolyOuts; + TEdge *m_ActiveEdges; + + typedef std::priority_queue ScanbeamList; + ScanbeamList m_Scanbeam; +}; +//------------------------------------------------------------------------------ + +class Clipper : public virtual ClipperBase +{ +public: + Clipper(int initOptions = 0); + bool Execute(ClipType clipType, + Paths &solution, + PolyFillType fillType = pftEvenOdd); + bool Execute(ClipType clipType, + Paths &solution, + PolyFillType subjFillType, + PolyFillType clipFillType); + bool Execute(ClipType clipType, + PolyTree &polytree, + PolyFillType fillType = pftEvenOdd); + bool Execute(ClipType clipType, + PolyTree &polytree, + PolyFillType subjFillType, + PolyFillType clipFillType); + bool ReverseSolution() { return m_ReverseOutput; }; + void ReverseSolution(bool value) {m_ReverseOutput = value;}; + bool StrictlySimple() {return m_StrictSimple;}; + void StrictlySimple(bool value) {m_StrictSimple = value;}; + //set the callback function for z value filling on intersections (otherwise Z is 0) +#ifdef use_xyz + void ZFillFunction(ZFillCallback zFillFunc); +#endif +protected: + virtual bool ExecuteInternal(); +private: + JoinList m_Joins; + JoinList m_GhostJoins; + IntersectList m_IntersectList; + ClipType m_ClipType; + typedef std::list MaximaList; + MaximaList m_Maxima; + TEdge *m_SortedEdges; + bool m_ExecuteLocked; + PolyFillType m_ClipFillType; + PolyFillType m_SubjFillType; + bool m_ReverseOutput; + bool m_UsingPolyTree; + bool m_StrictSimple; +#ifdef use_xyz + ZFillCallback m_ZFill; //custom callback +#endif + void SetWindingCount(TEdge& edge); + bool IsEvenOddFillType(const TEdge& edge) const; + bool IsEvenOddAltFillType(const TEdge& edge) const; + void InsertLocalMinimaIntoAEL(const cInt botY); + void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge); + void AddEdgeToSEL(TEdge *edge); + bool PopEdgeFromSEL(TEdge *&edge); + void CopyAELToSEL(); + void DeleteFromSEL(TEdge *e); + void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); + bool IsContributing(const TEdge& edge) const; + bool IsTopHorz(const cInt XPos); + void DoMaxima(TEdge *e); + void ProcessHorizontals(); + void ProcessHorizontal(TEdge *horzEdge); + void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); + OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); + OutRec* GetOutRec(int idx); + void AppendPolygon(TEdge *e1, TEdge *e2); + void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt); + OutPt* AddOutPt(TEdge *e, const IntPoint &pt); + OutPt* GetLastOutPt(TEdge *e); + bool ProcessIntersections(const cInt topY); + void BuildIntersectList(const cInt topY); + void ProcessIntersectList(); + void ProcessEdgesAtTopOfScanbeam(const cInt topY); + void BuildResult(Paths& polys); + void BuildResult2(PolyTree& polytree); + void SetHoleState(TEdge *e, OutRec *outrec); + void DisposeIntersectNodes(); + bool FixupIntersectionOrder(); + void FixupOutPolygon(OutRec &outrec); + void FixupOutPolyline(OutRec &outrec); + bool IsHole(TEdge *e); + bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl); + void FixHoleLinkage(OutRec &outrec); + void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt); + void ClearJoins(); + void ClearGhostJoins(); + void AddGhostJoin(OutPt *op, const IntPoint offPt); + bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2); + void JoinCommonEdges(); + void DoSimplePolygons(); + void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); + void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec); + void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec); +#ifdef use_xyz + void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2); +#endif +}; +//------------------------------------------------------------------------------ + +class ClipperOffset +{ +public: + ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25); + ~ClipperOffset(); + void AddPath(const Path& path, JoinType joinType, EndType endType); + void AddPaths(const Paths& paths, JoinType joinType, EndType endType); + void Execute(Paths& solution, double delta); + void Execute(PolyTree& solution, double delta); + void Clear(); + double MiterLimit; + double ArcTolerance; +private: + Paths m_destPolys; + Path m_srcPoly; + Path m_destPoly; + std::vector m_normals; + double m_delta, m_sinA, m_sin, m_cos; + double m_miterLim, m_StepsPerRad; + IntPoint m_lowest; + PolyNode m_polyNodes; + + void FixOrientations(); + void DoOffset(double delta); + void OffsetPoint(int j, int& k, JoinType jointype); + void DoSquare(int j, int k); + void DoMiter(int j, int k, double r); + void DoRound(int j, int k); +}; +//------------------------------------------------------------------------------ + +class clipperException : public std::exception +{ + public: + clipperException(const char* description): m_descr(description) {} + virtual ~clipperException() throw() {} + virtual const char* what() const throw() {return m_descr.c_str();} + private: + std::string m_descr; +}; +//------------------------------------------------------------------------------ + +} //ClipperLib namespace + +#endif //clipper_hpp + + diff --git a/ThirdParty/custom-clipper/clipper/cpp_agg/agg_conv_clipper.h b/ThirdParty/custom-clipper/clipper/cpp_agg/agg_conv_clipper.h new file mode 100644 index 0000000000..99ee9200db --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_agg/agg_conv_clipper.h @@ -0,0 +1,295 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 1.1 * +* Date : 4 April 2011 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2011 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +*******************************************************************************/ + +#ifndef AGG_CONV_CLIPPER_INCLUDED +#define AGG_CONV_CLIPPER_INCLUDED + +#include +#include "agg_basics.h" +#include "agg_array.h" +#include "../clipper.hpp" + +namespace agg +{ + enum clipper_op_e { clipper_or, + clipper_and, clipper_xor, clipper_a_minus_b, clipper_b_minus_a }; + enum clipper_PolyFillType {clipper_even_odd, clipper_non_zero, clipper_positive, clipper_negative}; + + template class conv_clipper + { + enum status { status_move_to, status_line_to, status_stop }; + typedef VSA source_a_type; + typedef VSB source_b_type; + typedef conv_clipper self_type; + + private: + source_a_type* m_src_a; + source_b_type* m_src_b; + status m_status; + int m_vertex; + int m_contour; + int m_scaling_factor; + clipper_op_e m_operation; + pod_bvector m_vertex_accumulator; + ClipperLib::Paths m_poly_a; + ClipperLib::Paths m_poly_b; + ClipperLib::Paths m_result; + ClipperLib::Clipper m_clipper; + clipper_PolyFillType m_subjFillType; + clipper_PolyFillType m_clipFillType; + + int Round(double val) + { + if ((val < 0)) return (int)(val - 0.5); else return (int)(val + 0.5); + } + + public: + conv_clipper(source_a_type &a, source_b_type &b, + clipper_op_e op = clipper_or, + clipper_PolyFillType subjFillType = clipper_even_odd, + clipper_PolyFillType clipFillType = clipper_even_odd, + int scaling_factor = 2) : + m_src_a(&a), + m_src_b(&b), + m_status(status_move_to), + m_vertex(-1), + m_contour(-1), + m_operation(op), + m_subjFillType(subjFillType), + m_clipFillType(clipFillType) + { + m_scaling_factor = std::max(std::min(scaling_factor, 6),0); + m_scaling_factor = Round(std::pow((double)10, m_scaling_factor)); + } + + ~conv_clipper() + { + } + + void attach1(VSA &source, clipper_PolyFillType subjFillType = clipper_even_odd) + { m_src_a = &source; m_subjFillType = subjFillType; } + void attach2(VSB &source, clipper_PolyFillType clipFillType = clipper_even_odd) + { m_src_b = &source; m_clipFillType = clipFillType; } + + void operation(clipper_op_e v) { m_operation = v; } + + void rewind(unsigned path_id); + unsigned vertex(double* x, double* y); + + bool next_contour(); + bool next_vertex(double* x, double* y); + void start_extracting(); + void add_vertex_(double &x, double &y); + void end_contour(ClipperLib::Paths &p); + + template void add(VS &src, ClipperLib::Paths &p){ + unsigned cmd; + double x; double y; double start_x; double start_y; + bool starting_first_line; + + start_x = 0.0; + start_y = 0.0; + starting_first_line = true; + p.resize(0); + + cmd = src->vertex( &x , &y ); + while(!is_stop(cmd)) + { + if(is_vertex(cmd)) + { + if(is_move_to(cmd)) + { + if(!starting_first_line ) end_contour(p); + start_x = x; + start_y = y; + } + add_vertex_( x, y ); + starting_first_line = false; + } + else if(is_end_poly(cmd)) + { + if(!starting_first_line && is_closed(cmd)) + add_vertex_( start_x, start_y ); + } + cmd = src->vertex( &x, &y ); + } + end_contour(p); + } + }; + + //------------------------------------------------------------------------ + + template + void conv_clipper::start_extracting() + { + m_status = status_move_to; + m_contour = -1; + m_vertex = -1; + } + //------------------------------------------------------------------------------ + + template + void conv_clipper::rewind(unsigned path_id) + { + m_src_a->rewind( path_id ); + m_src_b->rewind( path_id ); + + add( m_src_a , m_poly_a ); + add( m_src_b , m_poly_b ); + m_result.resize(0); + + ClipperLib::PolyFillType pftSubj, pftClip; + switch (m_subjFillType) + { + case clipper_even_odd: pftSubj = ClipperLib::pftEvenOdd; break; + case clipper_non_zero: pftSubj = ClipperLib::pftNonZero; break; + case clipper_positive: pftSubj = ClipperLib::pftPositive; break; + default: pftSubj = ClipperLib::pftNegative; + } + switch (m_clipFillType) + { + case clipper_even_odd: pftClip = ClipperLib::pftEvenOdd; break; + case clipper_non_zero: pftClip = ClipperLib::pftNonZero; break; + case clipper_positive: pftClip = ClipperLib::pftPositive; break; + default: pftClip = ClipperLib::pftNegative; + } + + m_clipper.Clear(); + switch( m_operation ) { + case clipper_or: + { + m_clipper.AddPaths( m_poly_a , ClipperLib::ptSubject, true ); + m_clipper.AddPaths( m_poly_b , ClipperLib::ptClip, true ); + m_clipper.Execute( ClipperLib::ctUnion , m_result , pftSubj, pftClip); + break; + } + case clipper_and: + { + m_clipper.AddPaths( m_poly_a , ClipperLib::ptSubject, true ); + m_clipper.AddPaths( m_poly_b , ClipperLib::ptClip, true ); + m_clipper.Execute( ClipperLib::ctIntersection , m_result, pftSubj, pftClip ); + break; + } + case clipper_xor: + { + m_clipper.AddPaths( m_poly_a , ClipperLib::ptSubject, true ); + m_clipper.AddPaths( m_poly_b , ClipperLib::ptClip, true ); + m_clipper.Execute( ClipperLib::ctXor , m_result, pftSubj, pftClip ); + break; + } + case clipper_a_minus_b: + { + m_clipper.AddPaths( m_poly_a , ClipperLib::ptSubject, true ); + m_clipper.AddPaths( m_poly_b , ClipperLib::ptClip, true ); + m_clipper.Execute( ClipperLib::ctDifference , m_result, pftSubj, pftClip ); + break; + } + case clipper_b_minus_a: + { + m_clipper.AddPaths( m_poly_b , ClipperLib::ptSubject, true ); + m_clipper.AddPaths( m_poly_a , ClipperLib::ptClip, true ); + m_clipper.Execute( ClipperLib::ctDifference , m_result, pftSubj, pftClip ); + break; + } + } + start_extracting(); + } + //------------------------------------------------------------------------------ + + template + void conv_clipper::end_contour( ClipperLib::Paths &p) + { + unsigned i, len; + + if( m_vertex_accumulator.size() < 3 ) return; + len = p.size(); + p.resize(len+1); + p[len].resize(m_vertex_accumulator.size()); + for( i = 0 ; i < m_vertex_accumulator.size() ; i++ ) + p[len][i] = m_vertex_accumulator[i]; + m_vertex_accumulator.remove_all(); + } + //------------------------------------------------------------------------------ + + template + void conv_clipper::add_vertex_(double &x, double &y) + { + ClipperLib::IntPoint v; + + v.X = Round(x * m_scaling_factor); + v.Y = Round(y * m_scaling_factor); + m_vertex_accumulator.add( v ); + } + //------------------------------------------------------------------------------ + + template + bool conv_clipper::next_contour() + { + m_contour++; + if(m_contour >= (int)m_result.size()) return false; + m_vertex =-1; + return true; +} +//------------------------------------------------------------------------------ + + template + bool conv_clipper::next_vertex(double *x, double *y) + { + m_vertex++; + if(m_vertex >= (int)m_result[m_contour].size()) return false; + *x = (double)m_result[ m_contour ][ m_vertex ].X / m_scaling_factor; + *y = (double)m_result[ m_contour ][ m_vertex ].Y / m_scaling_factor; + return true; + } + //------------------------------------------------------------------------------ + + template + unsigned conv_clipper::vertex(double *x, double *y) +{ + if( m_status == status_move_to ) + { + if( next_contour() ) + { + if( next_vertex( x, y ) ) + { + m_status =status_line_to; + return path_cmd_move_to; + } + else + { + m_status = status_stop; + return path_cmd_end_poly | path_flags_close; + } + } + else + return path_cmd_stop; + } + else + { + if( next_vertex( x, y ) ) + { + return path_cmd_line_to; + } + else + { + m_status = status_move_to; + return path_cmd_end_poly | path_flags_close; + } + } +} +//------------------------------------------------------------------------------ + + +} //namespace agg +#endif //AGG_CONV_CLIPPER_INCLUDED diff --git a/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.cpp b/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.cpp new file mode 100644 index 0000000000..0f263d72b2 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.cpp @@ -0,0 +1,574 @@ +#include +#include "agg_basics.h" +#include "agg_rendering_buffer.h" +#include "agg_rasterizer_scanline_aa.h" +#include "agg_scanline_u.h" +#include "agg_scanline_p.h" +#include "agg_renderer_scanline.h" +#include "agg_renderer_primitives.h" +#include "agg_conv_curve.h" +#include "agg_conv_stroke.h" +#include "agg_conv_clip_polygon.h" +#include "agg_gsv_text.h" +#include "agg_pixfmt_rgb.h" +#include "agg_platform_support.h" + +#include "agg_slider_ctrl.h" +#include "agg_cbox_ctrl.h" +#include "agg_rbox_ctrl.h" + +#include "agg_conv_clipper.h" +#include "windows.h" + +enum flip_y_e { flip_y = true }; + + +class spiral +{ +public: + spiral(double x, double y, double r1, double r2, double step, double start_angle=0) : + m_x(x), + m_y(y), + m_r1(r1), + m_r2(r2), + m_step(step), + m_start_angle(start_angle), + m_angle(start_angle), + m_da(agg::deg2rad(4.0)), + m_dr(m_step / 90.0) + { + } + + void rewind(unsigned) + { + m_angle = m_start_angle; + m_curr_r = m_r1; + m_start = true; + } + + unsigned vertex(double* x, double* y) + { + if(m_curr_r > m_r2) return agg::path_cmd_stop; + + *x = m_x + cos(m_angle) * m_curr_r; + *y = m_y + sin(m_angle) * m_curr_r; + m_curr_r += m_dr; + m_angle += m_da; + if(m_start) + { + m_start = false; + return agg::path_cmd_move_to; + } + return agg::path_cmd_line_to; + } + +private: + double m_x; + double m_y; + double m_r1; + double m_r2; + double m_step; + double m_start_angle; + + double m_angle; + double m_curr_r; + double m_da; + double m_dr; + bool m_start; +}; + + + +namespace agg +{ + // A simple counter of points and contours + template struct conv_poly_counter + { + unsigned m_contours; + unsigned m_points; + + conv_poly_counter(Src& src) : m_src(&src), m_contours(0), m_points(0) {} + + void rewind(unsigned path_id) + { + m_contours = 0; + m_points = 0; + m_src->rewind(path_id); + } + + unsigned vertex(double* x, double* y) + { + unsigned cmd = m_src->vertex(x, y); + if(is_vertex(cmd)) ++m_points; + if(is_move_to(cmd)) ++m_contours; + return cmd; + } + + private: + Src* m_src; + }; +} + + +void make_gb_poly(agg::path_storage& ps); +void make_arrows(agg::path_storage& ps); + + +class the_application : public agg::platform_support +{ + agg::rbox_ctrl m_polygons; + agg::rbox_ctrl m_operation; + double m_x; + double m_y; + + virtual void on_key(int x, int y, unsigned key, unsigned flags) + { + if(key == agg::key_escape) exit(0); + + } + +public: + the_application(agg::pix_format_e format, bool flip_y) : + agg::platform_support(format, flip_y), + m_polygons (5.0, 5.0, 5.0+205.0, 110.0, !flip_y), + m_operation(555.0, 5.0, 555.0+80.0, 130.0, !flip_y) + { + m_operation.add_item("None"); + m_operation.add_item("OR"); + m_operation.add_item("AND"); + m_operation.add_item("XOR"); + m_operation.add_item("A-B"); + m_operation.add_item("B-A"); + m_operation.cur_item(2); + add_ctrl(m_operation); + + m_polygons.add_item("Two Simple Paths"); + m_polygons.add_item("Closed Stroke"); + m_polygons.add_item("Great Britain and Arrows"); + m_polygons.add_item("Great Britain and Spiral"); + m_polygons.add_item("Spiral and Glyph"); + m_polygons.cur_item(3); + add_ctrl(m_polygons); + } + + + template + void perform_rendering(Scanline &sl, Ras &ras, Ren &ren, Clp &clp) + { + if(m_operation.cur_item() > 0) + { + ras.reset(); + switch(m_operation.cur_item()) + { + case 1: clp.operation(agg::clipper_or); break; + case 2: clp.operation(agg::clipper_and); break; + case 3: clp.operation(agg::clipper_xor); break; + case 4: clp.operation(agg::clipper_a_minus_b); break; + case 5: clp.operation(agg::clipper_b_minus_a); break; + } + agg::conv_poly_counter counter(clp); + + + start_timer(); + counter.rewind(0); + double t1 = elapsed_time(); + + agg::path_storage ps; + double x; + double y; + unsigned cmd; + start_timer(); + while(!agg::is_stop(cmd = counter.vertex(&x, &y))) + { + if(agg::is_move_to(cmd)) + ps.move_to(x, y); + else if(agg::is_line_to(cmd)) + ps.line_to(x, y); + else if(agg::is_close(cmd)) + ps.close_polygon(); + } + ras.add_path(ps); + ren.color(agg::rgba(0.25, 0.9, 0.25, 0.65)); + agg::render_scanlines(ras, sl, ren); + double t2 = elapsed_time(); + + agg::conv_stroke stroke(ps); + stroke.width(0.4); + ras.add_path(stroke); + ren.color(agg::rgba(0, 0, 0)); + agg::render_scanlines(ras, sl, ren); + + char buf[100]; + sprintf_s(buf, "Contours: %d Points: %d", counter.m_contours, counter.m_points); + agg::gsv_text txt; + agg::conv_stroke txt_stroke(txt); + txt_stroke.width(1.5); + txt_stroke.line_cap(agg::round_cap); + txt.size(10.0); + txt.start_point(250, 5); + txt.text(buf); + ras.add_path(txt_stroke); + ren.color(agg::rgba(0.0, 0.0, 0.0)); + agg::render_scanlines(ras, sl, ren); + + sprintf_s(buf, "Clipper=%.3fms Render=%.3fms", t1, t2); + txt.start_point(250, 20); + txt.text(buf); + ras.add_path(txt_stroke); + ren.color(agg::rgba(0.0, 0.0, 0.0)); + agg::render_scanlines(ras, sl, ren); + } + } + + + template + unsigned render_clipper(Scanline& sl, Ras& ras) + { + agg::pixfmt_bgr24 pf(rbuf_window()); + agg::renderer_base rb(pf); + agg::renderer_scanline_aa_solid > ren(rb); + + + switch(m_polygons.cur_item()) + { + case 0: + { + //------------------------------------ + // Two simple paths + // + agg::path_storage ps1; + agg::path_storage ps2; + + agg::conv_clipper clp(ps1, ps2, agg::clipper_or, agg::clipper_non_zero, agg::clipper_non_zero); + + double x = m_x - initial_width()/2 + 100; + double y = m_y - initial_height()/2 + 100; + ps1.move_to(x+140, y+145); + ps1.line_to(x+225, y+44); + ps1.line_to(x+296, y+219); + ps1.close_polygon(); + + ps1.line_to(x+226, y+289); + ps1.line_to(x+82, y+292); + + ps1.move_to(x+220, y+222); + ps1.line_to(x+363, y+249); + ps1.line_to(x+265, y+331); + + ps1.move_to(x+242, y+243); + ps1.line_to(x+268, y+309); + ps1.line_to(x+325, y+261); + + ps1.move_to(x+259, y+259); + ps1.line_to(x+273, y+288); + ps1.line_to(x+298, y+266); + + ps2.move_to(100+32, 100+77); + ps2.line_to(100+473, 100+263); + ps2.line_to(100+351, 100+290); + ps2.line_to(100+354, 100+374); + + ras.reset(); + ras.add_path(ps1); + ren.color(agg::rgba(0, 0, 0, 0.1)); + agg::render_scanlines(ras, sl, ren); + + ras.reset(); + ras.add_path(ps2); + ren.color(agg::rgba(0, 0.6, 0, 0.1)); + agg::render_scanlines(ras, sl, ren); + + perform_rendering(sl, ras, ren, clp); + } + break; + + case 1: + { + //------------------------------------ + // Closed stroke + // + agg::path_storage ps1; + agg::path_storage ps2; + agg::conv_stroke stroke(ps2); + stroke.width(10.0); + + agg::conv_clipper > clp(ps1, stroke, agg::clipper_or, agg::clipper_non_zero, agg::clipper_non_zero); + + + double x = m_x - initial_width()/2 + 100; + double y = m_y - initial_height()/2 + 100; + ps1.move_to(x+140, y+145); + ps1.line_to(x+225, y+44); + ps1.line_to(x+296, y+219); + ps1.close_polygon(); + + ps1.line_to(x+226, y+289); + ps1.line_to(x+82, y+292); + + ps1.move_to(x+220-50, y+222); + ps1.line_to(x+265-50, y+331); + ps1.line_to(x+363-50, y+249); + ps1.close_polygon(agg::path_flags_ccw); + + ps2.move_to(100+32, 100+77); + ps2.line_to(100+473, 100+263); + ps2.line_to(100+351, 100+290); + ps2.line_to(100+354, 100+374); + ps2.close_polygon(); + + ras.reset(); + ras.add_path(ps1); + ren.color(agg::rgba(0, 0, 0, 0.1)); + agg::render_scanlines(ras, sl, ren); + + ras.reset(); + ras.add_path(stroke); + ren.color(agg::rgba(0, 0.6, 0, 0.1)); + agg::render_scanlines(ras, sl, ren); + + perform_rendering(sl, ras, ren, clp); + } + break; + + + case 2: + { + //------------------------------------ + // Great Britain and Arrows + // + agg::path_storage gb_poly; + agg::path_storage arrows; + make_gb_poly(gb_poly); + make_arrows(arrows); + + agg::trans_affine mtx1; + agg::trans_affine mtx2; + mtx1 *= agg::trans_affine_translation(-1150, -1150); + mtx1 *= agg::trans_affine_scaling(2.0); + + mtx2 = mtx1; + mtx2 *= agg::trans_affine_translation(m_x - initial_width()/2, + m_y - initial_height()/2); + + agg::conv_transform trans_gb_poly(gb_poly, mtx1); + agg::conv_transform trans_arrows(arrows, mtx2); + + agg::conv_clipper, + agg::conv_transform > clp(trans_gb_poly, trans_arrows, agg::clipper_or, agg::clipper_non_zero, agg::clipper_non_zero); + + ras.add_path(trans_gb_poly); + ren.color(agg::rgba(0.5, 0.5, 0, 0.1)); + agg::render_scanlines(ras, sl, ren); + + agg::conv_stroke > stroke_gb_poly(trans_gb_poly); + stroke_gb_poly.width(0.1); + ras.add_path(stroke_gb_poly); + ren.color(agg::rgba(0, 0, 0)); + agg::render_scanlines(ras, sl, ren); + + ras.add_path(trans_arrows); + ren.color(agg::rgba(0.0, 0.5, 0.5, 0.1)); + agg::render_scanlines(ras, sl, ren); + + perform_rendering(sl, ras, ren, clp); + } + break; + + + case 3: + { + //------------------------------------ + // Great Britain and a Spiral + // + spiral sp(m_x, m_y, 10, 150, 30, 0.0); + agg::conv_stroke stroke(sp); + stroke.width(15.0); + + agg::path_storage gb_poly; + make_gb_poly(gb_poly); + + agg::trans_affine mtx; + mtx *= agg::trans_affine_translation(-1150, -1150); + mtx *= agg::trans_affine_scaling(2.0); + + agg::conv_transform trans_gb_poly(gb_poly, mtx); + + agg::conv_clipper, + agg::conv_stroke > clp(trans_gb_poly, stroke, agg::clipper_or, agg::clipper_non_zero, agg::clipper_non_zero); + + ras.add_path(trans_gb_poly); + ren.color(agg::rgba(0.5, 0.5, 0, 0.1)); + agg::render_scanlines(ras, sl, ren); + + agg::conv_stroke > stroke_gb_poly(trans_gb_poly); + stroke_gb_poly.width(0.1); + ras.add_path(stroke_gb_poly); + ren.color(agg::rgba(0, 0, 0)); + agg::render_scanlines(ras, sl, ren); + + ras.add_path(stroke); + ren.color(agg::rgba(0.0, 0.5, 0.5, 0.1)); + agg::render_scanlines(ras, sl, ren); + + perform_rendering(sl, ras, ren, clp); + } + break; + + + case 4: + { + //------------------------------------ + // Spiral and glyph + // + spiral sp(m_x, m_y, 10, 150, 30, 0.0); + agg::conv_stroke stroke(sp); + stroke.width(15.0); + + agg::path_storage glyph; + glyph.move_to(28.47, 6.45); + glyph.curve3(21.58, 1.12, 19.82, 0.29); + glyph.curve3(17.19, -0.93, 14.21, -0.93); + glyph.curve3(9.57, -0.93, 6.57, 2.25); + glyph.curve3(3.56, 5.42, 3.56, 10.60); + glyph.curve3(3.56, 13.87, 5.03, 16.26); + glyph.curve3(7.03, 19.58, 11.99, 22.51); + glyph.curve3(16.94, 25.44, 28.47, 29.64); + glyph.line_to(28.47, 31.40); + glyph.curve3(28.47, 38.09, 26.34, 40.58); + glyph.curve3(24.22, 43.07, 20.17, 43.07); + glyph.curve3(17.09, 43.07, 15.28, 41.41); + glyph.curve3(13.43, 39.75, 13.43, 37.60); + glyph.line_to(13.53, 34.77); + glyph.curve3(13.53, 32.52, 12.38, 31.30); + glyph.curve3(11.23, 30.08, 9.38, 30.08); + glyph.curve3(7.57, 30.08, 6.42, 31.35); + glyph.curve3(5.27, 32.62, 5.27, 34.81); + glyph.curve3(5.27, 39.01, 9.57, 42.53); + glyph.curve3(13.87, 46.04, 21.63, 46.04); + glyph.curve3(27.59, 46.04, 31.40, 44.04); + glyph.curve3(34.28, 42.53, 35.64, 39.31); + glyph.curve3(36.52, 37.21, 36.52, 30.71); + glyph.line_to(36.52, 15.53); + glyph.curve3(36.52, 9.13, 36.77, 7.69); + glyph.curve3(37.01, 6.25, 37.57, 5.76); + glyph.curve3(38.13, 5.27, 38.87, 5.27); + glyph.curve3(39.65, 5.27, 40.23, 5.62); + glyph.curve3(41.26, 6.25, 44.19, 9.18); + glyph.line_to(44.19, 6.45); + glyph.curve3(38.72, -0.88, 33.74, -0.88); + glyph.curve3(31.35, -0.88, 29.93, 0.78); + glyph.curve3(28.52, 2.44, 28.47, 6.45); + glyph.close_polygon(); + + glyph.move_to(28.47, 9.62); + glyph.line_to(28.47, 26.66); + glyph.curve3(21.09, 23.73, 18.95, 22.51); + glyph.curve3(15.09, 20.36, 13.43, 18.02); + glyph.curve3(11.77, 15.67, 11.77, 12.89); + glyph.curve3(11.77, 9.38, 13.87, 7.06); + glyph.curve3(15.97, 4.74, 18.70, 4.74); + glyph.curve3(22.41, 4.74, 28.47, 9.62); + glyph.close_polygon(); + + agg::trans_affine mtx; + mtx *= agg::trans_affine_scaling(4.0); + mtx *= agg::trans_affine_translation(220, 200); + agg::conv_transform trans(glyph, mtx); + agg::conv_curve > curve(trans); + + agg::conv_clipper, + agg::conv_curve< + agg::conv_transform< + agg::path_storage> > > clp(stroke, curve, agg::clipper_or, agg::clipper_non_zero, agg::clipper_non_zero); + + ras.reset(); + ras.add_path(stroke); + ren.color(agg::rgba(0, 0, 0, 0.1)); + agg::render_scanlines(ras, sl, ren); + + ras.reset(); + ras.add_path(curve); + ren.color(agg::rgba(0, 0.6, 0, 0.1)); + agg::render_scanlines(ras, sl, ren); + + perform_rendering(sl, ras, ren, clp); + } + break; + } + + return 0; + } + + + virtual void on_init() + { + m_x = width() / 2.0; + m_y = height() / 2.0; + } + + virtual void on_draw() + { + typedef agg::renderer_base base_ren_type; + + agg::pixfmt_bgr24 pf(rbuf_window()); + base_ren_type ren_base(pf); + ren_base.clear(agg::rgba(1,1,1)); + + agg::scanline_u8 sl; + agg::rasterizer_scanline_aa<> ras; + + render_clipper(sl, ras); + + agg::render_ctrl(ras, sl, ren_base, m_polygons); + agg::render_ctrl(ras, sl, ren_base, m_operation); + } + + virtual void on_mouse_button_down(int x, int y, unsigned flags) + { + if(flags & agg::mouse_left) + { + m_x = x; + m_y = y; + force_redraw(); + } + } + + + virtual void on_mouse_move(int x, int y, unsigned flags) + { + if(flags & agg::mouse_left) + { + m_x = x; + m_y = y; + force_redraw(); + } + } + + + +}; + + +int agg_main(int argc, char* argv[]) +{ + the_application app(agg::pix_format_bgr24, flip_y); + app.caption("AGG Example. Clipper"); + + if(app.init(640, 520, agg::window_resize)) + { + //replace the main window icon with Resource Icon #1 ... + HWND w = GetActiveWindow(); + HMODULE m = GetModuleHandle(0); //hInstance + HANDLE small_ico = LoadImage(m, MAKEINTRESOURCE(1), IMAGE_ICON, 16, 16, 0); + HANDLE big_ico = LoadImage(m, MAKEINTRESOURCE(1), IMAGE_ICON, 32, 32, 0); + SendMessage(w, WM_SETICON, ICON_SMALL, (LPARAM)small_ico); + SendMessage(w, WM_SETICON, ICON_BIG, (LPARAM)big_ico); + + //main message loop ... + return app.run(); + } + return 0; +} + + diff --git a/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.exe b/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.exe new file mode 100644 index 0000000000000000000000000000000000000000..2311a437c9a6f2e4c73cb7758b127d4f87f0eb44 GIT binary patch literal 240640 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 literal 0 HcmV?d00001 diff --git a/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.sln b/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.sln new file mode 100644 index 0000000000..f2626c5e4d --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "clipper_test", "clipper_test.vcxproj", "{4DF13A7A-6137-E76C-8C62-F591D0E4B69F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4DF13A7A-6137-E76C-8C62-F591D0E4B69F}.Debug|Win32.ActiveCfg = Debug|Win32 + {4DF13A7A-6137-E76C-8C62-F591D0E4B69F}.Debug|Win32.Build.0 = Debug|Win32 + {4DF13A7A-6137-E76C-8C62-F591D0E4B69F}.Release|Win32.ActiveCfg = Release|Win32 + {4DF13A7A-6137-E76C-8C62-F591D0E4B69F}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.vcxproj b/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.vcxproj new file mode 100644 index 0000000000..e789bb39b0 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.vcxproj @@ -0,0 +1,114 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + Win32Proj + clipper_test + + + + Application + true + + + Application + false + + + + + + + + + + + + + true + C:\Program Files (x86)\Borland\agg-2.5\include;C:\Program Files (x86)\Borland\agg-2.5\include\platform;C:\Program Files (x86)\Borland\agg-2.5\include\platform\win32;C:\Program Files (x86)\Borland\agg-2.5\include\ctrl;C:\Program Files (x86)\Borland\agg-2.5\include\util;$(IncludePath) + + + true + C:\Program Files (x86)\Borland\agg-2.5\include;C:\Program Files (x86)\Borland\agg-2.5\include\platform;C:\Program Files (x86)\Borland\agg-2.5\include\platform\win32;C:\Program Files (x86)\Borland\agg-2.5\include\ctrl;C:\Program Files (x86)\Borland\agg-2.5\include\util;$(IncludePath) + + + + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + ProgramDatabase + Disabled + + + MachineX86 + true + Windows + + + + + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + + + MachineX86 + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.vcxproj.filters b/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.vcxproj.filters new file mode 100644 index 0000000000..188f95dda9 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_agg/clipper_test.vcxproj.filters @@ -0,0 +1,118 @@ + + + + + + ClipperLib + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + agg_src + + + + + {31703eea-b46a-4b7c-93fe-7b3889404c6f} + + + {0d7823fd-c31f-4f5d-b1f5-3f3c91751bf3} + + + {0ea31d0f-7e25-4f22-964b-8c74b5ced2fd} + + + + + ClipperLib + + + agg_clipper + + + \ No newline at end of file diff --git a/ThirdParty/custom-clipper/clipper/cpp_agg/icon.res b/ThirdParty/custom-clipper/clipper/cpp_agg/icon.res new file mode 100644 index 0000000000000000000000000000000000000000..a4fc1a701c1e02251b98d56d49031b54cf400cf3 GIT binary patch literal 5556 zcmcgw4Nz3q6@L5P+g$-+VG(ozaa}?A3*sNFT@<1yMkgwugE5W78qlJh5YQ-ziTDF% zsz@6r(@YpOnvBLo(HN&%A_`hb!z5LkWUAHFq#|*WIMFd_lU8&3ovZK7F1wpu+tD}k z?R|UiJ?A_3oOA!4BuSDTAi52_dOUALYV8X87(`oEWQeMDO2LaA$OjDK4KMfMaVc%h zK=gf}@}dCm0stPn{||Ua?5$W_~J-fQ-bA|)Eg0cJ3^~Tc*kxDv>)q~9Yr^=*T%-3_FRmX-En@N^UlvGeiD=vLakM2Dv_*>@KZm|r| z3yR$~ilg+`zfcyMRY26bcr%}X!II2GTIX(T^6)IS>UbiDMB$?tZ*(58f7%%f` z(EQ(Zho60=`2jwd7K{yXeQXuzN3N=+x?a}b+m5M?FM7258o!9u-wspfg7}-rqqD)p z;m8c7Ha#kejOI{UaO8v+2iq}w$8N8Bzx?pQxi@RII0T#%Jipt1ney+b@OX;oKTyO# z^KYP1^Z%=j+r9Gjk3YBm2jk!MQ!zk0uWR)2@5-ok-&RuP5E`62LCmc{-0tI7)leD` zHkL~As_5Ox$`L87AIsm zmmE_{+lP?sKh_5bhFsDo%9yjJZEsxW4?@doCQbu*Jx#@Sl_^Z188#h z1^9LU*H>*OMF|nM^V-^5U!ecICNk&PB~=tRVzgKw$tJ2APS3)rA3{84tm_$ z+%teLzF!*6oH&P?f73u0J~|+BDVX_}Dz6KTF=qag*Vf10KJ3NKV=O!Pu2((#M&m!x zy47p$2fO~*<%R9=59KXisdI4NPp;oUj{J$F+{s~I>z~H&zV_eE`ip$1aViJMr1Yh@ ztkJ|d9}zcD8cQy!nm6haTodPMh;yZ_zCAI$y>&SAh8z#(99s=Ou(<1KwW#SnXZmg#&)iSfrz zn#*;5_UYP{ON3wC~ME0Ot_EYb}BeJRiff^H*0*){mdIHVQi~ojXiv zLsLECpz*giKPAp;kY)a$&tJ^v?|~jZe_m&uyqEL&^Y=L!a0Adttgs&rjxN{C1rD9Qyk7r!T$#OC9v{I_YYiuFRg&KYv?> zyone|a`iUoyQkc~>_z_Y-GTR&RleHqbscyun7`d9pS{;y{`7;J&+cXZ+WplN-5{bb zfcJ>LH`B3pg_`ON)GkS@fV|IuYmzhwuxLP?1uz2!K)O?!xgGBU?U1R1tOSgQE`m;i zZss6rx`R`+2wyDh=tRWdF=V_+Qt$5=k*Ko+|L=DU_{Zi{_H{#5&=2z52sri^#wF*d zdpn)#z8+t~&>ibkTFyJwmf746nfQ((bxY?H1FwJhd>$1gXHZnUgC^P14x=sBmk#K@ z=2Z9p%PMDWX(+ILed)D&Vl=K^Lm9=TRQdiHnm2hk?!dMl-0Md6)&U!0#zbxUGG*#? zv45ow8&1zuRa4@qTv~SVinyzl&o34_p`#miczvfC*)Q}^VZ%nTw=DkPBg(F*q+gvr zEB^CcPm^c6AivSw2K+aktW3U^gL~urL+u{>6Yo(hpPH0Tn^vzEHefCF@FnDvPBlCv z+F}P~(9%zPJanwMe3c&Ce@NWT5=J^{ge``g>Yj@jw@4gKzNTUsjeLB8hphYg?a7ZX zP|+*fDK;$w@-1hyoM8LwA56V5Bp>(r?yFw%eCJDeU^Kb1$5L%|1-)1h!}c3AAK2wZ zqhjspx2n&5PK!={NR!sSK+~FD()DDP&J|Tt?#2e_<*kN_gZ|0M?cTti=$A*@mkRM`Qd2%q0m aIn1(TM;Bg&`0J}diWI+giPtb5)PDh&WBnok literal 0 HcmV?d00001 diff --git a/ThirdParty/custom-clipper/clipper/cpp_cairo/Cairo Resources.txt b/ThirdParty/custom-clipper/clipper/cpp_cairo/Cairo Resources.txt new file mode 100644 index 0000000000..8e2227a67b --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_cairo/Cairo Resources.txt @@ -0,0 +1,6 @@ +http://cairographics.org/ + +The Windows dynamic linked libraries necessary to run Cairo can be downloaded from +http://www.gtk.org/download/win32.php +All the dlls listed under the heading "Required third party dependencies" are +required except gettext-runtime.dll. diff --git a/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo.sln b/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo.sln new file mode 100644 index 0000000000..5ed969c239 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cairo", "cairo.vcxproj", "{6AFBCA2B-9262-6D28-7506-E13747347388}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6AFBCA2B-9262-6D28-7506-E13747347388}.Debug|Win32.ActiveCfg = Debug|Win32 + {6AFBCA2B-9262-6D28-7506-E13747347388}.Debug|Win32.Build.0 = Debug|Win32 + {6AFBCA2B-9262-6D28-7506-E13747347388}.Release|Win32.ActiveCfg = Release|Win32 + {6AFBCA2B-9262-6D28-7506-E13747347388}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo.vcxproj b/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo.vcxproj new file mode 100644 index 0000000000..156717b435 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo.vcxproj @@ -0,0 +1,93 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + Win32Proj + + + + Application + true + Unicode + + + Application + false + + + + + + + + + + + + + true + C:\Program Files %28x86%29\Borland\Clipper\PreReleaseTesting\cpp\cairo_src;$(IncludePath) + C:\Program Files %28x86%29\Borland\Clipper\PreReleaseTesting\cpp\cairo_src;C:\Program Files %28x86%29\Borland\graphics32\Examples\Vcl\Drawing\Clipper\PreReleaseTesting\cpp\cairo_src;$(SourcePath) + + + true + + + + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + C:\Program Files (x86)\Borland\graphics32\Examples\Vcl\Drawing\Clipper\PreReleaseTesting\cpp\cairo_src;%(AdditionalIncludeDirectories) + MultiThreadedDebugDLL + Level3 + ProgramDatabase + Disabled + + + + + MachineX86 + true + Windows + + + + + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + C:\Program Files (x86)\Borland\graphics32\Examples\Vcl\Drawing\Clipper\PreReleaseTesting\cpp\cairo_src;%(AdditionalIncludeDirectories) + MultiThreadedDLL + Level3 + ProgramDatabase + + + MachineX86 + true + Windows + true + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo_clipper.cpp b/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo_clipper.cpp new file mode 100644 index 0000000000..3cae1f41b2 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo_clipper.cpp @@ -0,0 +1,134 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 1.1 * +* Date : 4 April 2011 * +* Copyright : Angus Johnson 2010-2011 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Modified by Mike Owens to support coordinate transformation * +*******************************************************************************/ + +#include +#include +#include +#include "clipper.hpp" +#include "cairo_clipper.hpp" + +namespace ClipperLib { + namespace cairo { + + namespace { + + inline cInt Round(double val) + { + if ((val < 0)) return (cInt)(val - 0.5); else return (cInt)(val + 0.5); + } + + void transform_point(cairo_t* pen, Transform transform, cInt* x, cInt* y) + { + double _x = (double)*x, _y = (double)*y; + switch (transform) + { + case tDeviceToUser: + cairo_device_to_user(pen, &_x, &_y); + break; + case tUserToDevice: + cairo_user_to_device(pen, &_x, &_y); + break; + default: + ; + } + *x = Round(_x); *y = Round(_y); + } + } + + void cairo_to_clipper(cairo_t* cr, + Paths &pg, + int scaling_factor, + Transform transform) + { + if (scaling_factor > 8 || scaling_factor < 0) + throw clipperCairoException("cairo_to_clipper: invalid scaling factor"); + double scaling = std::pow((double)10, scaling_factor); + + pg.clear(); + cairo_path_t *path = cairo_copy_path_flat(cr); + + int poly_count = 0; + for (int i = 0; i < path->num_data; i += path->data[i].header.length) { + if( path->data[i].header.type == CAIRO_PATH_CLOSE_PATH) poly_count++; + } + + pg.resize(poly_count); + int i = 0, pc = 0; + while (pc < poly_count) + { + int vert_count = 1; + int j = i; + while(j < path->num_data && + path->data[j].header.type != CAIRO_PATH_CLOSE_PATH) + { + if (path->data[j].header.type == CAIRO_PATH_LINE_TO) + vert_count++; + j += path->data[j].header.length; + } + pg[pc].resize(vert_count); + if (path->data[i].header.type != CAIRO_PATH_MOVE_TO) { + pg.resize(pc); + break; + } + pg[pc][0].X = Round(path->data[i+1].point.x *scaling); + pg[pc][0].Y = Round(path->data[i+1].point.y *scaling); + if (transform != tNone) + transform_point(cr, transform, &pg[pc][0].X, &pg[pc][0].Y); + + i += path->data[i].header.length; + + j = 1; + while (j < vert_count && i < path->num_data && + path->data[i].header.type == CAIRO_PATH_LINE_TO) { + pg[pc][j].X = Round(path->data[i+1].point.x *scaling); + pg[pc][j].Y = Round(path->data[i+1].point.y *scaling); + if (transform != tNone) + transform_point(cr, transform, &pg[pc][j].X, &pg[pc][j].Y); + j++; + i += path->data[i].header.length; + } + pc++; + i += path->data[i].header.length; + } + cairo_path_destroy(path); + } + //-------------------------------------------------------------------------- + + void clipper_to_cairo(const Paths &pg, + cairo_t* cr, + int scaling_factor, + Transform transform) + { + if (scaling_factor > 8 || scaling_factor < 0) + throw clipperCairoException("clipper_to_cairo: invalid scaling factor"); + double scaling = std::pow((double)10, scaling_factor); + for (size_t i = 0; i < pg.size(); ++i) + { + size_t sz = pg[i].size(); + if (sz < 3) + continue; + cairo_new_sub_path(cr); + for (size_t j = 0; j < sz; ++j) { + cInt x = pg[i][j].X, y = pg[i][j].Y; + if (transform != tNone) + transform_point(cr, transform, &x, &y); + cairo_line_to(cr, (double)x / scaling, (double)y / scaling); + } + cairo_close_path(cr); + } + } + //-------------------------------------------------------------------------- + + } +} diff --git a/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo_clipper.hpp b/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo_clipper.hpp new file mode 100644 index 0000000000..af5d8b0ee6 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_cairo/cairo_clipper.hpp @@ -0,0 +1,59 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 1.1 * +* Date : 4 April 2011 * +* Copyright : Angus Johnson 2010-2011 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Modified by Mike Owens to support coordinate transformation * +*******************************************************************************/ + +#ifndef CLIPPER_CAIRO_CLIPPER_HPP +#define CLIPPER_CAIRO_CLIPPER_HPP + +#include "clipper.hpp" + +typedef struct _cairo cairo_t; + +namespace ClipperLib { + namespace cairo { + + enum Transform { + tNone, + tUserToDevice, + tDeviceToUser + }; + +//nb: Since Clipper only accepts integer coordinates, fractional values have to +//be scaled up and down when being passed to and from Clipper. This is easily +//accomplished by setting the scaling factor (10^x) in the following functions. +//When scaling, remember that on most platforms, integer is only a 32bit value. + void cairo_to_clipper(cairo_t* cr, + ClipperLib::Paths &pg, + int scaling_factor = 0, + Transform transform = tNone); + + void clipper_to_cairo(const ClipperLib::Paths &pg, + cairo_t* cr, + int scaling_factor = 0, + Transform transform = tNone); + } + + class clipperCairoException : public std::exception + { + public: + clipperCairoException(const char* description) + throw(): std::exception(), m_description (description) {} + virtual ~clipperCairoException() throw() {} + virtual const char* what() const throw() {return m_description.c_str();} + private: + std::string m_description; + }; +} + +#endif + diff --git a/ThirdParty/custom-clipper/clipper/cpp_cairo/main.cpp b/ThirdParty/custom-clipper/clipper/cpp_cairo/main.cpp new file mode 100644 index 0000000000..e31dcae6e5 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_cairo/main.cpp @@ -0,0 +1,182 @@ +//--------------------------------------------------------------------------- + +#include +#include +#include +#include +#pragma hdrstop + +#include "clipper.hpp" +#include "cairo.h" +#include "cairo-win32.h" +#include "cairo_clipper.hpp" +//--------------------------------------------------------------------------- + +int offsetVal; + +LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +int CALLBACK wWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) +{ + WCHAR* ClsName = L"CairoApp"; + WCHAR* WndName = L"A Simple Cairo Clipper Demo"; + offsetVal = 0; + + MSG Msg; + HWND hWnd; + WNDCLASSEX WndClsEx; + + // Create the application window + WndClsEx.cbSize = sizeof(WNDCLASSEX); + WndClsEx.style = CS_HREDRAW | CS_VREDRAW; + WndClsEx.lpfnWndProc = WndProcedure; + WndClsEx.cbClsExtra = 0; + WndClsEx.cbWndExtra = 0; + WndClsEx.hIcon = LoadIcon(NULL, IDI_APPLICATION); + WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW); + WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + WndClsEx.lpszMenuName = NULL; + WndClsEx.lpszClassName = ClsName; + WndClsEx.hInstance = hInstance; + WndClsEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + // Register the application + RegisterClassEx(&WndClsEx); + + // Create the window object + hWnd = CreateWindow(ClsName, WndName, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, + NULL, NULL, hInstance, NULL); + if( !hWnd ) return 0; + + ShowWindow(hWnd, SW_SHOWNORMAL); + UpdateWindow(hWnd); + + while( GetMessage(&Msg, NULL, 0, 0) ) + { + TranslateMessage(&Msg); + DispatchMessage(&Msg); + } + return Msg.wParam; +} +//------------------------------------------------------------------------------ + + +void OnPaint(HWND hWnd, HDC dc) +{ + RECT rec; + GetClientRect(hWnd, &rec); + cairo_surface_t* surface = cairo_win32_surface_create(dc); + cairo_t* cr = cairo_create(surface); + + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); + cairo_set_line_width (cr, 2.0); + + //fill background with white ... + cairo_rectangle(cr, 0, 0, rec.right, rec.bottom); + cairo_set_source_rgba(cr, 1, 1, 1, 1); + cairo_fill(cr); + + using namespace ClipperLib; + + const int scaling = 2; + + Clipper clpr; //clipper class + Paths pg; //std::vector for polygon(s) storage + + //create a circular pattern, add the path to clipper and then draw it ... + cairo_arc(cr, 170,110,70,0,2*3.1415926); + cairo_close_path(cr); + cairo::cairo_to_clipper(cr, pg, scaling); + clpr.AddPaths(pg, ptSubject, true); + cairo_set_source_rgba(cr, 0, 0, 1, 0.25); + cairo_fill_preserve (cr); + cairo_set_source_rgba(cr, 0, 0, 0, 0.5); + cairo_stroke (cr); + + //draw a star and another circle, add them to clipper and draw ... + cairo_move_to(cr, 60,110); + cairo_line_to (cr, 240,70); + cairo_line_to (cr, 110,210); + cairo_line_to (cr, 140,25); + cairo_line_to (cr, 230,200); + cairo_close_path(cr); + cairo_new_sub_path(cr); + cairo_arc(cr, 190,50,20,0,2*3.1415926); + cairo_close_path(cr); + cairo::cairo_to_clipper(cr, pg, scaling); + clpr.AddPaths(pg, ptClip, true); + cairo_set_source_rgba(cr, 1, 0, 0, 0.25); + cairo_fill_preserve (cr); + cairo_set_source_rgba(cr, 0, 0, 0, 0.5); + cairo_stroke (cr); + + clpr.Execute(ctIntersection, pg, pftNonZero, pftNonZero); + //now do something fancy with the returned polygons ... + OffsetPaths(pg, pg, offsetVal * std::pow((double)10,scaling), jtMiter, etClosed); + + //finally copy the clipped path back to the cairo context and draw it ... + cairo::clipper_to_cairo(pg, cr, scaling); + cairo_set_source_rgba(cr, 1, 1, 0, 1); + cairo_fill_preserve (cr); + cairo_set_source_rgba(cr, 0, 0, 0, 1); + cairo_stroke (cr); + + cairo_text_extents_t extent; + cairo_set_font_size(cr,11); + std::stringstream ss; + ss << "Polygon offset = " << offsetVal << ". (Adjust with arrow keys)"; + std::string s = ss.str(); + cairo_text_extents(cr, s.c_str(), &extent); + cairo_move_to(cr, 10, rec.bottom - extent.height); + cairo_show_text(cr, s.c_str()); + + cairo_destroy (cr); + cairo_surface_destroy (surface); +} +//------------------------------------------------------------------------------ + +LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + HDC Handle; + + switch(Msg) + { + case WM_DESTROY: + PostQuitMessage(WM_QUIT); + return 0; + + case WM_PAINT: + Handle = BeginPaint(hWnd, &ps); + OnPaint(hWnd, Handle); + EndPaint(hWnd, &ps); + return 0; + + case WM_KEYDOWN: + switch(wParam) + { + case VK_ESCAPE: + PostQuitMessage(0); + return 0; + case VK_RIGHT: + case VK_UP: + if (offsetVal < 20) offsetVal++; + InvalidateRect(hWnd, 0, false); + return 0; + case VK_LEFT: + case VK_DOWN: + if (offsetVal > -20) offsetVal--; + InvalidateRect(hWnd, 0, false); + return 0; + default: + return DefWindowProc(hWnd, Msg, wParam, lParam); + } + + default: + return DefWindowProc(hWnd, Msg, wParam, lParam); + } +} +//--------------------------------------------------------------------------- + diff --git a/ThirdParty/custom-clipper/clipper/cpp_console/clipper_console_demo.cpp b/ThirdParty/custom-clipper/clipper/cpp_console/clipper_console_demo.cpp new file mode 100644 index 0000000000..1e53f9ae3d --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_console/clipper_console_demo.cpp @@ -0,0 +1,461 @@ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clipper.hpp" + +using namespace std; +using namespace ClipperLib; + +//--------------------------------------------------------------------------- +// SVGBuilder class +// a very simple class that creates an SVG image file +//--------------------------------------------------------------------------- + +class SVGBuilder +{ + static string ColorToHtml(unsigned clr) + { + stringstream ss; + ss << '#' << hex << std::setfill('0') << setw(6) << (clr & 0xFFFFFF); + return ss.str(); + } + //------------------------------------------------------------------------------ + + static float GetAlphaAsFrac(unsigned clr) + { + return ((float)(clr >> 24) / 255); + } + //------------------------------------------------------------------------------ + + class StyleInfo + { + public: + PolyFillType pft; + unsigned brushClr; + unsigned penClr; + double penWidth; + bool showCoords; + + StyleInfo() + { + pft = pftNonZero; + brushClr = 0xFFFFFFCC; + penClr = 0xFF000000; + penWidth = 0.8; + showCoords = false; + } + }; + + class PolyInfo + { + public: + Paths paths; + StyleInfo si; + + PolyInfo(Paths paths, StyleInfo style) + { + this->paths = paths; + this->si = style; + } + }; + + typedef std::vector PolyInfoList; + +private: + PolyInfoList polyInfos; + static const std::string svg_xml_start[]; + static const std::string poly_end[]; + +public: + StyleInfo style; + + void AddPaths(Paths& poly) + { + if (poly.size() == 0) return; + polyInfos.push_back(PolyInfo(poly, style)); + } + + bool SaveToFile(const string& filename, double scale = 1.0, int margin = 10) + { + //calculate the bounding rect ... + PolyInfoList::size_type i = 0; + Paths::size_type j; + while (i < polyInfos.size()) + { + j = 0; + while (j < polyInfos[i].paths.size() && + polyInfos[i].paths[j].size() == 0) j++; + if (j < polyInfos[i].paths.size()) break; + i++; + } + if (i == polyInfos.size()) return false; + + IntRect rec; + rec.left = polyInfos[i].paths[j][0].X; + rec.right = rec.left; + rec.top = polyInfos[i].paths[j][0].Y; + rec.bottom = rec.top; + for ( ; i < polyInfos.size(); ++i) + for (Paths::size_type j = 0; j < polyInfos[i].paths.size(); ++j) + for (Path::size_type k = 0; k < polyInfos[i].paths[j].size(); ++k) + { + IntPoint ip = polyInfos[i].paths[j][k]; + if (ip.X < rec.left) rec.left = ip.X; + else if (ip.X > rec.right) rec.right = ip.X; + if (ip.Y < rec.top) rec.top = ip.Y; + else if (ip.Y > rec.bottom) rec.bottom = ip.Y; + } + + if (scale == 0) scale = 1.0; + if (margin < 0) margin = 0; + rec.left = (cInt)((double)rec.left * scale); + rec.top = (cInt)((double)rec.top * scale); + rec.right = (cInt)((double)rec.right * scale); + rec.bottom = (cInt)((double)rec.bottom * scale); + cInt offsetX = -rec.left + margin; + cInt offsetY = -rec.top + margin; + + ofstream file; + file.open(filename); + if (!file.is_open()) return false; + file.setf(ios::fixed); + file.precision(0); + file << svg_xml_start[0] << + ((rec.right - rec.left) + margin*2) << "px" << svg_xml_start[1] << + ((rec.bottom - rec.top) + margin*2) << "px" << svg_xml_start[2] << + ((rec.right - rec.left) + margin*2) << " " << + ((rec.bottom - rec.top) + margin*2) << svg_xml_start[3]; + setlocale(LC_NUMERIC, "C"); + file.precision(2); + + for (PolyInfoList::size_type i = 0; i < polyInfos.size(); ++i) + { + file << " \n\n"; + for (Paths::size_type j = 0; j < polyInfos[i].paths.size(); ++j) + { + if (polyInfos[i].paths[j].size() < 3) continue; + for (Path::size_type k = 0; k < polyInfos[i].paths[j].size(); ++k) + { + IntPoint ip = polyInfos[i].paths[j][k]; + file << "" << + ip.X << "," << ip.Y << "\n"; + file << "\n"; + } + } + file << "\n"; + } + } + file << "\n"; + file.close(); + setlocale(LC_NUMERIC, ""); + return true; + } +}; //SVGBuilder +//------------------------------------------------------------------------------ + +const std::string SVGBuilder::svg_xml_start [] = + {"\n" + "\n\n" + "\n\n" + }; +const std::string SVGBuilder::poly_end [] = + {"\"\n style=\"fill:", + "; fill-opacity:", + "; fill-rule:", + "; stroke:", + "; stroke-opacity:", + "; stroke-width:", + ";\"/>\n\n" + }; + +//------------------------------------------------------------------------------ +// Miscellaneous function ... +//------------------------------------------------------------------------------ + +bool SaveToFile(const string& filename, Paths &ppg, double scale = 1.0, unsigned decimal_places = 0) +{ + ofstream ofs(filename); + if (!ofs) return false; + + if (decimal_places > 8) decimal_places = 8; + ofs << setprecision(decimal_places) << std::fixed; + + Path pg; + for (size_t i = 0; i < ppg.size(); ++i) + { + for (size_t j = 0; j < ppg[i].size(); ++j) + ofs << ppg[i][j].X / scale << ", " << ppg[i][j].Y / scale << "," << std::endl; + ofs << std::endl; + } + ofs.close(); + return true; +} +//------------------------------------------------------------------------------ + +bool LoadFromFile(Paths &ppg, const string& filename, double scale) +{ + //file format assumes: + // 1. path coordinates (x,y) are comma separated (+/- spaces) and + // each coordinate is on a separate line + // 2. each path is separated by one or more blank lines + + ppg.clear(); + ifstream ifs(filename); + if (!ifs) return false; + string line; + Path pg; + while (std::getline(ifs, line)) + { + stringstream ss(line); + double X = 0.0, Y = 0.0; + if (!(ss >> X)) + { + //ie blank lines => flag start of next polygon + if (pg.size() > 0) ppg.push_back(pg); + pg.clear(); + continue; + } + char c = ss.peek(); + while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces before comma + if (c == ',') {ss.read(&c, 1); c = ss.peek();} //gobble comma + while (c == ' ') {ss.read(&c, 1); c = ss.peek();} //gobble spaces after comma + if (!(ss >> Y)) break; //oops! + pg.push_back(IntPoint((cInt)(X * scale),(cInt)(Y * scale))); + } + if (pg.size() > 0) ppg.push_back(pg); + ifs.close(); + return true; +} +//------------------------------------------------------------------------------ + +void MakeRandomPoly(int edgeCount, int width, int height, Paths & poly) +{ + poly.resize(1); + poly[0].resize(edgeCount); + for (int i = 0; i < edgeCount; i++){ + poly[0][i].X = rand() % width; + poly[0][i].Y = rand() % height; + } +} +//------------------------------------------------------------------------------ + +bool ASCII_icompare(const char* str1, const char* str2) +{ + //case insensitive compare for ASCII chars only + while (*str1) + { + if (toupper(*str1) != toupper(*str2)) return false; + str1++; + str2++; + } + return (!*str2); +} + +//------------------------------------------------------------------------------ +// Main entry point ... +//------------------------------------------------------------------------------ + +int main(int argc, char* argv[]) +{ + if (argc > 1 && + (strcmp(argv[1], "-b") == 0 || strcmp(argv[1], "--benchmark") == 0)) + { + //do a benchmark test that creates a subject and a clip polygon both with + //100 vertices randomly placed in a 400 * 400 space. Then perform an + //intersection operation based on even-odd filling. Repeat all this X times. + int loop_cnt = 1000; + char * dummy; + if (argc > 2) loop_cnt = strtol(argv[2], &dummy, 10); + if (loop_cnt == 0) loop_cnt = 1000; + cout << "\nPerforming " << loop_cnt << " random intersection operations ... "; + srand((int)time(0)); + int error_cnt = 0; + Paths subject, clip, solution; + Clipper clpr; + + time_t time_start = clock(); + for (int i = 0; i < loop_cnt; i++) { + MakeRandomPoly(100, 400, 400, subject); + MakeRandomPoly(100, 400, 400, clip); + clpr.Clear(); + clpr.AddPaths(subject, ptSubject, true); + clpr.AddPaths(clip, ptClip, true); + if (!clpr.Execute(ctIntersection, solution, pftEvenOdd, pftEvenOdd)) + error_cnt++; + } + double time_elapsed = double(clock() - time_start)/CLOCKS_PER_SEC; + + cout << "\nFinished in " << time_elapsed << " secs with "; + cout << error_cnt << " errors.\n\n"; + //let's save the very last result ... + SaveToFile("Subject.txt", subject); + SaveToFile("Clip.txt", clip); + SaveToFile("Solution.txt", solution); + + //and see the final clipping op as an image too ... + SVGBuilder svg; + svg.style.penWidth = 0.8; + svg.style.pft = pftEvenOdd; + svg.style.brushClr = 0x1200009C; + svg.style.penClr = 0xCCD3D3DA; + svg.AddPaths(subject); + svg.style.brushClr = 0x129C0000; + svg.style.penClr = 0xCCFFA07A; + svg.AddPaths(clip); + svg.style.brushClr = 0x6080ff9C; + svg.style.penClr = 0xFF003300; + svg.style.pft = pftNonZero; + svg.AddPaths(solution); + svg.SaveToFile("solution.svg"); + return 0; + } + + if (argc < 3) + { + cout << "\nUsage:\n" + << " clipper_console_demo S_FILE C_FILE CT [S_FILL C_FILL] [PRECISION] [SVG_SCALE]\n" + << "or\n" + << " clipper_console_demo --benchmark [LOOP_COUNT]\n\n" + << "Legend: [optional parameters in square braces]; {comments in curly braces}\n\n" + << "Parameters:\n" + << " S_FILE & C_FILE are the subject and clip input files (see format below)\n" + << " CT: cliptype, either INTERSECTION or UNION or DIFFERENCE or XOR\n" + << " SUBJECT_FILL & CLIP_FILL: either EVENODD or NONZERO. Default: NONZERO\n" + << " PRECISION (in decimal places) for input data. Default = 0\n" + << " SVG_SCALE: scale of the output svg image. Default = 1.0\n" + << " LOOP_COUNT is the number of random clipping operations. Default = 1000\n\n" + << "\nFile format for input and output files:\n" + << " X, Y[,] {first vertex of first path}\n" + << " X, Y[,] {next vertex of first path}\n" + << " {etc.}\n" + << " X, Y[,] {last vertex of first path}\n" + << " {blank line(s) between paths}\n" + << " X, Y[,] {first vertex of second path}\n" + << " X, Y[,] {next vertex of second path}\n" + << " {etc.}\n\n" + << "Examples:\n" + << " clipper_console_demo \"subj.txt\" \"clip.txt\" INTERSECTION EVENODD EVENODD\n" + << " clipper_console_demo --benchmark 1000\n"; + return 1; + } + + int scale_log10 = 0; + char* dummy; + if (argc > 6) scale_log10 = strtol(argv[6], &dummy, 10); + double scale = std::pow(double(10), scale_log10); + + double svg_scale = 1.0; + if (argc > 7) svg_scale = strtod(argv[7], &dummy); + svg_scale /= scale; + + Paths subject, clip; + + if (!LoadFromFile(subject, argv[1], scale)) + { + cerr << "\nCan't open the file " << argv[1] + << " or the file format is invalid.\n"; + return 1; + } + if (!LoadFromFile(clip, argv[2], scale)) + { + cerr << "\nCan't open the file " << argv[2] + << " or the file format is invalid.\n"; + return 1; + } + + ClipType clipType = ctIntersection; + const string sClipType[] = {"INTERSECTION", "UNION", "DIFFERENCE", "XOR"}; + + if (argc > 3) + { + if (ASCII_icompare(argv[3], "XOR")) clipType = ctXor; + else if (ASCII_icompare(argv[3], "UNION")) clipType = ctUnion; + else if (ASCII_icompare(argv[3], "DIFFERENCE")) clipType = ctDifference; + else clipType = ctIntersection; + } + + PolyFillType subj_pft = pftNonZero, clip_pft = pftNonZero; + if (argc > 5) + { + if (ASCII_icompare(argv[4], "EVENODD")) subj_pft = pftEvenOdd; + if (ASCII_icompare(argv[5], "EVENODD")) clip_pft = pftEvenOdd; + } + + Clipper c; + c.AddPaths(subject, ptSubject, true); + c.AddPaths(clip, ptClip, true); + Paths solution; + + if (!c.Execute(clipType, solution, subj_pft, clip_pft)) + { + cout << (sClipType[clipType] + " failed!\n\n"); + return 1; + } + + cout << "\nFinished!\n\n"; + SaveToFile("solution.txt", solution, scale); + + //let's see the result too ... + SVGBuilder svg; + svg.style.penWidth = 0.8; + svg.style.brushClr = 0x1200009C; + svg.style.penClr = 0xCCD3D3DA; + svg.style.pft = subj_pft; + svg.AddPaths(subject); + svg.style.brushClr = 0x129C0000; + svg.style.penClr = 0xCCFFA07A; + svg.style.pft = clip_pft; + svg.AddPaths(clip); + svg.style.brushClr = 0x6080ff9C; + svg.style.penClr = 0xFF003300; + svg.style.pft = pftNonZero; + svg.AddPaths(solution); + svg.SaveToFile("solution.svg", svg_scale); + + //finally, show the svg image in the default viewing application + system("solution.svg"); + return 0; +} +//--------------------------------------------------------------------------- diff --git a/ThirdParty/custom-clipper/clipper/cpp_console/clipper_console_demo.exe b/ThirdParty/custom-clipper/clipper/cpp_console/clipper_console_demo.exe new file mode 100644 index 0000000000000000000000000000000000000000..a0d973acab3f5e6c3786b237c88955fd5cb2bc93 GIT binary patch literal 74240 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 + + + + Debug + Win32 + + + Release + Win32 + + + + {0710EFB8-6D8B-4DF1-9D14-907AE3857FE4} + Win32Proj + clipper_console_demo + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + + + false + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + + + Console + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + + + Console + true + true + true + + + + + + + + + NotUsing + + + + + + + + \ No newline at end of file diff --git a/ThirdParty/custom-clipper/clipper/cpp_opengl/clipper_demo.exe b/ThirdParty/custom-clipper/clipper/cpp_opengl/clipper_demo.exe new file mode 100644 index 0000000000000000000000000000000000000000..01fdc3d0c95324b8af3a432f5e1a4a4d0d522876 GIT binary patch literal 307200 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%0AE=2aHR7ZSfuWj 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 + + + + Debug + Win32 + + + Release + Win32 + + + + {4D48A928-F288-40F9-9FA0-4AC650602636} + Win32Proj + opengl_app + clipper_demo + + + + Application + true + Unicode + v120 + + + Application + false + true + Unicode + v120 + + + + + + + + + + + + + true + $(SourcePath) + $(IncludePath) + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + opengl32.lib;glu32.lib;comctl32.lib;%(AdditionalDependencies) + + + + + Level4 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + + + Windows + true + true + true + opengl32.lib;glu32.lib;comctl32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ThirdParty/custom-clipper/clipper/cpp_opengl/icon.res b/ThirdParty/custom-clipper/clipper/cpp_opengl/icon.res new file mode 100644 index 0000000000000000000000000000000000000000..a4fc1a701c1e02251b98d56d49031b54cf400cf3 GIT binary patch literal 5556 zcmcgw4Nz3q6@L5P+g$-+VG(ozaa}?A3*sNFT@<1yMkgwugE5W78qlJh5YQ-ziTDF% zsz@6r(@YpOnvBLo(HN&%A_`hb!z5LkWUAHFq#|*WIMFd_lU8&3ovZK7F1wpu+tD}k z?R|UiJ?A_3oOA!4BuSDTAi52_dOUALYV8X87(`oEWQeMDO2LaA$OjDK4KMfMaVc%h zK=gf}@}dCm0stPn{||Ua?5$W_~J-fQ-bA|)Eg0cJ3^~Tc*kxDv>)q~9Yr^=*T%-3_FRmX-En@N^UlvGeiD=vLakM2Dv_*>@KZm|r| z3yR$~ilg+`zfcyMRY26bcr%}X!II2GTIX(T^6)IS>UbiDMB$?tZ*(58f7%%f` z(EQ(Zho60=`2jwd7K{yXeQXuzN3N=+x?a}b+m5M?FM7258o!9u-wspfg7}-rqqD)p z;m8c7Ha#kejOI{UaO8v+2iq}w$8N8Bzx?pQxi@RII0T#%Jipt1ney+b@OX;oKTyO# z^KYP1^Z%=j+r9Gjk3YBm2jk!MQ!zk0uWR)2@5-ok-&RuP5E`62LCmc{-0tI7)leD` zHkL~As_5Ox$`L87AIsm zmmE_{+lP?sKh_5bhFsDo%9yjJZEsxW4?@doCQbu*Jx#@Sl_^Z188#h z1^9LU*H>*OMF|nM^V-^5U!ecICNk&PB~=tRVzgKw$tJ2APS3)rA3{84tm_$ z+%teLzF!*6oH&P?f73u0J~|+BDVX_}Dz6KTF=qag*Vf10KJ3NKV=O!Pu2((#M&m!x zy47p$2fO~*<%R9=59KXisdI4NPp;oUj{J$F+{s~I>z~H&zV_eE`ip$1aViJMr1Yh@ ztkJ|d9}zcD8cQy!nm6haTodPMh;yZ_zCAI$y>&SAh8z#(99s=Ou(<1KwW#SnXZmg#&)iSfrz zn#*;5_UYP{ON3wC~ME0Ot_EYb}BeJRiff^H*0*){mdIHVQi~ojXiv zLsLECpz*giKPAp;kY)a$&tJ^v?|~jZe_m&uyqEL&^Y=L!a0Adttgs&rjxN{C1rD9Qyk7r!T$#OC9v{I_YYiuFRg&KYv?> zyone|a`iUoyQkc~>_z_Y-GTR&RleHqbscyun7`d9pS{;y{`7;J&+cXZ+WplN-5{bb zfcJ>LH`B3pg_`ON)GkS@fV|IuYmzhwuxLP?1uz2!K)O?!xgGBU?U1R1tOSgQE`m;i zZss6rx`R`+2wyDh=tRWdF=V_+Qt$5=k*Ko+|L=DU_{Zi{_H{#5&=2z52sri^#wF*d zdpn)#z8+t~&>ibkTFyJwmf746nfQ((bxY?H1FwJhd>$1gXHZnUgC^P14x=sBmk#K@ z=2Z9p%PMDWX(+ILed)D&Vl=K^Lm9=TRQdiHnm2hk?!dMl-0Md6)&U!0#zbxUGG*#? zv45ow8&1zuRa4@qTv~SVinyzl&o34_p`#miczvfC*)Q}^VZ%nTw=DkPBg(F*q+gvr zEB^CcPm^c6AivSw2K+aktW3U^gL~urL+u{>6Yo(hpPH0Tn^vzEHefCF@FnDvPBlCv z+F}P~(9%zPJanwMe3c&Ce@NWT5=J^{ge``g>Yj@jw@4gKzNTUsjeLB8hphYg?a7ZX zP|+*fDK;$w@-1hyoM8LwA56V5Bp>(r?yFw%eCJDeU^Kb1$5L%|1-)1h!}c3AAK2wZ zqhjspx2n&5PK!={NR!sSK+~FD()DDP&J|Tt?#2e_<*kN_gZ|0M?cTti=$A*@mkRM`Qd2%q0m aIn1(TM;Bg&`0J}diWI+giPtb5)PDh&WBnok literal 0 HcmV?d00001 diff --git a/ThirdParty/custom-clipper/clipper/cpp_opengl/main.cpp b/ThirdParty/custom-clipper/clipper/cpp_opengl/main.cpp new file mode 100644 index 0000000000..6f3246bd98 --- /dev/null +++ b/ThirdParty/custom-clipper/clipper/cpp_opengl/main.cpp @@ -0,0 +1,621 @@ +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include "../clipper.hpp" + +using namespace std; +using namespace ClipperLib; + +enum poly_color_type { pctSubject, pctClip, pctSolution }; + +//global vars ... +HWND hWnd; +HWND hStatus; +HDC hDC; +HGLRC hRC; +ClipType ct = ctIntersection; +PolyFillType pft = pftEvenOdd; +JoinType jt = jtRound; +bool show_clipping = true; +Paths sub, clp, sol; +int VertCount = 5; +int scale = 10; +double delta = 0.0; + +const LPCWSTR helpText = +L"Clipper Demo tips...\n\n" +L"I - for Intersection operations.\n" +L"U - for Union operations.\n" +L"D - for Difference operations.\n" +L"X - for XOR operations.\n" +L"------------------------------\n" +L"Q - Toggle clipping on/off.\n" +L"------------------------------\n" +L"E - for EvenOdd fills.\n" +L"Z - for NonZero fills.\n" +L"P - for Positive fills.\n" +L"N - for Negative fills.\n" +L"------------------------------\n" +L"nn - number of vertices (3..50).\n" +L"------------------------------\n" +L"UP arrow - Expand Solution.\n" +L"DN arrow - Contract Solution.\n" +L"LT or RT arrow - Reset Solution.\n" +L"------------------------------\n" +L"M - Miter OffsetPolygons.\n" +L"S - Square OffsetPolygons.\n" +L"R - Round OffsetPolygons.\n" +L"------------------------------\n" +L"SPACE, ENTER or click to refresh.\n" +L"F1 - to see this help dialog again.\n" +L"Esc - to quit.\n"; + +typedef std::vector< GLdouble* > Vectors; +Vectors vectors; + +//------------------------------------------------------------------------------ +// heap memory management for GLUtesselator ... +//------------------------------------------------------------------------------ + +GLdouble* NewVector(GLdouble x, GLdouble y) +{ + GLdouble *vert = new GLdouble[3]; + vert[0] = x; + vert[1] = y; + vert[2] = 0; + vectors.push_back(vert); + return vert; +} +//------------------------------------------------------------------------------ + +void ClearVectors() +{ + for (Vectors::size_type i = 0; i < vectors.size(); ++i) + delete[] vectors[i]; + vectors.clear(); +} + +//------------------------------------------------------------------------------ +// GLUtesselator callback functions ... +//------------------------------------------------------------------------------ + +void CALLBACK BeginCallback(GLenum type) +{ + glBegin(type); +} +//------------------------------------------------------------------------------ + +void CALLBACK EndCallback() +{ + glEnd(); +} +//------------------------------------------------------------------------------ + +void CALLBACK VertexCallback(GLvoid *vertex) +{ + glVertex3dv( (const double *)vertex ); +} +//------------------------------------------------------------------------------ + +void CALLBACK CombineCallback(GLdouble coords[3], + GLdouble*[4], GLfloat[4], GLdouble **dataOut ) +{ + GLdouble *vert = NewVector(coords[0], coords[1]); + *dataOut = vert; +} +//------------------------------------------------------------------------------ + +wstring str2wstr(const std::string &s) { + int slength = (int)s.length() + 1; + int len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); + wchar_t* buf = new wchar_t[len]; + MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len); + std::wstring r(buf); + delete[] buf; + return r; +} +//------------------------------------------------------------------------------ + +void CALLBACK ErrorCallback(GLenum errorCode) +{ + std::wstring s = str2wstr( (char *)gluErrorString(errorCode) ); + SetWindowText(hWnd, s.c_str()); +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +// Set up pixel format for graphics initialization +void SetupPixelFormat() +{ + PIXELFORMATDESCRIPTOR pfd; + ZeroMemory( &pfd, sizeof(pfd)); + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + int pfIdx = ChoosePixelFormat(hDC, &pfd); + if (pfIdx != 0) SetPixelFormat(hDC, pfIdx, &pfd); +} +//------------------------------------------------------------------------------ + +// Initialize OpenGL graphics +void InitGraphics() +{ + hDC = GetDC(hWnd); + SetupPixelFormat(); + hRC = wglCreateContext(hDC); + wglMakeCurrent(hDC, hRC); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glTranslatef (0.375, 0.375, 0); +} +//------------------------------------------------------------------------------ + +void MakeRandomPoly(Path &p, int width, int height, int edgeCount) +{ + p.resize(edgeCount); + for (int i = 0; i < edgeCount; i++) + { + p[i].X = (rand()%(width -20) +10)*scale; + p[i].Y = (rand()%(height -20) +10)*scale; + } +} +//------------------------------------------------------------------------------ + +void ResizeGraphics(int width, int height) +{ + //setup 2D projection with origin at top-left corner ... + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, width, height, 0, 0, 1); + glViewport(0, 0, width, height); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} +//------------------------------------------------------------------------------ + +void DrawPolygon(Paths &pgs, poly_color_type pct) +{ + switch (pct) + { + case pctSubject: glColor4f(0.0f, 0.0f, 1.0f, 0.062f); break; + case pctClip: glColor4f(1.0f, 1.0f, 0.0f, 0.062f); break; + default: glColor4f(0.0f, 1.0f, 0.0f, 0.25f); + } + + GLUtesselator* tess = gluNewTess(); + gluTessCallback(tess, GLU_TESS_BEGIN, (void (CALLBACK*)())&BeginCallback); + gluTessCallback(tess, GLU_TESS_VERTEX, (void (CALLBACK*)())&VertexCallback); + gluTessCallback(tess, GLU_TESS_END, (void (CALLBACK*)())&EndCallback); + gluTessCallback(tess, GLU_TESS_COMBINE, (void (CALLBACK*)())&CombineCallback); + gluTessCallback(tess, GLU_TESS_ERROR, (void (CALLBACK*)())&ErrorCallback); + gluTessNormal(tess, 0.0, 0.0, 1.0); + + switch (pft) + { + case pftEvenOdd: + gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); + break; + case pftNonZero: + gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); + break; + case pftPositive: + gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE); + break; + default: //case pftNegative + if (pct == pctSolution) + gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); + else + gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NEGATIVE); + } + + gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); //GL_FALSE + gluTessBeginPolygon(tess, NULL); + for (Paths::size_type i = 0; i < pgs.size(); ++i) + { + gluTessBeginContour(tess); + for (Path::size_type j = 0; j < pgs[i].size(); ++j) + { + GLdouble *vert = + NewVector((GLdouble)pgs[i][j].X/scale, (GLdouble)pgs[i][j].Y/scale); + gluTessVertex(tess, vert, vert); + } + gluTessEndContour(tess); + } + gluTessEndPolygon(tess); + ClearVectors(); + + switch (pct) + { + case pctSubject: + glColor4f(0.0f, 0.6f, 1.0f, 0.5f); + break; + case pctClip: + glColor4f(1.0f, 0.6f, 0.0f, 0.5f); + break; + default: + glColor4f(0.0f, 0.4f, 0.0f, 1.0f); + } + if (pct == pctSolution) glLineWidth(1.0f); else glLineWidth(0.8f); + + gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); + gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_TRUE); + for (Paths::size_type i = 0; i < pgs.size(); ++i) + { + gluTessBeginPolygon(tess, NULL); + gluTessBeginContour(tess); + for (Path::size_type j = 0; j < pgs[i].size(); ++j) + { + GLdouble *vert = + NewVector((GLdouble)pgs[i][j].X/scale, (GLdouble)pgs[i][j].Y/scale); + gluTessVertex(tess, vert, vert); + } + + switch (pct) + { + case pctSubject: + glColor4f(0.0f, 0.0f, 0.8f, 0.5f); + break; + case pctClip: + glColor4f(0.6f, 0.0f, 0.0f, 0.5f); + } + gluTessEndContour(tess); + gluTessEndPolygon(tess); + } + + //final cleanup ... + gluDeleteTess(tess); + ClearVectors(); +} +//------------------------------------------------------------------------------ + +void DrawGraphics() +{ + //this can take a few moments ... + HCURSOR hWaitCursor = LoadCursor(NULL, IDC_WAIT); + SetCursor(hWaitCursor); + SetClassLong(hWnd, GCL_HCURSOR, (DWORD)hWaitCursor); + + //fill background with a light off-gray color ... + glClearColor(1,1,1,1); + glClear(GL_COLOR_BUFFER_BIT); + + //glRasterPos2f(110, 340); + //glColor4f(0.0f, 1.0f, 0.0f, 1.0f); + //char * text = "Positive Fills"; + //for (int i = 0; i < strlen(text); ++i) + // glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text[i]); + + DrawPolygon(sub, pctSubject); + DrawPolygon(clp, pctClip); + if (show_clipping) + DrawPolygon(sol, pctSolution); + wstringstream ss; + if (!show_clipping) + ss << L"Clipper Demo - NO CLIPPING"; + else + switch (ct) + { + case ctUnion: + ss << L"Clipper Demo - UNION"; + break; + case ctDifference: + ss << L"Clipper Demo - DIFFERENCE"; + break; + case ctXor: + ss << L"Clipper Demo - XOR"; + break; + default: + ss << L"Clipper Demo - INTERSECTION"; + } + + switch(pft) + { + case pftEvenOdd: + ss << L" (EvenOdd filled polygons with "; + break; + case pftNonZero: + ss << L" (NonZero filled polygons with "; + break; + case pftPositive: + ss << L" (Positive filled polygons with "; + break; + default: + ss << L" (Negative filled polygons with "; + } + ss << VertCount << " vertices each.)"; + SetWindowText(hWnd, ss.str().c_str()); + + HCURSOR hArrowCursor = LoadCursor(NULL, IDC_ARROW); + SetCursor(hArrowCursor); + SetClassLong(hWnd, GCL_HCURSOR, (DWORD)hArrowCursor); +} +//------------------------------------------------------------------------------ + +inline long64 Round(double val) +{ + if ((val < 0)) return (long64)(val - 0.5); else return (long64)(val + 0.5); +} +//------------------------------------------------------------------------------ + +//bool LoadFromFile(Polygons &ppg, char * filename, double scale= 1, +// int xOffset = 0, int yOffset = 0) +//{ +// ppg.clear(); +// ifstream infile(filename); +// if (!infile.is_open()) return false; +// int polyCnt, vertCnt; +// double X, Y; +// +// infile >> polyCnt; +// infile.ignore(80, '\n'); +// if (infile.good() && polyCnt > 0) +// { +// ppg.resize(polyCnt); +// for (int i = 0; i < polyCnt; i++) +// { +// infile >> vertCnt; +// infile.ignore(80, '\n'); +// if (!infile.good() || vertCnt < 0) break; +// ppg[i].resize(vertCnt); +// for (int j = 0; infile.good() && j < vertCnt; j++) +// { +// infile >> X; +// while (infile.peek() == ' ') infile.ignore(); +// if (infile.peek() == ',') infile.ignore(); +// while (infile.peek() == ' ') infile.ignore(); +// infile >> Y; +// ppg[i][j].X = Round((X + xOffset) * scale); +// ppg[i][j].Y = Round((Y + yOffset) * scale); +// infile.ignore(80, '\n'); +// } +// } +// } +// infile.close(); +// return true; +//} +//------------------------------------------------------------------------------ + +void SaveToFile(const char *filename, Paths &pp, double scale = 1) +{ + ofstream of(filename); + if (!of.is_open()) return; + of << pp.size() << "\n"; + for (Paths::size_type i = 0; i < pp.size(); ++i) + { + of << pp[i].size() << "\n"; + if (scale > 1.01 || scale < 0.99) + of << fixed << setprecision(6); + for (Path::size_type j = 0; j < pp[i].size(); ++j) + of << (double)pp[i][j].X /scale << ", " << (double)pp[i][j].Y /scale << ",\n"; + } + of.close(); +} +//--------------------------------------------------------------------------- + +void UpdatePolygons(bool updateSolutionOnly) +{ + if (VertCount < 0) VertCount = -VertCount; + if (VertCount > 50) VertCount = 50; + if (VertCount < 3) VertCount = 3; + + Clipper c; + if (!updateSolutionOnly) + { + delta = 0.0; + + RECT r; + GetWindowRect(hStatus, &r); + int statusHeight = r.bottom - r.top; + GetClientRect(hWnd, &r); + + sub.resize(1); + clp.resize(1); + + + MakeRandomPoly(sub[0], r.right, r.bottom - statusHeight, VertCount); + MakeRandomPoly(clp[0], r.right, r.bottom - statusHeight, VertCount); + + //SaveToFile("subj.txt", sub); + //SaveToFile("clip.txt", clp); + } + + c.AddPaths(sub, ptSubject, true); + c.AddPaths(clp, ptClip, true); + + c.Execute(ct, sol, pft, pft); + SaveToFile("solution.txt", sol); + + if (delta != 0.0) + { + ClipperOffset co; + co.AddPaths(sol, jt, etClosedPolygon); + co.Execute(sol, delta); + } + + InvalidateRect(hWnd, NULL, false); +} +//------------------------------------------------------------------------------ + +void DoNumericKeyPress(int num) +{ + if (VertCount >= 0) VertCount = -num; + else if (VertCount > -10) VertCount = VertCount*10 - num; + else Beep(1000, 100); +} +//------------------------------------------------------------------------------ + +LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + int clientwidth, clientheight; + switch (uMsg) + { + + case WM_SIZE: + clientwidth = LOWORD(lParam); + clientheight = HIWORD(lParam); + ResizeGraphics(clientwidth, clientheight); + SetWindowPos(hStatus, NULL, 0, + clientheight, clientwidth, 0, SWP_NOACTIVATE | SWP_NOZORDER); + return 0; + + case WM_PAINT: + HDC hdc; + PAINTSTRUCT ps; + hdc = BeginPaint(hWnd, &ps); + //do the drawing ... + DrawGraphics(); + SwapBuffers(hdc); + EndPaint(hWnd, &ps); + return 0; + + case WM_CLOSE: + DestroyWindow(hWnd); + return 0; + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + case WM_HELP: + MessageBox(hWnd, helpText, L"Clipper Demo - Help", 0); + return 0; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case 1: case 27: PostQuitMessage(0); break; //escape + case 98: MessageBox(hWnd, helpText, L"Clipper Demo - Help", 0); break; + case 99: MessageBox(hWnd, L"After closing this dialog,\ntype the required number of vertices (3-50) then ...", L"Clipper Demo", 0); + case 101: show_clipping = true; ct = ctIntersection; UpdatePolygons(true); break; + case 102: show_clipping = true; ct = ctUnion; UpdatePolygons(true); break; + case 103: show_clipping = true; ct = ctDifference; UpdatePolygons(true); break; + case 104: show_clipping = true; ct = ctXor; UpdatePolygons(true); break; + case 105: pft = pftEvenOdd; UpdatePolygons(true); break; + case 106: pft = pftNonZero; UpdatePolygons(true); break; + case 107: pft = pftPositive; UpdatePolygons(true); break; + case 108: pft = pftNegative; UpdatePolygons(true); break; + case 109: show_clipping = !show_clipping; UpdatePolygons(true); break; + case 110: case 111: case 112: case 113: case 114: + case 115: case 116: case 117: case 118: case 119: + DoNumericKeyPress(LOWORD(wParam) - 110); + break; + case 120: UpdatePolygons(false); break; //space, return + case 131: if (delta < 20*scale) {delta += scale; UpdatePolygons(true);} break; + case 132: if (delta > -20*scale) {delta -= scale; UpdatePolygons(true);} break; + case 133: if (delta != 0.0) {delta = 0.0; UpdatePolygons(true);} break; + case 141: {jt = jtMiter; if (delta != 0.0) UpdatePolygons(true);} break; + case 142: {jt = jtSquare; if (delta != 0.0) UpdatePolygons(true);} break; + case 143: {jt = jtRound; if (delta != 0.0) UpdatePolygons(true);} break; + default: return DefWindowProc (hWnd, uMsg, wParam, lParam); + } + return 0; + + case WM_LBUTTONUP: + UpdatePolygons(false); + return 0; + + // Default event handler + default: return DefWindowProc (hWnd, uMsg, wParam, lParam); + } +} +//------------------------------------------------------------------------------ + +int WINAPI WinMain (HINSTANCE hInstance, + HINSTANCE, LPSTR, int nCmdShow) +{ + + const LPCWSTR appname = TEXT("Clipper Demo"); + + WNDCLASS wndclass; + MSG msg; + + // Define the window class + wndclass.style = 0; + wndclass.lpfnWndProc = (WNDPROC)MainWndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIcon(hInstance, appname); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wndclass.lpszMenuName = appname; + wndclass.lpszClassName = appname; + + // Register the window class + if (!RegisterClass(&wndclass)) return FALSE; + + HMENU menu = LoadMenu(hInstance, MAKEINTRESOURCE(1)); + HACCEL accel = LoadAccelerators(hInstance, MAKEINTRESOURCE(1)); + + int windowSizeX = 540, windowSizeY = 400; + + int dx = GetSystemMetrics(SM_XVIRTUALSCREEN); + int dy = GetSystemMetrics(SM_YVIRTUALSCREEN); + dx += ((GetSystemMetrics(SM_CXSCREEN) -windowSizeX) /2); + dy += ((GetSystemMetrics(SM_CYSCREEN) -windowSizeY) /2); + + // Create the window + hWnd = CreateWindow( + appname, + appname, + WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + dx, dy, windowSizeX, windowSizeY, + NULL, + menu, + hInstance, + NULL); + + if (!hWnd) return FALSE; + + //replace the main window icon with Resource Icon #1 ... + HANDLE small_ico = LoadImage(hInstance, MAKEINTRESOURCE(1), IMAGE_ICON, 16, 16, 0); + HANDLE big_ico = LoadImage(hInstance, MAKEINTRESOURCE(1), IMAGE_ICON, 32, 32, 0); + SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)small_ico); + SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)big_ico); + + InitCommonControls(); + hStatus = CreateWindowEx(0, L"msctls_statusbar32", NULL, WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, hWnd, (HMENU)0, hInstance, NULL); + SetWindowText(hStatus, L" Copyright © Angus Johnson 2011"); + + // Initialize OpenGL + InitGraphics(); + + srand((unsigned)time(0)); + UpdatePolygons(false); + + // Display the window + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + // Event loop + for (;;) + { + if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == TRUE) + { + if (!GetMessage(&msg, NULL, 0, 0)) break; + + if (!TranslateAccelerator(hWnd, accel, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hRC); + ReleaseDC(hWnd, hDC); + return TRUE; +} +//------------------------------------------------------------------------------ diff --git a/ThirdParty/custom-clipper/clipper/cpp_opengl/menu.res b/ThirdParty/custom-clipper/clipper/cpp_opengl/menu.res new file mode 100644 index 0000000000000000000000000000000000000000..9f8ff5487bef61cbde803baa53c18ba61d52caaf GIT binary patch literal 1364 zcmai!%}*Lp6vYpTi`t}#`)+1aN*6ZT@2+KxCKdURgs@XY934SHE8S_-rP@EU{{{Ws zJ5P`nBQL|5ci%ntTAGvi}y$ctnWPZ-q^2>UjnD==k;*j8J`z9-D6p# zHeM~hEmARf?vFhi+Emrg8rj*4tcyf-ufeK{_0yv);=9X=LT@Qqy6QMP4v`PWypq?q z2*2rdScjP=k9p0&I~?=!D#IMOI*DhV#VZG1`iNH|Pe`*!=P>p?uz#DHT^7aS7$`p z;oVq0?k@7)``(R39AJ6xiyI1Yu82SMoL#?{8qAbProd!6$}qQy+sAeubh{?Md7NUk zifz(nv5R#3Kl_H6v5MMH@_wMJ^KcQEPYYINctU2>S_b{tOJR_#f@^ieZ^M1oxBTtIj_KV(8g$N1C9TH=U zQ=6Ks##JqcD*xac@r*|EGyf}cdd(9559`D>tkb<=k**CJOo?Gke8Z*=9LwajeTj+; zD@>2!5?vWC)1l!9uQ#WUI`RD{)H3^LYBl_V@`hjO#_$_cXZW2-F^rfm!&d?Gy7GNN X*N$&=