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

#include <src/clipper/clipper.hpp>

+ Inheritance diagram for ClipperLib::ClipperBase:
+ Collaboration diagram for ClipperLib::ClipperBase:

Public Member Functions

 ClipperBase ()
 
 ~ClipperBase ()
 
bool AddPath (const Path &pg, PolyType PolyTyp, bool Closed)
 
template<typename PathsProvider >
bool AddPaths (PathsProvider &&paths_provider, PolyType PolyTyp, bool Closed)
 
void Clear ()
 
IntRect GetBounds ()
 
bool PreserveCollinear () const
 
void PreserveCollinear (bool value)
 

Protected Types

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

Protected Member Functions

bool AddPathInternal (const Path &pg, int highI, PolyType PolyTyp, bool Closed, TEdge *edges)
 
TEdgeAddBoundsToLML (TEdge *e, bool IsClosed)
 
void Reset ()
 
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
 

Detailed Description

Member Typedef Documentation

◆ Edges

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

Constructor & Destructor Documentation

◆ ClipperBase()

ClipperLib::ClipperBase::ClipperBase ( )
inline
325 :
326#ifndef CLIPPERLIB_INT32
327 m_UseFullRange(false),
328#endif // CLIPPERLIB_INT32
329 m_HasOpenPaths(false) {}
static constexpr const bool m_UseFullRange
Definition clipper.hpp:402
bool m_HasOpenPaths
Definition clipper.hpp:415

◆ ~ClipperBase()

ClipperLib::ClipperBase::~ClipperBase ( )
inline
330{ Clear(); }
void Clear()
Definition clipper.cpp:959

Member Function Documentation

◆ AddBoundsToLML()

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

◆ AddPath()

bool ClipperLib::ClipperBase::AddPath ( const Path pg,
PolyType  PolyTyp,
bool  Closed 
)
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 
)
protected
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
bool m_PreserveCollinear
Definition clipper.hpp:413
std::vector< LocalMinimum, Allocator< LocalMinimum > > m_MinimaList
Definition clipper.hpp:399
@ esLeft
Definition clipper.hpp:226
@ esRight
Definition clipper.hpp:226
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
bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool)
Definition clipper.cpp:296
@ 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 
)
inline
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:

◆ AscendToMax()

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

◆ Clear()

void ClipperLib::ClipperBase::Clear ( )
960{
961 m_MinimaList.clear();
962 m_edges.clear();
963#ifndef CLIPPERLIB_INT32
964 m_UseFullRange = false;
965#endif // CLIPPERLIB_INT32
966 m_HasOpenPaths = false;
967}

◆ DescendToMin()

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

◆ GetBounds()

IntRect ClipperLib::ClipperBase::GetBounds ( )
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:

◆ PreserveCollinear() [1/2]

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

◆ PreserveCollinear() [2/2]

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

◆ ProcessBound()

TEdge * ClipperLib::ClipperBase::ProcessBound ( TEdge E,
bool  IsClockwise 
)
protected
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}
bool IsHorizontal(TEdge &e)
Definition clipper.cpp:320

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:

◆ Reset()

void ClipperLib::ClipperBase::Reset ( )
protected
973{
974 if (m_MinimaList.empty()) return; //ie nothing to process
975 std::sort(m_MinimaList.begin(), m_MinimaList.end(), [](const LocalMinimum& lm1, const LocalMinimum& lm2){ return lm1.Y < lm2.Y; });
976
977 //reset all edges ...
978 for (LocalMinimum &lm : m_MinimaList) {
979 TEdge* e = lm.LeftBound;
980 if (e)
981 {
982 e->Curr = e->Bot;
983 e->Side = esLeft;
984 e->OutIdx = Unassigned;
985 }
986
987 e = lm.RightBound;
988 if (e)
989 {
990 e->Curr = e->Bot;
991 e->Side = esRight;
992 e->OutIdx = Unassigned;
993 }
994 }
995}
static int const Unassigned
Definition clipper.cpp:69

References ClipperLib::TEdge::Bot, ClipperLib::TEdge::Curr, ClipperLib::esLeft, ClipperLib::esRight, ClipperLib::TEdge::OutIdx, ClipperLib::TEdge::Side, and ClipperLib::Unassigned.

Referenced by ClipperLib::Clipper::Reset().

+ Here is the caller graph for this function:

Member Data Documentation

◆ m_edges

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

◆ m_HasOpenPaths

bool ClipperLib::ClipperBase::m_HasOpenPaths
protected

◆ m_MinimaList

◆ m_PreserveCollinear

bool ClipperLib::ClipperBase::m_PreserveCollinear
protected

◆ m_UseFullRange


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