Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
ClipperLib::Clipper Class Reference

#include <src/clipper/clipper.hpp>

+ Inheritance diagram for ClipperLib::Clipper:
+ Collaboration diagram for ClipperLib::Clipper:

Public Member Functions

 Clipper (int initOptions=0)
 
 ~Clipper ()
 
void Clear ()
 
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 () const
 
void ReverseSolution (bool value)
 
bool StrictlySimple () const
 
void StrictlySimple (bool value)
 
bool AddPath (const Path &pg, PolyType PolyTyp, bool Closed)
 
template<typename PathsProvider >
bool AddPaths (PathsProvider &&paths_provider, PolyType PolyTyp, bool Closed)
 
IntRect GetBounds ()
 
bool PreserveCollinear () const
 
void PreserveCollinear (bool value)
 

Protected Types

using Edges = std::vector< TEdge, Allocator< TEdge > >
 

Protected Member Functions

void Reset ()
 
virtual bool ExecuteInternal ()
 
bool AddPathInternal (const Path &pg, int highI, PolyType PolyTyp, bool Closed, TEdge *edges)
 
TEdgeAddBoundsToLML (TEdge *e, bool IsClosed)
 
TEdgeProcessBound (TEdge *E, bool IsClockwise)
 
TEdgeDescendToMin (TEdge *&E)
 
void AscendToMax (TEdge *&E, bool Appending, bool IsClosed)
 

Protected Attributes

std::vector< LocalMinimum, Allocator< LocalMinimum > > m_MinimaList
 
std::vector< Edges, Allocator< Edges > > m_edges
 
bool m_PreserveCollinear
 
bool m_HasOpenPaths
 

Static Protected Attributes

static constexpr const bool m_UseFullRange = false
 

Private Types

using cInts = std::vector< cInt, Allocator< cInt > >
 

Private Member Functions

void SetWindingCount (TEdge &edge) const
 
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)
 
void CopyAELToSEL ()
 
void DeleteFromSEL (TEdge *e)
 
void DeleteFromAEL (TEdge *e)
 
void UpdateEdgeIntoAEL (TEdge *&e)
 
void SwapPositionsInSEL (TEdge *edge1, TEdge *edge2)
 
bool IsContributing (const TEdge &edge) const
 
bool IsTopHorz (const cInt XPos)
 
void SwapPositionsInAEL (TEdge *edge1, TEdge *edge2)
 
void DoMaxima (TEdge *e)
 
void ProcessHorizontals ()
 
void ProcessHorizontal (TEdge *horzEdge)
 
void AddLocalMaxPoly (TEdge *e1, TEdge *e2, const IntPoint &pt)
 
OutPtAddLocalMinPoly (TEdge *e1, TEdge *e2, const IntPoint &pt)
 
OutRecGetOutRec (int idx)
 
void AppendPolygon (TEdge *e1, TEdge *e2)
 
void IntersectEdges (TEdge *e1, TEdge *e2, IntPoint &pt)
 
OutRecCreateOutRec ()
 
OutPtAddOutPt (TEdge *e, const IntPoint &pt)
 
OutPtGetLastOutPt (TEdge *e)
 
OutPtAllocateOutPt ()
 
OutPtDupOutPt (OutPt *outPt, bool InsertAfter)
 
void DisposeOutPt (OutPt *pt)
 
void DisposeOutPts (OutPt *&pp)
 
void DisposeAllOutRecs ()
 
bool ProcessIntersections (const cInt topY)
 
void BuildIntersectList (const cInt topY)
 
void ProcessEdgesAtTopOfScanbeam (const cInt topY)
 
void BuildResult (Paths &polys)
 
void BuildResult2 (PolyTree &polytree)
 
void SetHoleState (TEdge *e, OutRec *outrec)
 
bool FixupIntersectionOrder ()
 
void FixupOutPolygon (OutRec &outrec)
 
void FixupOutPolyline (OutRec &outrec)
 
bool FindOwnerFromSplitRecs (OutRec &outRec, OutRec *&currOrfl)
 
void FixHoleLinkage (OutRec &outrec)
 
bool JoinPoints (Join *j, OutRec *outRec1, OutRec *outRec2)
 
bool JoinHorz (OutPt *op1, OutPt *op1b, OutPt *op2, OutPt *op2b, const IntPoint &Pt, bool DiscardLeft)
 
void JoinCommonEdges ()
 
void DoSimplePolygons ()
 
void FixupFirstLefts1 (OutRec *OldOutRec, OutRec *NewOutRec)
 
void FixupFirstLefts2 (OutRec *OldOutRec, OutRec *NewOutRec)
 

Private Attributes

std::deque< OutRec, Allocator< OutRec > > m_PolyOuts
 
std::deque< std::array< OutPt, m_OutPtsChunkSize >, Allocator< std::array< OutPt, m_OutPtsChunkSize > > > m_OutPts
 
OutPtm_OutPtsFree
 
size_t m_OutPtsChunkLast
 
std::vector< Join, Allocator< Join > > m_Joins
 
std::vector< Join, Allocator< Join > > m_GhostJoins
 
std::vector< IntersectNode, Allocator< IntersectNode > > m_IntersectList
 
ClipType m_ClipType
 
std::priority_queue< cInt, cIntsm_Scanbeam
 
cInts m_Maxima
 
TEdgem_ActiveEdges
 
TEdgem_SortedEdges
 
PolyFillType m_ClipFillType
 
PolyFillType m_SubjFillType
 
bool m_ReverseOutput
 
bool m_UsingPolyTree
 
bool m_StrictSimple
 

Static Private Attributes

static constexpr const size_t m_OutPtsChunkSize = 32
 

Detailed Description

Member Typedef Documentation

◆ cInts

using ClipperLib::Clipper::cInts = std::vector<cInt, Allocator<cInt> >
private

◆ Edges

using ClipperLib::ClipperBase::Edges = std::vector<TEdge, Allocator<TEdge> >
protectedinherited

Constructor & Destructor Documentation

◆ Clipper()

ClipperLib::Clipper::Clipper ( int  initOptions = 0)
1042 :
1043 ClipperBase(),
1044 m_OutPtsFree(nullptr),
1046 m_ActiveEdges(nullptr),
1047 m_SortedEdges(nullptr)
1048{
1049 m_ReverseOutput = ((initOptions & ioReverseSolution) != 0);
1050 m_StrictSimple = ((initOptions & ioStrictlySimple) != 0);
1051 m_PreserveCollinear = ((initOptions & ioPreserveCollinear) != 0);
1052 m_HasOpenPaths = false;
1053#ifdef CLIPPERLIB_USE_XYZ
1054 m_ZFill = 0;
1055#endif
1056}
bool m_HasOpenPaths
Definition clipper.hpp:415
bool m_PreserveCollinear
Definition clipper.hpp:413
ClipperBase()
Definition clipper.hpp:325
static constexpr const size_t m_OutPtsChunkSize
Definition clipper.hpp:457
size_t m_OutPtsChunkLast
Definition clipper.hpp:461
bool m_StrictSimple
Definition clipper.hpp:479
bool m_ReverseOutput
Definition clipper.hpp:476
OutPt * m_OutPtsFree
Definition clipper.hpp:460
TEdge * m_ActiveEdges
Definition clipper.hpp:472
TEdge * m_SortedEdges
Definition clipper.hpp:473
@ ioReverseSolution
Definition clipper.hpp:137
@ ioPreserveCollinear
Definition clipper.hpp:137
@ ioStrictlySimple
Definition clipper.hpp:137

References ClipperLib::ioPreserveCollinear, ClipperLib::ioReverseSolution, ClipperLib::ioStrictlySimple, ClipperLib::ClipperBase::m_HasOpenPaths, ClipperLib::ClipperBase::m_PreserveCollinear, m_ReverseOutput, and m_StrictSimple.

◆ ~Clipper()

ClipperLib::Clipper::~Clipper ( )
inline
423{ Clear(); }
void Clear()
Definition clipper.hpp:424

Member Function Documentation

◆ AddBoundsToLML()

TEdge * ClipperLib::ClipperBase::AddBoundsToLML ( TEdge e,
bool  IsClosed 
)
protectedinherited

◆ AddEdgeToSEL()

void ClipperLib::Clipper::AddEdgeToSEL ( TEdge edge)
private
1449{
1450 //SEL pointers in PEdge are reused to build a list of horizontal edges.
1451 //However, we don't need to worry about order with horizontal edge processing.
1452 if( !m_SortedEdges )
1453 {
1454 m_SortedEdges = edge;
1455 edge->PrevInSEL = 0;
1456 edge->NextInSEL = 0;
1457 }
1458 else
1459 {
1460 edge->NextInSEL = m_SortedEdges;
1461 edge->PrevInSEL = 0;
1462 m_SortedEdges->PrevInSEL = edge;
1463 m_SortedEdges = edge;
1464 }
1465}
TEdge * NextInSEL
Definition clipper.hpp:256
TEdge * PrevInSEL
Definition clipper.hpp:257

References m_SortedEdges, ClipperLib::TEdge::NextInSEL, and ClipperLib::TEdge::PrevInSEL.

Referenced by InsertLocalMinimaIntoAEL(), and ProcessEdgesAtTopOfScanbeam().

+ Here is the caller graph for this function:

◆ AddLocalMaxPoly()

void ClipperLib::Clipper::AddLocalMaxPoly ( TEdge e1,
TEdge e2,
const IntPoint pt 
)
private
1433{
1434 AddOutPt( e1, Pt );
1435 if (e2->WindDelta == 0) AddOutPt(e2, Pt);
1436 if( e1->OutIdx == e2->OutIdx )
1437 {
1438 e1->OutIdx = Unassigned;
1439 e2->OutIdx = Unassigned;
1440 }
1441 else if (e1->OutIdx < e2->OutIdx)
1442 AppendPolygon(e1, e2);
1443 else
1444 AppendPolygon(e2, e1);
1445}
void AppendPolygon(TEdge *e1, TEdge *e2)
Definition clipper.cpp:1869
OutPt * AddOutPt(TEdge *e, const IntPoint &pt)
Definition clipper.cpp:1983
static int const Unassigned
Definition clipper.cpp:69

References AddOutPt(), AppendPolygon(), ClipperLib::TEdge::OutIdx, ClipperLib::Unassigned, and ClipperLib::TEdge::WindDelta.

Referenced by DoMaxima(), IntersectEdges(), and ProcessHorizontal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ AddLocalMinPoly()

OutPt * ClipperLib::Clipper::AddLocalMinPoly ( TEdge e1,
TEdge e2,
const IntPoint pt 
)
private
1393{
1394 OutPt* result;
1395 TEdge *e, *prevE;
1396 if (IsHorizontal(*e2) || ( e1->Dx > e2->Dx ))
1397 {
1398 result = AddOutPt(e1, Pt);
1399 e2->OutIdx = e1->OutIdx;
1400 e1->Side = esLeft;
1401 e2->Side = esRight;
1402 e = e1;
1403 if (e->PrevInAEL == e2)
1404 prevE = e2->PrevInAEL;
1405 else
1406 prevE = e->PrevInAEL;
1407 } else
1408 {
1409 result = AddOutPt(e2, Pt);
1410 e1->OutIdx = e2->OutIdx;
1411 e1->Side = esRight;
1412 e2->Side = esLeft;
1413 e = e2;
1414 if (e->PrevInAEL == e1)
1415 prevE = e1->PrevInAEL;
1416 else
1417 prevE = e->PrevInAEL;
1418 }
1419
1420 if (prevE && prevE->OutIdx >= 0 &&
1421 (TopX(*prevE, Pt.y()) == TopX(*e, Pt.y())) &&
1422 SlopesEqual(*e, *prevE, m_UseFullRange) &&
1423 (e->WindDelta != 0) && (prevE->WindDelta != 0))
1424 {
1425 OutPt* outPt = AddOutPt(prevE, Pt);
1426 m_Joins.emplace_back(Join(result, outPt, e->Top));
1427 }
1428 return result;
1429}
static constexpr const bool m_UseFullRange
Definition clipper.hpp:402
std::vector< Join, Allocator< Join > > m_Joins
Definition clipper.hpp:463
@ esLeft
Definition clipper.hpp:226
@ esRight
Definition clipper.hpp:226
bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool)
Definition clipper.cpp:296
cInt TopX(TEdge &edge, const cInt currentY)
Definition clipper.cpp:333
bool IsHorizontal(TEdge &e)
Definition clipper.cpp:320

References AddOutPt(), ClipperLib::TEdge::Dx, ClipperLib::esLeft, ClipperLib::esRight, ClipperLib::IsHorizontal(), m_Joins, ClipperLib::ClipperBase::m_UseFullRange, ClipperLib::TEdge::OutIdx, ClipperLib::TEdge::PrevInAEL, ClipperLib::TEdge::Side, ClipperLib::SlopesEqual(), ClipperLib::TEdge::Top, ClipperLib::TopX(), and ClipperLib::TEdge::WindDelta.

Referenced by InsertLocalMinimaIntoAEL(), and IntersectEdges().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ AddOutPt()

OutPt * ClipperLib::Clipper::AddOutPt ( TEdge e,
const IntPoint pt 
)
private
1984{
1985 if( e->OutIdx < 0 )
1986 {
1987 OutRec *outRec = CreateOutRec();
1988 outRec->IsOpen = (e->WindDelta == 0);
1989 OutPt* newOp = this->AllocateOutPt();
1990 outRec->Pts = newOp;
1991 newOp->Idx = outRec->Idx;
1992 newOp->Pt = pt;
1993 newOp->Next = newOp;
1994 newOp->Prev = newOp;
1995 if (!outRec->IsOpen)
1996 SetHoleState(e, outRec);
1997 e->OutIdx = outRec->Idx;
1998 return newOp;
1999 } else
2000 {
2001 OutRec *outRec = &m_PolyOuts[e->OutIdx];
2002 //OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most'
2003 OutPt* op = outRec->Pts;
2004
2005 bool ToFront = (e->Side == esLeft);
2006 if (ToFront && (pt == op->Pt)) return op;
2007 else if (!ToFront && (pt == op->Prev->Pt)) return op->Prev;
2008
2009 OutPt* newOp = this->AllocateOutPt();
2010 newOp->Idx = outRec->Idx;
2011 newOp->Pt = pt;
2012 newOp->Next = op;
2013 newOp->Prev = op->Prev;
2014 newOp->Prev->Next = newOp;
2015 op->Prev = newOp;
2016 if (ToFront) outRec->Pts = newOp;
2017 return newOp;
2018 }
2019}
OutRec * CreateOutRec()
Definition clipper.cpp:1968
OutPt * AllocateOutPt()
Definition clipper.cpp:1168
void SetHoleState(TEdge *e, OutRec *outrec)
Definition clipper.cpp:1811
std::deque< OutRec, Allocator< OutRec > > m_PolyOuts
Definition clipper.hpp:455

References AllocateOutPt(), CreateOutRec(), ClipperLib::esLeft, ClipperLib::OutPt::Idx, ClipperLib::OutRec::Idx, ClipperLib::OutRec::IsOpen, m_PolyOuts, ClipperLib::OutPt::Next, ClipperLib::TEdge::OutIdx, ClipperLib::OutPt::Prev, ClipperLib::OutPt::Pt, ClipperLib::OutRec::Pts, SetHoleState(), ClipperLib::TEdge::Side, and ClipperLib::TEdge::WindDelta.

Referenced by AddLocalMaxPoly(), AddLocalMinPoly(), DoMaxima(), InsertLocalMinimaIntoAEL(), IntersectEdges(), ProcessEdgesAtTopOfScanbeam(), and ProcessHorizontal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ AddPath()

bool ClipperLib::ClipperBase::AddPath ( const Path pg,
PolyType  PolyTyp,
bool  Closed 
)
inherited
755{
756 // Remove duplicate end point from a closed input path.
757 // Remove duplicate points from the end of the input path.
758 int highI = (int)pg.size() -1;
759 if (Closed)
760 while (highI > 0 && (pg[highI] == pg[0]))
761 --highI;
762 while (highI > 0 && (pg[highI] == pg[highI -1]))
763 --highI;
764 if ((Closed && highI < 2) || (!Closed && highI < 1))
765 return false;
766
767 // Allocate a new edge array.
768 Edges edges(highI + 1);
769 // Fill in the edge array.
770 bool result = AddPathInternal(pg, highI, PolyTyp, Closed, edges.data());
771 if (result)
772 // Success, remember the edge array.
773 m_edges.emplace_back(std::move(edges));
774 return result;
775}
std::vector< TEdge, Allocator< TEdge > > Edges
Definition clipper.hpp:410
bool AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, bool Closed, TEdge *edges)
Definition clipper.cpp:777
std::vector< Edges, Allocator< Edges > > m_edges
Definition clipper.hpp:411
IGL_INLINE void edges(const Eigen::MatrixBase< DerivedF > &F, Eigen::PlainObjectBase< DerivedE > &E)
Definition edges.cpp:13

Referenced by ClipperLib::ClipperOffset::Execute(), ClipperLib::ClipperOffset::Execute(), Slic3r::fix_after_inner_offset(), Slic3r::fix_after_outer_offset(), and Slic3r::shrink_paths().

+ Here is the caller graph for this function:

◆ AddPathInternal()

bool ClipperLib::ClipperBase::AddPathInternal ( const Path pg,
int  highI,
PolyType  PolyTyp,
bool  Closed,
TEdge edges 
)
protectedinherited
778{
779#ifdef use_lines
780 if (!Closed && PolyTyp == ptClip)
781 throw clipperException("AddPath: Open paths must be subject.");
782#else
783 if (!Closed)
784 throw clipperException("AddPath: Open paths have been disabled.");
785#endif
786
787 assert(highI >= 0 && highI < pg.size());
788
789 //1. Basic (first) edge initialization ...
790 try
791 {
792 edges[1].Curr = pg[1];
793#ifdef CLIPPERLIB_INT32
794 RangeTest(pg[0]);
795 RangeTest(pg[highI]);
796#else
798 RangeTest(pg[highI], m_UseFullRange);
799#endif // CLIPPERLIB_INT32
800 InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]);
801 InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]);
802 for (int i = highI - 1; i >= 1; --i)
803 {
804#ifdef CLIPPERLIB_INT32
805 RangeTest(pg[i]);
806#else
808#endif // CLIPPERLIB_INT32
809 InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]);
810 }
811 }
812 catch(...)
813 {
814 throw; //range test fails
815 }
816 TEdge *eStart = &edges[0];
817
818 //2. Remove duplicate vertices, and (when closed) collinear edges ...
819 TEdge *E = eStart, *eLoopStop = eStart;
820 for (;;)
821 {
822 //nb: allows matching start and end points when not Closed ...
823 if (E->Curr == E->Next->Curr && (Closed || E->Next != eStart))
824 {
825 if (E == E->Next) break;
826 if (E == eStart) eStart = E->Next;
827 E = RemoveEdge(E);
828 eLoopStop = E;
829 continue;
830 }
831 if (E->Prev == E->Next)
832 break; //only two vertices
833 else if (Closed &&
834 SlopesEqual(E->Prev->Curr, E->Curr, E->Next->Curr, m_UseFullRange) &&
836 !Pt2IsBetweenPt1AndPt3(E->Prev->Curr, E->Curr, E->Next->Curr)))
837 {
838 //Collinear edges are allowed for open paths but in closed paths
839 //the default is to merge adjacent collinear edges into a single edge.
840 //However, if the PreserveCollinear property is enabled, only overlapping
841 //collinear edges (ie spikes) will be removed from closed paths.
842 if (E == eStart) eStart = E->Next;
843 E = RemoveEdge(E);
844 E = E->Prev;
845 eLoopStop = E;
846 continue;
847 }
848 E = E->Next;
849 if ((E == eLoopStop) || (!Closed && E->Next == eStart)) break;
850 }
851
852 if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next)))
853 {
854 return false;
855 }
856
857 if (!Closed)
858 {
859 m_HasOpenPaths = true;
860 eStart->Prev->OutIdx = Skip;
861 }
862
863 //3. Do second stage of edge initialization ...
864 // IsFlat means all vertices have the same Y coordinate.
865 bool IsFlat = true;
866 E = eStart;
867 do
868 {
869 InitEdge2(*E, PolyTyp);
870 E = E->Next;
871 if (IsFlat && E->Curr.y() != eStart->Curr.y()) IsFlat = false;
872 }
873 while (E != eStart);
874
875 //4. Finally, add edge bounds to LocalMinima list ...
876
877 //Totally flat paths must be handled differently when adding them
878 //to LocalMinima list to avoid endless loops etc ...
879 if (IsFlat)
880 {
881 if (Closed)
882 {
883 return false;
884 }
885 E->Prev->OutIdx = Skip;
886 LocalMinimum locMin;
887 locMin.Y = E->Bot.y();
888 locMin.LeftBound = 0;
889 locMin.RightBound = E;
890 locMin.RightBound->Side = esRight;
891 locMin.RightBound->WindDelta = 0;
892 for (;;)
893 {
894 if (E->Bot.x() != E->Prev->Top.x()) ReverseHorizontal(*E);
895 if (E->Next->OutIdx == Skip) break;
896 E->NextInLML = E->Next;
897 E = E->Next;
898 }
899 m_MinimaList.emplace_back(locMin);
900 return true;
901 }
902
903 bool leftBoundIsForward;
904 TEdge* EMin = 0;
905
906 //workaround to avoid an endless loop in the while loop below when
907 //open paths have matching start and end points ...
908 if (E->Prev->Bot == E->Prev->Top) E = E->Next;
909
910 // Find local minima and store them into a Local Minima List.
911 // Multiple Local Minima could be created for a single path.
912 for (;;)
913 {
914 E = FindNextLocMin(E);
915 if (E == EMin) break;
916 else if (!EMin) EMin = E;
917
918 //E and E.Prev now share a local minima (left aligned if horizontal).
919 //Compare their slopes to find which starts which bound ...
920 LocalMinimum locMin;
921 locMin.Y = E->Bot.y();
922 if (E->Dx < E->Prev->Dx)
923 {
924 locMin.LeftBound = E->Prev;
925 locMin.RightBound = E;
926 leftBoundIsForward = false; //Q.nextInLML = Q.prev
927 } else
928 {
929 locMin.LeftBound = E;
930 locMin.RightBound = E->Prev;
931 leftBoundIsForward = true; //Q.nextInLML = Q.next
932 }
933 locMin.LeftBound->Side = esLeft;
934 locMin.RightBound->Side = esRight;
935
936 if (!Closed) locMin.LeftBound->WindDelta = 0;
937 else if (locMin.LeftBound->Next == locMin.RightBound)
938 locMin.LeftBound->WindDelta = -1;
939 else locMin.LeftBound->WindDelta = 1;
940 locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta;
941
942 E = ProcessBound(locMin.LeftBound, leftBoundIsForward);
943 if (E->OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward);
944
945 TEdge* E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward);
946 if (E2->OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward);
947
948 if (locMin.LeftBound->OutIdx == Skip)
949 locMin.LeftBound = 0;
950 else if (locMin.RightBound->OutIdx == Skip)
951 locMin.RightBound = 0;
952 m_MinimaList.emplace_back(locMin);
953 if (!leftBoundIsForward) E = E2;
954 }
955 return true;
956}
TEdge * ProcessBound(TEdge *E, bool IsClockwise)
Definition clipper.cpp:637
std::vector< LocalMinimum, Allocator< LocalMinimum > > m_MinimaList
Definition clipper.hpp:399
void InitEdge(TEdge *e, TEdge *eNext, TEdge *ePrev, const IntPoint &Pt)
Definition clipper.cpp:425
bool Pt2IsBetweenPt1AndPt3(const IntPoint &pt1, const IntPoint &pt2, const IntPoint &pt3)
Definition clipper.cpp:567
void ReverseHorizontal(TEdge &e)
Definition clipper.cpp:469
static void RangeTest(const IntPoint &pt)
Definition clipper.cpp:591
@ ptClip
Definition clipper.hpp:76
TEdge * RemoveEdge(TEdge *e)
Definition clipper.cpp:458
TEdge * FindNextLocMin(TEdge *E)
Definition clipper.cpp:619
static int const Skip
Definition clipper.cpp:70
void InitEdge2(TEdge &e, PolyType Pt)
Definition clipper.cpp:435
@ E
Definition libslic3r.h:101

References ClipperLib::TEdge::Curr, ClipperLib::esLeft, ClipperLib::esRight, ClipperLib::FindNextLocMin(), ClipperLib::InitEdge(), ClipperLib::InitEdge2(), ClipperLib::LocalMinimum::LeftBound, ClipperLib::TEdge::Next, ClipperLib::TEdge::OutIdx, ClipperLib::TEdge::Prev, ClipperLib::Pt2IsBetweenPt1AndPt3(), ClipperLib::ptClip, ClipperLib::RangeTest(), ClipperLib::RemoveEdge(), ClipperLib::ReverseHorizontal(), ClipperLib::LocalMinimum::RightBound, ClipperLib::TEdge::Side, ClipperLib::Skip, ClipperLib::SlopesEqual(), ClipperLib::TEdge::WindDelta, and ClipperLib::LocalMinimum::Y.

+ Here is the call graph for this function:

◆ AddPaths()

template<typename PathsProvider >
bool ClipperLib::ClipperBase::AddPaths ( PathsProvider &&  paths_provider,
PolyType  PolyTyp,
bool  Closed 
)
inlineinherited
335 {
336 size_t num_paths = paths_provider.size();
337 if (num_paths == 0)
338 return false;
339 if (num_paths == 1)
340 return AddPath(*paths_provider.begin(), PolyTyp, Closed);
341
342 std::vector<int, Allocator<int>> num_edges(num_paths, 0);
343 int num_edges_total = 0;
344 size_t i = 0;
345 for (const Path &pg : paths_provider) {
346 // Remove duplicate end point from a closed input path.
347 // Remove duplicate points from the end of the input path.
348 int highI = (int)pg.size() -1;
349 if (Closed)
350 while (highI > 0 && (pg[highI] == pg[0]))
351 --highI;
352 while (highI > 0 && (pg[highI] == pg[highI -1]))
353 --highI;
354 if ((Closed && highI < 2) || (!Closed && highI < 1))
355 highI = -1;
356 num_edges[i ++] = highI + 1;
357 num_edges_total += highI + 1;
358 }
359 if (num_edges_total == 0)
360 return false;
361
362 // Allocate a new edge array.
363 std::vector<TEdge, Allocator<TEdge>> edges(num_edges_total);
364 // Fill in the edge array.
365 bool result = false;
366 TEdge *p_edge = edges.data();
367 i = 0;
368 for (const Path &pg : paths_provider) {
369 if (num_edges[i]) {
370 bool res = AddPathInternal(pg, num_edges[i] - 1, PolyTyp, Closed, p_edge);
371 if (res) {
372 p_edge += num_edges[i];
373 result = true;
374 }
375 }
376 ++ i;
377 }
378 if (result)
379 // At least some edges were generated. Remember the edge array.
380 m_edges.emplace_back(std::move(edges));
381 return result;
382 }
bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
Definition clipper.cpp:754
std::vector< IntPoint, Allocator< IntPoint > > Path
Definition clipper.hpp:121

Referenced by Slic3r::_clipper_pl_open(), Slic3r::clipper_do(), Slic3r::clipper_union(), ClipperLib::ClipperOffset::Execute(), ClipperLib::ClipperOffset::Execute(), Slic3r::expolygons_to_zpaths_shrunk(), Slic3r::shrink_paths(), Slic3r::top_level_islands(), Slic3r::variable_offset_inner(), Slic3r::variable_offset_inner_ex(), Slic3r::variable_offset_outer(), Slic3r::variable_offset_outer_ex(), and Slic3r::Algorithm::wavefront_clip().

+ Here is the caller graph for this function:

◆ AllocateOutPt()

OutPt * ClipperLib::Clipper::AllocateOutPt ( )
private
1169{
1170 OutPt *pt;
1171 if (m_OutPtsFree) {
1172 // Recycle some of the already released points.
1173 pt = m_OutPtsFree;
1174 m_OutPtsFree = pt->Next;
1175 } else if (m_OutPtsChunkLast < m_OutPtsChunkSize) {
1176 // Get a point from the last chunk.
1177 pt = &m_OutPts.back()[m_OutPtsChunkLast ++];
1178 } else {
1179 // The last chunk is full. Allocate a new one.
1180 m_OutPts.emplace_back();
1182 pt = &m_OutPts.back().front();
1183 }
1184 return pt;
1185}
std::deque< std::array< OutPt, m_OutPtsChunkSize >, Allocator< std::array< OutPt, m_OutPtsChunkSize > > > m_OutPts
Definition clipper.hpp:458
OutPt * Next
Definition clipper.hpp:282

References m_OutPts, m_OutPtsChunkLast, m_OutPtsChunkSize, m_OutPtsFree, and ClipperLib::OutPt::Next.

Referenced by AddOutPt(), and DupOutPt().

+ Here is the caller graph for this function:

◆ AppendPolygon()

void ClipperLib::Clipper::AppendPolygon ( TEdge e1,
TEdge e2 
)
private
1870{
1871 //get the start and ends of both output polygons ...
1872 OutRec *outRec1 = &m_PolyOuts[e1->OutIdx];
1873 OutRec *outRec2 = &m_PolyOuts[e2->OutIdx];
1874
1875 OutRec *holeStateRec;
1876 if (Param1RightOfParam2(outRec1, outRec2))
1877 holeStateRec = outRec2;
1878 else if (Param1RightOfParam2(outRec2, outRec1))
1879 holeStateRec = outRec1;
1880 else
1881 holeStateRec = GetLowermostRec(outRec1, outRec2);
1882
1883 //get the start and ends of both output polygons and
1884 //join e2 poly onto e1 poly and delete pointers to e2 ...
1885
1886 OutPt* p1_lft = outRec1->Pts;
1887 OutPt* p1_rt = p1_lft->Prev;
1888 OutPt* p2_lft = outRec2->Pts;
1889 OutPt* p2_rt = p2_lft->Prev;
1890
1891 EdgeSide Side;
1892 //join e2 poly onto e1 poly and delete pointers to e2 ...
1893 if( e1->Side == esLeft )
1894 {
1895 if( e2->Side == esLeft )
1896 {
1897 //z y x a b c
1898 ReversePolyPtLinks(p2_lft);
1899 p2_lft->Next = p1_lft;
1900 p1_lft->Prev = p2_lft;
1901 p1_rt->Next = p2_rt;
1902 p2_rt->Prev = p1_rt;
1903 outRec1->Pts = p2_rt;
1904 } else
1905 {
1906 //x y z a b c
1907 p2_rt->Next = p1_lft;
1908 p1_lft->Prev = p2_rt;
1909 p2_lft->Prev = p1_rt;
1910 p1_rt->Next = p2_lft;
1911 outRec1->Pts = p2_lft;
1912 }
1913 Side = esLeft;
1914 } else
1915 {
1916 if( e2->Side == esRight )
1917 {
1918 //a b c z y x
1919 ReversePolyPtLinks(p2_lft);
1920 p1_rt->Next = p2_rt;
1921 p2_rt->Prev = p1_rt;
1922 p2_lft->Next = p1_lft;
1923 p1_lft->Prev = p2_lft;
1924 } else
1925 {
1926 //a b c x y z
1927 p1_rt->Next = p2_lft;
1928 p2_lft->Prev = p1_rt;
1929 p1_lft->Prev = p2_rt;
1930 p2_rt->Next = p1_lft;
1931 }
1932 Side = esRight;
1933 }
1934
1935 outRec1->BottomPt = 0;
1936 if (holeStateRec == outRec2)
1937 {
1938 if (outRec2->FirstLeft != outRec1)
1939 outRec1->FirstLeft = outRec2->FirstLeft;
1940 outRec1->IsHole = outRec2->IsHole;
1941 }
1942 outRec2->Pts = 0;
1943 outRec2->BottomPt = 0;
1944 outRec2->FirstLeft = outRec1;
1945
1946 int OKIdx = e1->OutIdx;
1947 int ObsoleteIdx = e2->OutIdx;
1948
1949 e1->OutIdx = Unassigned; //nb: safe because we only get here via AddLocalMaxPoly
1950 e2->OutIdx = Unassigned;
1951
1952 TEdge* e = m_ActiveEdges;
1953 while( e )
1954 {
1955 if( e->OutIdx == ObsoleteIdx )
1956 {
1957 e->OutIdx = OKIdx;
1958 e->Side = Side;
1959 break;
1960 }
1961 e = e->NextInAEL;
1962 }
1963
1964 outRec2->Idx = outRec1->Idx;
1965}
EdgeSide
Definition clipper.hpp:226
OutRec * GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
Definition clipper.cpp:1829
void ReversePolyPtLinks(OutPt *pp)
Definition clipper.cpp:412
int OutIdx
Definition clipper.hpp:247
bool Param1RightOfParam2(OutRec *outRec1, OutRec *outRec2)
Definition clipper.cpp:1849

References ClipperLib::OutRec::BottomPt, ClipperLib::esLeft, ClipperLib::esRight, ClipperLib::OutRec::FirstLeft, ClipperLib::GetLowermostRec(), ClipperLib::OutRec::Idx, ClipperLib::OutRec::IsHole, m_ActiveEdges, m_PolyOuts, ClipperLib::OutPt::Next, ClipperLib::TEdge::NextInAEL, ClipperLib::TEdge::OutIdx, ClipperLib::Param1RightOfParam2(), ClipperLib::OutPt::Prev, ClipperLib::OutRec::Pts, ClipperLib::ReversePolyPtLinks(), ClipperLib::TEdge::Side, and ClipperLib::Unassigned.

Referenced by AddLocalMaxPoly().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ AscendToMax()

void ClipperLib::ClipperBase::AscendToMax ( TEdge *&  E,
bool  Appending,
bool  IsClosed 
)
protectedinherited

◆ BuildIntersectList()

void ClipperLib::Clipper::BuildIntersectList ( const cInt  topY)
private
2436{
2437 if ( !m_ActiveEdges ) return;
2438
2439 //prepare for sorting ...
2440 TEdge* e = m_ActiveEdges;
2441 m_SortedEdges = e;
2442 while( e )
2443 {
2444 e->PrevInSEL = e->PrevInAEL;
2445 e->NextInSEL = e->NextInAEL;
2446 e->Curr.x() = TopX( *e, topY );
2447 e = e->NextInAEL;
2448 }
2449
2450 //bubblesort ...
2451 bool isModified;
2452 do
2453 {
2454 isModified = false;
2455 e = m_SortedEdges;
2456 while( e->NextInSEL )
2457 {
2458 TEdge *eNext = e->NextInSEL;
2459 IntPoint Pt;
2460 if(e->Curr.x() > eNext->Curr.x())
2461 {
2462 IntersectPoint(*e, *eNext, Pt);
2463 m_IntersectList.emplace_back(IntersectNode(e, eNext, Pt));
2464 SwapPositionsInSEL(e, eNext);
2465 isModified = true;
2466 }
2467 else
2468 e = eNext;
2469 }
2470 if( e->PrevInSEL ) e->PrevInSEL->NextInSEL = 0;
2471 else break;
2472 }
2473 while ( isModified );
2474 m_SortedEdges = 0; //important
2475}
std::vector< IntersectNode, Allocator< IntersectNode > > m_IntersectList
Definition clipper.hpp:465
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2)
Definition clipper.cpp:2119
Eigen::Matrix< cInt, 2, 1, Eigen::DontAlign > IntPoint
Definition clipper.hpp:111
TEdge * PrevInAEL
Definition clipper.hpp:255
TEdge * NextInAEL
Definition clipper.hpp:254
void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
Definition clipper.cpp:341
IntPoint Curr
Definition clipper.hpp:234

References ClipperLib::TEdge::Curr, ClipperLib::IntersectPoint(), m_ActiveEdges, m_IntersectList, m_SortedEdges, ClipperLib::TEdge::NextInAEL, ClipperLib::TEdge::NextInSEL, ClipperLib::TEdge::PrevInAEL, ClipperLib::TEdge::PrevInSEL, SwapPositionsInSEL(), and ClipperLib::TopX().

Referenced by ProcessIntersections().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ BuildResult()

void ClipperLib::Clipper::BuildResult ( Paths polys)
private
2755{
2756 polys.reserve(m_PolyOuts.size());
2757 for (OutRec &outRec : m_PolyOuts)
2758 {
2759 assert(! outRec.IsOpen);
2760 if (!outRec.Pts) continue;
2761 Path pg;
2762 OutPt* p = outRec.Pts->Prev;
2763 int cnt = PointCount(p);
2764 if (cnt < 2) continue;
2765 pg.reserve(cnt);
2766 for (int i = 0; i < cnt; ++i)
2767 {
2768 pg.emplace_back(p->Pt);
2769 p = p->Prev;
2770 }
2771 polys.emplace_back(std::move(pg));
2772 }
2773}
int PointCount(OutPt *Pts)
Definition clipper.cpp:2739

References m_PolyOuts, ClipperLib::PointCount(), ClipperLib::OutPt::Prev, and ClipperLib::OutPt::Pt.

Referenced by Execute().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ BuildResult2()

void ClipperLib::Clipper::BuildResult2 ( PolyTree polytree)
private
2777{
2778 polytree.Clear();
2779 polytree.AllNodes.reserve(m_PolyOuts.size());
2780 //add each output polygon/contour to polytree ...
2781 for (OutRec &outRec : m_PolyOuts)
2782 {
2783 int cnt = PointCount(outRec.Pts);
2784 if ((outRec.IsOpen && cnt < 2) || (!outRec.IsOpen && cnt < 3))
2785 // Ignore an invalid output loop or a polyline.
2786 continue;
2787
2788 //skip OutRecs that (a) contain outermost polygons or
2789 //(b) already have the correct owner/child linkage ...
2790 if (outRec.FirstLeft &&
2791 (outRec.IsHole == outRec.FirstLeft->IsHole || ! outRec.FirstLeft->Pts)) {
2792 OutRec* orfl = outRec.FirstLeft;
2793 while (orfl && ((orfl->IsHole == outRec.IsHole) || !orfl->Pts))
2794 orfl = orfl->FirstLeft;
2795 outRec.FirstLeft = orfl;
2796 }
2797
2798 //nb: polytree takes ownership of all the PolyNodes
2799 polytree.AllNodes.emplace_back(PolyNode());
2800 PolyNode* pn = &polytree.AllNodes.back();
2801 outRec.PolyNd = pn;
2802 pn->Parent = 0;
2803 pn->Index = 0;
2804 pn->Contour.reserve(cnt);
2805 OutPt *op = outRec.Pts->Prev;
2806 for (int j = 0; j < cnt; j++)
2807 {
2808 pn->Contour.emplace_back(op->Pt);
2809 op = op->Prev;
2810 }
2811 }
2812
2813 //fixup PolyNode links etc ...
2814 polytree.Childs.reserve(m_PolyOuts.size());
2815 for (OutRec &outRec : m_PolyOuts)
2816 {
2817 if (!outRec.PolyNd) continue;
2818 if (outRec.IsOpen)
2819 {
2820 outRec.PolyNd->m_IsOpen = true;
2821 polytree.AddChild(*outRec.PolyNd);
2822 }
2823 else if (outRec.FirstLeft && outRec.FirstLeft->PolyNd)
2824 outRec.FirstLeft->PolyNd->AddChild(*outRec.PolyNd);
2825 else
2826 polytree.AddChild(*outRec.PolyNd);
2827 }
2828}

References ClipperLib::PolyNode::AddChild(), ClipperLib::PolyTree::AllNodes, ClipperLib::PolyNode::Childs, ClipperLib::PolyTree::Clear(), ClipperLib::PolyNode::Contour, ClipperLib::OutRec::FirstLeft, ClipperLib::PolyNode::Index, ClipperLib::OutRec::IsHole, m_PolyOuts, ClipperLib::PolyNode::Parent, ClipperLib::PointCount(), ClipperLib::OutPt::Prev, ClipperLib::OutPt::Pt, and ClipperLib::OutRec::Pts.

Referenced by Execute().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Clear()

void ClipperLib::Clipper::Clear ( )
inline
void Clear()
Definition clipper.cpp:959
void DisposeAllOutRecs()
Definition clipper.cpp:1187

Referenced by Slic3r::expolygons_to_zpaths_shrunk(), Slic3r::top_level_islands(), Slic3r::variable_offset_inner(), and Slic3r::variable_offset_outer().

+ Here is the caller graph for this function:

◆ CopyAELToSEL()

void ClipperLib::Clipper::CopyAELToSEL ( )
private
1469{
1470 TEdge* e = m_ActiveEdges;
1471 m_SortedEdges = e;
1472 while ( e )
1473 {
1474 e->PrevInSEL = e->PrevInAEL;
1475 e->NextInSEL = e->NextInAEL;
1476 e = e->NextInAEL;
1477 }
1478}

References m_ActiveEdges, m_SortedEdges, ClipperLib::TEdge::NextInAEL, ClipperLib::TEdge::NextInSEL, ClipperLib::TEdge::PrevInAEL, and ClipperLib::TEdge::PrevInSEL.

Referenced by FixupIntersectionOrder().

+ Here is the caller graph for this function:

◆ CreateOutRec()

OutRec * ClipperLib::Clipper::CreateOutRec ( )
private
1969{
1970 m_PolyOuts.emplace_back();
1971 OutRec &result = m_PolyOuts.back();
1972 result.IsHole = false;
1973 result.IsOpen = false;
1974 result.FirstLeft = 0;
1975 result.Pts = 0;
1976 result.BottomPt = 0;
1977 result.PolyNd = 0;
1978 result.Idx = (int)m_PolyOuts.size()-1;
1979 return &result;
1980}

References ClipperLib::OutRec::BottomPt, ClipperLib::OutRec::FirstLeft, ClipperLib::OutRec::Idx, ClipperLib::OutRec::IsHole, ClipperLib::OutRec::IsOpen, m_PolyOuts, ClipperLib::OutRec::PolyNd, and ClipperLib::OutRec::Pts.

Referenced by AddOutPt(), DoSimplePolygons(), and JoinCommonEdges().

+ Here is the caller graph for this function:

◆ DeleteFromAEL()

void ClipperLib::Clipper::DeleteFromAEL ( TEdge e)
private
1578{
1579 TEdge* AelPrev = e->PrevInAEL;
1580 TEdge* AelNext = e->NextInAEL;
1581 if( !AelPrev && !AelNext && (e != m_ActiveEdges) ) return; //already deleted
1582 if( AelPrev ) AelPrev->NextInAEL = AelNext;
1583 else m_ActiveEdges = AelNext;
1584 if( AelNext ) AelNext->PrevInAEL = AelPrev;
1585 e->NextInAEL = 0;
1586 e->PrevInAEL = 0;
1587}

References m_ActiveEdges, ClipperLib::TEdge::NextInAEL, and ClipperLib::TEdge::PrevInAEL.

Referenced by DoMaxima(), and ProcessHorizontal().

+ Here is the caller graph for this function:

◆ DeleteFromSEL()

void ClipperLib::Clipper::DeleteFromSEL ( TEdge e)
private
1591{
1592 TEdge* SelPrev = e->PrevInSEL;
1593 TEdge* SelNext = e->NextInSEL;
1594 if( !SelPrev && !SelNext && (e != m_SortedEdges) ) return; //already deleted
1595 if( SelPrev ) SelPrev->NextInSEL = SelNext;
1596 else m_SortedEdges = SelNext;
1597 if( SelNext ) SelNext->PrevInSEL = SelPrev;
1598 e->NextInSEL = 0;
1599 e->PrevInSEL = 0;
1600}

References m_SortedEdges, ClipperLib::TEdge::NextInSEL, and ClipperLib::TEdge::PrevInSEL.

Referenced by ProcessHorizontals().

+ Here is the caller graph for this function:

◆ DescendToMin()

TEdge * ClipperLib::ClipperBase::DescendToMin ( TEdge *&  E)
protectedinherited

◆ DisposeAllOutRecs()

void ClipperLib::Clipper::DisposeAllOutRecs ( )
private
1188{
1189 m_OutPts.clear();
1190 m_OutPtsFree = nullptr;
1192 m_PolyOuts.clear();
1193}

References m_OutPts, m_OutPtsChunkLast, m_OutPtsChunkSize, m_OutPtsFree, and m_PolyOuts.

Referenced by Execute(), and Execute().

+ Here is the caller graph for this function:

◆ DisposeOutPt()

void ClipperLib::Clipper::DisposeOutPt ( OutPt pt)
inlineprivate
513{ pt->Next = m_OutPtsFree; m_OutPtsFree = pt; }

References ClipperLib::OutPt::Next.

Referenced by FixupOutPolygon(), and FixupOutPolyline().

+ Here is the caller graph for this function:

◆ DisposeOutPts()

void ClipperLib::Clipper::DisposeOutPts ( OutPt *&  pp)
inlineprivate
514{ if (pp != nullptr) { pp->Prev->Next = m_OutPtsFree; m_OutPtsFree = pp; } }

References ClipperLib::OutPt::Next, and ClipperLib::OutPt::Prev.

Referenced by FixupOutPolygon(), and FixupOutPolyline().

+ Here is the caller graph for this function:

◆ DoMaxima()

void ClipperLib::Clipper::DoMaxima ( TEdge e)
private
2511{
2512 TEdge* eMaxPair = GetMaximaPair(e);
2513 if (!eMaxPair)
2514 {
2515 if (e->OutIdx >= 0)
2516 AddOutPt(e, e->Top);
2517 DeleteFromAEL(e);
2518 return;
2519 }
2520
2521 TEdge* eNext = e->NextInAEL;
2522 while(eNext && eNext != eMaxPair)
2523 {
2524 IntersectEdges(e, eNext, e->Top);
2525 SwapPositionsInAEL(e, eNext);
2526 eNext = e->NextInAEL;
2527 }
2528
2529 if(e->OutIdx == Unassigned && eMaxPair->OutIdx == Unassigned)
2530 {
2531 DeleteFromAEL(e);
2532 DeleteFromAEL(eMaxPair);
2533 }
2534 else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 )
2535 {
2536 if (e->OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e->Top);
2537 DeleteFromAEL(e);
2538 DeleteFromAEL(eMaxPair);
2539 }
2540#ifdef use_lines
2541 else if (e->WindDelta == 0)
2542 {
2543 if (e->OutIdx >= 0)
2544 {
2545 AddOutPt(e, e->Top);
2546 e->OutIdx = Unassigned;
2547 }
2548 DeleteFromAEL(e);
2549
2550 if (eMaxPair->OutIdx >= 0)
2551 {
2552 AddOutPt(eMaxPair, e->Top);
2553 eMaxPair->OutIdx = Unassigned;
2554 }
2555 DeleteFromAEL(eMaxPair);
2556 }
2557#endif
2558 else throw clipperException("DoMaxima error");
2559}
void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt)
Definition clipper.cpp:1616
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
Definition clipper.cpp:1432
void DeleteFromAEL(TEdge *e)
Definition clipper.cpp:1577
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2)
Definition clipper.cpp:2072
TEdge * GetMaximaPair(TEdge *e)
Definition clipper.cpp:2056

References AddLocalMaxPoly(), AddOutPt(), DeleteFromAEL(), ClipperLib::GetMaximaPair(), IntersectEdges(), ClipperLib::TEdge::NextInAEL, ClipperLib::TEdge::OutIdx, SwapPositionsInAEL(), ClipperLib::TEdge::Top, ClipperLib::Unassigned, and ClipperLib::TEdge::WindDelta.

Referenced by ProcessEdgesAtTopOfScanbeam().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ DoSimplePolygons()

void ClipperLib::Clipper::DoSimplePolygons ( )
private
3746{
3747 size_t i = 0;
3748 while (i < m_PolyOuts.size())
3749 {
3750 OutRec &outrec = m_PolyOuts[i++];
3751 OutPt* op = outrec.Pts;
3752 if (!op || outrec.IsOpen) continue;
3753 do //for each Pt in Polygon until duplicate found do ...
3754 {
3755 OutPt* op2 = op->Next;
3756 while (op2 != outrec.Pts)
3757 {
3758 if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op)
3759 {
3760 //split the polygon into two ...
3761 OutPt* op3 = op->Prev;
3762 OutPt* op4 = op2->Prev;
3763 op->Prev = op4;
3764 op4->Next = op;
3765 op2->Prev = op3;
3766 op3->Next = op2;
3767
3768 outrec.Pts = op;
3769 OutRec* outrec2 = CreateOutRec();
3770 outrec2->Pts = op2;
3771 UpdateOutPtIdxs(*outrec2);
3772 if (Poly2ContainsPoly1(outrec2->Pts, outrec.Pts))
3773 {
3774 //OutRec2 is contained by OutRec1 ...
3775 outrec2->IsHole = !outrec.IsHole;
3776 outrec2->FirstLeft = &outrec;
3777 // For each m_PolyOuts, replace FirstLeft from outRec2 to outrec.
3778 if (m_UsingPolyTree) FixupFirstLefts2(outrec2, &outrec);
3779 }
3780 else
3781 if (Poly2ContainsPoly1(outrec.Pts, outrec2->Pts))
3782 {
3783 //OutRec1 is contained by OutRec2 ...
3784 outrec2->IsHole = outrec.IsHole;
3785 outrec.IsHole = !outrec2->IsHole;
3786 outrec2->FirstLeft = outrec.FirstLeft;
3787 outrec.FirstLeft = outrec2;
3788 // For each m_PolyOuts, replace FirstLeft from outrec to outrec2.
3789 if (m_UsingPolyTree) FixupFirstLefts2(&outrec, outrec2);
3790 }
3791 else
3792 {
3793 //the 2 polygons are separate ...
3794 outrec2->IsHole = outrec.IsHole;
3795 outrec2->FirstLeft = outrec.FirstLeft;
3796 // For each polygon of m_PolyOuts, replace FirstLeft from outrec to outrec2 if the polygon is inside outRec2.
3797 //FIXME This is potentially very expensive! O(n^3)!
3798 if (m_UsingPolyTree) FixupFirstLefts1(&outrec, outrec2);
3799 }
3800 op2 = op; //ie get ready for the Next iteration
3801 }
3802 op2 = op2->Next;
3803 }
3804 op = op->Next;
3805 }
3806 while (op != outrec.Pts);
3807 }
3808}
void FixupFirstLefts2(OutRec *OldOutRec, OutRec *NewOutRec)
Definition clipper.cpp:3187
bool m_UsingPolyTree
Definition clipper.hpp:478
void FixupFirstLefts1(OutRec *OldOutRec, OutRec *NewOutRec)
Definition clipper.cpp:3172
void UpdateOutPtIdxs(OutRec &outrec)
Definition clipper.cpp:2861
bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
Definition clipper.cpp:280

References CreateOutRec(), ClipperLib::OutRec::FirstLeft, FixupFirstLefts1(), FixupFirstLefts2(), ClipperLib::OutRec::IsHole, ClipperLib::OutRec::IsOpen, m_PolyOuts, m_UsingPolyTree, ClipperLib::OutPt::Next, ClipperLib::Poly2ContainsPoly1(), ClipperLib::OutPt::Prev, ClipperLib::OutPt::Pt, ClipperLib::OutRec::Pts, and ClipperLib::UpdateOutPtIdxs().

Referenced by ExecuteInternal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ DupOutPt()

OutPt * ClipperLib::Clipper::DupOutPt ( OutPt outPt,
bool  InsertAfter 
)
private
2903{
2904 OutPt* result = this->AllocateOutPt();
2905 result->Pt = outPt->Pt;
2906 result->Idx = outPt->Idx;
2907 if (InsertAfter)
2908 {
2909 result->Next = outPt->Next;
2910 result->Prev = outPt;
2911 outPt->Next->Prev = result;
2912 outPt->Next = result;
2913 }
2914 else
2915 {
2916 result->Prev = outPt->Prev;
2917 result->Next = outPt;
2918 outPt->Prev->Next = result;
2919 outPt->Prev = result;
2920 }
2921 return result;
2922}

References AllocateOutPt(), ClipperLib::OutPt::Idx, ClipperLib::OutPt::Next, ClipperLib::OutPt::Prev, and ClipperLib::OutPt::Pt.

Referenced by JoinHorz(), and JoinPoints().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Execute() [1/4]

bool ClipperLib::Clipper::Execute ( ClipType  clipType,
Paths solution,
PolyFillType  fillType = pftEvenOdd 
)
inline
428 { return Execute(clipType, solution, fillType, fillType); }
bool Execute(ClipType clipType, Paths &solution, PolyFillType fillType=pftEvenOdd)
Definition clipper.hpp:425

Referenced by Slic3r::_clipper_pl_open(), Slic3r::clipper_do(), Slic3r::clipper_union(), ClipperLib::ClipperOffset::Execute(), ClipperLib::ClipperOffset::Execute(), Slic3r::expolygons_to_zpaths_shrunk(), Slic3r::fix_after_inner_offset(), Slic3r::fix_after_outer_offset(), Slic3r::shrink_paths(), Slic3r::top_level_islands(), Slic3r::variable_offset_inner(), Slic3r::variable_offset_inner_ex(), Slic3r::variable_offset_outer(), Slic3r::variable_offset_outer_ex(), and Slic3r::Algorithm::wavefront_clip().

+ Here is the caller graph for this function:

◆ Execute() [2/4]

bool ClipperLib::Clipper::Execute ( ClipType  clipType,
Paths solution,
PolyFillType  subjFillType,
PolyFillType  clipFillType 
)
1074{
1075 if (m_HasOpenPaths)
1076 throw clipperException("Error: PolyTree struct is needed for open path clipping.");
1077 solution.clear();
1078 m_SubjFillType = subjFillType;
1079 m_ClipFillType = clipFillType;
1080 m_ClipType = clipType;
1081 m_UsingPolyTree = false;
1082 bool succeeded = ExecuteInternal();
1083 if (succeeded) BuildResult(solution);
1085 return succeeded;
1086}
void BuildResult(Paths &polys)
Definition clipper.cpp:2754
virtual bool ExecuteInternal()
Definition clipper.cpp:1103
ClipType m_ClipType
Definition clipper.hpp:466
PolyFillType m_SubjFillType
Definition clipper.hpp:475
PolyFillType m_ClipFillType
Definition clipper.hpp:474

References BuildResult(), DisposeAllOutRecs(), ExecuteInternal(), m_ClipFillType, m_ClipType, ClipperLib::ClipperBase::m_HasOpenPaths, m_SubjFillType, and m_UsingPolyTree.

+ Here is the call graph for this function:

◆ Execute() [3/4]

bool ClipperLib::Clipper::Execute ( ClipType  clipType,
PolyTree polytree,
PolyFillType  fillType = pftEvenOdd 
)
inline
436 { return Execute(clipType, polytree, fillType, fillType); }

◆ Execute() [4/4]

bool ClipperLib::Clipper::Execute ( ClipType  clipType,
PolyTree polytree,
PolyFillType  subjFillType,
PolyFillType  clipFillType 
)
1091{
1092 m_SubjFillType = subjFillType;
1093 m_ClipFillType = clipFillType;
1094 m_ClipType = clipType;
1095 m_UsingPolyTree = true;
1096 bool succeeded = ExecuteInternal();
1097 if (succeeded) BuildResult2(polytree);
1099 return succeeded;
1100}
void BuildResult2(PolyTree &polytree)
Definition clipper.cpp:2776

References BuildResult2(), DisposeAllOutRecs(), ExecuteInternal(), m_ClipFillType, m_ClipType, m_SubjFillType, and m_UsingPolyTree.

+ Here is the call graph for this function:

◆ ExecuteInternal()

bool ClipperLib::Clipper::ExecuteInternal ( )
protectedvirtual
1104{
1105 bool succeeded = true;
1106 try {
1107 Reset();
1108 if (m_MinimaList.empty()) return true;
1109 cInt botY = m_Scanbeam.top();
1110 do { m_Scanbeam.pop(); } while (! m_Scanbeam.empty() && botY == m_Scanbeam.top());
1111 do {
1114 m_GhostJoins.clear();
1115 if (m_Scanbeam.empty()) break;
1116 cInt topY = m_Scanbeam.top();
1117 do { m_Scanbeam.pop(); } while (! m_Scanbeam.empty() && topY == m_Scanbeam.top());
1118 succeeded = ProcessIntersections(topY);
1119 if (!succeeded) break;
1121 botY = topY;
1122 } while (!m_Scanbeam.empty() || !m_MinimaList.empty());
1123 }
1124 catch(...)
1125 {
1126 succeeded = false;
1127 }
1128
1129 if (succeeded)
1130 {
1131
1132 //fix orientations ...
1133 //FIXME Vojtech: Does it not invalidate the loop hierarchy maintained as OutRec::FirstLeft pointers?
1134 //FIXME Vojtech: The area is calculated with floats, it may not be numerically stable!
1135 {
1136 for (OutRec &outRec : m_PolyOuts)
1137 if (outRec.Pts && !outRec.IsOpen && (outRec.IsHole ^ m_ReverseOutput) == (Area(outRec) > 0))
1138 ReversePolyPtLinks(outRec.Pts);
1139 }
1140
1142
1143 //unfortunately FixupOutPolygon() must be done after JoinCommonEdges()
1144 {
1145 for (OutRec &outRec : m_PolyOuts)
1146 if (outRec.Pts) {
1147 if (outRec.IsOpen)
1148 // Removes duplicate points.
1149 FixupOutPolyline(outRec);
1150 else
1151 // Removes duplicate points and simplifies consecutive parallel edges by removing the middle vertex.
1152 FixupOutPolygon(outRec);
1153 }
1154 }
1155 // For each polygon, search for exactly duplicate non-successive points.
1156 // If such a point is found, the loop is split into two pieces.
1157 // Search for the duplicate points is O(n^2)!
1158 // http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/Clipper/Properties/StrictlySimple.htm
1160 }
1161
1162 m_Joins.clear();
1163 m_GhostJoins.clear();
1164 return succeeded;
1165}
void Reset()
Definition clipper.cpp:1059
void InsertLocalMinimaIntoAEL(const cInt botY)
Definition clipper.cpp:1483
void DoSimplePolygons()
Definition clipper.cpp:3745
std::priority_queue< cInt, cInts > m_Scanbeam
Definition clipper.hpp:469
void ProcessHorizontals()
Definition clipper.cpp:2032
std::vector< Join, Allocator< Join > > m_GhostJoins
Definition clipper.hpp:464
void ProcessEdgesAtTopOfScanbeam(const cInt topY)
Definition clipper.cpp:2562
bool ProcessIntersections(const cInt topY)
Definition clipper.cpp:2408
void JoinCommonEdges()
Definition clipper.cpp:3195
void FixupOutPolyline(OutRec &outrec)
Definition clipper.cpp:2669
void FixupOutPolygon(OutRec &outrec)
Definition clipper.cpp:2696
if(!(yy_init))
Definition lexer.c:1190
double Area(const Path &poly)
Definition clipper.cpp:151
int32_t cInt
Definition clipper.hpp:91

References ClipperLib::Area(), DoSimplePolygons(), FixupOutPolygon(), FixupOutPolyline(), InsertLocalMinimaIntoAEL(), JoinCommonEdges(), m_GhostJoins, m_Joins, ClipperLib::ClipperBase::m_MinimaList, m_PolyOuts, m_ReverseOutput, m_Scanbeam, m_StrictSimple, ProcessEdgesAtTopOfScanbeam(), ProcessHorizontals(), ProcessIntersections(), Reset(), and ClipperLib::ReversePolyPtLinks().

Referenced by Execute(), and Execute().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ FindOwnerFromSplitRecs()

bool ClipperLib::Clipper::FindOwnerFromSplitRecs ( OutRec outRec,
OutRec *&  currOrfl 
)
private

◆ FixHoleLinkage()

void ClipperLib::Clipper::FixHoleLinkage ( OutRec outrec)
private

◆ FixupFirstLefts1()

void ClipperLib::Clipper::FixupFirstLefts1 ( OutRec OldOutRec,
OutRec NewOutRec 
)
private
3173{
3174 //tests if NewOutRec contains the polygon before reassigning FirstLeft
3175 for (OutRec &outRec : m_PolyOuts)
3176 {
3177 if (!outRec.Pts || !outRec.FirstLeft) continue;
3178 OutRec* firstLeft = outRec.FirstLeft;
3179 // Skip empty polygons.
3180 while (firstLeft && !firstLeft->Pts) firstLeft = firstLeft->FirstLeft;
3181 if (firstLeft == OldOutRec && Poly2ContainsPoly1(outRec.Pts, NewOutRec->Pts))
3182 outRec.FirstLeft = NewOutRec;
3183 }
3184}

References ClipperLib::OutRec::FirstLeft, m_PolyOuts, ClipperLib::Poly2ContainsPoly1(), and ClipperLib::OutRec::Pts.

Referenced by DoSimplePolygons(), and JoinCommonEdges().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ FixupFirstLefts2()

void ClipperLib::Clipper::FixupFirstLefts2 ( OutRec OldOutRec,
OutRec NewOutRec 
)
private
3188{
3189 //reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon
3190 for (OutRec &outRec : m_PolyOuts)
3191 if (outRec.FirstLeft == OldOutRec) outRec.FirstLeft = NewOutRec;
3192}

References m_PolyOuts.

Referenced by DoSimplePolygons(), and JoinCommonEdges().

+ Here is the caller graph for this function:

◆ FixupIntersectionOrder()

bool ClipperLib::Clipper::FixupIntersectionOrder ( )
private
2487{
2488 //pre-condition: intersections are sorted Bottom-most first.
2489 //Now it's crucial that intersections are made only between adjacent edges,
2490 //so to ensure this the order of intersections may need adjusting ...
2491 CopyAELToSEL();
2492 std::sort(m_IntersectList.begin(), m_IntersectList.end(), [](const IntersectNode &node1, const IntersectNode &node2) { return node2.Pt.y() < node1.Pt.y(); });
2493
2494 size_t cnt = m_IntersectList.size();
2495 for (size_t i = 0; i < cnt; ++i)
2496 {
2498 {
2499 size_t j = i + 1;
2500 while (j < cnt && !EdgesAdjacent(m_IntersectList[j])) j++;
2501 if (j == cnt) return false;
2502 std::swap(m_IntersectList[i], m_IntersectList[j]);
2503 }
2505 }
2506 return true;
2507}
void CopyAELToSEL()
Definition clipper.cpp:1468
bool EdgesAdjacent(const IntersectNode &inode)
Definition clipper.cpp:2479

References CopyAELToSEL(), ClipperLib::EdgesAdjacent(), m_IntersectList, and SwapPositionsInSEL().

Referenced by ProcessIntersections().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ FixupOutPolygon()

void ClipperLib::Clipper::FixupOutPolygon ( OutRec outrec)
private
2697{
2698 //FixupOutPolygon() - removes duplicate points and simplifies consecutive
2699 //parallel edges by removing the middle vertex.
2700 OutPt *lastOK = nullptr;
2701 outrec.BottomPt = nullptr;
2702 OutPt *pp = outrec.Pts;
2703 bool preserveCol = m_PreserveCollinear || m_StrictSimple;
2704
2705 for (;;)
2706 {
2707 if (pp->Prev == pp || pp->Prev == pp->Next)
2708 {
2709 // Empty loop or a stick. Release the polygon.
2710 this->DisposeOutPts(pp);
2711 outrec.Pts = nullptr;
2712 return;
2713 }
2714
2715 //test for duplicate points and collinear edges ...
2716 if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) ||
2717 (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) &&
2718 (!preserveCol || !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt))))
2719 {
2720 lastOK = nullptr;
2721 OutPt *tmp = pp;
2722 pp->Prev->Next = pp->Next;
2723 pp->Next->Prev = pp->Prev;
2724 pp = pp->Prev;
2725 this->DisposeOutPt(tmp);
2726 }
2727 else if (pp == lastOK) break;
2728 else
2729 {
2730 if (!lastOK) lastOK = pp;
2731 pp = pp->Next;
2732 }
2733 }
2734 outrec.Pts = pp;
2735}
void DisposeOutPt(OutPt *pt)
Definition clipper.hpp:513
void DisposeOutPts(OutPt *&pp)
Definition clipper.hpp:514

References ClipperLib::OutRec::BottomPt, DisposeOutPt(), DisposeOutPts(), ClipperLib::ClipperBase::m_PreserveCollinear, m_StrictSimple, ClipperLib::ClipperBase::m_UseFullRange, ClipperLib::OutPt::Next, ClipperLib::OutPt::Prev, ClipperLib::OutPt::Pt, ClipperLib::Pt2IsBetweenPt1AndPt3(), ClipperLib::OutRec::Pts, and ClipperLib::SlopesEqual().

Referenced by ExecuteInternal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ FixupOutPolyline()

void ClipperLib::Clipper::FixupOutPolyline ( OutRec outrec)
private
2670{
2671 OutPt *pp = outrec.Pts;
2672 OutPt *lastPP = pp->Prev;
2673 while (pp != lastPP)
2674 {
2675 pp = pp->Next;
2676 if (pp->Pt == pp->Prev->Pt)
2677 {
2678 if (pp == lastPP) lastPP = pp->Prev;
2679 OutPt *tmpPP = pp->Prev;
2680 tmpPP->Next = pp->Next;
2681 pp->Next->Prev = tmpPP;
2682 this->DisposeOutPt(pp);
2683 pp = tmpPP;
2684 }
2685 }
2686
2687 if (pp == pp->Prev)
2688 {
2689 this->DisposeOutPts(pp);
2690 outrec.Pts = 0;
2691 return;
2692 }
2693}

References DisposeOutPt(), DisposeOutPts(), ClipperLib::OutPt::Next, ClipperLib::OutPt::Prev, ClipperLib::OutPt::Pt, and ClipperLib::OutRec::Pts.

Referenced by ExecuteInternal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ GetBounds()

IntRect ClipperLib::ClipperBase::GetBounds ( )
inherited
1001{
1002 IntRect result;
1003 auto lm = m_MinimaList.begin();
1004 if (lm == m_MinimaList.end())
1005 {
1006 result.left = result.top = result.right = result.bottom = 0;
1007 return result;
1008 }
1009 result.left = lm->LeftBound->Bot.x();
1010 result.top = lm->LeftBound->Bot.y();
1011 result.right = lm->LeftBound->Bot.x();
1012 result.bottom = lm->LeftBound->Bot.y();
1013 while (lm != m_MinimaList.end())
1014 {
1015 result.bottom = std::max(result.bottom, lm->LeftBound->Bot.y());
1016 TEdge* e = lm->LeftBound;
1017 for (;;) {
1018 TEdge* bottomE = e;
1019 while (e->NextInLML)
1020 {
1021 if (e->Bot.x() < result.left) result.left = e->Bot.x();
1022 if (e->Bot.x() > result.right) result.right = e->Bot.x();
1023 e = e->NextInLML;
1024 }
1025 result.left = std::min(result.left, e->Bot.x());
1026 result.right = std::max(result.right, e->Bot.x());
1027 result.left = std::min(result.left, e->Top.x());
1028 result.right = std::max(result.right, e->Top.x());
1029 result.top = std::min(result.top, e->Top.y());
1030 if (bottomE == lm->LeftBound) e = lm->RightBound;
1031 else break;
1032 }
1033 ++lm;
1034 }
1035 return result;
1036}

References ClipperLib::TEdge::Bot, ClipperLib::IntRect::bottom, ClipperLib::IntRect::left, ClipperLib::TEdge::NextInLML, ClipperLib::IntRect::right, ClipperLib::IntRect::top, and ClipperLib::TEdge::Top.

Referenced by ClipperLib::ClipperOffset::Execute(), ClipperLib::ClipperOffset::Execute(), Slic3r::fix_after_inner_offset(), and Slic3r::shrink_paths().

+ Here is the caller graph for this function:

◆ GetLastOutPt()

OutPt * ClipperLib::Clipper::GetLastOutPt ( TEdge e)
private
2023{
2024 OutRec *outRec = &m_PolyOuts[e->OutIdx];
2025 if (e->Side == esLeft)
2026 return outRec->Pts;
2027 else
2028 return outRec->Pts->Prev;
2029}

References ClipperLib::esLeft, m_PolyOuts, ClipperLib::TEdge::OutIdx, ClipperLib::OutPt::Prev, ClipperLib::OutRec::Pts, and ClipperLib::TEdge::Side.

Referenced by ProcessHorizontal().

+ Here is the caller graph for this function:

◆ GetOutRec()

OutRec * ClipperLib::Clipper::GetOutRec ( int  idx)
private
1861{
1862 OutRec* outrec = &m_PolyOuts[Idx];
1863 while (outrec != &m_PolyOuts[outrec->Idx])
1864 outrec = &m_PolyOuts[outrec->Idx];
1865 return outrec;
1866}

References ClipperLib::OutRec::Idx, and m_PolyOuts.

Referenced by JoinCommonEdges().

+ Here is the caller graph for this function:

◆ InsertEdgeIntoAEL()

void ClipperLib::Clipper::InsertEdgeIntoAEL ( TEdge edge,
TEdge startEdge 
)
private
2874{
2875 if(!m_ActiveEdges)
2876 {
2877 edge->PrevInAEL = 0;
2878 edge->NextInAEL = 0;
2879 m_ActiveEdges = edge;
2880 }
2881 else if(!startEdge && E2InsertsBeforeE1(*m_ActiveEdges, *edge))
2882 {
2883 edge->PrevInAEL = 0;
2884 edge->NextInAEL = m_ActiveEdges;
2885 m_ActiveEdges->PrevInAEL = edge;
2886 m_ActiveEdges = edge;
2887 }
2888 else
2889 {
2890 if(!startEdge) startEdge = m_ActiveEdges;
2891 while(startEdge->NextInAEL &&
2892 !E2InsertsBeforeE1(*startEdge->NextInAEL , *edge))
2893 startEdge = startEdge->NextInAEL;
2894 edge->NextInAEL = startEdge->NextInAEL;
2895 if(startEdge->NextInAEL) startEdge->NextInAEL->PrevInAEL = edge;
2896 edge->PrevInAEL = startEdge;
2897 startEdge->NextInAEL = edge;
2898 }
2899}
bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
Definition clipper.cpp:2831

References ClipperLib::E2InsertsBeforeE1(), m_ActiveEdges, ClipperLib::TEdge::NextInAEL, and ClipperLib::TEdge::PrevInAEL.

Referenced by InsertLocalMinimaIntoAEL().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ InsertLocalMinimaIntoAEL()

void ClipperLib::Clipper::InsertLocalMinimaIntoAEL ( const cInt  botY)
private
1484{
1485 while (!m_MinimaList.empty() && m_MinimaList.back().Y == botY)
1486 {
1487 TEdge* lb = m_MinimaList.back().LeftBound;
1488 TEdge* rb = m_MinimaList.back().RightBound;
1489 m_MinimaList.pop_back();
1490
1491 OutPt *Op1 = 0;
1492 if (!lb)
1493 {
1494 //nb: don't insert LB into either AEL or SEL
1495 InsertEdgeIntoAEL(rb, 0);
1496 SetWindingCount(*rb);
1497 if (IsContributing(*rb))
1498 Op1 = AddOutPt(rb, rb->Bot);
1499 }
1500 else if (!rb)
1501 {
1502 InsertEdgeIntoAEL(lb, 0);
1503 SetWindingCount(*lb);
1504 if (IsContributing(*lb))
1505 Op1 = AddOutPt(lb, lb->Bot);
1506 m_Scanbeam.push(lb->Top.y());
1507 }
1508 else
1509 {
1510 InsertEdgeIntoAEL(lb, 0);
1511 InsertEdgeIntoAEL(rb, lb);
1512 SetWindingCount( *lb );
1513 rb->WindCnt = lb->WindCnt;
1514 rb->WindCnt2 = lb->WindCnt2;
1515 if (IsContributing(*lb))
1516 Op1 = AddLocalMinPoly(lb, rb, lb->Bot);
1517 m_Scanbeam.push(lb->Top.y());
1518 }
1519
1520 if (rb)
1521 {
1522 if(IsHorizontal(*rb)) AddEdgeToSEL(rb);
1523 else m_Scanbeam.push(rb->Top.y());
1524 }
1525
1526 if (!lb || !rb) continue;
1527
1528 //if any output polygons share an edge, they'll need joining later ...
1529 if (Op1 && IsHorizontal(*rb) &&
1530 m_GhostJoins.size() > 0 && (rb->WindDelta != 0))
1531 {
1532 for (Join &jr : m_GhostJoins)
1533 //if the horizontal Rb and a 'ghost' horizontal overlap, then convert
1534 //the 'ghost' join to a real join ready for later ...
1535 if (HorzSegmentsOverlap(jr.OutPt1->Pt.x(), jr.OffPt.x(), rb->Bot.x(), rb->Top.x()))
1536 m_Joins.emplace_back(Join(jr.OutPt1, Op1, jr.OffPt));
1537 }
1538
1539 if (lb->OutIdx >= 0 && lb->PrevInAEL &&
1540 lb->PrevInAEL->Curr.x() == lb->Bot.x() &&
1541 lb->PrevInAEL->OutIdx >= 0 &&
1542 SlopesEqual(*lb->PrevInAEL, *lb, m_UseFullRange) &&
1543 (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0))
1544 {
1545 OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot);
1546 m_Joins.emplace_back(Join(Op1, Op2, lb->Top));
1547 }
1548
1549 if(lb->NextInAEL != rb)
1550 {
1551
1552 if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 &&
1553 SlopesEqual(*rb->PrevInAEL, *rb, m_UseFullRange) &&
1554 (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0))
1555 {
1556 OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot);
1557 m_Joins.emplace_back(Join(Op1, Op2, rb->Top));
1558 }
1559
1560 TEdge* e = lb->NextInAEL;
1561 if (e)
1562 {
1563 while( e != rb )
1564 {
1565 //nb: For calculating winding counts etc, IntersectEdges() assumes
1566 //that param1 will be to the Right of param2 ABOVE the intersection ...
1567 IntersectEdges(rb , e , lb->Curr); //order important here
1568 e = e->NextInAEL;
1569 }
1570 }
1571 }
1572
1573 }
1574}
void InsertEdgeIntoAEL(TEdge *edge, TEdge *startEdge)
Definition clipper.cpp:2873
bool IsContributing(const TEdge &edge) const
Definition clipper.cpp:1291
OutPt * AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
Definition clipper.cpp:1392
void SetWindingCount(TEdge &edge) const
Definition clipper.cpp:1196
void AddEdgeToSEL(TEdge *edge)
Definition clipper.cpp:1448
bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
Definition clipper.cpp:579
TCoord< P > x(const P &p)
Definition geometry_traits.hpp:297

References AddEdgeToSEL(), AddLocalMinPoly(), AddOutPt(), ClipperLib::TEdge::Bot, ClipperLib::TEdge::Curr, ClipperLib::HorzSegmentsOverlap(), InsertEdgeIntoAEL(), IntersectEdges(), IsContributing(), ClipperLib::IsHorizontal(), m_GhostJoins, m_Joins, ClipperLib::ClipperBase::m_MinimaList, m_Scanbeam, ClipperLib::ClipperBase::m_UseFullRange, ClipperLib::TEdge::NextInAEL, ClipperLib::TEdge::OutIdx, ClipperLib::TEdge::PrevInAEL, SetWindingCount(), ClipperLib::SlopesEqual(), ClipperLib::TEdge::Top, ClipperLib::TEdge::WindCnt, ClipperLib::TEdge::WindCnt2, and ClipperLib::TEdge::WindDelta.

Referenced by ExecuteInternal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ IntersectEdges()

void ClipperLib::Clipper::IntersectEdges ( TEdge e1,
TEdge e2,
IntPoint pt 
)
private
1617{
1618 bool e1Contributing = ( e1->OutIdx >= 0 );
1619 bool e2Contributing = ( e2->OutIdx >= 0 );
1620
1621#ifdef CLIPPERLIB_USE_XYZ
1622 SetZ(Pt, *e1, *e2);
1623#endif
1624
1625#ifdef use_lines
1626 //if either edge is on an OPEN path ...
1627 if (e1->WindDelta == 0 || e2->WindDelta == 0)
1628 {
1629 //ignore subject-subject open path intersections UNLESS they
1630 //are both open paths, AND they are both 'contributing maximas' ...
1631 if (e1->WindDelta == 0 && e2->WindDelta == 0) return;
1632
1633 //if intersecting a subj line with a subj poly ...
1634 else if (e1->PolyTyp == e2->PolyTyp &&
1635 e1->WindDelta != e2->WindDelta && m_ClipType == ctUnion)
1636 {
1637 if (e1->WindDelta == 0)
1638 {
1639 if (e2Contributing)
1640 {
1641 AddOutPt(e1, Pt);
1642 if (e1Contributing) e1->OutIdx = Unassigned;
1643 }
1644 }
1645 else
1646 {
1647 if (e1Contributing)
1648 {
1649 AddOutPt(e2, Pt);
1650 if (e2Contributing) e2->OutIdx = Unassigned;
1651 }
1652 }
1653 }
1654 else if (e1->PolyTyp != e2->PolyTyp)
1655 {
1656 //toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ...
1657 if ((e1->WindDelta == 0) && std::abs(e2->WindCnt) == 1 &&
1658 (m_ClipType != ctUnion || e2->WindCnt2 == 0))
1659 {
1660 AddOutPt(e1, Pt);
1661 if (e1Contributing) e1->OutIdx = Unassigned;
1662 }
1663 else if ((e2->WindDelta == 0) && (std::abs(e1->WindCnt) == 1) &&
1664 (m_ClipType != ctUnion || e1->WindCnt2 == 0))
1665 {
1666 AddOutPt(e2, Pt);
1667 if (e2Contributing) e2->OutIdx = Unassigned;
1668 }
1669 }
1670 return;
1671 }
1672#endif
1673
1674 //update winding counts...
1675 //assumes that e1 will be to the Right of e2 ABOVE the intersection
1676 if ( e1->PolyTyp == e2->PolyTyp )
1677 {
1678 if ( IsEvenOddFillType( *e1) )
1679 {
1680 int oldE1WindCnt = e1->WindCnt;
1681 e1->WindCnt = e2->WindCnt;
1682 e2->WindCnt = oldE1WindCnt;
1683 } else
1684 {
1685 if (e1->WindCnt + e2->WindDelta == 0 ) e1->WindCnt = -e1->WindCnt;
1686 else e1->WindCnt += e2->WindDelta;
1687 if ( e2->WindCnt - e1->WindDelta == 0 ) e2->WindCnt = -e2->WindCnt;
1688 else e2->WindCnt -= e1->WindDelta;
1689 }
1690 } else
1691 {
1692 if (!IsEvenOddFillType(*e2)) e1->WindCnt2 += e2->WindDelta;
1693 else e1->WindCnt2 = ( e1->WindCnt2 == 0 ) ? 1 : 0;
1694 if (!IsEvenOddFillType(*e1)) e2->WindCnt2 -= e1->WindDelta;
1695 else e2->WindCnt2 = ( e2->WindCnt2 == 0 ) ? 1 : 0;
1696 }
1697
1698 PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
1699 if (e1->PolyTyp == ptSubject)
1700 {
1701 e1FillType = m_SubjFillType;
1702 e1FillType2 = m_ClipFillType;
1703 } else
1704 {
1705 e1FillType = m_ClipFillType;
1706 e1FillType2 = m_SubjFillType;
1707 }
1708 if (e2->PolyTyp == ptSubject)
1709 {
1710 e2FillType = m_SubjFillType;
1711 e2FillType2 = m_ClipFillType;
1712 } else
1713 {
1714 e2FillType = m_ClipFillType;
1715 e2FillType2 = m_SubjFillType;
1716 }
1717
1718 cInt e1Wc, e2Wc;
1719 switch (e1FillType)
1720 {
1721 case pftPositive: e1Wc = e1->WindCnt; break;
1722 case pftNegative: e1Wc = -e1->WindCnt; break;
1723 default: e1Wc = std::abs(e1->WindCnt);
1724 }
1725 switch(e2FillType)
1726 {
1727 case pftPositive: e2Wc = e2->WindCnt; break;
1728 case pftNegative: e2Wc = -e2->WindCnt; break;
1729 default: e2Wc = std::abs(e2->WindCnt);
1730 }
1731
1732 if ( e1Contributing && e2Contributing )
1733 {
1734 if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
1735 (e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) )
1736 {
1737 AddLocalMaxPoly(e1, e2, Pt);
1738 }
1739 else
1740 {
1741 AddOutPt(e1, Pt);
1742 AddOutPt(e2, Pt);
1743 std::swap(e1->Side, e2->Side);
1744 std::swap(e1->OutIdx, e2->OutIdx);
1745 }
1746 }
1747 else if ( e1Contributing )
1748 {
1749 if (e2Wc == 0 || e2Wc == 1)
1750 {
1751 AddOutPt(e1, Pt);
1752 std::swap(e1->Side, e2->Side);
1753 std::swap(e1->OutIdx, e2->OutIdx);
1754 }
1755 }
1756 else if ( e2Contributing )
1757 {
1758 if (e1Wc == 0 || e1Wc == 1)
1759 {
1760 AddOutPt(e2, Pt);
1761 std::swap(e1->Side, e2->Side);
1762 std::swap(e1->OutIdx, e2->OutIdx);
1763 }
1764 }
1765 else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1))
1766 {
1767 //neither edge is currently contributing ...
1768
1769 cInt e1Wc2, e2Wc2;
1770 switch (e1FillType2)
1771 {
1772 case pftPositive: e1Wc2 = e1->WindCnt2; break;
1773 case pftNegative : e1Wc2 = -e1->WindCnt2; break;
1774 default: e1Wc2 = std::abs(e1->WindCnt2);
1775 }
1776 switch (e2FillType2)
1777 {
1778 case pftPositive: e2Wc2 = e2->WindCnt2; break;
1779 case pftNegative: e2Wc2 = -e2->WindCnt2; break;
1780 default: e2Wc2 = std::abs(e2->WindCnt2);
1781 }
1782
1783 if (e1->PolyTyp != e2->PolyTyp)
1784 {
1785 AddLocalMinPoly(e1, e2, Pt);
1786 }
1787 else if (e1Wc == 1 && e2Wc == 1)
1788 switch( m_ClipType ) {
1789 case ctIntersection:
1790 if (e1Wc2 > 0 && e2Wc2 > 0)
1791 AddLocalMinPoly(e1, e2, Pt);
1792 break;
1793 case ctUnion:
1794 if ( e1Wc2 <= 0 && e2Wc2 <= 0 )
1795 AddLocalMinPoly(e1, e2, Pt);
1796 break;
1797 case ctDifference:
1798 if (((e1->PolyTyp == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
1799 ((e1->PolyTyp == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
1800 AddLocalMinPoly(e1, e2, Pt);
1801 break;
1802 case ctXor:
1803 AddLocalMinPoly(e1, e2, Pt);
1804 }
1805 else
1806 std::swap(e1->Side, e2->Side);
1807 }
1808}
bool IsEvenOddFillType(const TEdge &edge) const
Definition clipper.hpp:484
@ ctXor
Definition clipper.hpp:75
@ ctIntersection
Definition clipper.hpp:75
@ ctUnion
Definition clipper.hpp:75
@ ctDifference
Definition clipper.hpp:75
@ ptSubject
Definition clipper.hpp:76
PolyFillType
Definition clipper.hpp:81
@ pftNegative
Definition clipper.hpp:81
@ pftPositive
Definition clipper.hpp:81

References AddLocalMaxPoly(), AddLocalMinPoly(), AddOutPt(), ClipperLib::ctDifference, ClipperLib::ctIntersection, ClipperLib::ctUnion, ClipperLib::ctXor, IsEvenOddFillType(), m_ClipFillType, m_ClipType, m_SubjFillType, ClipperLib::TEdge::OutIdx, ClipperLib::pftNegative, ClipperLib::pftPositive, ClipperLib::TEdge::PolyTyp, ClipperLib::ptClip, ClipperLib::ptSubject, ClipperLib::TEdge::Side, ClipperLib::Unassigned, ClipperLib::TEdge::WindCnt, ClipperLib::TEdge::WindCnt2, and ClipperLib::TEdge::WindDelta.

Referenced by DoMaxima(), InsertLocalMinimaIntoAEL(), ProcessHorizontal(), and ProcessIntersections().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ IsContributing()

bool ClipperLib::Clipper::IsContributing ( const TEdge edge) const
private
1292{
1293 PolyFillType pft, pft2;
1294 if (edge.PolyTyp == ptSubject)
1295 {
1296 pft = m_SubjFillType;
1297 pft2 = m_ClipFillType;
1298 } else
1299 {
1300 pft = m_ClipFillType;
1301 pft2 = m_SubjFillType;
1302 }
1303
1304 switch(pft)
1305 {
1306 case pftEvenOdd:
1307 //return false if a subj line has been flagged as inside a subj polygon
1308 if (edge.WindDelta == 0 && edge.WindCnt != 1) return false;
1309 break;
1310 case pftNonZero:
1311 if (std::abs(edge.WindCnt) != 1) return false;
1312 break;
1313 case pftPositive:
1314 if (edge.WindCnt != 1) return false;
1315 break;
1316 default: //pftNegative
1317 if (edge.WindCnt != -1) return false;
1318 }
1319
1320 switch(m_ClipType)
1321 {
1322 case ctIntersection:
1323 switch(pft2)
1324 {
1325 case pftEvenOdd:
1326 case pftNonZero:
1327 return (edge.WindCnt2 != 0);
1328 case pftPositive:
1329 return (edge.WindCnt2 > 0);
1330 default:
1331 return (edge.WindCnt2 < 0);
1332 }
1333 break;
1334 case ctUnion:
1335 switch(pft2)
1336 {
1337 case pftEvenOdd:
1338 case pftNonZero:
1339 return (edge.WindCnt2 == 0);
1340 case pftPositive:
1341 return (edge.WindCnt2 <= 0);
1342 default:
1343 return (edge.WindCnt2 >= 0);
1344 }
1345 break;
1346 case ctDifference:
1347 if (edge.PolyTyp == ptSubject)
1348 switch(pft2)
1349 {
1350 case pftEvenOdd:
1351 case pftNonZero:
1352 return (edge.WindCnt2 == 0);
1353 case pftPositive:
1354 return (edge.WindCnt2 <= 0);
1355 default:
1356 return (edge.WindCnt2 >= 0);
1357 }
1358 else
1359 switch(pft2)
1360 {
1361 case pftEvenOdd:
1362 case pftNonZero:
1363 return (edge.WindCnt2 != 0);
1364 case pftPositive:
1365 return (edge.WindCnt2 > 0);
1366 default:
1367 return (edge.WindCnt2 < 0);
1368 }
1369 break;
1370 case ctXor:
1371 if (edge.WindDelta == 0) //XOr always contributing unless open
1372 switch(pft2)
1373 {
1374 case pftEvenOdd:
1375 case pftNonZero:
1376 return (edge.WindCnt2 == 0);
1377 case pftPositive:
1378 return (edge.WindCnt2 <= 0);
1379 default:
1380 return (edge.WindCnt2 >= 0);
1381 }
1382 else
1383 return true;
1384 break;
1385 default:
1386 return true;
1387 }
1388}
@ pftEvenOdd
Definition clipper.hpp:81
@ pftNonZero
Definition clipper.hpp:81

References ClipperLib::ctDifference, ClipperLib::ctIntersection, ClipperLib::ctUnion, ClipperLib::ctXor, m_ClipFillType, m_ClipType, m_SubjFillType, ClipperLib::pftEvenOdd, ClipperLib::pftNonZero, ClipperLib::pftPositive, ClipperLib::TEdge::PolyTyp, ClipperLib::ptSubject, ClipperLib::TEdge::WindCnt, ClipperLib::TEdge::WindCnt2, and ClipperLib::TEdge::WindDelta.

Referenced by InsertLocalMinimaIntoAEL().

+ Here is the caller graph for this function:

◆ IsEvenOddAltFillType()

bool ClipperLib::Clipper::IsEvenOddAltFillType ( const TEdge edge) const
inlineprivate
487 { return (edge.PolyTyp == ptSubject) ? m_ClipFillType == pftEvenOdd : m_SubjFillType == pftEvenOdd; }

References ClipperLib::pftEvenOdd, ClipperLib::TEdge::PolyTyp, and ClipperLib::ptSubject.

Referenced by SetWindingCount().

+ Here is the caller graph for this function:

◆ IsEvenOddFillType()

bool ClipperLib::Clipper::IsEvenOddFillType ( const TEdge edge) const
inlineprivate
485 { return (edge.PolyTyp == ptSubject) ? m_SubjFillType == pftEvenOdd : m_ClipFillType == pftEvenOdd; }

References ClipperLib::pftEvenOdd, ClipperLib::TEdge::PolyTyp, and ClipperLib::ptSubject.

Referenced by IntersectEdges(), and SetWindingCount().

+ Here is the caller graph for this function:

◆ IsTopHorz()

bool ClipperLib::Clipper::IsTopHorz ( const cInt  XPos)
private

◆ JoinCommonEdges()

void ClipperLib::Clipper::JoinCommonEdges ( )
private
3196{
3197 for (Join &join : m_Joins)
3198 {
3199 OutRec *outRec1 = GetOutRec(join.OutPt1->Idx);
3200 OutRec *outRec2 = GetOutRec(join.OutPt2->Idx);
3201
3202 if (!outRec1->Pts || !outRec2->Pts) continue;
3203 if (outRec1->IsOpen || outRec2->IsOpen) continue;
3204
3205 //get the polygon fragment with the correct hole state (FirstLeft)
3206 //before calling JoinPoints() ...
3207 OutRec *holeStateRec;
3208 if (outRec1 == outRec2) holeStateRec = outRec1;
3209 else if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2;
3210 else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1;
3211 else holeStateRec = GetLowermostRec(outRec1, outRec2);
3212
3213 if (!JoinPoints(&join, outRec1, outRec2)) continue;
3214
3215 if (outRec1 == outRec2)
3216 {
3217 //instead of joining two polygons, we've just created a new one by
3218 //splitting one polygon into two.
3219 outRec1->Pts = join.OutPt1;
3220 outRec1->BottomPt = 0;
3221 outRec2 = CreateOutRec();
3222 outRec2->Pts = join.OutPt2;
3223
3224 //update all OutRec2.Pts Idx's ...
3225 UpdateOutPtIdxs(*outRec2);
3226
3227 //We now need to check every OutRec.FirstLeft pointer. If it points
3228 //to OutRec1 it may need to point to OutRec2 instead ...
3229 if (m_UsingPolyTree)
3230 for (size_t j = 0; j < m_PolyOuts.size() - 1; j++)
3231 {
3232 OutRec &oRec = m_PolyOuts[j];
3233 OutRec* firstLeft = oRec.FirstLeft;
3234 while (firstLeft && !firstLeft->Pts) firstLeft = firstLeft->FirstLeft;
3235 if (!oRec.Pts || firstLeft != outRec1 ||
3236 oRec.IsHole == outRec1->IsHole) continue;
3237 if (Poly2ContainsPoly1(oRec.Pts, join.OutPt2))
3238 oRec.FirstLeft = outRec2;
3239 }
3240
3241 if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts))
3242 {
3243 //outRec2 is contained by outRec1 ...
3244 outRec2->IsHole = !outRec1->IsHole;
3245 outRec2->FirstLeft = outRec1;
3246
3247 // For each m_PolyOuts, replace FirstLeft from outRec2 to outRec1.
3248 if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1);
3249
3250 if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0))
3251 ReversePolyPtLinks(outRec2->Pts);
3252
3253 } else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts))
3254 {
3255 //outRec1 is contained by outRec2 ...
3256 outRec2->IsHole = outRec1->IsHole;
3257 outRec1->IsHole = !outRec2->IsHole;
3258 outRec2->FirstLeft = outRec1->FirstLeft;
3259 outRec1->FirstLeft = outRec2;
3260
3261 // For each m_PolyOuts, replace FirstLeft from outRec1 to outRec2.
3262 if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2);
3263
3264 if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0))
3265 ReversePolyPtLinks(outRec1->Pts);
3266 }
3267 else
3268 {
3269 //the 2 polygons are completely separate ...
3270 outRec2->IsHole = outRec1->IsHole;
3271 outRec2->FirstLeft = outRec1->FirstLeft;
3272
3273 //fixup FirstLeft pointers that may need reassigning to OutRec2
3274 // For each polygon of m_PolyOuts, replace FirstLeft from outRec1 to outRec2 if the polygon is inside outRec2.
3275 //FIXME This is potentially very expensive! O(n^3)!
3276 if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2);
3277 }
3278
3279 } else
3280 {
3281 //joined 2 polygons together ...
3282
3283 outRec2->Pts = 0;
3284 outRec2->BottomPt = 0;
3285 outRec2->Idx = outRec1->Idx;
3286
3287 outRec1->IsHole = holeStateRec->IsHole;
3288 if (holeStateRec == outRec2)
3289 outRec1->FirstLeft = outRec2->FirstLeft;
3290 outRec2->FirstLeft = outRec1;
3291
3292 // For each m_PolyOuts, replace FirstLeft from outRec2 to outRec1.
3293 if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1);
3294 }
3295 }
3296}
bool JoinPoints(Join *j, OutRec *outRec1, OutRec *outRec2)
Definition clipper.cpp:3012
OutRec * GetOutRec(int idx)
Definition clipper.cpp:1860

References ClipperLib::Area(), ClipperLib::OutRec::BottomPt, CreateOutRec(), ClipperLib::OutRec::FirstLeft, FixupFirstLefts1(), FixupFirstLefts2(), ClipperLib::GetLowermostRec(), GetOutRec(), ClipperLib::OutRec::Idx, ClipperLib::OutRec::IsHole, ClipperLib::OutRec::IsOpen, JoinPoints(), m_Joins, m_PolyOuts, m_ReverseOutput, m_UsingPolyTree, ClipperLib::Param1RightOfParam2(), ClipperLib::Poly2ContainsPoly1(), ClipperLib::OutRec::Pts, ClipperLib::ReversePolyPtLinks(), and ClipperLib::UpdateOutPtIdxs().

Referenced by ExecuteInternal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ JoinHorz()

bool ClipperLib::Clipper::JoinHorz ( OutPt op1,
OutPt op1b,
OutPt op2,
OutPt op2b,
const IntPoint Pt,
bool  DiscardLeft 
)
private
2927{
2928 Direction Dir1 = (op1->Pt.x() > op1b->Pt.x() ? dRightToLeft : dLeftToRight);
2929 Direction Dir2 = (op2->Pt.x() > op2b->Pt.x() ? dRightToLeft : dLeftToRight);
2930 if (Dir1 == Dir2) return false;
2931
2932 //When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we
2933 //want Op1b to be on the Right. (And likewise with Op2 and Op2b.)
2934 //So, to facilitate this while inserting Op1b and Op2b ...
2935 //when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b,
2936 //otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.)
2937 if (Dir1 == dLeftToRight)
2938 {
2939 while (op1->Next->Pt.x() <= Pt.x() &&
2940 op1->Next->Pt.x() >= op1->Pt.x() && op1->Next->Pt.y() == Pt.y())
2941 op1 = op1->Next;
2942 if (DiscardLeft && (op1->Pt.x() != Pt.x())) op1 = op1->Next;
2943 op1b = this->DupOutPt(op1, !DiscardLeft);
2944 if (op1b->Pt != Pt)
2945 {
2946 op1 = op1b;
2947 op1->Pt = Pt;
2948 op1b = this->DupOutPt(op1, !DiscardLeft);
2949 }
2950 }
2951 else
2952 {
2953 while (op1->Next->Pt.x() >= Pt.x() &&
2954 op1->Next->Pt.x() <= op1->Pt.x() && op1->Next->Pt.y() == Pt.y())
2955 op1 = op1->Next;
2956 if (!DiscardLeft && (op1->Pt.x() != Pt.x())) op1 = op1->Next;
2957 op1b = this->DupOutPt(op1, DiscardLeft);
2958 if (op1b->Pt != Pt)
2959 {
2960 op1 = op1b;
2961 op1->Pt = Pt;
2962 op1b = this->DupOutPt(op1, DiscardLeft);
2963 }
2964 }
2965
2966 if (Dir2 == dLeftToRight)
2967 {
2968 while (op2->Next->Pt.x() <= Pt.x() &&
2969 op2->Next->Pt.x() >= op2->Pt.x() && op2->Next->Pt.y() == Pt.y())
2970 op2 = op2->Next;
2971 if (DiscardLeft && (op2->Pt.x() != Pt.x())) op2 = op2->Next;
2972 op2b = this->DupOutPt(op2, !DiscardLeft);
2973 if (op2b->Pt != Pt)
2974 {
2975 op2 = op2b;
2976 op2->Pt = Pt;
2977 op2b = this->DupOutPt(op2, !DiscardLeft);
2978 };
2979 } else
2980 {
2981 while (op2->Next->Pt.x() >= Pt.x() &&
2982 op2->Next->Pt.x() <= op2->Pt.x() && op2->Next->Pt.y() == Pt.y())
2983 op2 = op2->Next;
2984 if (!DiscardLeft && (op2->Pt.x() != Pt.x())) op2 = op2->Next;
2985 op2b = this->DupOutPt(op2, DiscardLeft);
2986 if (op2b->Pt != Pt)
2987 {
2988 op2 = op2b;
2989 op2->Pt = Pt;
2990 op2b = this->DupOutPt(op2, DiscardLeft);
2991 };
2992 };
2993
2994 if ((Dir1 == dLeftToRight) == DiscardLeft)
2995 {
2996 op1->Prev = op2;
2997 op2->Next = op1;
2998 op1b->Next = op2b;
2999 op2b->Prev = op1b;
3000 }
3001 else
3002 {
3003 op1->Next = op2;
3004 op2->Prev = op1;
3005 op1b->Prev = op2b;
3006 op2b->Next = op1b;
3007 }
3008 return true;
3009}
OutPt * DupOutPt(OutPt *outPt, bool InsertAfter)
Definition clipper.cpp:2902
Direction
Definition clipper.cpp:67
@ dRightToLeft
Definition clipper.cpp:67
@ dLeftToRight
Definition clipper.cpp:67

References ClipperLib::dLeftToRight, ClipperLib::dRightToLeft, DupOutPt(), ClipperLib::OutPt::Next, ClipperLib::OutPt::Prev, and ClipperLib::OutPt::Pt.

Referenced by JoinPoints().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ JoinPoints()

bool ClipperLib::Clipper::JoinPoints ( Join j,
OutRec outRec1,
OutRec outRec2 
)
private
3013{
3014 OutPt *op1 = j->OutPt1, *op1b;
3015 OutPt *op2 = j->OutPt2, *op2b;
3016
3017 //There are 3 kinds of joins for output polygons ...
3018 //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere
3019 //along (horizontal) collinear edges (& Join.OffPt is on the same horizontal).
3020 //2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same
3021 //location at the Bottom of the overlapping segment (& Join.OffPt is above).
3022 //3. StrictSimple joins where edges touch but are not collinear and where
3023 //Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point.
3024 bool isHorizontal = (j->OutPt1->Pt.y() == j->OffPt.y());
3025
3026 if (isHorizontal && (j->OffPt == j->OutPt1->Pt) &&
3027 (j->OffPt == j->OutPt2->Pt))
3028 {
3029 //Strictly Simple join ...
3030 if (outRec1 != outRec2) return false;
3031 op1b = j->OutPt1->Next;
3032 while (op1b != op1 && (op1b->Pt == j->OffPt))
3033 op1b = op1b->Next;
3034 bool reverse1 = (op1b->Pt.y() > j->OffPt.y());
3035 op2b = j->OutPt2->Next;
3036 while (op2b != op2 && (op2b->Pt == j->OffPt))
3037 op2b = op2b->Next;
3038 bool reverse2 = (op2b->Pt.y() > j->OffPt.y());
3039 if (reverse1 == reverse2) return false;
3040 if (reverse1)
3041 {
3042 op1b = this->DupOutPt(op1, false);
3043 op2b = this->DupOutPt(op2, true);
3044 op1->Prev = op2;
3045 op2->Next = op1;
3046 op1b->Next = op2b;
3047 op2b->Prev = op1b;
3048 j->OutPt1 = op1;
3049 j->OutPt2 = op1b;
3050 return true;
3051 } else
3052 {
3053 op1b = this->DupOutPt(op1, true);
3054 op2b = this->DupOutPt(op2, false);
3055 op1->Next = op2;
3056 op2->Prev = op1;
3057 op1b->Prev = op2b;
3058 op2b->Next = op1b;
3059 j->OutPt1 = op1;
3060 j->OutPt2 = op1b;
3061 return true;
3062 }
3063 }
3064 else if (isHorizontal)
3065 {
3066 //treat horizontal joins differently to non-horizontal joins since with
3067 //them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt
3068 //may be anywhere along the horizontal edge.
3069 op1b = op1;
3070 while (op1->Prev->Pt.y() == op1->Pt.y() && op1->Prev != op1b && op1->Prev != op2)
3071 op1 = op1->Prev;
3072 while (op1b->Next->Pt.y() == op1b->Pt.y() && op1b->Next != op1 && op1b->Next != op2)
3073 op1b = op1b->Next;
3074 if (op1b->Next == op1 || op1b->Next == op2) return false; //a flat 'polygon'
3075
3076 op2b = op2;
3077 while (op2->Prev->Pt.y() == op2->Pt.y() && op2->Prev != op2b && op2->Prev != op1b)
3078 op2 = op2->Prev;
3079 while (op2b->Next->Pt.y() == op2b->Pt.y() && op2b->Next != op2 && op2b->Next != op1)
3080 op2b = op2b->Next;
3081 if (op2b->Next == op2 || op2b->Next == op1) return false; //a flat 'polygon'
3082
3083 cInt Left, Right;
3084 //Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges
3085 if (!GetOverlap(op1->Pt.x(), op1b->Pt.x(), op2->Pt.x(), op2b->Pt.x(), Left, Right))
3086 return false;
3087
3088 //DiscardLeftSide: when overlapping edges are joined, a spike will created
3089 //which needs to be cleaned up. However, we don't want Op1 or Op2 caught up
3090 //on the discard Side as either may still be needed for other joins ...
3091 IntPoint Pt;
3092 bool DiscardLeftSide;
3093 if (op1->Pt.x() >= Left && op1->Pt.x() <= Right)
3094 {
3095 Pt = op1->Pt; DiscardLeftSide = (op1->Pt.x() > op1b->Pt.x());
3096 }
3097 else if (op2->Pt.x() >= Left&& op2->Pt.x() <= Right)
3098 {
3099 Pt = op2->Pt; DiscardLeftSide = (op2->Pt.x() > op2b->Pt.x());
3100 }
3101 else if (op1b->Pt.x() >= Left && op1b->Pt.x() <= Right)
3102 {
3103 Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.x() > op1->Pt.x();
3104 }
3105 else
3106 {
3107 Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.x() > op2->Pt.x());
3108 }
3109 j->OutPt1 = op1; j->OutPt2 = op2;
3110 return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide);
3111 } else
3112 {
3113 //nb: For non-horizontal joins ...
3114 // 1. Jr.OutPt1.Pt.y() == Jr.OutPt2.Pt.y()
3115 // 2. Jr.OutPt1.Pt > Jr.OffPt.y()
3116
3117 //make sure the polygons are correctly oriented ...
3118 op1b = op1->Next;
3119 while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Next;
3120 bool Reverse1 = ((op1b->Pt.y() > op1->Pt.y()) ||
3121 !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange));
3122 if (Reverse1)
3123 {
3124 op1b = op1->Prev;
3125 while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Prev;
3126 if ((op1b->Pt.y() > op1->Pt.y()) ||
3127 !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)) return false;
3128 };
3129 op2b = op2->Next;
3130 while ((op2b->Pt == op2->Pt) && (op2b != op2))op2b = op2b->Next;
3131 bool Reverse2 = ((op2b->Pt.y() > op2->Pt.y()) ||
3132 !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange));
3133 if (Reverse2)
3134 {
3135 op2b = op2->Prev;
3136 while ((op2b->Pt == op2->Pt) && (op2b != op2)) op2b = op2b->Prev;
3137 if ((op2b->Pt.y() > op2->Pt.y()) ||
3138 !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)) return false;
3139 }
3140
3141 if ((op1b == op1) || (op2b == op2) || (op1b == op2b) ||
3142 ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false;
3143
3144 if (Reverse1)
3145 {
3146 op1b = this->DupOutPt(op1, false);
3147 op2b = this->DupOutPt(op2, true);
3148 op1->Prev = op2;
3149 op2->Next = op1;
3150 op1b->Next = op2b;
3151 op2b->Prev = op1b;
3152 j->OutPt1 = op1;
3153 j->OutPt2 = op1b;
3154 return true;
3155 } else
3156 {
3157 op1b = this->DupOutPt(op1, true);
3158 op2b = this->DupOutPt(op2, false);
3159 op1->Next = op2;
3160 op2->Prev = op1;
3161 op1b->Prev = op2b;
3162 op2b->Next = op1b;
3163 j->OutPt1 = op1;
3164 j->OutPt2 = op1b;
3165 return true;
3166 }
3167 }
3168}
bool JoinHorz(OutPt *op1, OutPt *op1b, OutPt *op2, OutPt *op2b, const IntPoint &Pt, bool DiscardLeft)
Definition clipper.cpp:2925
bool GetOverlap(const cInt a1, const cInt a2, const cInt b1, const cInt b2, cInt &Left, cInt &Right)
Definition clipper.cpp:2843

References DupOutPt(), ClipperLib::GetOverlap(), JoinHorz(), ClipperLib::ClipperBase::m_UseFullRange, ClipperLib::OutPt::Next, ClipperLib::Join::OffPt, ClipperLib::Join::OutPt1, ClipperLib::Join::OutPt2, ClipperLib::OutPt::Prev, ClipperLib::OutPt::Pt, and ClipperLib::SlopesEqual().

Referenced by JoinCommonEdges().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ PreserveCollinear() [1/2]

bool ClipperLib::ClipperBase::PreserveCollinear ( ) const
inlineinherited
388{return m_PreserveCollinear;};

◆ PreserveCollinear() [2/2]

void ClipperLib::ClipperBase::PreserveCollinear ( bool  value)
inlineinherited
389{m_PreserveCollinear = value;};

◆ ProcessBound()

TEdge * ClipperLib::ClipperBase::ProcessBound ( TEdge E,
bool  IsClockwise 
)
protectedinherited
638{
639 TEdge *Result = E;
640 TEdge *Horz = 0;
641
642 if (E->OutIdx == Skip)
643 {
644 //if edges still remain in the current bound beyond the skip edge then
645 //create another LocMin and call ProcessBound once more
646 if (NextIsForward)
647 {
648 while (E->Top.y() == E->Next->Bot.y()) E = E->Next;
649 //don't include top horizontals when parsing a bound a second time,
650 //they will be contained in the opposite bound ...
651 while (E != Result && IsHorizontal(*E)) E = E->Prev;
652 }
653 else
654 {
655 while (E->Top.y() == E->Prev->Bot.y()) E = E->Prev;
656 while (E != Result && IsHorizontal(*E)) E = E->Next;
657 }
658
659 if (E == Result)
660 {
661 if (NextIsForward) Result = E->Next;
662 else Result = E->Prev;
663 }
664 else
665 {
666 //there are more edges in the bound beyond result starting with E
667 if (NextIsForward)
668 E = Result->Next;
669 else
670 E = Result->Prev;
671 LocalMinimum locMin;
672 locMin.Y = E->Bot.y();
673 locMin.LeftBound = 0;
674 locMin.RightBound = E;
675 E->WindDelta = 0;
676 Result = ProcessBound(E, NextIsForward);
677 m_MinimaList.emplace_back(locMin);
678 }
679 return Result;
680 }
681
682 TEdge *EStart;
683
684 if (IsHorizontal(*E))
685 {
686 //We need to be careful with open paths because this may not be a
687 //true local minima (ie E may be following a skip edge).
688 //Also, consecutive horz. edges may start heading left before going right.
689 if (NextIsForward)
690 EStart = E->Prev;
691 else
692 EStart = E->Next;
693 if (IsHorizontal(*EStart)) //ie an adjoining horizontal skip edge
694 {
695 if (EStart->Bot.x() != E->Bot.x() && EStart->Top.x() != E->Bot.x())
697 }
698 else if (EStart->Bot.x() != E->Bot.x())
700 }
701
702 EStart = E;
703 if (NextIsForward)
704 {
705 while (Result->Top.y() == Result->Next->Bot.y() && Result->Next->OutIdx != Skip)
706 Result = Result->Next;
707 if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip)
708 {
709 //nb: at the top of a bound, horizontals are added to the bound
710 //only when the preceding edge attaches to the horizontal's left vertex
711 //unless a Skip edge is encountered when that becomes the top divide
712 Horz = Result;
713 while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev;
714 if (Horz->Prev->Top.x() > Result->Next->Top.x()) Result = Horz->Prev;
715 }
716 while (E != Result)
717 {
718 E->NextInLML = E->Next;
719 if (IsHorizontal(*E) && E != EStart &&
720 E->Bot.x() != E->Prev->Top.x()) ReverseHorizontal(*E);
721 E = E->Next;
722 }
723 if (IsHorizontal(*E) && E != EStart && E->Bot.x() != E->Prev->Top.x())
725 Result = Result->Next; //move to the edge just beyond current bound
726 } else
727 {
728 while (Result->Top.y() == Result->Prev->Bot.y() && Result->Prev->OutIdx != Skip)
729 Result = Result->Prev;
730 if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip)
731 {
732 Horz = Result;
733 while (IsHorizontal(*Horz->Next)) Horz = Horz->Next;
734 if (Horz->Next->Top.x() == Result->Prev->Top.x() ||
735 Horz->Next->Top.x() > Result->Prev->Top.x()) Result = Horz->Next;
736 }
737
738 while (E != Result)
739 {
740 E->NextInLML = E->Prev;
741 if (IsHorizontal(*E) && E != EStart && E->Bot.x() != E->Next->Top.x())
743 E = E->Prev;
744 }
745 if (IsHorizontal(*E) && E != EStart && E->Bot.x() != E->Next->Top.x())
747 Result = Result->Prev; //move to the edge just beyond current bound
748 }
749
750 return Result;
751}

References ClipperLib::TEdge::Bot, ClipperLib::IsHorizontal(), ClipperLib::LocalMinimum::LeftBound, ClipperLib::TEdge::Next, ClipperLib::TEdge::OutIdx, ClipperLib::TEdge::Prev, ClipperLib::ReverseHorizontal(), ClipperLib::LocalMinimum::RightBound, ClipperLib::Skip, ClipperLib::TEdge::Top, and ClipperLib::LocalMinimum::Y.

+ Here is the call graph for this function:

◆ ProcessEdgesAtTopOfScanbeam()

void ClipperLib::Clipper::ProcessEdgesAtTopOfScanbeam ( const cInt  topY)
private
2563{
2564 TEdge* e = m_ActiveEdges;
2565 while( e )
2566 {
2567 //1. process maxima, treating them as if they're 'bent' horizontal edges,
2568 // but exclude maxima with horizontal edges. nb: e can't be a horizontal.
2569 bool IsMaximaEdge = IsMaxima(e, topY);
2570
2571 if(IsMaximaEdge)
2572 {
2573 TEdge* eMaxPair = GetMaximaPair(e);
2574 IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair));
2575 }
2576
2577 if(IsMaximaEdge)
2578 {
2579 if (m_StrictSimple) m_Maxima.emplace_back(e->Top.x());
2580 TEdge* ePrev = e->PrevInAEL;
2581 DoMaxima(e);
2582 if( !ePrev ) e = m_ActiveEdges;
2583 else e = ePrev->NextInAEL;
2584 }
2585 else
2586 {
2587 //2. promote horizontal edges, otherwise update Curr.x() and Curr.y() ...
2588 if (IsIntermediate(e, topY) && IsHorizontal(*e->NextInLML))
2589 {
2591 if (e->OutIdx >= 0)
2592 AddOutPt(e, e->Bot);
2593 AddEdgeToSEL(e);
2594 }
2595 else
2596 {
2597 e->Curr.x() = TopX( *e, topY );
2598 e->Curr.y() = topY;
2599#ifdef CLIPPERLIB_USE_XYZ
2600 e->Curr.z() = topY == e->Top.y() ? e->Top.z() : (topY == e->Bot.y() ? e->Bot.z() : 0);
2601#endif
2602 }
2603
2604 //When StrictlySimple and 'e' is being touched by another edge, then
2605 //make sure both edges have a vertex here ...
2606 if (m_StrictSimple)
2607 {
2608 TEdge* ePrev = e->PrevInAEL;
2609 if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) &&
2610 (ePrev->Curr.x() == e->Curr.x()) && (ePrev->WindDelta != 0))
2611 {
2612 IntPoint pt = e->Curr;
2613#ifdef CLIPPERLIB_USE_XYZ
2614 SetZ(pt, *ePrev, *e);
2615#endif
2616 OutPt* op = AddOutPt(ePrev, pt);
2617 OutPt* op2 = AddOutPt(e, pt);
2618 m_Joins.emplace_back(Join(op, op2, pt)); //StrictlySimple (type-3) join
2619 }
2620 }
2621
2622 e = e->NextInAEL;
2623 }
2624 }
2625
2626 //3. Process horizontals at the Top of the scanbeam ...
2627 std::sort(m_Maxima.begin(), m_Maxima.end());
2629 m_Maxima.clear();
2630
2631 //4. Promote intermediate vertices ...
2632 e = m_ActiveEdges;
2633 while(e)
2634 {
2635 if(IsIntermediate(e, topY))
2636 {
2637 OutPt* op = 0;
2638 if( e->OutIdx >= 0 )
2639 op = AddOutPt(e, e->Top);
2641
2642 //if output polygons share an edge, they'll need joining later ...
2643 TEdge* ePrev = e->PrevInAEL;
2644 TEdge* eNext = e->NextInAEL;
2645 if (ePrev && ePrev->Curr.x() == e->Bot.x() &&
2646 ePrev->Curr.y() == e->Bot.y() && op &&
2647 ePrev->OutIdx >= 0 && ePrev->Curr.y() > ePrev->Top.y() &&
2648 SlopesEqual(*e, *ePrev, m_UseFullRange) &&
2649 (e->WindDelta != 0) && (ePrev->WindDelta != 0))
2650 {
2651 OutPt* op2 = AddOutPt(ePrev, e->Bot);
2652 m_Joins.emplace_back(Join(op, op2, e->Top));
2653 }
2654 else if (eNext && eNext->Curr.x() == e->Bot.x() &&
2655 eNext->Curr.y() == e->Bot.y() && op &&
2656 eNext->OutIdx >= 0 && eNext->Curr.y() > eNext->Top.y() &&
2657 SlopesEqual(*e, *eNext, m_UseFullRange) &&
2658 (e->WindDelta != 0) && (eNext->WindDelta != 0))
2659 {
2660 OutPt* op2 = AddOutPt(eNext, e->Bot);
2661 m_Joins.emplace_back(Join(op, op2, e->Top));
2662 }
2663 }
2664 e = e->NextInAEL;
2665 }
2666}
cInts m_Maxima
Definition clipper.hpp:471
void UpdateEdgeIntoAEL(TEdge *&e)
Definition clipper.cpp:2384
void DoMaxima(TEdge *e)
Definition clipper.cpp:2510
bool IsMaxima(TEdge *e, const cInt Y)
Definition clipper.cpp:2044
bool IsIntermediate(TEdge *e, const cInt Y)
Definition clipper.cpp:2050

References AddEdgeToSEL(), AddOutPt(), ClipperLib::TEdge::Bot, ClipperLib::TEdge::Curr, DoMaxima(), ClipperLib::GetMaximaPair(), ClipperLib::IsHorizontal(), ClipperLib::IsIntermediate(), ClipperLib::IsMaxima(), m_ActiveEdges, m_Joins, m_Maxima, m_StrictSimple, ClipperLib::ClipperBase::m_UseFullRange, ClipperLib::TEdge::NextInAEL, ClipperLib::TEdge::NextInLML, ClipperLib::TEdge::OutIdx, ClipperLib::TEdge::PrevInAEL, ProcessHorizontals(), ClipperLib::SlopesEqual(), ClipperLib::TEdge::Top, ClipperLib::TopX(), UpdateEdgeIntoAEL(), and ClipperLib::TEdge::WindDelta.

Referenced by ExecuteInternal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ProcessHorizontal()

void ClipperLib::Clipper::ProcessHorizontal ( TEdge horzEdge)
private
2192{
2193 Direction dir;
2194 cInt horzLeft, horzRight;
2195 bool IsOpen = (horzEdge->OutIdx >= 0 && m_PolyOuts[horzEdge->OutIdx].IsOpen);
2196
2197 GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
2198
2199 TEdge* eLastHorz = horzEdge, *eMaxPair = 0;
2200 while (eLastHorz->NextInLML && IsHorizontal(*eLastHorz->NextInLML))
2201 eLastHorz = eLastHorz->NextInLML;
2202 if (!eLastHorz->NextInLML)
2203 eMaxPair = GetMaximaPair(eLastHorz);
2204
2205 cInts::const_iterator maxIt;
2206 cInts::const_reverse_iterator maxRit;
2207 if (!m_Maxima.empty())
2208 {
2209 //get the first maxima in range (X) ...
2210 if (dir == dLeftToRight)
2211 {
2212 maxIt = m_Maxima.begin();
2213 while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.x()) ++maxIt;
2214 if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.x())
2215 maxIt = m_Maxima.end();
2216 }
2217 else
2218 {
2219 maxRit = m_Maxima.rbegin();
2220 while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.x()) ++maxRit;
2221 if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.x())
2222 maxRit = m_Maxima.rend();
2223 }
2224 }
2225
2226 OutPt* op1 = 0;
2227
2228 for (;;) //loop through consec. horizontal edges
2229 {
2230
2231 bool IsLastHorz = (horzEdge == eLastHorz);
2232 TEdge* e = (dir == dLeftToRight) ? horzEdge->NextInAEL : horzEdge->PrevInAEL;
2233 while(e)
2234 {
2235
2236 //this code block inserts extra coords into horizontal edges (in output
2237 //polygons) whereever maxima touch these horizontal edges. This helps
2238 //'simplifying' polygons (ie if the Simplify property is set).
2239 if (!m_Maxima.empty())
2240 {
2241 if (dir == dLeftToRight)
2242 {
2243 while (maxIt != m_Maxima.end() && *maxIt < e->Curr.x())
2244 {
2245 if (horzEdge->OutIdx >= 0 && !IsOpen)
2246 AddOutPt(horzEdge, IntPoint2d(*maxIt, horzEdge->Bot.y()));
2247 ++maxIt;
2248 }
2249 }
2250 else
2251 {
2252 while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.x())
2253 {
2254 if (horzEdge->OutIdx >= 0 && !IsOpen)
2255 AddOutPt(horzEdge, IntPoint2d(*maxRit, horzEdge->Bot.y()));
2256 ++maxRit;
2257 }
2258 }
2259 };
2260
2261 if ((dir == dLeftToRight && e->Curr.x() > horzRight) ||
2262 (dir == dRightToLeft && e->Curr.x() < horzLeft)) break;
2263
2264 //Also break if we've got to the end of an intermediate horizontal edge ...
2265 //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
2266 if (e->Curr.x() == horzEdge->Top.x() && horzEdge->NextInLML &&
2267 e->Dx < horzEdge->NextInLML->Dx) break;
2268
2269 if (horzEdge->OutIdx >= 0 && !IsOpen) //note: may be done multiple times
2270 {
2271#ifdef CLIPPERLIB_USE_XYZ
2272 if (dir == dLeftToRight)
2273 SetZ(e->Curr, *horzEdge, *e);
2274 else
2275 SetZ(e->Curr, *e, *horzEdge);
2276#endif
2277 op1 = AddOutPt(horzEdge, e->Curr);
2278 TEdge* eNextHorz = m_SortedEdges;
2279 while (eNextHorz)
2280 {
2281 if (eNextHorz->OutIdx >= 0 &&
2282 HorzSegmentsOverlap(horzEdge->Bot.x(),
2283 horzEdge->Top.x(), eNextHorz->Bot.x(), eNextHorz->Top.x()))
2284 {
2285 OutPt* op2 = GetLastOutPt(eNextHorz);
2286 m_Joins.emplace_back(Join(op2, op1, eNextHorz->Top));
2287 }
2288 eNextHorz = eNextHorz->NextInSEL;
2289 }
2290 m_GhostJoins.emplace_back(Join(op1, 0, horzEdge->Bot));
2291 }
2292
2293 //OK, so far we're still in range of the horizontal Edge but make sure
2294 //we're at the last of consec. horizontals when matching with eMaxPair
2295 if(e == eMaxPair && IsLastHorz)
2296 {
2297 if (horzEdge->OutIdx >= 0)
2298 AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top);
2299 DeleteFromAEL(horzEdge);
2300 DeleteFromAEL(eMaxPair);
2301 return;
2302 }
2303
2304 if(dir == dLeftToRight)
2305 {
2306 IntPoint Pt = IntPoint2d(e->Curr.x(), horzEdge->Curr.y());
2307 IntersectEdges(horzEdge, e, Pt);
2308 }
2309 else
2310 {
2311 IntPoint Pt = IntPoint2d(e->Curr.x(), horzEdge->Curr.y());
2312 IntersectEdges( e, horzEdge, Pt);
2313 }
2314 TEdge* eNext = (dir == dLeftToRight) ? e->NextInAEL : e->PrevInAEL;
2315 SwapPositionsInAEL( horzEdge, e );
2316 e = eNext;
2317 } //end while(e)
2318
2319 //Break out of loop if HorzEdge.NextInLML is not also horizontal ...
2320 if (!horzEdge->NextInLML || !IsHorizontal(*horzEdge->NextInLML)) break;
2321
2322 UpdateEdgeIntoAEL(horzEdge);
2323 if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot);
2324 GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
2325
2326 } //end for (;;)
2327
2328 if (horzEdge->OutIdx >= 0 && !op1)
2329 {
2330 op1 = GetLastOutPt(horzEdge);
2331 TEdge* eNextHorz = m_SortedEdges;
2332 while (eNextHorz)
2333 {
2334 if (eNextHorz->OutIdx >= 0 &&
2335 HorzSegmentsOverlap(horzEdge->Bot.x(),
2336 horzEdge->Top.x(), eNextHorz->Bot.x(), eNextHorz->Top.x()))
2337 {
2338 OutPt* op2 = GetLastOutPt(eNextHorz);
2339 m_Joins.emplace_back(Join(op2, op1, eNextHorz->Top));
2340 }
2341 eNextHorz = eNextHorz->NextInSEL;
2342 }
2343 m_GhostJoins.emplace_back(Join(op1, 0, horzEdge->Top));
2344 }
2345
2346 if (horzEdge->NextInLML)
2347 {
2348 if(horzEdge->OutIdx >= 0)
2349 {
2350 op1 = AddOutPt( horzEdge, horzEdge->Top);
2351 UpdateEdgeIntoAEL(horzEdge);
2352 if (horzEdge->WindDelta == 0) return;
2353 //nb: HorzEdge is no longer horizontal here
2354 TEdge* ePrev = horzEdge->PrevInAEL;
2355 TEdge* eNext = horzEdge->NextInAEL;
2356 if (ePrev && ePrev->Curr.x() == horzEdge->Bot.x() &&
2357 ePrev->Curr.y() == horzEdge->Bot.y() && ePrev->WindDelta != 0 &&
2358 (ePrev->OutIdx >= 0 && ePrev->Curr.y() > ePrev->Top.y() &&
2359 SlopesEqual(*horzEdge, *ePrev, m_UseFullRange)))
2360 {
2361 OutPt* op2 = AddOutPt(ePrev, horzEdge->Bot);
2362 m_Joins.emplace_back(Join(op1, op2, horzEdge->Top));
2363 }
2364 else if (eNext && eNext->Curr.x() == horzEdge->Bot.x() &&
2365 eNext->Curr.y() == horzEdge->Bot.y() && eNext->WindDelta != 0 &&
2366 eNext->OutIdx >= 0 && eNext->Curr.y() > eNext->Top.y() &&
2367 SlopesEqual(*horzEdge, *eNext, m_UseFullRange))
2368 {
2369 OutPt* op2 = AddOutPt(eNext, horzEdge->Bot);
2370 m_Joins.emplace_back(Join(op1, op2, horzEdge->Top));
2371 }
2372 }
2373 else
2374 UpdateEdgeIntoAEL(horzEdge);
2375 }
2376 else
2377 {
2378 if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top);
2379 DeleteFromAEL(horzEdge);
2380 }
2381}
OutPt * GetLastOutPt(TEdge *e)
Definition clipper.cpp:2022
void GetHorzDirection(TEdge &HorzEdge, Direction &Dir, cInt &Left, cInt &Right)
Definition clipper.cpp:2165
IntPoint IntPoint2d(cInt x, cInt y)
Definition clipper.cpp:78

References AddLocalMaxPoly(), AddOutPt(), ClipperLib::TEdge::Bot, ClipperLib::TEdge::Curr, DeleteFromAEL(), ClipperLib::dLeftToRight, ClipperLib::dRightToLeft, ClipperLib::TEdge::Dx, ClipperLib::GetHorzDirection(), GetLastOutPt(), ClipperLib::GetMaximaPair(), ClipperLib::HorzSegmentsOverlap(), IntersectEdges(), ClipperLib::IntPoint2d(), ClipperLib::IsHorizontal(), m_GhostJoins, m_Joins, m_Maxima, m_PolyOuts, m_SortedEdges, ClipperLib::ClipperBase::m_UseFullRange, ClipperLib::TEdge::NextInAEL, ClipperLib::TEdge::NextInLML, ClipperLib::TEdge::NextInSEL, ClipperLib::TEdge::OutIdx, ClipperLib::TEdge::PrevInAEL, ClipperLib::SlopesEqual(), SwapPositionsInAEL(), ClipperLib::TEdge::Top, UpdateEdgeIntoAEL(), and ClipperLib::TEdge::WindDelta.

Referenced by ProcessHorizontals().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ProcessHorizontals()

void ClipperLib::Clipper::ProcessHorizontals ( )
private
2033{
2034 TEdge* horzEdge = m_SortedEdges;
2035 while(horzEdge)
2036 {
2037 DeleteFromSEL(horzEdge);
2038 ProcessHorizontal(horzEdge);
2039 horzEdge = m_SortedEdges;
2040 }
2041}
void ProcessHorizontal(TEdge *horzEdge)
Definition clipper.cpp:2191
void DeleteFromSEL(TEdge *e)
Definition clipper.cpp:1590

References DeleteFromSEL(), m_SortedEdges, and ProcessHorizontal().

Referenced by ExecuteInternal(), and ProcessEdgesAtTopOfScanbeam().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ProcessIntersections()

bool ClipperLib::Clipper::ProcessIntersections ( const cInt  topY)
private
2409{
2410 if( !m_ActiveEdges ) return true;
2411 try {
2412 BuildIntersectList(topY);
2413 size_t IlSize = m_IntersectList.size();
2414 if (IlSize == 0) return true;
2415 if (IlSize == 1 || FixupIntersectionOrder()) {
2416 for (IntersectNode &iNode : m_IntersectList) {
2417 IntersectEdges( iNode.Edge1, iNode.Edge2, iNode.Pt);
2418 SwapPositionsInAEL( iNode.Edge1 , iNode.Edge2 );
2419 }
2420 m_IntersectList.clear();
2421 }
2422 else return false;
2423 }
2424 catch(...)
2425 {
2426 m_SortedEdges = 0;
2427 m_IntersectList.clear();
2428 throw clipperException("ProcessIntersections error");
2429 }
2430 m_SortedEdges = 0;
2431 return true;
2432}
bool FixupIntersectionOrder()
Definition clipper.cpp:2486
void BuildIntersectList(const cInt topY)
Definition clipper.cpp:2435

References BuildIntersectList(), FixupIntersectionOrder(), IntersectEdges(), m_ActiveEdges, m_IntersectList, m_SortedEdges, and SwapPositionsInAEL().

Referenced by ExecuteInternal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Reset()

void ClipperLib::Clipper::Reset ( )
protected
1060{
1062 m_Scanbeam = std::priority_queue<cInt, cInts>{};
1063 m_Maxima.clear();
1064 m_ActiveEdges = 0;
1065 m_SortedEdges = 0;
1066 for (auto lm = m_MinimaList.rbegin(); lm != m_MinimaList.rend(); ++lm)
1067 m_Scanbeam.push(lm->Y);
1068}
void Reset()
Definition clipper.cpp:972

References m_ActiveEdges, m_Maxima, ClipperLib::ClipperBase::m_MinimaList, m_Scanbeam, m_SortedEdges, and ClipperLib::ClipperBase::Reset().

Referenced by ExecuteInternal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ReverseSolution() [1/2]

bool ClipperLib::Clipper::ReverseSolution ( ) const
inline
441{ return m_ReverseOutput; };

Referenced by ClipperLib::ClipperOffset::Execute(), ClipperLib::ClipperOffset::Execute(), Slic3r::fix_after_inner_offset(), Slic3r::fix_after_outer_offset(), and Slic3r::shrink_paths().

+ Here is the caller graph for this function:

◆ ReverseSolution() [2/2]

void ClipperLib::Clipper::ReverseSolution ( bool  value)
inline
442{m_ReverseOutput = value;};

◆ SetHoleState()

void ClipperLib::Clipper::SetHoleState ( TEdge e,
OutRec outrec 
)
private
1812{
1813 bool IsHole = false;
1814 TEdge *e2 = e->PrevInAEL;
1815 while (e2)
1816 {
1817 if (e2->OutIdx >= 0 && e2->WindDelta != 0)
1818 {
1819 IsHole = !IsHole;
1820 if (! outrec->FirstLeft)
1821 outrec->FirstLeft = &m_PolyOuts[e2->OutIdx];
1822 }
1823 e2 = e2->PrevInAEL;
1824 }
1825 if (IsHole) outrec->IsHole = true;
1826}

References ClipperLib::OutRec::FirstLeft, ClipperLib::OutRec::IsHole, m_PolyOuts, ClipperLib::TEdge::OutIdx, ClipperLib::TEdge::PrevInAEL, and ClipperLib::TEdge::WindDelta.

Referenced by AddOutPt().

+ Here is the caller graph for this function:

◆ SetWindingCount()

void ClipperLib::Clipper::SetWindingCount ( TEdge edge) const
private
1197{
1198 TEdge *e = edge.PrevInAEL;
1199 //find the edge of the same polytype that immediately preceeds 'edge' in AEL
1200 while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL;
1201 if (!e)
1202 {
1203 edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta);
1204 edge.WindCnt2 = 0;
1205 e = m_ActiveEdges; //ie get ready to calc WindCnt2
1206 }
1207 else if (edge.WindDelta == 0 && m_ClipType != ctUnion)
1208 {
1209 edge.WindCnt = 1;
1210 edge.WindCnt2 = e->WindCnt2;
1211 e = e->NextInAEL; //ie get ready to calc WindCnt2
1212 }
1213 else if (IsEvenOddFillType(edge))
1214 {
1215 //EvenOdd filling ...
1216 if (edge.WindDelta == 0)
1217 {
1218 //are we inside a subj polygon ...
1219 bool Inside = true;
1220 TEdge *e2 = e->PrevInAEL;
1221 while (e2)
1222 {
1223 if (e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0)
1224 Inside = !Inside;
1225 e2 = e2->PrevInAEL;
1226 }
1227 edge.WindCnt = (Inside ? 0 : 1);
1228 }
1229 else
1230 {
1231 edge.WindCnt = edge.WindDelta;
1232 }
1233 edge.WindCnt2 = e->WindCnt2;
1234 e = e->NextInAEL; //ie get ready to calc WindCnt2
1235 }
1236 else
1237 {
1238 //nonZero, Positive or Negative filling ...
1239 if (e->WindCnt * e->WindDelta < 0)
1240 {
1241 //prev edge is 'decreasing' WindCount (WC) toward zero
1242 //so we're outside the previous polygon ...
1243 if (std::abs(e->WindCnt) > 1)
1244 {
1245 //outside prev poly but still inside another.
1246 //when reversing direction of prev poly use the same WC
1247 if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt;
1248 //otherwise continue to 'decrease' WC ...
1249 else edge.WindCnt = e->WindCnt + edge.WindDelta;
1250 }
1251 else
1252 //now outside all polys of same polytype so set own WC ...
1253 edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta);
1254 } else
1255 {
1256 //prev edge is 'increasing' WindCount (WC) away from zero
1257 //so we're inside the previous polygon ...
1258 if (edge.WindDelta == 0)
1259 edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1);
1260 //if wind direction is reversing prev then use same WC
1261 else if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt;
1262 //otherwise add to WC ...
1263 else edge.WindCnt = e->WindCnt + edge.WindDelta;
1264 }
1265 edge.WindCnt2 = e->WindCnt2;
1266 e = e->NextInAEL; //ie get ready to calc WindCnt2
1267 }
1268
1269 //update WindCnt2 ...
1270 if (IsEvenOddAltFillType(edge))
1271 {
1272 //EvenOdd filling ...
1273 while (e != &edge)
1274 {
1275 if (e->WindDelta != 0)
1276 edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0);
1277 e = e->NextInAEL;
1278 }
1279 } else
1280 {
1281 //nonZero, Positive or Negative filling ...
1282 while ( e != &edge )
1283 {
1284 edge.WindCnt2 += e->WindDelta;
1285 e = e->NextInAEL;
1286 }
1287 }
1288}
bool IsEvenOddAltFillType(const TEdge &edge) const
Definition clipper.hpp:486
int WindCnt
Definition clipper.hpp:245

References ClipperLib::ctUnion, IsEvenOddAltFillType(), IsEvenOddFillType(), m_ActiveEdges, m_ClipType, ClipperLib::TEdge::NextInAEL, ClipperLib::TEdge::PolyTyp, ClipperLib::TEdge::PrevInAEL, ClipperLib::TEdge::WindCnt, ClipperLib::TEdge::WindCnt2, and ClipperLib::TEdge::WindDelta.

Referenced by InsertLocalMinimaIntoAEL().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ StrictlySimple() [1/2]

bool ClipperLib::Clipper::StrictlySimple ( ) const
inline
443{return m_StrictSimple;};

◆ StrictlySimple() [2/2]

void ClipperLib::Clipper::StrictlySimple ( bool  value)
inline
444{m_StrictSimple = value;};

◆ SwapPositionsInAEL()

void ClipperLib::Clipper::SwapPositionsInAEL ( TEdge edge1,
TEdge edge2 
)
private
2073{
2074 //check that one or other edge hasn't already been removed from AEL ...
2075 if (Edge1->NextInAEL == Edge1->PrevInAEL ||
2076 Edge2->NextInAEL == Edge2->PrevInAEL) return;
2077
2078 if( Edge1->NextInAEL == Edge2 )
2079 {
2080 TEdge* Next = Edge2->NextInAEL;
2081 if( Next ) Next->PrevInAEL = Edge1;
2082 TEdge* Prev = Edge1->PrevInAEL;
2083 if( Prev ) Prev->NextInAEL = Edge2;
2084 Edge2->PrevInAEL = Prev;
2085 Edge2->NextInAEL = Edge1;
2086 Edge1->PrevInAEL = Edge2;
2087 Edge1->NextInAEL = Next;
2088 }
2089 else if( Edge2->NextInAEL == Edge1 )
2090 {
2091 TEdge* Next = Edge1->NextInAEL;
2092 if( Next ) Next->PrevInAEL = Edge2;
2093 TEdge* Prev = Edge2->PrevInAEL;
2094 if( Prev ) Prev->NextInAEL = Edge1;
2095 Edge1->PrevInAEL = Prev;
2096 Edge1->NextInAEL = Edge2;
2097 Edge2->PrevInAEL = Edge1;
2098 Edge2->NextInAEL = Next;
2099 }
2100 else
2101 {
2102 TEdge* Next = Edge1->NextInAEL;
2103 TEdge* Prev = Edge1->PrevInAEL;
2104 Edge1->NextInAEL = Edge2->NextInAEL;
2105 if( Edge1->NextInAEL ) Edge1->NextInAEL->PrevInAEL = Edge1;
2106 Edge1->PrevInAEL = Edge2->PrevInAEL;
2107 if( Edge1->PrevInAEL ) Edge1->PrevInAEL->NextInAEL = Edge1;
2108 Edge2->NextInAEL = Next;
2109 if( Edge2->NextInAEL ) Edge2->NextInAEL->PrevInAEL = Edge2;
2110 Edge2->PrevInAEL = Prev;
2111 if( Edge2->PrevInAEL ) Edge2->PrevInAEL->NextInAEL = Edge2;
2112 }
2113
2114 if( !Edge1->PrevInAEL ) m_ActiveEdges = Edge1;
2115 else if( !Edge2->PrevInAEL ) m_ActiveEdges = Edge2;
2116}

References m_ActiveEdges, ClipperLib::TEdge::NextInAEL, and ClipperLib::TEdge::PrevInAEL.

Referenced by DoMaxima(), ProcessHorizontal(), and ProcessIntersections().

+ Here is the caller graph for this function:

◆ SwapPositionsInSEL()

void ClipperLib::Clipper::SwapPositionsInSEL ( TEdge edge1,
TEdge edge2 
)
private
2120{
2121 if( !( Edge1->NextInSEL ) && !( Edge1->PrevInSEL ) ) return;
2122 if( !( Edge2->NextInSEL ) && !( Edge2->PrevInSEL ) ) return;
2123
2124 if( Edge1->NextInSEL == Edge2 )
2125 {
2126 TEdge* Next = Edge2->NextInSEL;
2127 if( Next ) Next->PrevInSEL = Edge1;
2128 TEdge* Prev = Edge1->PrevInSEL;
2129 if( Prev ) Prev->NextInSEL = Edge2;
2130 Edge2->PrevInSEL = Prev;
2131 Edge2->NextInSEL = Edge1;
2132 Edge1->PrevInSEL = Edge2;
2133 Edge1->NextInSEL = Next;
2134 }
2135 else if( Edge2->NextInSEL == Edge1 )
2136 {
2137 TEdge* Next = Edge1->NextInSEL;
2138 if( Next ) Next->PrevInSEL = Edge2;
2139 TEdge* Prev = Edge2->PrevInSEL;
2140 if( Prev ) Prev->NextInSEL = Edge1;
2141 Edge1->PrevInSEL = Prev;
2142 Edge1->NextInSEL = Edge2;
2143 Edge2->PrevInSEL = Edge1;
2144 Edge2->NextInSEL = Next;
2145 }
2146 else
2147 {
2148 TEdge* Next = Edge1->NextInSEL;
2149 TEdge* Prev = Edge1->PrevInSEL;
2150 Edge1->NextInSEL = Edge2->NextInSEL;
2151 if( Edge1->NextInSEL ) Edge1->NextInSEL->PrevInSEL = Edge1;
2152 Edge1->PrevInSEL = Edge2->PrevInSEL;
2153 if( Edge1->PrevInSEL ) Edge1->PrevInSEL->NextInSEL = Edge1;
2154 Edge2->NextInSEL = Next;
2155 if( Edge2->NextInSEL ) Edge2->NextInSEL->PrevInSEL = Edge2;
2156 Edge2->PrevInSEL = Prev;
2157 if( Edge2->PrevInSEL ) Edge2->PrevInSEL->NextInSEL = Edge2;
2158 }
2159
2160 if( !Edge1->PrevInSEL ) m_SortedEdges = Edge1;
2161 else if( !Edge2->PrevInSEL ) m_SortedEdges = Edge2;
2162}

References m_SortedEdges, ClipperLib::TEdge::NextInSEL, and ClipperLib::TEdge::PrevInSEL.

Referenced by BuildIntersectList(), and FixupIntersectionOrder().

+ Here is the caller graph for this function:

◆ UpdateEdgeIntoAEL()

void ClipperLib::Clipper::UpdateEdgeIntoAEL ( TEdge *&  e)
private
2385{
2386 if( !e->NextInLML )
2387 throw clipperException("UpdateEdgeIntoAEL: invalid call");
2388
2389 e->NextInLML->OutIdx = e->OutIdx;
2390 TEdge* AelPrev = e->PrevInAEL;
2391 TEdge* AelNext = e->NextInAEL;
2392 if (AelPrev) AelPrev->NextInAEL = e->NextInLML;
2393 else m_ActiveEdges = e->NextInLML;
2394 if (AelNext) AelNext->PrevInAEL = e->NextInLML;
2395 e->NextInLML->Side = e->Side;
2396 e->NextInLML->WindDelta = e->WindDelta;
2397 e->NextInLML->WindCnt = e->WindCnt;
2398 e->NextInLML->WindCnt2 = e->WindCnt2;
2399 e = e->NextInLML;
2400 e->Curr = e->Bot;
2401 e->PrevInAEL = AelPrev;
2402 e->NextInAEL = AelNext;
2403 if (!IsHorizontal(*e))
2404 m_Scanbeam.push(e->Top.y());
2405}
TEdge * NextInLML
Definition clipper.hpp:253
EdgeSide Side
Definition clipper.hpp:242

References ClipperLib::TEdge::Bot, ClipperLib::TEdge::Curr, ClipperLib::IsHorizontal(), m_ActiveEdges, m_Scanbeam, ClipperLib::TEdge::NextInAEL, ClipperLib::TEdge::NextInLML, ClipperLib::TEdge::OutIdx, ClipperLib::TEdge::PrevInAEL, ClipperLib::TEdge::Side, ClipperLib::TEdge::Top, ClipperLib::TEdge::WindCnt, ClipperLib::TEdge::WindCnt2, and ClipperLib::TEdge::WindDelta.

Referenced by ProcessEdgesAtTopOfScanbeam(), and ProcessHorizontal().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ m_ActiveEdges

◆ m_ClipFillType

PolyFillType ClipperLib::Clipper::m_ClipFillType
private

◆ m_ClipType

ClipType ClipperLib::Clipper::m_ClipType
private

◆ m_edges

std::vector<Edges, Allocator<Edges> > ClipperLib::ClipperBase::m_edges
protectedinherited

◆ m_GhostJoins

std::vector<Join, Allocator<Join> > ClipperLib::Clipper::m_GhostJoins
private

◆ m_HasOpenPaths

bool ClipperLib::ClipperBase::m_HasOpenPaths
protectedinherited

Referenced by Clipper(), and Execute().

◆ m_IntersectList

std::vector<IntersectNode, Allocator<IntersectNode> > ClipperLib::Clipper::m_IntersectList
private

◆ m_Joins

◆ m_Maxima

cInts ClipperLib::Clipper::m_Maxima
private

◆ m_MinimaList

std::vector<LocalMinimum, Allocator<LocalMinimum> > ClipperLib::ClipperBase::m_MinimaList
protectedinherited

◆ m_OutPts

std::deque<std::array<OutPt, m_OutPtsChunkSize>, Allocator<std::array<OutPt, m_OutPtsChunkSize> > > ClipperLib::Clipper::m_OutPts
private

Referenced by AllocateOutPt(), and DisposeAllOutRecs().

◆ m_OutPtsChunkLast

size_t ClipperLib::Clipper::m_OutPtsChunkLast
private

Referenced by AllocateOutPt(), and DisposeAllOutRecs().

◆ m_OutPtsChunkSize

constexpr const size_t ClipperLib::Clipper::m_OutPtsChunkSize = 32
staticconstexprprivate

Referenced by AllocateOutPt(), and DisposeAllOutRecs().

◆ m_OutPtsFree

OutPt* ClipperLib::Clipper::m_OutPtsFree
private

Referenced by AllocateOutPt(), and DisposeAllOutRecs().

◆ m_PolyOuts

◆ m_PreserveCollinear

bool ClipperLib::ClipperBase::m_PreserveCollinear
protectedinherited

Referenced by Clipper(), and FixupOutPolygon().

◆ m_ReverseOutput

bool ClipperLib::Clipper::m_ReverseOutput
private

◆ m_Scanbeam

std::priority_queue<cInt, cInts> ClipperLib::Clipper::m_Scanbeam
private

◆ m_SortedEdges

◆ m_StrictSimple

bool ClipperLib::Clipper::m_StrictSimple
private

◆ m_SubjFillType

PolyFillType ClipperLib::Clipper::m_SubjFillType
private

◆ m_UseFullRange

constexpr const bool ClipperLib::ClipperBase::m_UseFullRange = false
staticconstexprprotectedinherited

◆ m_UsingPolyTree

bool ClipperLib::Clipper::m_UsingPolyTree
private

The documentation for this class was generated from the following files: