diff --git a/3d-viewer/3d_canvas/board_adapter.cpp b/3d-viewer/3d_canvas/board_adapter.cpp
index 4e0c5ddffa..77b19e85fe 100644
--- a/3d-viewer/3d_canvas/board_adapter.cpp
+++ b/3d-viewer/3d_canvas/board_adapter.cpp
@@ -947,9 +947,7 @@ bool BOARD_ADAPTER::createBoardPolygon( wxString* aErrorMsg )
         success = BuildFootprintPolygonOutlines( m_board, m_board_poly,
                                                  m_board->GetDesignSettings().m_MaxError,
                                                  chainingEpsilon );
-
-        // Make polygon strictly simple to avoid issues (especially in 3D viewer)
-        m_board_poly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+        m_board_poly.Simplify();
 
         if( !success && aErrorMsg )
         {
diff --git a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp
index ab11cccadc..08e2e19952 100644
--- a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp
+++ b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp
@@ -650,7 +650,7 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
                 aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
                                                  ERROR_INSIDE );
 
-                polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
+                polyList.Simplify();
 
                 if( margin != 0 )
                 {
@@ -700,7 +700,7 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
             // Some polygons can be a bit complex (especially when coming from a
             // picture ot a text converted to a polygon
             // So call Simplify before calling ConvertPolygonToTriangles, just in case.
-            polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
+            polyList.Simplify();
 
             if( polyList.IsEmpty() ) // Just for caution
                 break;
diff --git a/3d-viewer/3d_canvas/create_layer_items.cpp b/3d-viewer/3d_canvas/create_layer_items.cpp
index 7345bb5f11..5918a2b047 100644
--- a/3d-viewer/3d_canvas/create_layer_items.cpp
+++ b/3d-viewer/3d_canvas/create_layer_items.cpp
@@ -780,10 +780,10 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
     // End Build Copper layers
 
     // This will make a union of all added contours
-    m_TH_ODPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
-    m_NPTH_ODPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
-    m_viaTH_ODPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
-    m_viaAnnuliPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
+    m_TH_ODPolys.Simplify();
+    m_NPTH_ODPolys.Simplify();
+    m_viaTH_ODPolys.Simplify();
+    m_viaAnnuliPolys.Simplify();
 
     // Build Tech layers
     // Based on:
@@ -1022,7 +1022,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
             }
 
             // This will make a union of all added contours
-            layerPoly->Simplify( SHAPE_POLY_SET::PM_FAST );
+            layerPoly->Simplify();
         }
     }
     // End Build Tech layers
@@ -1061,14 +1061,12 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
         // TRIM PLATED COPPER TO SOLDERMASK
         if( m_layers_poly.find( F_Mask ) != m_layers_poly.end() )
         {
-            m_frontPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( F_Mask ),
-                                                           SHAPE_POLY_SET::PM_FAST );
+            m_frontPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( F_Mask ) );
         }
 
         if( m_layers_poly.find( B_Mask ) != m_layers_poly.end() )
         {
-            m_backPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( B_Mask ),
-                                                          SHAPE_POLY_SET::PM_FAST );
+            m_backPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( B_Mask ) );
         }
 
         // Subtract plated copper from unplated copper
@@ -1077,15 +1075,15 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
 
         if( m_layers_poly.find( F_Cu ) != m_layers_poly.end() )
         {
-            m_layers_poly[F_Cu]->BooleanSubtract( *m_frontPlatedPadAndGraphicPolys, SHAPE_POLY_SET::PM_FAST );
-            m_layers_poly[F_Cu]->BooleanSubtract( *m_frontPlatedCopperPolys, SHAPE_POLY_SET::PM_FAST );
+            m_layers_poly[F_Cu]->BooleanSubtract( *m_frontPlatedPadAndGraphicPolys );
+            m_layers_poly[F_Cu]->BooleanSubtract( *m_frontPlatedCopperPolys );
             hasF_Cu = true;
         }
 
         if( m_layers_poly.find( B_Cu ) != m_layers_poly.end() )
         {
-            m_layers_poly[B_Cu]->BooleanSubtract( *m_backPlatedPadAndGraphicPolys, SHAPE_POLY_SET::PM_FAST );
-            m_layers_poly[B_Cu]->BooleanSubtract( *m_backPlatedCopperPolys, SHAPE_POLY_SET::PM_FAST );
+            m_layers_poly[B_Cu]->BooleanSubtract( *m_backPlatedPadAndGraphicPolys );
+            m_layers_poly[B_Cu]->BooleanSubtract( *m_backPlatedCopperPolys );
             hasB_Cu = true;
         }
 
@@ -1096,10 +1094,10 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
         if( hasB_Cu && m_backPlatedCopperPolys->OutlineCount() )
             m_backPlatedPadAndGraphicPolys->Append( *m_backPlatedCopperPolys );
 
-        m_frontPlatedPadAndGraphicPolys->Simplify( SHAPE_POLY_SET::PM_FAST );
-        m_backPlatedPadAndGraphicPolys->Simplify( SHAPE_POLY_SET::PM_FAST );
-        m_frontPlatedCopperPolys->Simplify( SHAPE_POLY_SET::PM_FAST );
-        m_backPlatedCopperPolys->Simplify( SHAPE_POLY_SET::PM_FAST );
+        m_frontPlatedPadAndGraphicPolys->Simplify();
+        m_backPlatedPadAndGraphicPolys->Simplify();
+        m_frontPlatedCopperPolys->Simplify();
+        m_backPlatedCopperPolys->Simplify();
 
         // ADD PLATED PADS
         for( FOOTPRINT* footprint : m_board->Footprints() )
@@ -1168,7 +1166,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
                                 {
                                     // This will make a union of all added contours
                                     layerPoly->second->ClearArcs();
-                                    layerPoly->second->Simplify( SHAPE_POLY_SET::PM_FAST );
+                                    layerPoly->second->Simplify();
                                 }
                             }
 
@@ -1193,12 +1191,12 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
         {
             // found
             SHAPE_POLY_SET *polyLayer = m_layerHoleOdPolys[layer];
-            polyLayer->Simplify( SHAPE_POLY_SET::PM_FAST );
+            polyLayer->Simplify();
 
             wxASSERT( m_layerHoleIdPolys.find( layer ) != m_layerHoleIdPolys.end() );
 
             polyLayer = m_layerHoleIdPolys[layer];
-            polyLayer->Simplify( SHAPE_POLY_SET::PM_FAST );
+            polyLayer->Simplify();
         }
     }
 
diff --git a/3d-viewer/3d_rendering/opengl/create_scene.cpp b/3d-viewer/3d_rendering/opengl/create_scene.cpp
index ad8dcbe14f..55162b7222 100644
--- a/3d-viewer/3d_rendering/opengl/create_scene.cpp
+++ b/3d-viewer/3d_rendering/opengl/create_scene.cpp
@@ -476,13 +476,12 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
     m_antiBoardPolys.Append( VECTOR2I( -INT_MAX/2,  INT_MAX/2 ) );
     m_antiBoardPolys.Outline( 0 ).SetClosed( true );
 
-    m_antiBoardPolys.BooleanSubtract( m_boardAdapter.GetBoardPoly(),
-                                      SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    m_antiBoardPolys.BooleanSubtract( m_boardAdapter.GetBoardPoly() );
     m_antiBoard = createBoard( m_antiBoardPolys );
 
     SHAPE_POLY_SET board_poly_with_holes = m_boardAdapter.GetBoardPoly().CloneDropTriangulation();
-    board_poly_with_holes.BooleanSubtract( m_boardAdapter.GetTH_ODPolys(), SHAPE_POLY_SET::PM_FAST );
-    board_poly_with_holes.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys(), SHAPE_POLY_SET::PM_FAST );
+    board_poly_with_holes.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
+    board_poly_with_holes.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys() );
 
     m_boardWithHoles = createBoard( board_poly_with_holes );
 
@@ -495,8 +494,7 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
 
     SHAPE_POLY_SET outerPolyTHT = m_boardAdapter.GetTH_ODPolys().CloneDropTriangulation();
 
-    outerPolyTHT.BooleanIntersection( m_boardAdapter.GetBoardPoly(),
-                                      SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    outerPolyTHT.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
 
     m_outerThroughHoles = generateHoles( m_boardAdapter.GetTH_ODs().GetList(), outerPolyTHT,
                                          1.0f, 0.0f, false, &m_boardAdapter.GetTH_IDs() );
@@ -575,29 +573,24 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
 
                 if( LSET::PhysicalLayersMask().test( layer ) )
                 {
-                    polyListSubtracted.BooleanIntersection( m_boardAdapter.GetBoardPoly(),
-                                                            SHAPE_POLY_SET::PM_FAST );
+                    polyListSubtracted.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
                 }
 
                 if( layer != B_Mask && layer != F_Mask )
                 {
-                    polyListSubtracted.BooleanSubtract( m_boardAdapter.GetTH_ODPolys(),
-                                                        SHAPE_POLY_SET::PM_FAST );
-                    polyListSubtracted.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys(),
-                                                        SHAPE_POLY_SET::PM_FAST );
+                    polyListSubtracted.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
+                    polyListSubtracted.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys() );
                 }
 
                 if( m_boardAdapter.m_Cfg->m_Render.subtract_mask_from_silk )
                 {
                     if( layer == B_SilkS && map_poly.find( B_Mask ) != map_poly.end() )
                     {
-                        polyListSubtracted.BooleanSubtract( *map_poly.at( B_Mask ),
-                                                            SHAPE_POLY_SET::PM_FAST );
+                        polyListSubtracted.BooleanSubtract( *map_poly.at( B_Mask ) );
                     }
                     else if( layer == F_SilkS && map_poly.find( F_Mask ) != map_poly.end() )
                     {
-                        polyListSubtracted.BooleanSubtract( *map_poly.at( F_Mask ),
-                                                            SHAPE_POLY_SET::PM_FAST );
+                        polyListSubtracted.BooleanSubtract( *map_poly.at( F_Mask ) );
                     }
                 }
 
@@ -620,9 +613,9 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
         if( frontPlatedPadAndGraphicPolys )
         {
             SHAPE_POLY_SET poly = frontPlatedPadAndGraphicPolys->CloneDropTriangulation();
-            poly.BooleanIntersection( m_boardAdapter.GetBoardPoly(), SHAPE_POLY_SET::PM_FAST );
-            poly.BooleanSubtract( m_boardAdapter.GetTH_ODPolys(), SHAPE_POLY_SET::PM_FAST );
-            poly.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys(), SHAPE_POLY_SET::PM_FAST );
+            poly.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
+            poly.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
+            poly.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys() );
 
             m_platedPadsFront = generateLayerList( m_boardAdapter.GetPlatedPadsFront(), &poly, F_Cu );
 
@@ -634,9 +627,9 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
         if( backPlatedPadAndGraphicPolys )
         {
             SHAPE_POLY_SET poly = backPlatedPadAndGraphicPolys->CloneDropTriangulation();
-            poly.BooleanIntersection( m_boardAdapter.GetBoardPoly(), SHAPE_POLY_SET::PM_FAST );
-            poly.BooleanSubtract( m_boardAdapter.GetTH_ODPolys(), SHAPE_POLY_SET::PM_FAST );
-            poly.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys(), SHAPE_POLY_SET::PM_FAST );
+            poly.BooleanIntersection( m_boardAdapter.GetBoardPoly() );
+            poly.BooleanSubtract( m_boardAdapter.GetTH_ODPolys() );
+            poly.BooleanSubtract( m_boardAdapter.GetNPTH_ODPolys() );
 
             m_platedPadsBack = generateLayerList( m_boardAdapter.GetPlatedPadsBack(), &poly, B_Cu );
 
@@ -839,9 +832,9 @@ void RENDER_3D_OPENGL::generateViasAndPads()
         }
 
         // Subtract the holes
-        tht_outer_holes_poly.BooleanSubtract( tht_inner_holes_poly, SHAPE_POLY_SET::PM_FAST );
+        tht_outer_holes_poly.BooleanSubtract( tht_inner_holes_poly );
 
-        tht_outer_holes_poly.BooleanSubtract( m_antiBoardPolys, SHAPE_POLY_SET::PM_FAST );
+        tht_outer_holes_poly.BooleanSubtract( m_antiBoardPolys );
 
         CONTAINER_2D holesContainer;
 
diff --git a/3d-viewer/3d_rendering/raytracing/create_scene.cpp b/3d-viewer/3d_rendering/raytracing/create_scene.cpp
index 43ee1140c8..51e6306f60 100644
--- a/3d-viewer/3d_rendering/raytracing/create_scene.cpp
+++ b/3d-viewer/3d_rendering/raytracing/create_scene.cpp
@@ -415,8 +415,8 @@ void RENDER_3D_RAYTRACE_BASE::Reload( REPORTER* aStatusReporter, REPORTER* aWarn
 
             buildBoardBoundingBoxPoly( m_boardAdapter.GetBoard(), antiboardPoly );
 
-            antiboardPoly.BooleanSubtract( boardPolyCopy, SHAPE_POLY_SET::PM_FAST );
-            antiboardPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
+            antiboardPoly.BooleanSubtract( boardPolyCopy );
+            antiboardPoly.Fracture();
 
             for( int ii = 0; ii < antiboardPoly.OutlineCount(); ii++ )
             {
@@ -427,7 +427,7 @@ void RENDER_3D_RAYTRACE_BASE::Reload( REPORTER* aStatusReporter, REPORTER* aWarn
 
             m_antioutlineBoard2dObjects->BuildBVH();
 
-            boardPolyCopy.Fracture( SHAPE_POLY_SET::PM_FAST );
+            boardPolyCopy.Fracture();
 
             for( int ii = 0; ii < outlineCount; ii++ )
             {
diff --git a/3d-viewer/3d_rendering/raytracing/shapes2D/polygon_2d.cpp b/3d-viewer/3d_rendering/raytracing/shapes2D/polygon_2d.cpp
index bcba4dff31..04edd43fe6 100644
--- a/3d-viewer/3d_rendering/raytracing/shapes2D/polygon_2d.cpp
+++ b/3d-viewer/3d_rendering/raytracing/shapes2D/polygon_2d.cpp
@@ -612,10 +612,9 @@ void ConvertPolygonToBlocks( const SHAPE_POLY_SET& aMainPath, CONTAINER_2D_BASE&
 
                 subBlockPoly.AddOutline( sb );
 
-                // We need here a strictly simple polygon with outlines and holes
+                // We need here a simple polygon with outlines and holes
                 SHAPE_POLY_SET solution;
-                solution.BooleanIntersection( aMainPath, subBlockPoly,
-                                              SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                solution.BooleanIntersection( aMainPath, subBlockPoly );
 
                 OUTERS_AND_HOLES outersAndHoles;
 
@@ -659,68 +658,3 @@ void ConvertPolygonToBlocks( const SHAPE_POLY_SET& aMainPath, CONTAINER_2D_BASE&
         topToBottom += topToBottom_inc;
     }
 }
-
-
-#ifdef DEBUG
-static void polygon_Convert( const ClipperLib::Path& aPath, SEGMENTS& aOutSegment,
-                             float aBiuTo3dUnitsScale )
-{
-    aOutSegment.resize( aPath.size() );
-
-    for( unsigned i = 0; i < aPath.size(); i++ )
-    {
-        aOutSegment[i].m_Start = SFVEC2F(
-                (float) aPath[i].X * aBiuTo3dUnitsScale, (float) -aPath[i].Y * aBiuTo3dUnitsScale );
-    }
-
-    unsigned int i;
-    unsigned int j = aOutSegment.size() - 1;
-
-    for( i = 0; i < aOutSegment.size(); j = i++ )
-    {
-        // Calculate constants for each segment
-        aOutSegment[i].m_inv_JY_minus_IY =
-                1.0f / ( aOutSegment[j].m_Start.y - aOutSegment[i].m_Start.y );
-        aOutSegment[i].m_JX_minus_IX = ( aOutSegment[j].m_Start.x - aOutSegment[i].m_Start.x );
-    }
-}
-
-
-void Polygon2d_TestModule()
-{
-    // "This structure contains a sequence of IntPoint vertices defining a single contour"
-    ClipperLib::Path aPath;
-
-    SEGMENTS aSegments;
-
-    aPath.resize( 4 );
-
-    aPath[0] = ClipperLib::IntPoint( -2, -2 );
-    aPath[1] = ClipperLib::IntPoint( 2, -2 );
-    aPath[2] = ClipperLib::IntPoint( 2, 2 );
-    aPath[3] = ClipperLib::IntPoint( -2, 2 );
-
-    // It must be an outer polygon
-    wxASSERT( ClipperLib::Orientation( aPath ) );
-
-    polygon_Convert( aPath, aSegments, 1.0f );
-
-    wxASSERT( aPath.size() == aSegments.size() );
-
-    wxASSERT( aSegments[0].m_Start == SFVEC2F( -2.0f, 2.0f ) );
-    wxASSERT( aSegments[1].m_Start == SFVEC2F( 2.0f, 2.0f ) );
-    wxASSERT( aSegments[2].m_Start == SFVEC2F( 2.0f, -2.0f ) );
-    wxASSERT( aSegments[3].m_Start == SFVEC2F( -2.0f, -2.0f ) );
-
-    wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( 0.0f, 0.0f ) ) );
-    wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( -1.9f, -1.9f ) ) );
-    wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( -1.9f, 1.9f ) ) );
-    wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( 1.9f, 1.9f ) ) );
-    wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( 1.9f, -1.9f ) ) );
-
-    wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( -2.1f, -2.0f ) ) == false );
-    wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( -2.1f, 2.0f ) ) == false );
-    wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( 2.1f, 2.0f ) ) == false );
-    wxASSERT( polygon_IsPointInside( aSegments, SFVEC2F( 2.1f, -2.0f ) ) == false );
-}
-#endif
diff --git a/3d-viewer/3d_rendering/raytracing/shapes2D/polygon_2d.h b/3d-viewer/3d_rendering/raytracing/shapes2D/polygon_2d.h
index 8132dbf991..7582343731 100644
--- a/3d-viewer/3d_rendering/raytracing/shapes2D/polygon_2d.h
+++ b/3d-viewer/3d_rendering/raytracing/shapes2D/polygon_2d.h
@@ -152,6 +152,5 @@ void ConvertPolygonToBlocks( const SHAPE_POLY_SET& aMainPath, CONTAINER_2D_BASE&
                             float aBiuTo3dUnitsScale, float aDivFactor,
                             const BOARD_ITEM& aBoardItem, int aPolyIndex );
 
-void Polygon2d_TestModule();
 
 #endif // _CPOLYGON2D_H_
diff --git a/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.h b/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.h
index e3b7ffe25f..cb28ff1b58 100644
--- a/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.h
+++ b/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.h
@@ -33,7 +33,6 @@
 #include "../accelerators/container_2d.h"
 #include <geometry/shape_line_chain.h>
 #include <geometry/shape_poly_set.h>
-#include <clipper.hpp>
 
 class TRIANGLE_2D : public OBJECT_2D
 {
diff --git a/bitmap2component/bitmap2component.cpp b/bitmap2component/bitmap2component.cpp
index c43645f146..2a63ab8668 100644
--- a/bitmap2component/bitmap2component.cpp
+++ b/bitmap2component/bitmap2component.cpp
@@ -524,15 +524,15 @@ void BITMAPCONV_INFO::createOutputData( BMP2CMP_MOD_LAYER aModLayer )
         // at the end of a group of a positive path and its negative children, fill.
         if( paths->next == nullptr || paths->next->sign == '+' )
         {
-            polyset_areas.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
-            polyset_holes.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
-            polyset_areas.BooleanSubtract( polyset_holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            polyset_areas.Simplify();
+            polyset_holes.Simplify();
+            polyset_areas.BooleanSubtract( polyset_holes );
 
             // Ensure there are no self intersecting polygons
             if( polyset_areas.NormalizeAreaOutlines() )
             {
                 // Convert polygon with holes to a unique polygon
-                polyset_areas.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                polyset_areas.Fracture();
 
                 // Output current resulting polygon(s)
                 for( int ii = 0; ii < polyset_areas.OutlineCount(); ii++ )
diff --git a/common/advanced_config.cpp b/common/advanced_config.cpp
index c406889c90..43e98c0aa4 100644
--- a/common/advanced_config.cpp
+++ b/common/advanced_config.cpp
@@ -98,7 +98,6 @@ static const wxChar AllowManualCanvasScale[] = wxT( "AllowManualCanvasScale" );
 static const wxChar UpdateUIEventInterval[] = wxT( "UpdateUIEventInterval" );
 static const wxChar V3DRT_BevelHeight_um[] = wxT( "V3DRT_BevelHeight_um" );
 static const wxChar V3DRT_BevelExtentFactor[] = wxT( "V3DRT_BevelExtentFactor" );
-static const wxChar UseClipper2[] = wxT( "UseClipper2" );
 static const wxChar EnableDesignBlocks[] = wxT( "EnableDesignBlocks" );
 static const wxChar EnableGenerators[] = wxT( "EnableGenerators" );
 static const wxChar EnableGit[] = wxT( "EnableGit" );
@@ -263,7 +262,6 @@ ADVANCED_CFG::ADVANCED_CFG()
     m_3DRT_BevelHeight_um       = 30;
     m_3DRT_BevelExtentFactor    = 1.0 / 16.0;
 
-    m_UseClipper2               = true;
     m_EnableAPILogging          = false;
 
     m_Use3DConnexionDriver      = true;
@@ -464,9 +462,6 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
                                                   m_3DRT_BevelExtentFactor, 0.0, 100.0,
                                                   AC_GROUPS::V3D_RayTracing ) );
 
-    configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::UseClipper2,
-                                                &m_UseClipper2, m_UseClipper2 ) );
-
     configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::Use3DConnexionDriver,
                                                 &m_Use3DConnexionDriver, m_Use3DConnexionDriver ) );
 
diff --git a/common/callback_gal.cpp b/common/callback_gal.cpp
index 9441d3edf6..542b5f734c 100644
--- a/common/callback_gal.cpp
+++ b/common/callback_gal.cpp
@@ -71,7 +71,7 @@ void CALLBACK_GAL::DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal
             KIFONT::OUTLINE_GLYPH glyph = static_cast<const KIFONT::OUTLINE_GLYPH&>( aGlyph );
 
             if( glyph.HasHoles() )
-                glyph.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
+                glyph.Fracture();
 
             for( int ii = 0; ii < glyph.OutlineCount(); ++ii )
                 m_outlineCallback( glyph.Outline( ii ) );
diff --git a/common/eda_draw_frame.cpp b/common/eda_draw_frame.cpp
index 8b672445c5..264ebc7945 100644
--- a/common/eda_draw_frame.cpp
+++ b/common/eda_draw_frame.cpp
@@ -1022,9 +1022,9 @@ void EDA_DRAW_FRAME::FocusOnLocation( const VECTOR2I& aPos )
         {
             GetCanvas()->GetView()->SetCenter( aPos, dialogScreenRects );
         }
-        catch( const ClipperLib::clipperException& e )
+        catch( const Clipper2Lib::Clipper2Exception& e )
         {
-            wxFAIL_MSG( wxString::Format( wxT( "Clipper exception occurred centering object: %s" ),
+            wxFAIL_MSG( wxString::Format( wxT( "Clipper2 exception occurred centering object: %s" ),
                                           e.what() ) );
         }
     }
diff --git a/common/import_gfx/graphics_importer_buffer.cpp b/common/import_gfx/graphics_importer_buffer.cpp
index 55fd4ab655..4cc36ee4ab 100644
--- a/common/import_gfx/graphics_importer_buffer.cpp
+++ b/common/import_gfx/graphics_importer_buffer.cpp
@@ -250,9 +250,9 @@ static void convertPolygon( std::list<std::unique_ptr<IMPORTED_SHAPE>>& aShapes,
         upscaledPaths.push_back( lc );
     }
 
-    SHAPE_POLY_SET result = SHAPE_POLY_SET::BuildPolysetFromOrientedPaths(
-            upscaledPaths, false, aFillRule == GRAPHICS_IMPORTER::PF_EVEN_ODD );
-    result.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    SHAPE_POLY_SET result;
+    result.BuildPolysetFromOrientedPaths( upscaledPaths, aFillRule == GRAPHICS_IMPORTER::PF_EVEN_ODD );
+    result.Fracture();
 
     for( int outl = 0; outl < result.OutlineCount(); outl++ )
     {
diff --git a/common/plotters/DXF_plotter.cpp b/common/plotters/DXF_plotter.cpp
index 8f76970361..6f893f3677 100644
--- a/common/plotters/DXF_plotter.cpp
+++ b/common/plotters/DXF_plotter.cpp
@@ -574,8 +574,8 @@ void DXF_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFi
     // polygon and its thick outline
 
     // create the outline which contains thick outline:
-    bufferPolybase.BooleanAdd( bufferOutline, SHAPE_POLY_SET::PM_FAST );
-    bufferPolybase.Fracture( SHAPE_POLY_SET::PM_FAST );
+    bufferPolybase.BooleanAdd( bufferOutline );
+    bufferPolybase.Fracture();
 
     if( bufferPolybase.OutlineCount() < 1 )      // should not happen
         return;
diff --git a/common/view/view.cpp b/common/view/view.cpp
index cc664c347a..61f1504c45 100644
--- a/common/view/view.cpp
+++ b/common/view/view.cpp
@@ -622,7 +622,7 @@ void VIEW::SetCenter( const VECTOR2D& aCenter, const std::vector<BOX2D>& obscuri
     for( const BOX2D& obscuringScreenRect : obscuringScreenRects )
     {
         SHAPE_POLY_SET obscuringPoly( obscuringScreenRect );
-        unobscuredPoly.BooleanSubtract( obscuringPoly, SHAPE_POLY_SET::PM_FAST );
+        unobscuredPoly.BooleanSubtract( obscuringPoly );
     }
 
     /*
diff --git a/eeschema/gfx_import_utils.cpp b/eeschema/gfx_import_utils.cpp
index 7f96567eee..f7ee1ce763 100644
--- a/eeschema/gfx_import_utils.cpp
+++ b/eeschema/gfx_import_utils.cpp
@@ -91,7 +91,7 @@ std::unordered_map<uint32_t, SHAPE_POLY_SET> ConvertImageToPolygons( wxImage  im
 
     for( auto& [color, polySet] : colorPolys )
     {
-        polySet.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+        polySet.Simplify();
 
         for( int i = 0; i < polySet.OutlineCount(); i++ )
         {
@@ -114,7 +114,7 @@ void ConvertImageToLibShapes( LIB_SYMBOL* aSymbol, int unit, wxImage img, VECTOR
 
     for( auto& [color, polySet] : colorPolys )
     {
-        polySet.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+        polySet.Fracture();
 
         for( const SHAPE_POLY_SET::POLYGON& poly : polySet.CPolygons() )
         {
diff --git a/eeschema/sch_painter.cpp b/eeschema/sch_painter.cpp
index 8afe0082ed..ae4fe4b044 100644
--- a/eeschema/sch_painter.cpp
+++ b/eeschema/sch_painter.cpp
@@ -664,8 +664,8 @@ static void knockoutText( KIGFX::GAL& aGal, const wxString& aText, const VECTOR2
     finalPoly.Append( bbox.GetRight(), bbox.GetBottom() );
     finalPoly.Append( bbox.GetLeft(),  bbox.GetBottom() );
 
-    finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
-    finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
+    finalPoly.BooleanSubtract( knockouts );
+    finalPoly.Fracture();
 
     aGal.SetIsStroke( false );
     aGal.SetIsFill( true );
diff --git a/gerbview/aperture_macro.cpp b/gerbview/aperture_macro.cpp
index 45f6d841bb..060818f4f8 100644
--- a/gerbview/aperture_macro.cpp
+++ b/gerbview/aperture_macro.cpp
@@ -124,19 +124,19 @@ SHAPE_POLY_SET* APERTURE_MACRO::GetApertureMacroShape( const GERBER_DRAW_ITEM* a
 
             if( holeBuffer.OutlineCount() )     // we have a new hole in shape: remove the hole
             {
-                m_shape.BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );
+                m_shape.BooleanSubtract( holeBuffer );
                 holeBuffer.RemoveAllContours();
             }
         }
     }
 
     // Merge and cleanup basic shape polygons
-    m_shape.Simplify( SHAPE_POLY_SET::PM_FAST );
+    m_shape.Simplify();
 
     // A hole can be is defined inside a polygon, or the polygons themselve can create
     // a hole when merged, so we must fracture the polygon to be able to drawn it
     // (i.e link holes by overlapping edges)
-    m_shape.Fracture( SHAPE_POLY_SET::PM_FAST );
+    m_shape.Fracture();
 
     // Move m_shape to the actual draw position:
     for( int icnt = 0; icnt < m_shape.OutlineCount(); icnt++ )
diff --git a/gerbview/dcode.cpp b/gerbview/dcode.cpp
index 22ae7b0b41..ac44c5a3d4 100644
--- a/gerbview/dcode.cpp
+++ b/gerbview/dcode.cpp
@@ -448,6 +448,6 @@ static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon, APERTURE_DEF_HOLETYPE aH
         holeBuffer.Append( VECTOR2I( currpos ) );       // close hole
     }
 
-    aPolygon->BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );
-    aPolygon->Fracture( SHAPE_POLY_SET::PM_FAST );
+    aPolygon->BooleanSubtract( holeBuffer );
+    aPolygon->Fracture();
 }
diff --git a/gerbview/export_to_pcbnew.cpp b/gerbview/export_to_pcbnew.cpp
index b5045ada3b..49f7363edb 100644
--- a/gerbview/export_to_pcbnew.cpp
+++ b/gerbview/export_to_pcbnew.cpp
@@ -574,7 +574,7 @@ void GBR_TO_PCB_EXPORTER::writePcbPolygon( const SHAPE_POLY_SET& aPolys, int aLa
 void GBR_TO_PCB_EXPORTER::writePcbZoneItem( const GERBER_DRAW_ITEM* aGbrItem, int aLayer )
 {
     SHAPE_POLY_SET polys = aGbrItem->m_ShapeAsPolygon.CloneDropTriangulation();
-    polys.Simplify( SHAPE_POLY_SET::PM_FAST );
+    polys.Simplify();
 
     if( polys.OutlineCount() == 0 )
         return;
diff --git a/include/advanced_config.h b/include/advanced_config.h
index 508ba79b69..370101bc09 100644
--- a/include/advanced_config.h
+++ b/include/advanced_config.h
@@ -428,15 +428,6 @@ public:
      */
     double m_3DRT_BevelExtentFactor;
 
-    /**
-     * Use Clipper2 instead of Clipper1.
-     *
-     * Setting name: "UseClipper2"
-     * Valid values: 0 or 1
-     * Default value: 1
-     */
-    bool m_UseClipper2;
-
     /**
      * Use the 3DConnexion Driver.
      *
diff --git a/include/eda_shape.h b/include/eda_shape.h
index c7102a74f9..dd56e7bf79 100644
--- a/include/eda_shape.h
+++ b/include/eda_shape.h
@@ -299,7 +299,7 @@ public:
         {
             if( m_poly.HoleCount( ii ) )
             {
-                m_poly.Fracture( SHAPE_POLY_SET::PM_FAST );
+                m_poly.Fracture();
                 break;
             }
         }
diff --git a/libs/kimath/CMakeLists.txt b/libs/kimath/CMakeLists.txt
index 5311ff6399..7aa20b991e 100644
--- a/libs/kimath/CMakeLists.txt
+++ b/libs/kimath/CMakeLists.txt
@@ -51,7 +51,6 @@ add_library( kimath STATIC
 
 target_link_libraries( kimath
     core
-    clipper
     clipper2
     othermath
     rtree
diff --git a/libs/kimath/include/geometry/polygon_triangulation.h b/libs/kimath/include/geometry/polygon_triangulation.h
index fd5ea3e9df..651958f424 100644
--- a/libs/kimath/include/geometry/polygon_triangulation.h
+++ b/libs/kimath/include/geometry/polygon_triangulation.h
@@ -51,7 +51,6 @@
 #include <cmath>
 
 #include <advanced_config.h>
-#include <clipper.hpp>
 #include <geometry/shape_line_chain.h>
 #include <geometry/shape_poly_set.h>
 #include <geometry/vertex_set.h>
diff --git a/libs/kimath/include/geometry/shape_line_chain.h b/libs/kimath/include/geometry/shape_line_chain.h
index da0e09d08f..bd8b123059 100644
--- a/libs/kimath/include/geometry/shape_line_chain.h
+++ b/libs/kimath/include/geometry/shape_line_chain.h
@@ -27,7 +27,6 @@
 #define __SHAPE_LINE_CHAIN
 
 
-#include <clipper.hpp>
 #include <clipper2/clipper.h>
 #include <geometry/seg.h>
 #include <geometry/shape.h>
@@ -37,7 +36,7 @@
 
 /**
  * Holds information on each point of a SHAPE_LINE_CHAIN that is retrievable
- * after an operation with ClipperLib
+ * after an operation with Clipper2Lib
  */
 struct CLIPPER_Z_VALUE
 {
@@ -176,10 +175,6 @@ public:
 
     SHAPE_LINE_CHAIN( const SHAPE_ARC& aArc, bool aClosed = false );
 
-    SHAPE_LINE_CHAIN( const ClipperLib::Path& aPath,
-                      const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
-                      const std::vector<SHAPE_ARC>& aArcBuffer );
-
     SHAPE_LINE_CHAIN( const Clipper2Lib::Path64& aPath,
                       const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
                       const std::vector<SHAPE_ARC>& aArcBuffer );
@@ -920,13 +915,6 @@ protected:
             return m_shapes[aSegment].second;
     }
 
-    /**
-     * Create a new Clipper path from the SHAPE_LINE_CHAIN in a given orientation
-     */
-    ClipperLib::Path convertToClipper( bool aRequiredOrientation,
-                                       std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
-                                       std::vector<SHAPE_ARC>&       aArcBuffer ) const;
-
     /**
      * Create a new Clipper2 path from the SHAPE_LINE_CHAIN in a given orientation
      */
diff --git a/libs/kimath/include/geometry/shape_poly_set.h b/libs/kimath/include/geometry/shape_poly_set.h
index 0222f144ed..5ee469a011 100644
--- a/libs/kimath/include/geometry/shape_poly_set.h
+++ b/libs/kimath/include/geometry/shape_poly_set.h
@@ -39,7 +39,6 @@
 #include <stdlib.h>                     // for abs
 #include <vector>
 
-#include <clipper.hpp>                  // for ClipType, PolyTree (ptr only)
 #include <clipper2/clipper.h>
 #include <core/mirror.h>                // for FLIP_DIRECTION
 #include <geometry/corner_strategy.h>
@@ -986,55 +985,30 @@ public:
         return CIterateSegments( aOutline, aOutline, true );
     }
 
-    /**
-     * Operations on polygons use a \a aFastMode param
-     * if aFastMode is #PM_FAST (true) the result can be a weak polygon
-     * if aFastMode is #PM_STRICTLY_SIMPLE (false) (default) the result is (theoretically) a
-     * strictly simple polygon, but calculations can be really significantly time consuming
-     * Most of time #PM_FAST is preferable.
-     * #PM_STRICTLY_SIMPLE can be used in critical cases (Gerber output for instance)
-     */
-    enum POLYGON_MODE
-    {
-        PM_FAST = true,
-        PM_STRICTLY_SIMPLE = false
-    };
 
     /// Perform boolean polyset union
-    /// For \a aFastMode meaning, see function booleanOp
-    void BooleanAdd( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode );
+    void BooleanAdd( const SHAPE_POLY_SET& b );
 
     /// Perform boolean polyset difference
-    /// For \a aFastMode meaning, see function booleanOp
-    void BooleanSubtract( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode );
+    void BooleanSubtract( const SHAPE_POLY_SET& b );
 
     /// Perform boolean polyset intersection
-    /// For \a aFastMode meaning, see function booleanOp
-    void BooleanIntersection( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode );
+    void BooleanIntersection( const SHAPE_POLY_SET& b );
 
     /// Perform boolean polyset exclusive or
-    /// For \a aFastMode meaning, see function booleanOp
-    void BooleanXor( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode );
+    void BooleanXor( const SHAPE_POLY_SET& b );
 
     /// Perform boolean polyset union between a and b, store the result in it self
-    /// For \a aFastMode meaning, see function booleanOp
-    void BooleanAdd( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
-                     POLYGON_MODE aFastMode );
+    void BooleanAdd( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b );
 
     /// Perform boolean polyset difference between a and b, store the result in it self
-    /// For \a aFastMode meaning, see function booleanOp
-    void BooleanSubtract( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
-                          POLYGON_MODE aFastMode );
+    void BooleanSubtract( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b );
 
     /// Perform boolean polyset intersection between a and b, store the result in it self
-    /// For \a aFastMode meaning, see function booleanOp
-    void BooleanIntersection( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
-                              POLYGON_MODE aFastMode );
+    void BooleanIntersection( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b );
 
     /// Perform boolean polyset exclusive or between a and b, store the result in it self
-    /// For \a aFastMode meaning, see function booleanOp
-    void BooleanXor( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
-                              POLYGON_MODE aFastMode );
+    void BooleanXor( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b );
 
     /**
     * Extract all contours from this polygon set, then recreate polygons with holes.
@@ -1085,20 +1059,17 @@ public:
      * Perform outline inflation/deflation, using round corners.
      *
      * Polygons can have holes and/or linked holes with main outlines.  The resulting
-     * polygons are also polygons with linked holes to main outlines.  For \a aFastMode
-     * meaning, see function booleanOp  .
+     * polygons are also polygons with linked holes to main outlines.
      */
-    void InflateWithLinkedHoles( int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError,
-                                 POLYGON_MODE aFastMode );
+    void InflateWithLinkedHoles( int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError );
 
     /// Convert a set of polygons with holes to a single outline with "slits"/"fractures"
     /// connecting the outer ring to the inner holes
-    /// For \a aFastMode meaning, see function booleanOp
-    void Fracture( POLYGON_MODE aFastMode );
+    void Fracture();
 
     /// Convert a single outline slitted ("fractured") polygon into a set ouf outlines
     /// with holes.
-    void Unfracture( POLYGON_MODE aFastMode );
+    void Unfracture();
 
     /// Return true if the polygon set has any holes.
     bool HasHoles() const;
@@ -1108,8 +1079,7 @@ public:
 
 
     /// Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
-    /// For \a aFastMode meaning, see function booleanOp
-    void Simplify( POLYGON_MODE aFastMode );
+    void Simplify();
 
     /**
      * Simplifies the lines in the polyset.  This checks intermediate points to see if they are
@@ -1464,11 +1434,9 @@ public:
      * Build a SHAPE_POLY_SET from a bunch of outlines in provided in random order.
      *
      * @param aPath set of closed outlines forming the polygon. Positive orientation = outline, negative = hole
-     * @param aReverseOrientation inverts the sign of the orientation of aPaths (so negative = outline)
      * @param aEvenOdd forces the even-off fill rule (default is non zero)
-     * @return the constructed poly set
      */
-    static const SHAPE_POLY_SET BuildPolysetFromOrientedPaths( const std::vector<SHAPE_LINE_CHAIN>& aPaths, bool aReverseOrientation = false, bool aEvenOdd = false );
+    void BuildPolysetFromOrientedPaths( const std::vector<SHAPE_LINE_CHAIN>& aPaths, bool aEvenOdd = false );
 
     void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
                              ERROR_LOC aErrorLoc ) const override
@@ -1487,9 +1455,6 @@ private:
 
     void fractureSingle( POLYGON& paths );
     void unfractureSingle ( POLYGON& path );
-    void importTree( ClipperLib::PolyTree*               tree,
-                     const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
-                     const std::vector<SHAPE_ARC>&       aArcBuffe );
     void importTree( Clipper2Lib::PolyTree64&            tree,
                      const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
                      const std::vector<SHAPE_ARC>&       aArcBuffe );
@@ -1500,7 +1465,6 @@ private:
                      const std::vector<CLIPPER_Z_VALUE>&                 aZValueBuffer,
                      const std::vector<SHAPE_ARC>&                       aArcBuffer );
 
-    void inflate1( int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy );
     void inflate2( int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy, bool aSimplify = false );
 
     void inflateLine2( const SHAPE_LINE_CHAIN& aLine, int aAmount, int aCircleSegCount,
@@ -1510,20 +1474,9 @@ private:
      * This is the engine to execute all polygon boolean transforms (AND, OR, ... and polygon
      * simplification (merging overlapping  polygons).
      *
-     * @param aType is the transform type ( see ClipperLib::ClipType )
+     * @param aType is the transform type ( see Clipper2Lib::ClipType )
      * @param aOtherShape is the SHAPE_LINE_CHAIN to combine with me.
-     * @param aFastMode is an option to choose if the result can be a weak polygon
-     * or a strictly simple polygon.
-     * if aFastMode is PM_FAST the result can be a weak polygon
-     * if aFastMode is PM_STRICTLY_SIMPLE (default) the result is (theoretically) a strictly
-     * simple polygon, but calculations can be really significantly time consuming
      */
-    void booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aOtherShape,
-                    POLYGON_MODE aFastMode );
-
-    void booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aShape,
-                    const SHAPE_POLY_SET& aOtherShape, POLYGON_MODE aFastMode );
-
     void booleanOp( Clipper2Lib::ClipType aType, const SHAPE_POLY_SET& aOtherShape );
 
     void booleanOp( Clipper2Lib::ClipType aType, const SHAPE_POLY_SET& aShape,
diff --git a/libs/kimath/src/convert_basic_shapes_to_polygon.cpp b/libs/kimath/src/convert_basic_shapes_to_polygon.cpp
index c6ebe4ae9e..aabe133fdd 100644
--- a/libs/kimath/src/convert_basic_shapes_to_polygon.cpp
+++ b/libs/kimath/src/convert_basic_shapes_to_polygon.cpp
@@ -214,7 +214,7 @@ void TransformOvalToPolygon( SHAPE_POLY_SET& aBuffer, const VECTOR2I& aStart, co
     bbox.Append( corner.x, corner.y );
 
     // Now, clamp the shape
-    polyshape.BooleanIntersection( bbox, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    polyshape.BooleanIntersection( bbox );
     // Note the final polygon is a simple, convex polygon with no hole
     // due to the shape of initial polygons
 
@@ -663,6 +663,6 @@ void TransformRingToPolygon( SHAPE_POLY_SET& aBuffer, const VECTOR2I& aCentre, i
     TransformCircleToPolygon( buffer.Hole( 0, 0 ), aCentre, inner_radius,
                               aError, inner_err_loc );
 
-    buffer.Fracture( SHAPE_POLY_SET::PM_FAST );
+    buffer.Fracture();
     aBuffer.Append( buffer );
 }
diff --git a/libs/kimath/src/geometry/shape_line_chain.cpp b/libs/kimath/src/geometry/shape_line_chain.cpp
index 412048edf6..4264a99b9a 100644
--- a/libs/kimath/src/geometry/shape_line_chain.cpp
+++ b/libs/kimath/src/geometry/shape_line_chain.cpp
@@ -29,7 +29,6 @@
 #include <map>
 #include <string>            // for basic_string
 
-#include <clipper.hpp>
 #include <clipper2/clipper.h>
 #include <core/kicad_algo.h> // for alg::run_on_pair
 #include <geometry/circle.h>
@@ -79,50 +78,6 @@ SHAPE_LINE_CHAIN::SHAPE_LINE_CHAIN( const SHAPE_ARC& aArc, bool aClosed ) :
 }
 
 
-SHAPE_LINE_CHAIN::SHAPE_LINE_CHAIN( const ClipperLib::Path&             aPath,
-                                    const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
-                                    const std::vector<SHAPE_ARC>&       aArcBuffer ) :
-        SHAPE_LINE_CHAIN_BASE( SH_LINE_CHAIN ),
-        m_closed( true ), m_width( 0 )
-{
-    std::map<ssize_t, ssize_t> loadedArcs;
-    m_points.reserve( aPath.size() );
-    m_shapes.reserve( aPath.size() );
-
-    auto loadArc =
-        [&]( ssize_t aArcIndex ) -> ssize_t
-        {
-            if( aArcIndex == SHAPE_IS_PT )
-            {
-                return SHAPE_IS_PT;
-            }
-            else if( loadedArcs.count( aArcIndex ) == 0 )
-            {
-                loadedArcs.insert( { aArcIndex, m_arcs.size() } );
-                m_arcs.push_back( aArcBuffer.at( aArcIndex ) );
-            }
-
-            return loadedArcs.at( aArcIndex );
-        };
-
-    for( size_t ii = 0; ii < aPath.size(); ++ii )
-    {
-        Append( aPath[ii].X, aPath[ii].Y );
-
-        m_shapes[ii].first = loadArc( aZValueBuffer[aPath[ii].Z].m_FirstArcIdx );
-        m_shapes[ii].second = loadArc( aZValueBuffer[aPath[ii].Z].m_SecondArcIdx );
-    }
-
-    // Clipper shouldn't return duplicate contiguous points. if it did, these would be
-    // removed during Append() and we would have different number of shapes to points
-    wxASSERT( m_shapes.size() == m_points.size() );
-
-    // Clipper might mess up the rotation of the indices such that an arc can be split between
-    // the end point and wrap around to the start point. Lets fix the indices up now
-    fixIndicesRotation();
-}
-
-
 SHAPE_LINE_CHAIN::SHAPE_LINE_CHAIN( const Clipper2Lib::Path64&          aPath,
                                     const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
                                     const std::vector<SHAPE_ARC>&       aArcBuffer ) :
@@ -167,40 +122,6 @@ SHAPE_LINE_CHAIN::SHAPE_LINE_CHAIN( const Clipper2Lib::Path64&          aPath,
 }
 
 
-ClipperLib::Path SHAPE_LINE_CHAIN::convertToClipper( bool aRequiredOrientation,
-                                                     std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
-                                                     std::vector<SHAPE_ARC>& aArcBuffer ) const
-{
-    ClipperLib::Path c_path;
-    SHAPE_LINE_CHAIN input;
-    bool             orientation = Area( false ) >= 0;
-    ssize_t          shape_offset = aArcBuffer.size();
-
-    if( orientation != aRequiredOrientation )
-        input = Reverse();
-    else
-        input = *this;
-
-    int pointCount = input.PointCount();
-    c_path.reserve( pointCount );
-
-    for( int i = 0; i < pointCount; i++ )
-    {
-        const VECTOR2I& vertex = input.CPoint( i );
-
-        CLIPPER_Z_VALUE z_value( input.m_shapes[i], shape_offset );
-        size_t          z_value_ptr = aZValueBuffer.size();
-        aZValueBuffer.push_back( z_value );
-
-        c_path.emplace_back( vertex.x, vertex.y, z_value_ptr );
-    }
-
-    aArcBuffer.insert( aArcBuffer.end(), input.m_arcs.begin(), input.m_arcs.end() );
-
-    return c_path;
-}
-
-
 Clipper2Lib::Path64 SHAPE_LINE_CHAIN::convertToClipper2( bool aRequiredOrientation,
                                                      std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
                                                      std::vector<SHAPE_ARC>& aArcBuffer ) const
diff --git a/libs/kimath/src/geometry/shape_poly_set.cpp b/libs/kimath/src/geometry/shape_poly_set.cpp
index 1a9045b410..630059b131 100644
--- a/libs/kimath/src/geometry/shape_poly_set.cpp
+++ b/libs/kimath/src/geometry/shape_poly_set.cpp
@@ -744,118 +744,6 @@ void SHAPE_POLY_SET::RebuildHolesFromContours()
 }
 
 
-void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aOtherShape,
-                                POLYGON_MODE aFastMode )
-{
-    booleanOp( aType, *this, aOtherShape, aFastMode );
-}
-
-
-void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aShape,
-                                const SHAPE_POLY_SET& aOtherShape, POLYGON_MODE aFastMode )
-{
-    if( ( aShape.OutlineCount() > 1 || aOtherShape.OutlineCount() > 0 )
-        && ( aShape.ArcCount() > 0 || aOtherShape.ArcCount() > 0 ) )
-    {
-        wxFAIL_MSG( wxT( "Boolean ops on curved polygons are not supported. You should call "
-                         "ClearArcs() before carrying out the boolean operation." ) );
-    }
-
-    ClipperLib::Clipper c;
-
-    c.StrictlySimple( aFastMode == PM_STRICTLY_SIMPLE );
-
-    std::vector<CLIPPER_Z_VALUE> zValues;
-    std::vector<SHAPE_ARC> arcBuffer;
-    std::map<VECTOR2I, CLIPPER_Z_VALUE> newIntersectPoints;
-
-    for( const POLYGON& poly : aShape.m_polys )
-    {
-        for( size_t i = 0; i < poly.size(); i++ )
-        {
-            c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
-                       ClipperLib::ptSubject, true );
-        }
-    }
-
-    for( const POLYGON& poly : aOtherShape.m_polys )
-    {
-        for( size_t i = 0; i < poly.size(); i++ )
-        {
-            c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
-                       ClipperLib::ptClip, true );
-        }
-    }
-
-    ClipperLib::PolyTree solution;
-
-    ClipperLib::ZFillCallback callback =
-            [&]( ClipperLib::IntPoint & e1bot, ClipperLib::IntPoint & e1top,
-                ClipperLib::IntPoint & e2bot, ClipperLib::IntPoint & e2top,
-                ClipperLib::IntPoint & pt )
-            {
-                auto arcIndex =
-                    [&]( const ssize_t& aZvalue, const ssize_t& aCompareVal = -1 ) -> ssize_t
-                    {
-                        ssize_t retval;
-
-                        retval = zValues.at( aZvalue ).m_SecondArcIdx;
-
-                        if( retval == -1 || ( aCompareVal > 0 && retval != aCompareVal ) )
-                            retval = zValues.at( aZvalue ).m_FirstArcIdx;
-
-                        return retval;
-                    };
-
-                auto arcSegment =
-                    [&]( const ssize_t& aBottomZ, const ssize_t aTopZ ) -> ssize_t
-                    {
-                        ssize_t retval = arcIndex( aBottomZ );
-
-                        if( retval != -1 )
-                        {
-                            if( retval != arcIndex( aTopZ, retval ) )
-                                retval = -1; // Not an arc segment as the two indices do not match
-                        }
-
-                        return retval;
-                    };
-
-                ssize_t e1ArcSegmentIndex = arcSegment( e1bot.Z, e1top.Z );
-                ssize_t e2ArcSegmentIndex = arcSegment( e2bot.Z, e2top.Z );
-
-                CLIPPER_Z_VALUE newZval;
-
-                if( e1ArcSegmentIndex != -1 )
-                {
-                    newZval.m_FirstArcIdx = e1ArcSegmentIndex;
-                    newZval.m_SecondArcIdx = e2ArcSegmentIndex;
-                }
-                else
-                {
-                    newZval.m_FirstArcIdx = e2ArcSegmentIndex;
-                    newZval.m_SecondArcIdx = -1;
-                }
-
-                size_t z_value_ptr = zValues.size();
-                zValues.push_back( newZval );
-
-                // Only worry about arc segments for later processing
-                if( newZval.m_FirstArcIdx != -1 )
-                    newIntersectPoints.insert( { VECTOR2I( pt.X, pt.Y ), newZval } );
-
-                pt.Z = z_value_ptr;
-                //@todo amend X,Y values to true intersection between arcs or arc and segment
-            };
-
-    c.ZFillFunction( std::move( callback ) ); // register callback
-
-    c.Execute( aType, solution, ClipperLib::pftNonZero, ClipperLib::pftNonZero );
-
-    importTree( &solution, zValues, arcBuffer );
-}
-
-
 void SHAPE_POLY_SET::booleanOp( Clipper2Lib::ClipType aType, const SHAPE_POLY_SET& aOtherShape )
 {
     booleanOp( aType, *this, aOtherShape );
@@ -970,155 +858,60 @@ void SHAPE_POLY_SET::booleanOp( Clipper2Lib::ClipType aType, const SHAPE_POLY_SE
 }
 
 
-void SHAPE_POLY_SET::BooleanAdd( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::BooleanAdd( const SHAPE_POLY_SET& b )
 {
     booleanOp( Clipper2Lib::ClipType::Union, b );
 }
 
 
-void SHAPE_POLY_SET::BooleanSubtract( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::BooleanSubtract( const SHAPE_POLY_SET& b )
 {
     booleanOp( Clipper2Lib::ClipType::Difference, b );
 }
 
 
-void SHAPE_POLY_SET::BooleanIntersection( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::BooleanIntersection( const SHAPE_POLY_SET& b )
 {
     booleanOp( Clipper2Lib::ClipType::Intersection, b );
 }
 
 
-void SHAPE_POLY_SET::BooleanXor( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::BooleanXor( const SHAPE_POLY_SET& b )
 {
     booleanOp( Clipper2Lib::ClipType::Xor, b );
 }
 
 
-void SHAPE_POLY_SET::BooleanAdd( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
-                                 POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::BooleanAdd( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b )
 {
     booleanOp( Clipper2Lib::ClipType::Union, a, b );
 }
 
 
-void SHAPE_POLY_SET::BooleanSubtract( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
-                                      POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::BooleanSubtract( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b )
 {
     booleanOp( Clipper2Lib::ClipType::Difference, a, b );
 }
 
 
-void SHAPE_POLY_SET::BooleanIntersection( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
-                                          POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::BooleanIntersection( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b )
 {
     booleanOp( Clipper2Lib::ClipType::Intersection, a, b );
 }
 
 
-void SHAPE_POLY_SET::BooleanXor( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
-                                          POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::BooleanXor( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b )
 {
     booleanOp( Clipper2Lib::ClipType::Xor, a, b );
 }
 
 
 void SHAPE_POLY_SET::InflateWithLinkedHoles( int aFactor, CORNER_STRATEGY aCornerStrategy,
-                                             int aMaxError, POLYGON_MODE aFastMode )
+                                             int aMaxError )
 {
-    Unfracture( aFastMode );
+    Unfracture();
     Inflate( aFactor, aCornerStrategy, aMaxError );
-    Fracture( aFastMode );
-}
-
-
-void SHAPE_POLY_SET::inflate1( int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy )
-{
-    using namespace ClipperLib;
-    // A static table to avoid repetitive calculations of the coefficient
-    // 1.0 - cos( M_PI / aCircleSegCount )
-    // aCircleSegCount is most of time <= 64 and usually 8, 12, 16, 32
-    #define SEG_CNT_MAX 64
-    static double arc_tolerance_factor[SEG_CNT_MAX + 1];
-
-    ClipperOffset c;
-
-    // N.B. see the Clipper documentation for jtSquare/jtMiter/jtRound.  They are poorly named
-    // and are not what you'd think they are.
-    // http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/JoinType.htm
-    JoinType joinType = jtRound;    // The way corners are offsetted
-    double   miterLimit = 2.0;      // Smaller value when using jtMiter for joinType
-    JoinType miterFallback = jtSquare;
-
-    switch( aCornerStrategy )
-    {
-    case CORNER_STRATEGY::ALLOW_ACUTE_CORNERS:
-        joinType = jtMiter;
-        miterLimit = 10;        // Allows large spikes
-        miterFallback = jtSquare;
-        break;
-
-    case CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS: // Acute angles are chamfered
-        joinType = jtMiter;
-        miterFallback = jtRound;
-        break;
-
-    case CORNER_STRATEGY::ROUND_ACUTE_CORNERS: // Acute angles are rounded
-        joinType = jtMiter;
-        miterFallback = jtSquare;
-        break;
-
-    case CORNER_STRATEGY::CHAMFER_ALL_CORNERS: // All angles are chamfered.
-        joinType = jtSquare;
-        miterFallback = jtSquare;
-        break;
-
-    case CORNER_STRATEGY::ROUND_ALL_CORNERS: // All angles are rounded.
-        joinType = jtRound;
-        miterFallback = jtSquare;
-        break;
-    }
-
-    std::vector<CLIPPER_Z_VALUE> zValues;
-    std::vector<SHAPE_ARC>       arcBuffer;
-
-    for( const POLYGON& poly : m_polys )
-    {
-        for( size_t i = 0; i < poly.size(); i++ )
-        {
-            c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
-                       joinType, etClosedPolygon );
-        }
-    }
-
-    PolyTree solution;
-
-    // Calculate the arc tolerance (arc error) from the seg count by circle. The seg count is
-    // nn = M_PI / acos(1.0 - c.ArcTolerance / abs(aAmount))
-    // http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/Properties/ArcTolerance.htm
-
-    if( aCircleSegCount < 6 ) // avoid incorrect aCircleSegCount values
-        aCircleSegCount = 6;
-
-    double coeff;
-
-    if( aCircleSegCount > SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
-    {
-        coeff = 1.0 - cos( M_PI / aCircleSegCount );
-
-        if( aCircleSegCount <= SEG_CNT_MAX )
-            arc_tolerance_factor[aCircleSegCount] = coeff;
-    }
-    else
-    {
-        coeff = arc_tolerance_factor[aCircleSegCount];
-    }
-
-    c.ArcTolerance = std::abs( aAmount ) * coeff;
-    c.MiterLimit = miterLimit;
-    c.MiterFallback = miterFallback;
-    c.Execute( solution, aAmount );
-
-    importTree( &solution, zValues, arcBuffer );
+    Fracture();
 }
 
 
@@ -1341,30 +1134,6 @@ void SHAPE_POLY_SET::OffsetLineChain( const SHAPE_LINE_CHAIN& aLine, int aAmount
 }
 
 
-void SHAPE_POLY_SET::importTree( ClipperLib::PolyTree*               tree,
-                                 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
-                                 const std::vector<SHAPE_ARC>&       aArcBuffer )
-{
-    m_polys.clear();
-
-    for( ClipperLib::PolyNode* n = tree->GetFirst(); n; n = n->GetNext() )
-    {
-        if( !n->IsHole() )
-        {
-            POLYGON paths;
-            paths.reserve( n->Childs.size() + 1 );
-
-            paths.emplace_back( n->Contour, aZValueBuffer, aArcBuffer );
-
-            for( unsigned int i = 0; i < n->Childs.size(); i++ )
-                paths.emplace_back( n->Childs[i]->Contour, aZValueBuffer, aArcBuffer );
-
-            m_polys.push_back( paths );
-        }
-    }
-}
-
-
 void SHAPE_POLY_SET::importPolyPath( const std::unique_ptr<Clipper2Lib::PolyPath64>& aPolyPath,
                                      const std::vector<CLIPPER_Z_VALUE>&             aZValueBuffer,
                                      const std::vector<SHAPE_ARC>&                   aArcBuffer )
@@ -1886,9 +1655,9 @@ void SHAPE_POLY_SET::fractureSingle( POLYGON& paths )
 }
 
 
-void SHAPE_POLY_SET::Fracture( POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::Fracture()
 {
-    Simplify( aFastMode );    // remove overlapping holes/degeneracy
+    Simplify();    // remove overlapping holes/degeneracy
 
     for( POLYGON& paths : m_polys )
         fractureSingle( paths );
@@ -2077,16 +1846,16 @@ bool SHAPE_POLY_SET::HasHoles() const
 }
 
 
-void SHAPE_POLY_SET::Unfracture( POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::Unfracture()
 {
     for( POLYGON& path : m_polys )
         unfractureSingle( path );
 
-    Simplify( aFastMode );    // remove overlapping holes/degeneracy
+    Simplify();    // remove overlapping holes/degeneracy
 }
 
 
-void SHAPE_POLY_SET::Simplify( POLYGON_MODE aFastMode )
+void SHAPE_POLY_SET::Simplify()
 {
     SHAPE_POLY_SET empty;
 
@@ -2110,7 +1879,7 @@ int SHAPE_POLY_SET::NormalizeAreaOutlines()
 {
     // We are expecting only one main outline, but this main outline can have holes
     // if holes: combine holes and remove them from the main outline.
-    // Note also we are using SHAPE_POLY_SET::PM_STRICTLY_SIMPLE in polygon
+    // Note also we are usingin polygon
     // calculations, but it is not mandatory. It is used mainly
     // because there is usually only very few vertices in area outlines
     SHAPE_POLY_SET::POLYGON& outline = Polygon( 0 );
@@ -2124,13 +1893,13 @@ int SHAPE_POLY_SET::NormalizeAreaOutlines()
         outline.pop_back();
     }
 
-    Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    Simplify();
 
     // If any hole, subtract it to main outline
     if( holesBuffer.OutlineCount() )
     {
-        holesBuffer.Simplify( SHAPE_POLY_SET::PM_FAST );
-        BooleanSubtract( holesBuffer, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+        holesBuffer.Simplify();
+        BooleanSubtract( holesBuffer );
     }
 
     // In degenerate cases, simplify might return no outlines
@@ -3210,10 +2979,10 @@ static SHAPE_POLY_SET partitionPolyIntoRegularCellGrid( const SHAPE_POLY_SET& aP
         }
     }
 
-    ps1.BooleanIntersection( maskSetOdd, SHAPE_POLY_SET::PM_FAST );
-    ps2.BooleanIntersection( maskSetEven, SHAPE_POLY_SET::PM_FAST );
-    ps1.Fracture( SHAPE_POLY_SET::PM_FAST );
-    ps2.Fracture( SHAPE_POLY_SET::PM_FAST );
+    ps1.BooleanIntersection( maskSetOdd );
+    ps2.BooleanIntersection( maskSetEven );
+    ps1.Fracture();
+    ps2.Fracture();
 
     for( int i = 0; i < ps2.OutlineCount(); i++ )
         ps1.AddOutline( ps2.COutline( i ) );
@@ -3269,10 +3038,6 @@ void SHAPE_POLY_SET::cacheTriangulation( bool aPartition, bool aSimplify,
                         ++pass;
 
                         if( pass == 1 )
-                        {
-                            polySet.Fracture( PM_FAST );
-                        }
-                        else if( pass == 2 )
                         {
                             polySet.SimplifyOutlines( TRIANGULATESIMPLIFICATIONLEVEL );
                         }
@@ -3310,9 +3075,9 @@ void SHAPE_POLY_SET::cacheTriangulation( bool aPartition, bool aSimplify,
             flattened.ClearArcs();
 
             if( flattened.HasHoles() || flattened.IsSelfIntersecting() )
-                flattened.Fracture( PM_FAST );
+                flattened.Fracture();
             else if( aSimplify )
-                flattened.Simplify( PM_FAST );
+                flattened.Simplify();
 
             SHAPE_POLY_SET partitions = partitionPolyIntoRegularCellGrid( flattened, 1e7 );
 
@@ -3336,8 +3101,7 @@ void SHAPE_POLY_SET::cacheTriangulation( bool aPartition, bool aSimplify,
         SHAPE_POLY_SET tmpSet( *this );
 
         tmpSet.ClearArcs();
-
-        tmpSet.Fracture( PM_FAST );
+        tmpSet.Fracture();
 
         if( !triangulate( tmpSet, -1, m_triangulatedPolys, aHintData ) )
         {
@@ -3498,55 +3262,35 @@ SHAPE_POLY_SET::TRIANGULATED_POLYGON::~TRIANGULATED_POLYGON()
 }
 
 
-const SHAPE_POLY_SET
+void
 SHAPE_POLY_SET::BuildPolysetFromOrientedPaths( const std::vector<SHAPE_LINE_CHAIN>& aPaths,
-                                               bool aReverseOrientation, bool aEvenOdd )
+                                               bool                                 aEvenOdd )
 {
-    ClipperLib::Clipper  clipper;
-    ClipperLib::PolyTree tree;
-
-    // fixme: do we need aReverseOrientation?
+    Clipper2Lib::Clipper64 clipper;
+    Clipper2Lib::PolyTree64 tree;
+    Clipper2Lib::Paths64 paths;
 
     for( const SHAPE_LINE_CHAIN& path : aPaths )
     {
-        ClipperLib::Path lc;
+        Clipper2Lib::Path64 lc;
+        lc.reserve( path.PointCount() );
 
         for( int i = 0; i < path.PointCount(); i++ )
-        {
             lc.emplace_back( path.CPoint( i ).x, path.CPoint( i ).y );
-        }
 
-        clipper.AddPath( lc, ClipperLib::ptSubject, true );
+        paths.push_back( lc );
     }
 
-    clipper.StrictlySimple( true );
-    clipper.Execute( ClipperLib::ctUnion, tree,
-                     aEvenOdd ? ClipperLib::pftEvenOdd : ClipperLib::pftNonZero,
-                     ClipperLib::pftNonZero );
-    SHAPE_POLY_SET result;
+    clipper.AddSubject( paths );
+    clipper.Execute( Clipper2Lib::ClipType::Union, aEvenOdd ? Clipper2Lib::FillRule::EvenOdd
+                                                           : Clipper2Lib::FillRule::NonZero, tree );
 
-    for( ClipperLib::PolyNode* n = tree.GetFirst(); n; n = n->GetNext() )
-    {
-        if( !n->IsHole() )
-        {
-            int outl = result.NewOutline();
 
-            for( unsigned int i = 0; i < n->Contour.size(); i++ )
-                result.Outline( outl ).Append( n->Contour[i].X, n->Contour[i].Y );
+    std::vector<CLIPPER_Z_VALUE> zValues;
+    std::vector<SHAPE_ARC> arcBuffer;
 
-            for( unsigned int i = 0; i < n->Childs.size(); i++ )
-            {
-                int outh = result.NewHole( outl );
-                for( unsigned int j = 0; j < n->Childs[i]->Contour.size(); j++ )
-                {
-                    result.Hole( outl, outh )
-                            .Append( n->Childs[i]->Contour[j].X, n->Childs[i]->Contour[j].Y );
-                }
-            }
-        }
-    }
-
-    return result;
+    importTree( tree, zValues, arcBuffer );
+    tree.Clear(); // Free used memory (not done in dtor)
 }
 
 
diff --git a/pcbnew/autorouter/ar_autoplacer.cpp b/pcbnew/autorouter/ar_autoplacer.cpp
index 8312495d0a..f64d107e92 100644
--- a/pcbnew/autorouter/ar_autoplacer.cpp
+++ b/pcbnew/autorouter/ar_autoplacer.cpp
@@ -146,7 +146,7 @@ bool AR_AUTOPLACER::fillMatrix()
 
     // Create a single board outline:
     SHAPE_POLY_SET brd_shape = m_boardShape.CloneDropTriangulation();
-    brd_shape.Fracture( SHAPE_POLY_SET::PM_FAST );
+    brd_shape.Fracture();
     const SHAPE_LINE_CHAIN& outline = brd_shape.Outline(0);
     const BOX2I& rect = outline.BBox();
 
@@ -393,8 +393,8 @@ void AR_AUTOPLACER::genModuleOnRoutingMatrix( FOOTPRINT* Module )
     buildFpAreas( Module, margin );
 
     // Substract the shape to free areas
-    m_topFreeArea.BooleanSubtract( m_fpAreaTop, SHAPE_POLY_SET::PM_FAST );
-    m_bottomFreeArea.BooleanSubtract( m_fpAreaBottom, SHAPE_POLY_SET::PM_FAST );
+    m_topFreeArea.BooleanSubtract( m_fpAreaTop );
+    m_bottomFreeArea.BooleanSubtract( m_fpAreaBottom );
 }
 
 
@@ -802,7 +802,7 @@ void AR_AUTOPLACER::drawPlacementRoutingMatrix( )
     m_overlay->SetIsStroke( false );
 
     SHAPE_POLY_SET freeArea = m_topFreeArea.CloneDropTriangulation();
-    freeArea.Fracture( SHAPE_POLY_SET::PM_FAST );
+    freeArea.Fracture();
 
     // Draw the free polygon areas, top side:
     if( freeArea.OutlineCount() > 0 )
@@ -814,7 +814,7 @@ void AR_AUTOPLACER::drawPlacementRoutingMatrix( )
     }
 
     freeArea = m_bottomFreeArea;
-    freeArea.Fracture( SHAPE_POLY_SET::PM_FAST );
+    freeArea.Fracture();
 
     // Draw the free polygon areas, bottom side:
     if( freeArea.OutlineCount() > 0 )
diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp
index 1d70be6244..04ae430d7b 100644
--- a/pcbnew/board.cpp
+++ b/pcbnew/board.cpp
@@ -2541,7 +2541,7 @@ bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
     }
 
     // Make polygon strictly simple to avoid issues (especially in 3D viewer)
-    aOutlines.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    aOutlines.Simplify();
 
     return success;
 }
diff --git a/pcbnew/convert_shape_list_to_polygon.cpp b/pcbnew/convert_shape_list_to_polygon.cpp
index c85901b9ee..cb388d23b9 100644
--- a/pcbnew/convert_shape_list_to_polygon.cpp
+++ b/pcbnew/convert_shape_list_to_polygon.cpp
@@ -164,8 +164,7 @@ static bool isCopperOutside( const FOOTPRINT* aFootprint, SHAPE_POLY_SET& aShape
 
                 poly.ClearArcs();
 
-                poly.BooleanIntersection( *pad->GetEffectivePolygon( aLayer, ERROR_INSIDE ),
-                                          SHAPE_POLY_SET::PM_FAST );
+                poly.BooleanIntersection( *pad->GetEffectivePolygon( aLayer, ERROR_INSIDE ) );
 
                 if( poly.OutlineCount() == 0 )
                 {
diff --git a/pcbnew/drc/drc_test_provider_annular_width.cpp b/pcbnew/drc/drc_test_provider_annular_width.cpp
index df06c610a1..cf3ead8f78 100644
--- a/pcbnew/drc/drc_test_provider_annular_width.cpp
+++ b/pcbnew/drc/drc_test_provider_annular_width.cpp
@@ -283,7 +283,7 @@ bool DRC_TEST_PROVIDER_ANNULAR_WIDTH::Run()
                                                 otherPadHoles, 0, maxError, ERROR_INSIDE );
                                     }
 
-                                    otherPadOutline.BooleanSubtract( otherPadHoles, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
+                                    otherPadOutline.BooleanSubtract( otherPadHoles );
 
                                     // If the pad hole under test intersects with another pad outline,
                                     // the annular width calculated above is used.
diff --git a/pcbnew/drc/drc_test_provider_connection_width.cpp b/pcbnew/drc/drc_test_provider_connection_width.cpp
index 53ed29562e..537b863555 100644
--- a/pcbnew/drc/drc_test_provider_connection_width.cpp
+++ b/pcbnew/drc/drc_test_provider_connection_width.cpp
@@ -384,7 +384,7 @@ bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
                                                    ERROR_OUTSIDE );
                 }
 
-                itemsPoly.Poly.Fracture( SHAPE_POLY_SET::PM_FAST );
+                itemsPoly.Poly.Fracture();
 
                 done.fetch_add( calc_effort( itemsPoly.Items, aLayer ) );
 
diff --git a/pcbnew/drc/drc_test_provider_disallow.cpp b/pcbnew/drc/drc_test_provider_disallow.cpp
index e21b881f7a..4129448252 100644
--- a/pcbnew/drc/drc_test_provider_disallow.cpp
+++ b/pcbnew/drc/drc_test_provider_disallow.cpp
@@ -132,7 +132,7 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
                     // exclude it.  This is particularly important for detecting copper fills as
                     // they will be exactly touching along the entire exclusion border.
                     SHAPE_POLY_SET areaPoly = ruleArea->Outline()->CloneDropTriangulation();
-                    areaPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
+                    areaPoly.Fracture();
                     areaPoly.Deflate( epsilon, CORNER_STRATEGY::ALLOW_ACUTE_CORNERS, ARC_LOW_DEF );
 
                     DRC_RTREE* zoneRTree = board->m_CopperZoneRTreeCache[ copperZone ].get();
diff --git a/pcbnew/drc/drc_test_provider_physical_clearance.cpp b/pcbnew/drc/drc_test_provider_physical_clearance.cpp
index cc5db8f2fe..aa844c04be 100644
--- a/pcbnew/drc/drc_test_provider_physical_clearance.cpp
+++ b/pcbnew/drc/drc_test_provider_physical_clearance.cpp
@@ -555,7 +555,7 @@ void DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE::testZoneLayer( ZONE* aZone, PCB_LAYER
     SHAPE_POLY_SET fill = aZone->GetFilledPolysList( aLayer )->CloneDropTriangulation();
 
     // Turn fractured fill into outlines and holes
-    fill.Simplify( SHAPE_POLY_SET::PM_FAST );
+    fill.Simplify();
 
     for( int outlineIdx = 0; outlineIdx < fill.OutlineCount(); ++outlineIdx )
     {
diff --git a/pcbnew/drc/drc_test_provider_sliver_checker.cpp b/pcbnew/drc/drc_test_provider_sliver_checker.cpp
index 344de09212..765a692782 100644
--- a/pcbnew/drc/drc_test_provider_sliver_checker.cpp
+++ b/pcbnew/drc/drc_test_provider_sliver_checker.cpp
@@ -155,7 +155,7 @@ bool DRC_TEST_PROVIDER_SLIVER_CHECKER::Run()
                 if( m_drcEngine->IsCancelled() )
                     return 0;
 
-                poly.Simplify( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
+                poly.Simplify();
 
                 return 1;
             };
diff --git a/pcbnew/drc/drc_test_provider_solder_mask.cpp b/pcbnew/drc/drc_test_provider_solder_mask.cpp
index 77118bf2f5..285362f847 100644
--- a/pcbnew/drc/drc_test_provider_solder_mask.cpp
+++ b/pcbnew/drc/drc_test_provider_solder_mask.cpp
@@ -122,8 +122,7 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::addItemToRTrees( BOARD_ITEM* aItem )
         {
             if( zone->IsOnLayer( layer ) )
             {
-                solderMask->GetFill( layer )->BooleanAdd( *zone->GetFilledPolysList( layer ),
-                                                          SHAPE_POLY_SET::PM_FAST );
+                solderMask->GetFill( layer )->BooleanAdd( *zone->GetFilledPolysList( layer ) );
             }
         }
     }
@@ -222,8 +221,8 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::buildRTrees()
                 return true;
             } );
 
-    solderMask->GetFill( F_Mask )->Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
-    solderMask->GetFill( B_Mask )->Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    solderMask->GetFill( F_Mask )->Simplify();
+    solderMask->GetFill( B_Mask )->Simplify();
 
     solderMask->GetFill( F_Mask )->Deflate( m_webWidth / 2, CORNER_STRATEGY::CHAMFER_ALL_CORNERS,
                                             m_maxError );
diff --git a/pcbnew/drc/drc_test_provider_text_dims.cpp b/pcbnew/drc/drc_test_provider_text_dims.cpp
index 7e56ff9a14..1570ae6b69 100644
--- a/pcbnew/drc/drc_test_provider_text_dims.cpp
+++ b/pcbnew/drc/drc_test_provider_text_dims.cpp
@@ -177,7 +177,7 @@ bool DRC_TEST_PROVIDER_TEXT_DIMS::Run()
                         SHAPE_POLY_SET poly = outlineGlyph->CloneDropTriangulation();
                         poly.Deflate( constraint.Value().Min() / 2,
                                       CORNER_STRATEGY::CHAMFER_ALL_CORNERS, ARC_LOW_DEF );
-                        poly.Simplify( SHAPE_POLY_SET::PM_FAST );
+                        poly.Simplify();
 
                         int resultingOutlineCount = poly.OutlineCount();
                         int resultingHoleCount = 0;
diff --git a/pcbnew/exporters/export_hyperlynx.cpp b/pcbnew/exporters/export_hyperlynx.cpp
index 04e22dab22..3a4262ad82 100644
--- a/pcbnew/exporters/export_hyperlynx.cpp
+++ b/pcbnew/exporters/export_hyperlynx.cpp
@@ -502,7 +502,7 @@ bool HYPERLYNX_EXPORTER::writeNetObjects( const std::vector<BOARD_ITEM*>& aObjec
                 const wxString layerName   = m_board->GetLayerName( layer );
                 SHAPE_POLY_SET fill = zone->GetFilledPolysList( layer )->CloneDropTriangulation();
 
-                fill.Simplify( SHAPE_POLY_SET::PM_FAST );
+                fill.Simplify();
 
                 for( int i = 0; i < fill.OutlineCount(); i++ )
                 {
diff --git a/pcbnew/exporters/exporter_vrml.cpp b/pcbnew/exporters/exporter_vrml.cpp
index 4ea84054fb..66d793359d 100644
--- a/pcbnew/exporters/exporter_vrml.cpp
+++ b/pcbnew/exporters/exporter_vrml.cpp
@@ -394,8 +394,8 @@ void EXPORTER_PCB_VRML::ExportVrmlSolderMask()
         outlines = m_pcbOutlines;
         m_board->ConvertBrdLayerToPolygonalContours( pcb_layer, holes );
 
-        outlines.BooleanSubtract( holes, SHAPE_POLY_SET::PM_FAST );
-        outlines.Fracture( SHAPE_POLY_SET::PM_FAST );
+        outlines.BooleanSubtract( holes );
+        outlines.Fracture();
         ExportVrmlPolygonSet( vrmllayer, outlines );
 
         pcb_layer = B_Mask;
@@ -426,8 +426,8 @@ void EXPORTER_PCB_VRML::ExportStandardLayers()
 
         outlines.RemoveAllContours();
         m_board->ConvertBrdLayerToPolygonalContours( pcb_layer[lcnt], outlines );
-        outlines.BooleanIntersection( m_pcbOutlines, SHAPE_POLY_SET::PM_FAST );
-        outlines.Fracture( SHAPE_POLY_SET::PM_FAST );
+        outlines.BooleanIntersection( m_pcbOutlines );
+        outlines.Fracture();
 
         ExportVrmlPolygonSet( vrmllayer[lcnt], outlines );
     }
diff --git a/pcbnew/exporters/step/exporter_step.cpp b/pcbnew/exporters/step/exporter_step.cpp
index fdb518fa50..2fe828941b 100644
--- a/pcbnew/exporters/step/exporter_step.cpp
+++ b/pcbnew/exporters/step/exporter_step.cpp
@@ -463,7 +463,7 @@ void EXPORTER_STEP::buildZones3DShape( VECTOR2D aOrigin )
         {
             SHAPE_POLY_SET fill_shape;
             zone->TransformSolidAreasShapesToPolygon( layer, fill_shape );
-            fill_shape.Unfracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            fill_shape.Unfracture();
 
             fill_shape.SimplifyOutlines( ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel );
 
@@ -640,31 +640,31 @@ bool EXPORTER_STEP::buildBoard3DShapes()
     for( PCB_LAYER_ID pcblayer : m_layersToExport.Seq() )
     {
         SHAPE_POLY_SET poly = m_poly_shapes[pcblayer];
-        poly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+        poly.Simplify();
 
         poly.SimplifyOutlines( pcbIUScale.mmToIU( 0.003 ) );
-        poly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+        poly.Simplify();
 
         SHAPE_POLY_SET holes = m_poly_holes[pcblayer];
-        holes.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+        holes.Simplify();
 
         // Mask layer is negative
         if( pcblayer == F_Mask || pcblayer == B_Mask )
         {
             SHAPE_POLY_SET mask = pcbOutlinesNoArcs;
 
-            mask.BooleanSubtract( poly, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
-            mask.BooleanSubtract( holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            mask.BooleanSubtract( poly );
+            mask.BooleanSubtract( holes );
 
             poly = mask;
         }
         else
         {
             // Subtract holes
-            poly.BooleanSubtract( holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            poly.BooleanSubtract( holes );
 
             // Clip to board outline
-            poly.BooleanIntersection( pcbOutlinesNoArcs, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            poly.BooleanIntersection( pcbOutlinesNoArcs );
         }
 
         m_pcbModel->AddPolygonShapes( &poly, pcblayer, origin );
diff --git a/pcbnew/exporters/step/step_pcb_model.cpp b/pcbnew/exporters/step/step_pcb_model.cpp
index 1ca5fee1cd..a37c667bd6 100644
--- a/pcbnew/exporters/step/step_pcb_model.cpp
+++ b/pcbnew/exporters/step/step_pcb_model.cpp
@@ -1561,7 +1561,7 @@ bool STEP_PCB_MODEL::MakeShapes( std::vector<TopoDS_Shape>& aShapes, const SHAPE
                                  double aThickness, double aZposition, const VECTOR2D& aOrigin )
 {
     SHAPE_POLY_SET workingPoly = aPolySet;
-    workingPoly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    workingPoly.Simplify();
 
     SHAPE_POLY_SET fallbackPoly = workingPoly;
 
diff --git a/pcbnew/footprint.cpp b/pcbnew/footprint.cpp
index 750050354d..561984373e 100644
--- a/pcbnew/footprint.cpp
+++ b/pcbnew/footprint.cpp
@@ -2777,7 +2777,7 @@ double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLEC
             {
                 SHAPE_POLY_SET padPoly;
                 aItem->TransformShapeToPolygon( padPoly, aLayer, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
-                poly.BooleanAdd( padPoly, SHAPE_POLY_SET::PM_FAST );
+                poly.BooleanAdd( padPoly );
             } );
     }
     else
@@ -2837,7 +2837,7 @@ double FOOTPRINT::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const
         }
     }
 
-    coveredRegion.BooleanIntersection( footprintRegion, SHAPE_POLY_SET::PM_FAST );
+    coveredRegion.BooleanIntersection( footprintRegion );
 
     double footprintRegionArea = polygonArea( footprintRegion );
     double uncoveredRegionArea = footprintRegionArea - polygonArea( coveredRegion );
@@ -3327,7 +3327,7 @@ void FOOTPRINT::CheckNetTies( const std::function<void( const BOARD_ITEM* aItem,
             }
         }
 
-        copperOutlines.Simplify( SHAPE_POLY_SET::PM_FAST );
+        copperOutlines.Simplify();
 
         // Index each pad to the outline in the set that it is part of.
 
diff --git a/pcbnew/generators/pcb_tuning_pattern.cpp b/pcbnew/generators/pcb_tuning_pattern.cpp
index e445bdad6a..27ebe860c1 100644
--- a/pcbnew/generators/pcb_tuning_pattern.cpp
+++ b/pcbnew/generators/pcb_tuning_pattern.cpp
@@ -1804,7 +1804,7 @@ SHAPE_LINE_CHAIN PCB_TUNING_PATTERN::getOutline() const
                 }
 
                 SHAPE_POLY_SET merged;
-                merged.BooleanAdd( chain1, chain2, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                merged.BooleanAdd( chain1, chain2 );
 
                 if( merged.OutlineCount() > 0 )
                     return merged.Outline( 0 );
@@ -1832,7 +1832,7 @@ SHAPE_LINE_CHAIN PCB_TUNING_PATTERN::getOutline() const
                                          CORNER_STRATEGY::ROUND_ALL_CORNERS, ARC_LOW_DEF, false );
 
             SHAPE_POLY_SET merged;
-            merged.BooleanAdd( poly, polyCoupled, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            merged.BooleanAdd( poly, polyCoupled );
 
             if( merged.OutlineCount() > 0 )
                 return merged.Outline( 0 );
diff --git a/pcbnew/pad.cpp b/pcbnew/pad.cpp
index 4c96065e4e..04b7b871cd 100644
--- a/pcbnew/pad.cpp
+++ b/pcbnew/pad.cpp
@@ -1956,7 +1956,7 @@ void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
                 aClearance += aMaxError;
 
             outline.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aMaxError );
-            outline.Fracture( SHAPE_POLY_SET::PM_FAST );
+            outline.Fracture();
         }
         else if( aClearance < 0 )
         {
@@ -1965,7 +1965,7 @@ void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
 
             // aClearance is negative so this is actually a deflate
             outline.Inflate( aClearance, CORNER_STRATEGY::ALLOW_ACUTE_CORNERS, aMaxError );
-            outline.Fracture( SHAPE_POLY_SET::PM_FAST );
+            outline.Fracture();
         }
 
         aBuffer.Append( outline );
@@ -2008,7 +2008,7 @@ std::vector<PCB_SHAPE*> PAD::Recombine( bool aIsDryRun, int maxError )
 
                     SHAPE_POLY_SET drawPoly;
                     shape->TransformShapeToPolygon( drawPoly, aLayer, 0, maxError, ERROR_INSIDE );
-                    drawPoly.BooleanIntersection( padPoly, SHAPE_POLY_SET::PM_FAST );
+                    drawPoly.BooleanIntersection( padPoly );
 
                     if( !drawPoly.IsEmpty() )
                         return shape;
@@ -2275,7 +2275,7 @@ void PAD::doCheckPad( PCB_LAYER_ID aLayer, UNITS_PROVIDER* aUnitsProvider,
                                     hole->GetWidth(), ARC_HIGH_DEF, ERROR_OUTSIDE );
 
             SHAPE_POLY_SET copper = padOutline;
-            copper.BooleanSubtract( holeOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
+            copper.BooleanSubtract( holeOutline );
 
             if( copper.IsEmpty() )
             {
@@ -2284,7 +2284,7 @@ void PAD::doCheckPad( PCB_LAYER_ID aLayer, UNITS_PROVIDER* aUnitsProvider,
             else
             {
                 // Test if the pad hole is fully inside the copper area
-                holeOutline.BooleanSubtract( padOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
+                holeOutline.BooleanSubtract( padOutline );
 
                 if( !holeOutline.IsEmpty() )
                     aErrorHandler( DRCE_PADSTACK, _( "(PTH pad hole non fully inside copper)" ) );
diff --git a/pcbnew/pad_custom_shape_functions.cpp b/pcbnew/pad_custom_shape_functions.cpp
index 7b770fe008..68d6814e4b 100644
--- a/pcbnew/pad_custom_shape_functions.cpp
+++ b/pcbnew/pad_custom_shape_functions.cpp
@@ -45,7 +45,7 @@ void PAD::AddPrimitivePoly( PCB_LAYER_ID aLayer, const SHAPE_POLY_SET& aPoly, in
     poly_no_hole.Append( aPoly );
 
     if( poly_no_hole.HasHoles() )
-        poly_no_hole.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+        poly_no_hole.Fracture();
 
     // There should never be multiple shapes, but if there are, we split them into
     // primitives so that we can edit them both.
@@ -142,13 +142,13 @@ void PAD::addPadPrimitivesToPolygon( PCB_LAYER_ID aLayer, SHAPE_POLY_SET* aMerge
             primitive->TransformShapeToPolygon( polyset, UNDEFINED_LAYER, 0, aError, aErrorLoc );
     }
 
-    polyset.Simplify( SHAPE_POLY_SET::PM_FAST );
+    polyset.Simplify();
 
     // Merge all polygons with the initial pad anchor shape
     if( polyset.OutlineCount() )
     {
-        aMergedPolygon->BooleanAdd( polyset, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
-        aMergedPolygon->Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+        aMergedPolygon->BooleanAdd( polyset );
+        aMergedPolygon->Fracture();
     }
 }
 
diff --git a/pcbnew/pcb_base_frame.cpp b/pcbnew/pcb_base_frame.cpp
index 214d4990ce..13480a4343 100644
--- a/pcbnew/pcb_base_frame.cpp
+++ b/pcbnew/pcb_base_frame.cpp
@@ -320,7 +320,7 @@ void PCB_BASE_FRAME::FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID
 
         try
         {
-            viewportPoly.BooleanSubtract( dialogPoly, SHAPE_POLY_SET::PM_FAST );
+            viewportPoly.BooleanSubtract( dialogPoly );
         }
         catch( const std::exception& e )
         {
@@ -426,7 +426,7 @@ void PCB_BASE_FRAME::FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID
 
             try
             {
-                clippedPoly.BooleanIntersection( itemPoly, viewportPoly, SHAPE_POLY_SET::PM_FAST );
+                clippedPoly.BooleanIntersection( itemPoly, viewportPoly );
             }
             catch( const std::exception& e )
             {
diff --git a/pcbnew/pcb_io/altium/altium_pcb.cpp b/pcbnew/pcb_io/altium/altium_pcb.cpp
index f4d106a4f3..09773fe58d 100644
--- a/pcbnew/pcb_io/altium/altium_pcb.cpp
+++ b/pcbnew/pcb_io/altium/altium_pcb.cpp
@@ -598,7 +598,7 @@ void ALTIUM_PCB::Parse( const ALTIUM_PCB_COMPOUND_FILE&                  altiumP
             if( !zone->HasFilledPolysForLayer( layer ) )
                 continue;
 
-            zone->GetFilledPolysList( layer )->Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            zone->GetFilledPolysList( layer )->Fracture();
         }
     }
 
@@ -2824,9 +2824,9 @@ void ALTIUM_PCB::ParseRegions6Data( const ALTIUM_PCB_COMPOUND_FILE&     aAltiumP
             }
 
             if( zone->HasFilledPolysForLayer( klayer ) )
-                fill.BooleanAdd( *zone->GetFill( klayer ), SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                fill.BooleanAdd( *zone->GetFill( klayer ) );
 
-            fill.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            fill.Fracture();
 
             zone->SetFilledPolysList( klayer, fill );
             zone->SetIsFilled( true );
diff --git a/pcbnew/pcb_io/cadstar/cadstar_pcb_archive_loader.cpp b/pcbnew/pcb_io/cadstar/cadstar_pcb_archive_loader.cpp
index c1e618f079..99adba6a47 100644
--- a/pcbnew/pcb_io/cadstar/cadstar_pcb_archive_loader.cpp
+++ b/pcbnew/pcb_io/cadstar/cadstar_pcb_archive_loader.cpp
@@ -2173,7 +2173,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadCoppers()
                     }
 
                     poly.ClearArcs();
-                    fill.BooleanAdd( poly, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                    fill.BooleanAdd( poly );
                 }
 
             }
@@ -2186,11 +2186,10 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadCoppers()
 
             if( pouredZone->HasFilledPolysForLayer( getKiCadLayer( csCopper.LayerID ) ) )
             {
-                fill.BooleanAdd( *pouredZone->GetFill( getKiCadLayer( csCopper.LayerID ) ),
-                                 SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                fill.BooleanAdd( *pouredZone->GetFill( getKiCadLayer( csCopper.LayerID ) ) );
             }
 
-            fill.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            fill.Fracture();
 
             pouredZone->SetFilledPolysList( getKiCadLayer( csCopper.LayerID ), fill );
             pouredZone->SetIsFilled( true );
@@ -2270,7 +2269,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadCoppers()
             zone->SetAssignedPriority( m_zonesMap.size() + 1 ); // Highest priority (always fill first)
 
             SHAPE_POLY_SET fill( *zone->Outline() );
-            fill.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_STRICTLY_SIMPLE );
+            fill.Fracture();
 
             zone->SetFilledPolysList( getKiCadLayer( csCopper.LayerID ), fill );
         }
@@ -2822,7 +2821,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::drawCadstarShape( const SHAPE& aCadstarShape,
                                                                 aScalingFactor, aTransformCentre,
                                                                 aMirrorInvert );
 
-        shapePolys.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_STRICTLY_SIMPLE );
+        shapePolys.Fracture();
 
         shape->SetPolyShape( shapePolys );
         shape->SetStroke( STROKE_PARAMS( aLineThickness, LINE_STYLE::SOLID ) );
@@ -3770,9 +3769,9 @@ bool CADSTAR_PCB_ARCHIVE_LOADER::calculateZonePriorities( PCB_LAYER_ID& aLayer )
             SHAPE_POLY_SET lowerZoneFill( *aLowerZone->GetFilledPolysList( aLayer ) );
             SHAPE_POLY_SET lowerZoneOutline( *aLowerZone->Outline() );
 
-            lowerZoneOutline.BooleanSubtract( intersectShape, SHAPE_POLY_SET::PM_FAST );
+            lowerZoneOutline.BooleanSubtract( intersectShape );
 
-            lowerZoneFill.BooleanSubtract( lowerZoneOutline, SHAPE_POLY_SET::PM_FAST );
+            lowerZoneFill.BooleanSubtract( lowerZoneOutline );
 
             double leftOverArea = lowerZoneFill.Area();
 
@@ -3790,7 +3789,7 @@ bool CADSTAR_PCB_ARCHIVE_LOADER::calculateZonePriorities( PCB_LAYER_ID& aLayer )
             outLineB.Inflate( inflateValue( aZoneA, aZoneB ), CORNER_STRATEGY::ROUND_ALL_CORNERS,
                               ARC_HIGH_DEF );
 
-            outLineA.BooleanIntersection( outLineB, SHAPE_POLY_SET::PM_FAST );
+            outLineA.BooleanIntersection( outLineB );
 
             return outLineA.Area();
         };
diff --git a/pcbnew/pcb_io/easyeda/pcb_io_easyeda_parser.cpp b/pcbnew/pcb_io/easyeda/pcb_io_easyeda_parser.cpp
index ed8730fc26..971e138b54 100644
--- a/pcbnew/pcb_io/easyeda/pcb_io_easyeda_parser.cpp
+++ b/pcbnew/pcb_io/easyeda/pcb_io_easyeda_parser.cpp
@@ -572,7 +572,7 @@ void PCB_IO_EASYEDA_PARSER::ParseToBoardItemContainer(
                     }
                 }
 
-                fillPolySet.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                fillPolySet.Fracture();
 
                 zone->SetFilledPolysList( layer, fillPolySet );
                 zone->SetIsFilled( true );
diff --git a/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro_parser.cpp b/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro_parser.cpp
index 7c2e4c536a..68dc1928e5 100644
--- a/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro_parser.cpp
+++ b/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro_parser.cpp
@@ -880,7 +880,7 @@ FOOTPRINT* PCB_IO_EASYEDAPRO_PARSER::ParseFootprint( const nlohmann::json&
                                                     true );
                 }
 
-                polySet.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                polySet.Simplify();
 
                 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( footprint );
 
@@ -1158,7 +1158,7 @@ void PCB_IO_EASYEDAPRO_PARSER::ParseBoard(
                     zoneFillPoly.AddOutline( contour );
 
                 zoneFillPoly.RebuildHolesFromContours();
-                zoneFillPoly.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                zoneFillPoly.Fracture();
 
                 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( aBoard );
 
@@ -1771,7 +1771,7 @@ void PCB_IO_EASYEDAPRO_PARSER::ParseBoard(
 
                         // The contour can be self-intersecting
                         SHAPE_POLY_SET simple( contour );
-                        simple.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                        simple.Simplify();
 
                         if( dataId == 0 )
                         {
@@ -1779,7 +1779,7 @@ void PCB_IO_EASYEDAPRO_PARSER::ParseBoard(
                         }
                         else
                         {
-                            thisPoly.BooleanSubtract( simple, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                            thisPoly.BooleanSubtract( simple );
                         }
                     }
                     else
@@ -1801,16 +1801,16 @@ void PCB_IO_EASYEDAPRO_PARSER::ParseBoard(
 
             if( !fillPolySet.IsEmpty() )
             {
-                fillPolySet.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                fillPolySet.Simplify();
 
                 const int strokeWidth = pcbIUScale.MilsToIU( 8 ); // Seems to be 8 mils
 
                 fillPolySet.Inflate( strokeWidth / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS,
                                      ARC_HIGH_DEF, false );
 
-                fillPolySet.BooleanAdd( thermalSpokes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                fillPolySet.BooleanAdd( thermalSpokes );
 
-                fillPolySet.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                fillPolySet.Fracture();
 
                 zone->SetFilledPolysList( zone->GetFirstLayer(), fillPolySet );
                 zone->SetNeedRefill( false );
diff --git a/pcbnew/pcb_io/fabmaster/import_fabmaster.cpp b/pcbnew/pcb_io/fabmaster/import_fabmaster.cpp
index 5b7f453917..c7f8068f51 100644
--- a/pcbnew/pcb_io/fabmaster/import_fabmaster.cpp
+++ b/pcbnew/pcb_io/fabmaster/import_fabmaster.cpp
@@ -2724,7 +2724,7 @@ bool FABMASTER::loadFootprints( BOARD* aBoard )
                                 }
                                 else
                                 {
-                                    poly_outline.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
+                                    poly_outline.Fracture();
 
                                     poly_outline.Move( -newpad->GetPosition() );
 
@@ -3324,7 +3324,7 @@ bool FABMASTER::loadPolygon( BOARD* aBoard, const std::unique_ptr<FABMASTER::TRA
 
         SHAPE_POLY_SET poly_outline = loadShapePolySet( aLine->segment );
 
-        poly_outline.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
+        poly_outline.Fracture();
 
         if( poly_outline.OutlineCount() < 1 || poly_outline.COutline( 0 ).PointCount() < 3 )
             return false;
@@ -3552,7 +3552,7 @@ bool FABMASTER::loadGraphics( BOARD* aBoard )
             {
                 SHAPE_POLY_SET poly_outline = loadShapePolySet( *( geom.elements ) );
 
-                poly_outline.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
+                poly_outline.Fracture();
 
                 if( poly_outline.OutlineCount() < 1 || poly_outline.COutline( 0 ).PointCount() < 3 )
                     continue;
diff --git a/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.cpp b/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.cpp
index 5b23395466..4aeadf7570 100644
--- a/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.cpp
+++ b/pcbnew/pcb_io/ipc2581/pcb_io_ipc2581.cpp
@@ -606,7 +606,7 @@ void PCB_IO_IPC2581::addKnockoutText( wxXmlNode* aContentNode, PCB_TEXT* aText )
     SHAPE_POLY_SET finalPoly;
 
     aText->TransformTextToPolySet( finalPoly, 0, ARC_HIGH_DEF, ERROR_INSIDE );
-    finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
+    finalPoly.Fracture();
 
     for( int ii = 0; ii < finalPoly.OutlineCount(); ++ii )
         addContourNode( aContentNode, finalPoly, ii );
@@ -889,7 +889,7 @@ void PCB_IO_IPC2581::addShape( wxXmlNode* aContentNode, const PAD& aPad, PCB_LAY
         if( expansion.x )
         {
             outline.InflateWithLinkedHoles( expansion.x, CORNER_STRATEGY::ROUND_ALL_CORNERS,
-                                            maxError, SHAPE_POLY_SET::PM_FAST );
+                                            maxError );
         }
 
         addContourNode( entry_node, outline );
@@ -910,8 +910,7 @@ void PCB_IO_IPC2581::addShape( wxXmlNode* aContentNode, const PAD& aPad, PCB_LAY
         if( expansion != VECTOR2I( 0, 0 ) )
         {
             shape.InflateWithLinkedHoles( std::max( expansion.x, expansion.y ),
-                                          CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError,
-                                          SHAPE_POLY_SET::PM_FAST );
+                                          CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
         }
 
         addContourNode( entry_node, shape );
diff --git a/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp b/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp
index c60978949c..b8555012c7 100644
--- a/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp
+++ b/pcbnew/pcb_io/kicad_legacy/pcb_io_kicad_legacy.cpp
@@ -2627,8 +2627,7 @@ void PCB_IO_KICAD_LEGACY::loadZONE_CONTAINER()
 
                 inflatedFill.InflateWithLinkedHoles( zc->GetMinThickness() / 2,
                                                      CORNER_STRATEGY::ROUND_ALL_CORNERS,
-                                                     ARC_HIGH_DEF / 2,
-                                                     SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                                                     ARC_HIGH_DEF / 2 );
 
                 zc->SetFilledPolysList( layer, inflatedFill );
             }
diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp
index 883f99b8bd..39b73b75f5 100644
--- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp
+++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp
@@ -7231,8 +7231,7 @@ ZONE* PCB_IO_KICAD_SEXPR_PARSER::parseZONE( BOARD_ITEM_CONTAINER* aParent )
                 {
                     polyset.InflateWithLinkedHoles( zone->GetMinThickness() / 2,
                                                     CORNER_STRATEGY::ROUND_ALL_CORNERS,
-                                                    ARC_HIGH_DEF / 2,
-                                                    SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+                                                    ARC_HIGH_DEF / 2 );
                 }
             }
         }
@@ -7271,7 +7270,7 @@ ZONE* PCB_IO_KICAD_SEXPR_PARSER::parseZONE( BOARD_ITEM_CONTAINER* aParent )
                 TransformOvalToPolygon( segPolygon, seg.A, seg.B, zone->GetMinThickness(),
                                         ARC_HIGH_DEF, ERROR_OUTSIDE );
 
-                layerFill.BooleanAdd( segPolygon, SHAPE_POLY_SET::PM_FAST );
+                layerFill.BooleanAdd( segPolygon );
             }
 
 
diff --git a/pcbnew/pcb_io/odbpp/odb_feature.cpp b/pcbnew/pcb_io/odbpp/odb_feature.cpp
index 24f76f32e2..df4f639b80 100644
--- a/pcbnew/pcb_io/odbpp/odb_feature.cpp
+++ b/pcbnew/pcb_io/odbpp/odb_feature.cpp
@@ -141,7 +141,7 @@ void FEATURES_MANAGER::AddShape( const PCB_SHAPE& aShape, PCB_LAYER_ID aLayer )
         if( soldermask_min_thickness == 0 )
         {
             poly_set = aShape.GetPolyShape().CloneDropTriangulation();
-            poly_set.Fracture( SHAPE_POLY_SET::PM_FAST );
+            poly_set.Fracture();
         }
         else
         {
@@ -152,11 +152,11 @@ void FEATURES_MANAGER::AddShape( const PCB_SHAPE& aShape, PCB_LAYER_ID aLayer )
             aShape.TransformShapeToPolygon( poly_set, aLayer, soldermask_min_thickness / 2 - 1,
                                             maxError, ERROR_OUTSIDE );
 
-            poly_set.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            poly_set.Simplify();
             poly_set.Deflate( soldermask_min_thickness / 2 - 1,
                               CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
-            poly_set.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST );
-            poly_set.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            poly_set.BooleanAdd( initialPolys );
+            poly_set.Fracture();
         }
 
         int strokeWidth = aShape.GetStroke().GetWidth();
@@ -338,7 +338,7 @@ void FEATURES_MANAGER::AddPadShape( const PAD& aPad, PCB_LAYER_ID aLayer )
         if( mask_clearance )
         {
             outline.InflateWithLinkedHoles( expansion.x, CORNER_STRATEGY::ROUND_ALL_CORNERS,
-                                            maxError, SHAPE_POLY_SET::PM_FAST );
+                                            maxError );
         }
 
         for( int ii = 0; ii < outline.OutlineCount(); ++ii )
@@ -360,8 +360,7 @@ void FEATURES_MANAGER::AddPadShape( const PAD& aPad, PCB_LAYER_ID aLayer )
         if( expansion != VECTOR2I( 0, 0 ) )
         {
             shape.InflateWithLinkedHoles( std::max( expansion.x, expansion.y ),
-                                          CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError,
-                                          SHAPE_POLY_SET::PM_FAST );
+                                          CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
         }
 
         for( int ii = 0; ii < shape.OutlineCount(); ++ii )
@@ -644,7 +643,7 @@ void FEATURES_MANAGER::InitFeatureList( PCB_LAYER_ID aLayer, std::vector<BOARD_I
 
             text->TransformTextToPolySet( finalpolyset, 0, m_board->GetDesignSettings().m_MaxError,
                                           ERROR_INSIDE );
-            finalpolyset.Fracture( SHAPE_POLY_SET::PM_FAST );
+            finalpolyset.Fracture();
 
             for( int ii = 0; ii < finalpolyset.OutlineCount(); ++ii )
             {
diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp
index 43e2ccb410..9255793f26 100644
--- a/pcbnew/pcb_painter.cpp
+++ b/pcbnew/pcb_painter.cpp
@@ -2238,7 +2238,7 @@ void PCB_PAINTER::draw( const PCB_TEXT* aText, int aLayer )
     {
         SHAPE_POLY_SET finalPoly;
         aText->TransformTextToPolySet( finalPoly, 0, m_maxError, ERROR_INSIDE );
-        finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
+        finalPoly.Fracture();
 
         m_gal->SetIsStroke( false );
         m_gal->SetIsFill( true );
diff --git a/pcbnew/pcb_text.cpp b/pcbnew/pcb_text.cpp
index b2005b00db..b038c00353 100644
--- a/pcbnew/pcb_text.cpp
+++ b/pcbnew/pcb_text.cpp
@@ -538,7 +538,7 @@ void PCB_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance,
             } );
 
     font->Draw( &callback_gal, GetShownText( true ), GetTextPos(), attrs, GetFontMetrics() );
-    textShape.Simplify( SHAPE_POLY_SET::PM_FAST );
+    textShape.Simplify();
 
     if( IsKnockout() )
     {
@@ -546,7 +546,7 @@ void PCB_TEXT::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearance,
         int            margin = GetKnockoutTextMargin( attrs.m_Size, penWidth );
 
         buildBoundingHull( &finalPoly, textShape, margin + aClearance );
-        finalPoly.BooleanSubtract( textShape, SHAPE_POLY_SET::PM_FAST );
+        finalPoly.BooleanSubtract( textShape );
 
         aBuffer.Append( finalPoly );
     }
diff --git a/pcbnew/pcb_textbox.cpp b/pcbnew/pcb_textbox.cpp
index 3feb0ca9e8..29e199940a 100644
--- a/pcbnew/pcb_textbox.cpp
+++ b/pcbnew/pcb_textbox.cpp
@@ -665,7 +665,7 @@ void PCB_TEXTBOX::TransformTextToPolySet( SHAPE_POLY_SET& aBuffer, int aClearanc
     }
     else
     {
-        buffer.Simplify( SHAPE_POLY_SET::PM_FAST );
+        buffer.Simplify();
     }
 
     aBuffer.Append( buffer );
diff --git a/pcbnew/pcbexpr_functions.cpp b/pcbnew/pcbexpr_functions.cpp
index 582ca53580..8a946702dc 100644
--- a/pcbnew/pcbexpr_functions.cpp
+++ b/pcbnew/pcbexpr_functions.cpp
@@ -860,8 +860,7 @@ static void enclosedByAreaFunc( LIBEVAL::CONTEXT* aCtx, void* self )
                             }
                             else
                             {
-                                itemShape.BooleanSubtract( *aArea->Outline(),
-                                                           SHAPE_POLY_SET::PM_FAST );
+                                itemShape.BooleanSubtract( *aArea->Outline() );
 
                                 enclosedByArea = itemShape.IsEmpty();
                             }
diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp
index fbedde61d7..100e503869 100644
--- a/pcbnew/plot_board_layers.cpp
+++ b/pcbnew/plot_board_layers.cpp
@@ -467,8 +467,7 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
                             // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
                             // which can create bad shapes if margin.x is < 0
                             outline.InflateWithLinkedHoles( mask_clearance,
-                                                            CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError,
-                                                            SHAPE_POLY_SET::PM_FAST );
+                                                            CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
                             dummy.DeletePrimitivesList();
                             dummy.AddPrimitivePoly( aLayer, outline, 0, true );
 
@@ -518,8 +517,7 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
                             dummy.TransformShapeToPolygon( outline, UNDEFINED_LAYER, 0, maxError,
                                                            ERROR_INSIDE );
                             outline.InflateWithLinkedHoles( mask_clearance,
-                                                            CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError,
-                                                            SHAPE_POLY_SET::PM_FAST );
+                                                            CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
 
                             // Initialize the dummy pad shape:
                             dummy.SetAnchorPadShape( aLayer, PAD_SHAPE::CIRCLE );
@@ -554,8 +552,7 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
                         // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
                         // which can create bad shapes if margin.x is < 0
                         shape.InflateWithLinkedHoles( mask_clearance,
-                                                      CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError,
-                                                      SHAPE_POLY_SET::PM_FAST );
+                                                      CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
                         dummy.DeletePrimitivesList();
                         dummy.AddPrimitivePoly( aLayer, shape, 0, true );
 
@@ -792,7 +789,7 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
         outlines.RemoveAllContours();
         aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines );
 
-        outlines.Simplify( SHAPE_POLY_SET::PM_FAST );
+        outlines.Simplify();
 
         // Plot outlines
         std::vector<VECTOR2I> cornerList;
@@ -1046,7 +1043,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
 
     // Merge all polygons: After deflating, not merged (not overlapping) polygons will have the
     // initial shape (with perhaps small changes due to deflating transform)
-    areas.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    areas.Simplify();
     areas.Deflate( inflate, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
 
     // To avoid a lot of code, use a ZONE to handle and plot polygons, because our polygons look
@@ -1060,8 +1057,8 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
 
     // Combine the current areas to initial areas. This is mandatory because inflate/deflate
     // transform is not perfect, and we want the initial areas perfectly kept
-    areas.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST );
-    areas.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    areas.BooleanAdd( initialPolys );
+    areas.Fracture();
 
     itemplotter.PlotZone( &zone, layer, areas );
 }
diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp
index af3edf8253..1b08ba02ab 100644
--- a/pcbnew/plot_brditems_plotter.cpp
+++ b/pcbnew/plot_brditems_plotter.cpp
@@ -733,7 +733,7 @@ void BRDITEMS_PLOTTER::PlotText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer, boo
 
         text->TransformTextToPolySet( finalPoly, 0, m_board->GetDesignSettings().m_MaxError,
                                       ERROR_INSIDE );
-        finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
+        finalPoly.Fracture();
 
         for( int ii = 0; ii < finalPoly.OutlineCount(); ++ii )
             m_plotter->PlotPoly( finalPoly.Outline( ii ), FILL_T::FILLED_SHAPE, 0, &gbr_metadata );
@@ -966,7 +966,7 @@ void BRDITEMS_PLOTTER::PlotShape( const PCB_SHAPE* aShape )
                     // This must be simplified and fractured to prevent overlapping polygons
                     // from generating invalid Gerber files
                     SHAPE_POLY_SET tmpPoly = aShape->GetPolyShape().CloneDropTriangulation();
-                    tmpPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
+                    tmpPoly.Fracture();
 
                     if( margin < 0 )
                     {
diff --git a/pcbnew/router/pns_hole.cpp b/pcbnew/router/pns_hole.cpp
index 7e927fe8d8..7fbb857da5 100644
--- a/pcbnew/router/pns_hole.cpp
+++ b/pcbnew/router/pns_hole.cpp
@@ -89,7 +89,7 @@ const SHAPE_LINE_CHAIN HOLE::Hull( int aClearance, int aWalkaroundThickness, int
                         BuildHullForPrimitiveShape( shape, aClearance, aWalkaroundThickness ) );
             }
 
-            hullSet.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            hullSet.Simplify();
             return hullSet.Outline( 0 );
         }
     }
diff --git a/pcbnew/router/pns_item.h b/pcbnew/router/pns_item.h
index 615079e70e..51b197752d 100644
--- a/pcbnew/router/pns_item.h
+++ b/pcbnew/router/pns_item.h
@@ -24,6 +24,7 @@
 #define __PNS_ITEM_H
 
 #include <memory>
+#include <set>
 #include <unordered_set>
 #include <math/vector2d.h>
 
diff --git a/pcbnew/router/pns_solid.cpp b/pcbnew/router/pns_solid.cpp
index e9fba10479..09f9481e0b 100644
--- a/pcbnew/router/pns_solid.cpp
+++ b/pcbnew/router/pns_solid.cpp
@@ -60,7 +60,7 @@ const SHAPE_LINE_CHAIN SOLID::Hull( int aClearance, int aWalkaroundThickness, in
                                                                 aWalkaroundThickness ) );
             }
 
-            hullSet.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            hullSet.Simplify();
             return hullSet.Outline( 0 );
         }
     }
diff --git a/pcbnew/specctra_import_export/specctra_export.cpp b/pcbnew/specctra_import_export/specctra_export.cpp
index 094d8d96f8..cc4b6bffa7 100644
--- a/pcbnew/specctra_import_export/specctra_export.cpp
+++ b/pcbnew/specctra_import_export/specctra_export.cpp
@@ -843,7 +843,7 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, FOOTPRINT* aFootprint )
             TransformCircleToPolygon( polyBuffer, graphic->GetEnd() - move,
                                       graphic->GetWidth() / 2, ARC_HIGH_DEF, ERROR_INSIDE );
 
-            polyBuffer.Simplify( SHAPE_POLY_SET::PM_FAST );
+            polyBuffer.Simplify();
             SHAPE_LINE_CHAIN& poly = polyBuffer.Outline( 0 );
 
             for( int ii = 0; ii < poly.PointCount(); ++ii )
diff --git a/pcbnew/teardrop/teardrop_utils.cpp b/pcbnew/teardrop/teardrop_utils.cpp
index 9625103300..9cceceefbe 100644
--- a/pcbnew/teardrop/teardrop_utils.cpp
+++ b/pcbnew/teardrop/teardrop_utils.cpp
@@ -388,7 +388,7 @@ bool TEARDROP_MANAGER::computeAnchorPoints( const TEARDROP_PARAMETERS& aParams,
         clipping_rect.Move( ref_on_track );
 
         // Clip the shape to the max allowed teadrop area
-        c_buffer.BooleanIntersection( clipping_rect, SHAPE_POLY_SET::PM_FAST );
+        c_buffer.BooleanIntersection( clipping_rect );
     }
 
     /* in aPts:
diff --git a/pcbnew/tools/board_editor_control.cpp b/pcbnew/tools/board_editor_control.cpp
index 08f4f41e1e..9ed804f0b4 100644
--- a/pcbnew/tools/board_editor_control.cpp
+++ b/pcbnew/tools/board_editor_control.cpp
@@ -1320,11 +1320,10 @@ static bool mergeZones( EDA_DRAW_FRAME* aFrame, BOARD_COMMIT& aCommit,
 
     for( unsigned int i = 1; i < aOriginZones.size(); i++ )
     {
-        aOriginZones[0]->Outline()->BooleanAdd( *aOriginZones[i]->Outline(),
-                                                SHAPE_POLY_SET::PM_FAST );
+        aOriginZones[0]->Outline()->BooleanAdd( *aOriginZones[i]->Outline() );
     }
 
-    aOriginZones[0]->Outline()->Simplify( SHAPE_POLY_SET::PM_FAST );
+    aOriginZones[0]->Outline()->Simplify();
 
     // We should have one polygon, possibly with holes.  If we end up with two polygons (either
     // because the intersection was a single point or because the intersection was within one of
diff --git a/pcbnew/tools/convert_tool.cpp b/pcbnew/tools/convert_tool.cpp
index 9d1a67d143..fc7d4c90a2 100644
--- a/pcbnew/tools/convert_tool.cpp
+++ b/pcbnew/tools/convert_tool.cpp
@@ -373,7 +373,7 @@ int CONVERT_TOOL::CreatePolys( const TOOL_EVENT& aEvent )
                     polySet.Append( makePolysFromOpenGraphics( selection.GetItems(), 0 ) );
 
                     polySet.ClearArcs();
-                    polySet.Simplify( SHAPE_POLY_SET::PM_FAST );
+                    polySet.Simplify();
 
                     // Now inflate the bounding hull by cfg.m_Gap
                     polySet.Inflate( cfg.m_Gap, CORNER_STRATEGY::ROUND_ALL_CORNERS, bds.m_MaxError,
diff --git a/pcbnew/tools/item_modification_routine.cpp b/pcbnew/tools/item_modification_routine.cpp
index 967352ad07..38248d7dd1 100644
--- a/pcbnew/tools/item_modification_routine.cpp
+++ b/pcbnew/tools/item_modification_routine.cpp
@@ -571,8 +571,7 @@ std::optional<wxString> POLYGON_MERGE_ROUTINE::GetStatusMessage() const
 
 bool POLYGON_MERGE_ROUTINE::ProcessSubsequentPolygon( const SHAPE_POLY_SET& aPolygon )
 {
-    const SHAPE_POLY_SET::POLYGON_MODE poly_mode = SHAPE_POLY_SET::POLYGON_MODE::PM_FAST;
-    GetWorkingPolygons().BooleanAdd( aPolygon, poly_mode );
+    GetWorkingPolygons().BooleanAdd( aPolygon );
     return true;
 }
 
@@ -599,11 +598,9 @@ std::optional<wxString> POLYGON_SUBTRACT_ROUTINE::GetStatusMessage() const
 
 bool POLYGON_SUBTRACT_ROUTINE::ProcessSubsequentPolygon( const SHAPE_POLY_SET& aPolygon )
 {
-    const SHAPE_POLY_SET::POLYGON_MODE poly_mode = SHAPE_POLY_SET::POLYGON_MODE::PM_FAST;
-
     SHAPE_POLY_SET& working_polygons = GetWorkingPolygons();
     SHAPE_POLY_SET  working_copy = working_polygons;
-    working_copy.BooleanSubtract( aPolygon, poly_mode );
+    working_copy.BooleanSubtract( aPolygon );
 
     // Subtraction can create holes or delete the polygon
     // In theory we can allow holes as the EDA_SHAPE will fracture for us, but that's
@@ -642,11 +639,9 @@ std::optional<wxString> POLYGON_INTERSECT_ROUTINE::GetStatusMessage() const
 
 bool POLYGON_INTERSECT_ROUTINE::ProcessSubsequentPolygon( const SHAPE_POLY_SET& aPolygon )
 {
-    const SHAPE_POLY_SET::POLYGON_MODE poly_mode = SHAPE_POLY_SET::POLYGON_MODE::PM_FAST;
-
     SHAPE_POLY_SET& working_polygons = GetWorkingPolygons();
     SHAPE_POLY_SET  working_copy = working_polygons;
-    working_copy.BooleanIntersection( aPolygon, poly_mode );
+    working_copy.BooleanIntersection( aPolygon );
 
     // Is there anything left?
     if( working_copy.OutlineCount() == 0 )
diff --git a/pcbnew/tools/pcb_selection_tool.cpp b/pcbnew/tools/pcb_selection_tool.cpp
index 4161b6b554..d3a915e085 100644
--- a/pcbnew/tools/pcb_selection_tool.cpp
+++ b/pcbnew/tools/pcb_selection_tool.cpp
@@ -36,7 +36,6 @@ using namespace std::placeholders;
 #include <board.h>
 #include <board_design_settings.h>
 #include <board_item.h>
-#include <clipper.hpp>
 #include <pcb_reference_image.h>
 #include <pcb_track.h>
 #include <footprint.h>
diff --git a/pcbnew/tools/zone_create_helper.cpp b/pcbnew/tools/zone_create_helper.cpp
index 7f08e11314..6a71f0d853 100644
--- a/pcbnew/tools/zone_create_helper.cpp
+++ b/pcbnew/tools/zone_create_helper.cpp
@@ -171,7 +171,7 @@ void ZONE_CREATE_HELPER::performZoneCutout( ZONE& aZone, const ZONE& aCutout )
     toolMgr->RunAction( PCB_ACTIONS::selectionClear );
 
     SHAPE_POLY_SET originalOutline( *aZone.Outline() );
-    originalOutline.BooleanSubtract( *aCutout.Outline(), SHAPE_POLY_SET::PM_FAST );
+    originalOutline.BooleanSubtract( *aCutout.Outline() );
 
     // After substracting the hole, originalOutline can have more than one main outline.
     // But a zone can have only one main outline, so create as many zones as originalOutline
diff --git a/pcbnew/tracks_cleaner.cpp b/pcbnew/tracks_cleaner.cpp
index fd818565a8..b8c0e8d1d7 100644
--- a/pcbnew/tracks_cleaner.cpp
+++ b/pcbnew/tracks_cleaner.cpp
@@ -344,8 +344,7 @@ void TRACKS_CLEANER::deleteTracksInPads()
                 track->TransformShapeToPolygon( poly, track->GetLayer(), 0, ARC_HIGH_DEF,
                                                 ERROR_INSIDE );
 
-                poly.BooleanSubtract( *pad->GetEffectivePolygon( track->GetLayer(), ERROR_INSIDE ),
-                                      SHAPE_POLY_SET::PM_FAST );
+                poly.BooleanSubtract( *pad->GetEffectivePolygon( track->GetLayer(), ERROR_INSIDE ) );
 
                 if( poly.IsEmpty() )
                 {
diff --git a/pcbnew/zone.cpp b/pcbnew/zone.cpp
index 9f0c2c3b77..ac967a8e6d 100644
--- a/pcbnew/zone.cpp
+++ b/pcbnew/zone.cpp
@@ -991,7 +991,7 @@ void ZONE::RemoveCutout( int aOutlineIdx, int aHoleIdx )
     SHAPE_POLY_SET cutPoly( m_Poly->Hole( aOutlineIdx, aHoleIdx ) );
 
     // Add the cutout back to the zone
-    m_Poly->BooleanAdd( cutPoly, SHAPE_POLY_SET::PM_FAST );
+    m_Poly->BooleanAdd( cutPoly );
 
     SetNeedRefill( true );
 }
@@ -1434,7 +1434,7 @@ bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer
     {
         withFillets = flattened;
         smooth( withFillets );
-        withFillets.BooleanAdd( flattened, SHAPE_POLY_SET::PM_FAST );
+        withFillets.BooleanAdd( flattened );
         maxExtents = &withFillets;
     }
 
@@ -1466,7 +1466,7 @@ bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer
             if( diffNetZone->HigherPriority( sameNetZone )
                     && diffNetZone->GetBoundingBox().Intersects( sameNetBoundingBox ) )
             {
-                diffNetPoly.BooleanAdd( *diffNetZone->Outline(), SHAPE_POLY_SET::PM_FAST );
+                diffNetPoly.BooleanAdd( *diffNetZone->Outline() );
             }
         }
 
@@ -1479,19 +1479,19 @@ bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer
         {
             SHAPE_POLY_SET thisPoly = Outline()->CloneDropTriangulation();
 
-            thisPoly.BooleanSubtract( diffNetPoly, SHAPE_POLY_SET::PM_FAST );
+            thisPoly.BooleanSubtract( diffNetPoly );
             isolated = thisPoly.OutlineCount() == 0;
         }
 
         if( !isolated )
         {
             sameNetPoly.ClearArcs();
-            aSmoothedPoly.BooleanAdd( sameNetPoly, SHAPE_POLY_SET::PM_FAST );
+            aSmoothedPoly.BooleanAdd( sameNetPoly );
         }
     }
 
     if( aBoardOutline )
-        aSmoothedPoly.BooleanIntersection( *aBoardOutline, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+        aSmoothedPoly.BooleanIntersection( *aBoardOutline );
 
     SHAPE_POLY_SET withSameNetIntersectingZones = aSmoothedPoly.CloneDropTriangulation();
 
@@ -1508,13 +1508,13 @@ bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer
         poly.Inflate( m_ZoneMinThickness, CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
 
         if( !keepExternalFillets )
-            poly.BooleanIntersection( withSameNetIntersectingZones, SHAPE_POLY_SET::PM_FAST );
+            poly.BooleanIntersection( withSameNetIntersectingZones );
 
         *aSmoothedPolyWithApron = aSmoothedPoly;
-        aSmoothedPolyWithApron->BooleanIntersection( poly, SHAPE_POLY_SET::PM_FAST );
+        aSmoothedPolyWithApron->BooleanIntersection( poly );
     }
 
-    aSmoothedPoly.BooleanIntersection( *maxExtents, SHAPE_POLY_SET::PM_FAST );
+    aSmoothedPoly.BooleanIntersection( *maxExtents );
 
     return true;
 }
@@ -1576,7 +1576,7 @@ void ZONE::TransformSmoothedOutlineToPolygon( SHAPE_POLY_SET& aBuffer, int aClea
         polybuffer.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
     }
 
-    polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST );
+    polybuffer.Fracture();
     aBuffer.Append( polybuffer );
 }
 
@@ -1612,8 +1612,7 @@ void ZONE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer
         if( aErrorLoc == ERROR_OUTSIDE )
             aClearance += aError;
 
-        temp_buf.InflateWithLinkedHoles( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aError,
-                                         SHAPE_POLY_SET::PM_FAST );
+        temp_buf.InflateWithLinkedHoles( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aError );
     }
 
     aBuffer.Append( temp_buf );
diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp
index c90dd8066a..0c75226799 100644
--- a/pcbnew/zone_filler.cpp
+++ b/pcbnew/zone_filler.cpp
@@ -796,8 +796,7 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE*>& aZones, bool aCheck, wxWindow*
 
 
                         island.AddOutline( test_poly );
-                        intersection.BooleanIntersection( m_boardOutline, island,
-                                                          SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
+                        intersection.BooleanIntersection( m_boardOutline, island );
 
                         // Nominally, all of these areas should be either inside or outside the
                         // board outline.  So this test should be able to just compare areas (if
@@ -1118,7 +1117,7 @@ void ZONE_FILLER::knockoutThermalReliefs( const ZONE* aZone, PCB_LAYER_ID aLayer
         }
     }
 
-    aFill.BooleanSubtract( holes, SHAPE_POLY_SET::PM_FAST );
+    aFill.BooleanSubtract( holes );
 }
 
 
@@ -1505,7 +1504,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa
         }
     }
 
-    aHoles.Simplify( SHAPE_POLY_SET::PM_FAST );
+    aHoles.Simplify();
 }
 
 
@@ -1533,7 +1532,7 @@ void ZONE_FILLER::subtractHigherPriorityZones( const ZONE* aZone, PCB_LAYER_ID a
                     SHAPE_POLY_SET outline = aKnockout->Outline()->CloneDropTriangulation();
                     outline.ClearArcs();
 
-                    aRawFill.BooleanSubtract( outline, SHAPE_POLY_SET::PM_FAST );
+                    aRawFill.BooleanSubtract( outline );
                 }
             };
 
@@ -1617,7 +1616,7 @@ void ZONE_FILLER::connect_nearby_polys( SHAPE_POLY_SET& aPolys, double aDistance
         { \
             m_board->SetLayerName( b, c ); \
             SHAPE_POLY_SET d = a; \
-            d.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); \
+            d.Fracture(); \
             aFillPolys = d; \
             return false; \
         } \
@@ -1699,7 +1698,7 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
     // because the "real" subtract-clearance-holes has to be done after the spokes are added.
     static const bool USE_BBOX_CACHES = true;
     SHAPE_POLY_SET testAreas = aFillPolys.CloneDropTriangulation();
-    testAreas.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
+    testAreas.BooleanSubtract( clearanceHoles );
     DUMP_POLYS_TO_COPPER_LAYER( testAreas, In4_Cu, wxT( "minus-clearance-holes" ) );
 
     // Prune features that don't meet minimum-width criteria
@@ -1767,7 +1766,7 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
     if( m_progressReporter && m_progressReporter->IsCancelled() )
         return false;
 
-    aFillPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
+    aFillPolys.BooleanSubtract( clearanceHoles );
     DUMP_POLYS_TO_COPPER_LAYER( aFillPolys, In8_Cu, wxT( "after-spoke-trimming" ) );
 
     /* -------------------------------------------------------------------------------------
@@ -1818,7 +1817,7 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
          * Connect nearby polygons with zero-width lines in order to ensure correct
          * re-inflation.
          */
-        aFillPolys.Fracture( SHAPE_POLY_SET::PM_FAST );
+        aFillPolys.Fracture();
         connect_nearby_polys( aFillPolys, aZone->GetMinThickness() );
 
         DUMP_POLYS_TO_COPPER_LAYER( aFillPolys, In10_Cu, wxT( "connected-nearby-polys" ) );
@@ -1845,9 +1844,9 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
     for( PAD* pad : thermalConnectionPads )
         addHoleKnockout( pad, 0, clearanceHoles );
 
-    aFillPolys.BooleanIntersection( aMaxExtents, SHAPE_POLY_SET::PM_FAST );
+    aFillPolys.BooleanIntersection( aMaxExtents );
     DUMP_POLYS_TO_COPPER_LAYER( aFillPolys, In16_Cu, wxT( "after-trim-to-outline" ) );
-    aFillPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
+    aFillPolys.BooleanSubtract( clearanceHoles );
     DUMP_POLYS_TO_COPPER_LAYER( aFillPolys, In17_Cu, wxT( "after-trim-to-clearance-holes" ) );
 
     /* -------------------------------------------------------------------------------------
@@ -1857,7 +1856,7 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
     subtractHigherPriorityZones( aZone, aLayer, aFillPolys );
     DUMP_POLYS_TO_COPPER_LAYER( aFillPolys, In18_Cu, wxT( "minus-higher-priority-zones" ) );
 
-    aFillPolys.Fracture( SHAPE_POLY_SET::PM_FAST );
+    aFillPolys.Fracture();
     return true;
 }
 
@@ -1911,7 +1910,7 @@ bool ZONE_FILLER::fillNonCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer,
     }
 
     aFillPolys = aSmoothedOutline;
-    aFillPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
+    aFillPolys.BooleanSubtract( clearanceHoles );
 
     for( ZONE* keepout : m_board->Zones() )
     {
@@ -1927,13 +1926,13 @@ bool ZONE_FILLER::fillNonCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer,
             {
                 if( keepout->Outline()->ArcCount() == 0 )
                 {
-                    aFillPolys.BooleanSubtract( *keepout->Outline(), SHAPE_POLY_SET::PM_FAST );
+                    aFillPolys.BooleanSubtract( *keepout->Outline() );
                 }
                 else
                 {
                     SHAPE_POLY_SET keepoutOutline( *keepout->Outline() );
                     keepoutOutline.ClearArcs();
-                    aFillPolys.BooleanSubtract( keepoutOutline, SHAPE_POLY_SET::PM_FAST );
+                    aFillPolys.BooleanSubtract( keepoutOutline );
                 }
             }
         }
@@ -1958,7 +1957,7 @@ bool ZONE_FILLER::fillNonCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer,
     if( half_min_width - epsilon > epsilon )
         aFillPolys.Inflate( half_min_width - epsilon, CORNER_STRATEGY::ROUND_ALL_CORNERS, m_maxError );
 
-    aFillPolys.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    aFillPolys.Fracture();
     return true;
 }
 
@@ -2375,12 +2374,12 @@ bool ZONE_FILLER::addHatchFillTypeOnZone( const ZONE* aZone, PCB_LAYER_ID aLayer
     SHAPE_POLY_SET deflatedFilledPolys = aFillPolys.CloneDropTriangulation();
     deflatedFilledPolys.Deflate( outline_margin - aZone->GetMinThickness(),
                                  CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
-    holes.BooleanIntersection( deflatedFilledPolys, SHAPE_POLY_SET::PM_FAST );
+    holes.BooleanIntersection( deflatedFilledPolys );
     DUMP_POLYS_TO_COPPER_LAYER( holes, In11_Cu, wxT( "fill-clipped-hatch-holes" ) );
 
     SHAPE_POLY_SET deflatedOutline = aZone->Outline()->CloneDropTriangulation();
     deflatedOutline.Deflate( outline_margin, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
-    holes.BooleanIntersection( deflatedOutline, SHAPE_POLY_SET::PM_FAST );
+    holes.BooleanIntersection( deflatedOutline );
     DUMP_POLYS_TO_COPPER_LAYER( holes, In12_Cu, wxT( "outline-clipped-hatch-holes" ) );
 
     if( aZone->GetNetCode() != 0 )
@@ -2438,7 +2437,7 @@ bool ZONE_FILLER::addHatchFillTypeOnZone( const ZONE* aZone, PCB_LAYER_ID aLayer
             }
         }
 
-        holes.BooleanSubtract( aprons, SHAPE_POLY_SET::PM_FAST );
+        holes.BooleanSubtract( aprons );
     }
     DUMP_POLYS_TO_COPPER_LAYER( holes, In13_Cu, wxT( "pad-via-clipped-hatch-holes" ) );
 
@@ -2454,9 +2453,9 @@ bool ZONE_FILLER::addHatchFillTypeOnZone( const ZONE* aZone, PCB_LAYER_ID aLayer
             ++ii;
     }
 
-    // create grid. Use SHAPE_POLY_SET::PM_STRICTLY_SIMPLE to
+    // create grid. Useto
     // generate strictly simple polygons needed by Gerber files and Fracture()
-    aFillPolys.BooleanSubtract( aFillPolys, holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    aFillPolys.BooleanSubtract( aFillPolys, holes );
     DUMP_POLYS_TO_COPPER_LAYER( aFillPolys, In14_Cu, wxT( "after-hatching" ) );
 
     return true;
diff --git a/qa/tests/libs/kimath/geometry/test_shape_line_chain.cpp b/qa/tests/libs/kimath/geometry/test_shape_line_chain.cpp
index fb0b5dde48..a3dab0d439 100644
--- a/qa/tests/libs/kimath/geometry/test_shape_line_chain.cpp
+++ b/qa/tests/libs/kimath/geometry/test_shape_line_chain.cpp
@@ -131,21 +131,6 @@ BOOST_AUTO_TEST_CASE( ClipperConstructorCase1 )
     // Case of an arc followed by a segment
     // The clipper path is not in order (on purpose), to simulate the typical return from clipper
 
-    ClipperLib::Path pathClipper1 = {
-        { { 125663951, 120099260, 24 }, { 125388111, 120170850, 25 }, { 125124975, 120280270, 26 },
-          { 124879705, 120425376, 27 }, { 124657110, 120603322, 28 }, { 124461556, 120810617, 29 },
-          { 124296876, 121043198, 30 }, { 124166301, 121296503, 31 }, { 124072391, 121565564, 32 },
-          { 124016988, 121845106, 33 }, { 124001177, 122129646, 34 }, { 124025270, 122413605, 35 },
-          { 124088794, 122691414, 36 }, { 124190502, 122957625, 37 }, { 124328401, 123207018, 38 },
-          { 124499787, 123434703, 39 }, { 124598846, 123537154, 40 }, { 127171000, 123786000, 4 },
-          { 127287862, 123704439, 5 },  { 127499716, 123513831, 6 },  { 127682866, 123295498, 7 },
-          { 127833720, 123053722, 8 },  { 127949321, 122793242, 9 },  { 128027402, 122519168, 10 },
-          { 128066430, 122236874, 11 }, { 128065642, 121951896, 12 }, { 128025053, 121669823, 13 },
-          { 127945457, 121396185, 14 }, { 127828417, 121136349, 15 }, { 127676227, 120895410, 16 },
-          { 127491873, 120678094, 17 }, { 127278968, 120488661, 18 }, { 127041689, 120330827, 19 },
-          { 126784688, 120207687, 20 }, { 126513005, 120121655, 21 }, { 126231968, 120074419, 22 },
-          { 125947087, 120066905, 23 } }
-    };
     Clipper2Lib::Path64 pathClipper2 = {
         { { 125663951, 120099260, 24 }, { 125388111, 120170850, 25 }, { 125124975, 120280270, 26 },
           { 124879705, 120425376, 27 }, { 124657110, 120603322, 28 }, { 124461556, 120810617, 29 },
@@ -180,22 +165,16 @@ BOOST_AUTO_TEST_CASE( ClipperConstructorCase1 )
         SHAPE_ARC( { 127171000, 123786000 }, { 126231718, 120077003 }, { 124598846, 123537154 }, 0 )
     };
 
-    SHAPE_LINE_CHAIN clipper1chain( pathClipper1, z_values, arcs );
     SHAPE_LINE_CHAIN clipper2chain( pathClipper2, z_values, arcs );
 
-    BOOST_CHECK( GEOM_TEST::IsOutlineValid( clipper1chain ) );
     BOOST_CHECK( GEOM_TEST::IsOutlineValid( clipper2chain ) );
 
-    BOOST_CHECK_EQUAL( clipper1chain.PointCount(), 37 );
     BOOST_CHECK_EQUAL( clipper2chain.PointCount(), 37 );
 
-    BOOST_CHECK_EQUAL( clipper1chain.ArcCount(), 1 );
     BOOST_CHECK_EQUAL( clipper2chain.ArcCount(), 1 );
 
-    BOOST_CHECK_EQUAL( clipper1chain.ShapeCount(), 2 );
     BOOST_CHECK_EQUAL( clipper2chain.ShapeCount(), 2 );
 
-    BOOST_CHECK_EQUAL( clipper1chain.IsClosed(), true );
     BOOST_CHECK_EQUAL( clipper2chain.IsClosed(), true );
 }
 
diff --git a/qa/tests/libs/kimath/geometry/test_shape_poly_set_arcs.cpp b/qa/tests/libs/kimath/geometry/test_shape_poly_set_arcs.cpp
index b5a6fc356e..0139434fb6 100644
--- a/qa/tests/libs/kimath/geometry/test_shape_poly_set_arcs.cpp
+++ b/qa/tests/libs/kimath/geometry/test_shape_poly_set_arcs.cpp
@@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE( TestSimplify )
             {
                 BOOST_TEST_CONTEXT( "Simplify Iteration " << i )
                 {
-                    testPoly.Simplify( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
+                    testPoly.Simplify();
 
                     std::vector<SHAPE_ARC> foundArcs;
                     testPoly.GetArcs( foundArcs );
@@ -119,14 +119,14 @@ BOOST_AUTO_TEST_CASE( TestIntersectUnion )
             double opPolyArea = opPoly.Area();
 
             SHAPE_POLY_SET intersectionPoly = testPoly;
-            intersectionPoly.BooleanIntersection( opPoly, SHAPE_POLY_SET::POLYGON_MODE::PM_STRICTLY_SIMPLE );
+            intersectionPoly.BooleanIntersection( opPoly );
             double intersectArea = intersectionPoly.Area();
 
             BOOST_CHECK( GEOM_TEST::IsPolySetValid( intersectionPoly ) );
 
 
             SHAPE_POLY_SET unionPoly = testPoly;
-            unionPoly.BooleanAdd( opPoly, SHAPE_POLY_SET::POLYGON_MODE::PM_STRICTLY_SIMPLE );
+            unionPoly.BooleanAdd( opPoly );
             double unionArea = unionPoly.Area();
 
             BOOST_CHECK( GEOM_TEST::IsPolySetValid( unionPoly ) );
diff --git a/qa/tests/pcbnew/test_zone_filler.cpp b/qa/tests/pcbnew/test_zone_filler.cpp
index c002a604af..a03026fb0e 100644
--- a/qa/tests/pcbnew/test_zone_filler.cpp
+++ b/qa/tests/pcbnew/test_zone_filler.cpp
@@ -158,8 +158,7 @@ BOOST_FIXTURE_TEST_CASE( NotchedZones, ZONE_FILL_TEST_FIXTURE )
     {
         if( zone->GetLayerSet().Contains( F_Cu ) )
         {
-            frontCopper.BooleanAdd( *zone->GetFilledPolysList( F_Cu ),
-                                    SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+            frontCopper.BooleanAdd( *zone->GetFilledPolysList( F_Cu ) );
         }
     }
 
diff --git a/qa/tools/drc_proto/drc_proto.cpp b/qa/tools/drc_proto/drc_proto.cpp
index 0ee7a4e749..09ee7ad092 100644
--- a/qa/tools/drc_proto/drc_proto.cpp
+++ b/qa/tools/drc_proto/drc_proto.cpp
@@ -135,7 +135,7 @@ int runDRCProto( PROJECT_CONTEXT project, std::shared_ptr<KIGFX::VIEW_OVERLAY> a
     {
         drcEngine->RunTests( EDA_UNITS::MILLIMETRES, true, false );
     }
-    catch( const ClipperLib::clipperException& e )
+    catch( const Clipper2Lib::Clipper2Exception& e )
     {
         consoleLog.Print( wxString::Format( "Clipper exception %s occurred.", e.what() ) );
     }
diff --git a/qa/tools/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp b/qa/tools/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp
index bc17c2b5dc..ac4c5a22c0 100644
--- a/qa/tools/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp
+++ b/qa/tools/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp
@@ -246,7 +246,7 @@ int polygon_triangulation_main( int argc, char *argv[] )
                     ignore_unused( poly );
 #if 0
                 PROF_TIMER unfrac("unfrac");
-                poly.Unfracture( SHAPE_POLY_SET::PM_FAST );
+                poly.Unfracture();
                 unfrac.Show();
 
                 PROF_TIMER triangulate("triangulate");
diff --git a/qa/tools/pns/playground.cpp b/qa/tools/pns/playground.cpp
index 4937cdf67d..a217b4db92 100644
--- a/qa/tools/pns/playground.cpp
+++ b/qa/tools/pns/playground.cpp
@@ -307,12 +307,12 @@ int playground_main_func( int argc, char* argv[] )
 
     SHAPE_POLY_SET xorPad1ToPad2 = pad1Outline;
 
-    xorPad1ToPad2.BooleanXor( pad2Outline, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    xorPad1ToPad2.BooleanXor( pad2Outline );
     xorPad1ToPad2.Move( VECTOR2I( pcbIUScale.mmToIU( 10 ), 0 ) );
 
     SHAPE_POLY_SET andPad1ToPad2 = pad2Outline;
 
-    andPad1ToPad2.BooleanIntersection( pad1Outline, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    andPad1ToPad2.BooleanIntersection( pad1Outline );
     andPad1ToPad2.Move( VECTOR2I( pcbIUScale.mmToIU( 20 ), 0 ) );
 
     std::shared_ptr<SHAPE_SEGMENT> slot = pad2.GetEffectiveHoleShape();
diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt
index bb51237f6b..3d16c01838 100644
--- a/thirdparty/CMakeLists.txt
+++ b/thirdparty/CMakeLists.txt
@@ -34,7 +34,6 @@ set( CMAKE_POLICY_DEFAULT_CMP0077 NEW )
 
 set( ARGPARSE_INSTALL OFF )
 add_subdirectory( argparse )
-add_subdirectory( clipper )
 add_subdirectory( clipper2 )
 add_subdirectory( compoundfilereader )
 add_subdirectory( delaunator )
diff --git a/thirdparty/clipper/CMakeLists.txt b/thirdparty/clipper/CMakeLists.txt
deleted file mode 100644
index 8dc47eefad..0000000000
--- a/thirdparty/clipper/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-
-add_library( clipper OBJECT
-    clipper.cpp
-)
-
-target_include_directories( clipper
-    PUBLIC
-    ${CMAKE_CURRENT_SOURCE_DIR}
-)
diff --git a/thirdparty/clipper/LICENSE.BOOSTv1_0 b/thirdparty/clipper/LICENSE.BOOSTv1_0
deleted file mode 100644
index 36b7cd93cd..0000000000
--- a/thirdparty/clipper/LICENSE.BOOSTv1_0
+++ /dev/null
@@ -1,23 +0,0 @@
-Boost Software License - Version 1.0 - August 17th, 2003
-
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
diff --git a/thirdparty/clipper/README.txt b/thirdparty/clipper/README.txt
deleted file mode 100644
index 1e7557825e..0000000000
--- a/thirdparty/clipper/README.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This directory contains the Clipper library for interacting with polygons.
-https://sourceforge.net/projects/polyclipping/
-
-It is licensed under the Boost Software License, with the license text in this directory.
diff --git a/thirdparty/clipper/clipper.cpp b/thirdparty/clipper/clipper.cpp
deleted file mode 100644
index 0f6aac8f3a..0000000000
--- a/thirdparty/clipper/clipper.cpp
+++ /dev/null
@@ -1,5999 +0,0 @@
-/*******************************************************************************
-*                                                                              *
-* Author    :  Angus Johnson                                                   *
-* Version   :  6.4.2                                                           *
-* Date      :  27 February 2017                                                *
-* Website   :  http://www.angusj.com                                           *
-* Copyright :  Angus Johnson 2010-2017                                         *
-*                                                                              *
-* License:                                                                     *
-* Use, modification & distribution is subject to Boost Software License Ver 1. *
-* http://www.boost.org/LICENSE_1_0.txt                                         *
-*                                                                              *
-* Attributions:                                                                *
-* The code in this library is an extension of Bala Vatti's clipping algorithm: *
-* "A generic solution to polygon clipping"                                     *
-* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.             *
-* http://portal.acm.org/citation.cfm?id=129906                                 *
-*                                                                              *
-* Computer graphics and geometric modeling: implementation and algorithms      *
-* By Max K. Agoston                                                            *
-* Springer; 1 edition (January 4, 2005)                                        *
-* http://books.google.com/books?q=vatti+clipping+agoston                       *
-*                                                                              *
-* See also:                                                                    *
-* "Polygon Offsetting by Computing Winding Numbers"                            *
-* Paper no. DETC2005-85513 pp. 565-575                                         *
-* ASME 2005 International Design Engineering Technical Conferences             *
-* and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
-* September 24-28, 2005 , Long Beach, California, USA                          *
-* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
-*                                                                              *
-*******************************************************************************/
-
-/*******************************************************************************
-*                                                                              *
-* This is a translation of the Delphi Clipper library and the naming style     *
-* used has retained a Delphi flavour.                                          *
-*                                                                              *
-*******************************************************************************/
-
-#include "clipper.hpp"
-#include <cmath>
-#include <vector>
-#include <algorithm>
-#include <stdexcept>
-#include <cstring>
-#include <cstdlib>
-#include <ostream>
-#include <functional>
-
-namespace ClipperLib {
-static double const pi = 3.141592653589793238;
-static double const two_pi = pi * 2;
-static double const def_arc_tolerance = 0.25;
-
-enum Direction
-{
-    dRightToLeft, dLeftToRight
-};
-
-static int const Unassigned = -1;   // edge not currently 'owning' a solution
-static int const Skip = -2;         // edge that would otherwise close a path
-
-#define HORIZONTAL  (-1.0E+40)
-#define TOLERANCE   (1.0e-20)
-#define NEAR_ZERO( val ) ( ( (val) > -TOLERANCE ) && ( (val) < TOLERANCE ) )
-
-struct TEdge
-{
-    IntPoint Bot;
-    IntPoint Curr; // current (updated for every new scanbeam)
-    IntPoint Top;
-    double Dx;
-    PolyType PolyTyp;
-    EdgeSide Side;  // side only refers to current side of solution poly
-    int WindDelta;  // 1 or -1 depending on winding direction
-    int WindCnt;
-    int WindCnt2;   // winding count of the opposite polytype
-    int OutIdx;
-    TEdge* Next;
-    TEdge* Prev;
-    TEdge* NextInLML;
-    TEdge* NextInAEL;
-    TEdge* PrevInAEL;
-    TEdge* NextInSEL;
-    TEdge* PrevInSEL;
-};
-
-struct IntersectNode
-{
-    TEdge* Edge1;
-    TEdge* Edge2;
-    IntPoint Pt;
-};
-
-struct LocalMinimum
-{
-    cInt Y;
-    TEdge* LeftBound;
-    TEdge* RightBound;
-};
-
-struct OutPt;
-
-// OutRec: contains a path in the clipping solution. Edges in the AEL will
-// carry a pointer to an OutRec when they are part of the clipping solution.
-struct OutRec
-{
-    int Idx;
-    bool IsHole;
-    bool IsOpen;
-    OutRec* FirstLeft;  // see comments in clipper.pas
-    PolyNode*   PolyNd;
-    OutPt*  Pts;
-    OutPt*  BottomPt;
-};
-
-struct OutPt
-{
-    int Idx;
-    IntPoint Pt;
-    OutPt* Next;
-    OutPt* Prev;
-};
-
-struct Join
-{
-    OutPt* OutPt1;
-    OutPt* OutPt2;
-    IntPoint OffPt;
-};
-
-struct LocMinSorter
-{
-    inline bool operator()( const LocalMinimum& locMin1, const LocalMinimum& locMin2 )
-    {
-        return locMin2.Y < locMin1.Y;
-    }
-};
-
-// ------------------------------------------------------------------------------
-// ------------------------------------------------------------------------------
-
-inline cInt Round( double val )
-{
-    if( (val < 0) )
-        return static_cast<cInt>(val - 0.5);
-    else
-        return static_cast<cInt>(val + 0.5);
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline cInt Abs( cInt val )
-{
-    return val < 0 ? -val : val;
-}
-
-
-// ------------------------------------------------------------------------------
-// PolyTree methods ...
-// ------------------------------------------------------------------------------
-
-void PolyTree::Clear()
-{
-    for( PolyNodes::size_type i = 0; i < AllNodes.size(); ++i )
-        delete AllNodes[i];
-
-    AllNodes.resize( 0 );
-    Childs.resize( 0 );
-}
-
-
-// ------------------------------------------------------------------------------
-
-PolyNode* PolyTree::GetFirst() const
-{
-    if( !Childs.empty() )
-        return Childs[0];
-    else
-        return 0;
-}
-
-
-// ------------------------------------------------------------------------------
-
-int PolyTree::Total() const
-{
-    int result = (int) AllNodes.size();
-
-    // with negative offsets, ignore the hidden outer polygon ...
-    if( result > 0 && Childs[0] != AllNodes[0] )
-        result--;
-
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-// PolyNode methods ...
-// ------------------------------------------------------------------------------
-
-PolyNode::PolyNode() : Parent( 0 ), Index( 0 ), m_IsOpen( false ),
-        m_jointype( jtSquare ), m_endtype( etClosedPolygon )
-{
-}
-
-
-// ------------------------------------------------------------------------------
-
-int PolyNode::ChildCount() const
-{
-    return (int) Childs.size();
-}
-
-
-// ------------------------------------------------------------------------------
-
-void PolyNode::AddChild( PolyNode& child )
-{
-    unsigned cnt = (unsigned) Childs.size();
-
-    Childs.push_back( &child );
-    child.Parent = this;
-    child.Index = cnt;
-}
-
-
-// ------------------------------------------------------------------------------
-
-PolyNode* PolyNode::GetNext() const
-{
-    if( !Childs.empty() )
-        return Childs[0];
-    else
-        return GetNextSiblingUp();
-}
-
-
-// ------------------------------------------------------------------------------
-
-PolyNode* PolyNode::GetNextSiblingUp() const
-{
-    if( !Parent ) // protects against PolyTree.GetNextSiblingUp()
-        return 0;
-    else if( Index == Parent->Childs.size() - 1 )
-        return Parent->GetNextSiblingUp();
-    else
-        return Parent->Childs[Index + 1];
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool PolyNode::IsHole() const
-{
-    bool result = true;
-    PolyNode* node = Parent;
-
-    while( node )
-    {
-        result = !result;
-        node = node->Parent;
-    }
-
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool PolyNode::IsOpen() const
-{
-    return m_IsOpen;
-}
-
-
-// ------------------------------------------------------------------------------
-
-#ifndef use_int32
-
-// ------------------------------------------------------------------------------
-// Int128 class (enables safe math on signed 64bit integers)
-// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1
-// Int128 val2((long64)9223372036854775807);
-// Int128 val3 = val1 * val2;
-// val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
-// ------------------------------------------------------------------------------
-
-class Int128
-{
-public:
-    ulong64 lo;
-    long64  hi;
-
-    Int128( long64 _lo = 0 )
-    {
-        lo = (ulong64) _lo;
-
-        if( _lo < 0 )  hi = -1; else hi = 0;
-    }
-
-    Int128( const Int128& val ) : lo( val.lo ), hi( val.hi ) {}
-
-    Int128( const long64& _hi, const ulong64& _lo ) : lo( _lo ), hi( _hi ) {}
-
-    Int128& operator =( const long64& val )
-    {
-        lo = (ulong64) val;
-
-        if( val < 0 ) hi = -1; else hi = 0;
-
-        return *this;
-    }
-
-    bool operator ==( const Int128& val ) const
-    { return hi == val.hi && lo == val.lo; }
-
-    bool operator !=( const Int128& val ) const
-    { return !(*this == val); }
-
-    bool operator >( const Int128& val ) const
-    {
-        if( hi != val.hi )
-            return hi > val.hi;
-        else
-            return lo > val.lo;
-    }
-
-    bool operator <( const Int128& val ) const
-    {
-        if( hi != val.hi )
-            return hi < val.hi;
-        else
-            return lo < val.lo;
-    }
-
-    bool operator >=( const Int128& val ) const
-    { return !(*this < val); }
-
-    bool operator <=( const Int128& val ) const
-    { return !(*this > val); }
-
-    Int128& operator +=( const Int128& rhs )
-    {
-        hi  += rhs.hi;
-        lo  += rhs.lo;
-
-        if( lo < rhs.lo ) hi++;
-
-        return *this;
-    }
-
-    Int128 operator +( const Int128& rhs ) const
-    {
-        Int128 result( *this );
-
-        result += rhs;
-        return result;
-    }
-
-    Int128& operator -=( const Int128& rhs )
-    {
-        *this += -rhs;
-        return *this;
-    }
-
-    Int128 operator -( const Int128& rhs ) const
-    {
-        Int128 result( *this );
-
-        result -= rhs;
-        return result;
-    }
-
-    Int128 operator-() const    // unary negation
-    {
-        if( lo == 0 )
-            return Int128( -hi, 0 );
-        else
-            return Int128( ~hi, ~lo + 1 );
-    }
-
-    operator double() const
-    {
-        const double shift64 = 18446744073709551616.0; // 2^64
-
-        if( hi < 0 )
-        {
-            if( lo == 0 ) return (double) hi * shift64;
-            else return -(double) (~lo + ~hi * shift64);
-        }
-        else
-            return (double) (lo + hi * shift64);
-    }
-};
-// ------------------------------------------------------------------------------
-
-Int128 Int128Mul( long64 lhs, long64 rhs )
-{
-    bool negate = (lhs < 0) != (rhs < 0);
-
-    if( lhs < 0 )
-        lhs = -lhs;
-
-    ulong64 int1Hi  = ulong64( lhs ) >> 32;
-    ulong64 int1Lo  = ulong64( lhs & 0xFFFFFFFF );
-
-    if( rhs < 0 )
-        rhs = -rhs;
-
-    ulong64 int2Hi  = ulong64( rhs ) >> 32;
-    ulong64 int2Lo  = ulong64( rhs & 0xFFFFFFFF );
-
-    // nb: see comments in clipper.pas
-    ulong64 a = int1Hi * int2Hi;
-    ulong64 b = int1Lo * int2Lo;
-    ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi;
-
-    Int128 tmp;
-    tmp.hi  = long64( a + (c >> 32) );
-    tmp.lo  = long64( c << 32 );
-    tmp.lo  += long64( b );
-
-    if( tmp.lo < b )
-        tmp.hi++;
-
-    if( negate )
-        tmp = -tmp;
-
-    return tmp;
-}
-#endif
-
-// ------------------------------------------------------------------------------
-// Miscellaneous global functions
-// ------------------------------------------------------------------------------
-
-bool Orientation( const Path& poly )
-{
-    return Area( poly ) >= 0;
-}
-
-
-// ------------------------------------------------------------------------------
-
-double Area( const Path& poly )
-{
-    int size = (int) poly.size();
-
-    if( size < 3 )
-        return 0;
-
-    double a = 0;
-
-    for( int i = 0, j = size - 1; i < size; ++i )
-    {
-        a += ( (double) poly[j].X + poly[i].X ) * ( (double) poly[j].Y - poly[i].Y );
-        j = i;
-    }
-
-    return -a * 0.5;
-}
-
-
-// ------------------------------------------------------------------------------
-
-double Area( const OutPt* op )
-{
-    const OutPt* startOp = op;
-
-    if( !op )
-        return 0;
-
-    double a = 0;
-
-    do {
-        a += (double) (op->Prev->Pt.X + op->Pt.X) * (double) (op->Prev->Pt.Y - op->Pt.Y);
-        op = op->Next;
-    } while( op != startOp );
-
-    return a * 0.5;
-}
-
-
-// ------------------------------------------------------------------------------
-
-double Area( const OutRec& outRec )
-{
-    return Area( outRec.Pts );
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool PointIsVertex( const IntPoint& Pt, OutPt* pp )
-{
-    OutPt* pp2 = pp;
-
-    do
-    {
-        if( pp2->Pt == Pt )
-            return true;
-
-        pp2 = pp2->Next;
-    } while( pp2 != pp );
-
-    return false;
-}
-
-
-// ------------------------------------------------------------------------------
-
-// See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos
-// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
-int PointInPolygon( const IntPoint& pt, const Path& path )
-{
-    // returns 0 if false, +1 if true, -1 if pt ON polygon boundary
-    int result  = 0;
-    size_t cnt  = path.size();
-
-    if( cnt < 3 )
-        return 0;
-
-    IntPoint ip = path[0];
-
-    for( size_t i = 1; i <= cnt; ++i )
-    {
-        IntPoint ipNext = (i == cnt ? path[0] : path[i]);
-
-        if( ipNext.Y == pt.Y )
-        {
-            if( (ipNext.X == pt.X) || ( ip.Y == pt.Y
-                                        && ( (ipNext.X > pt.X) == (ip.X < pt.X) ) ) )
-                return -1;
-        }
-
-        if( (ip.Y < pt.Y) != (ipNext.Y < pt.Y) )
-        {
-            if( ip.X >= pt.X )
-            {
-                if( ipNext.X > pt.X )
-                    result = 1 - result;
-                else
-                {
-                    double d = (double) (ip.X - pt.X) * (ipNext.Y - pt.Y) -
-                               (double) (ipNext.X - pt.X) * (ip.Y - pt.Y);
-
-                    if( !d )
-                        return -1;
-
-                    if( (d > 0) == (ipNext.Y > ip.Y) )
-                        result = 1 - result;
-                }
-            }
-            else
-            {
-                if( ipNext.X > pt.X )
-                {
-                    double d = (double) (ip.X - pt.X) * (ipNext.Y - pt.Y) -
-                               (double) (ipNext.X - pt.X) * (ip.Y - pt.Y);
-
-                    if( !d )
-                        return -1;
-
-                    if( (d > 0) == (ipNext.Y > ip.Y) )
-                        result = 1 - result;
-                }
-            }
-        }
-
-        ip = ipNext;
-    }
-
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-int PointInPolygon( const IntPoint& pt, OutPt* op )
-{
-    // returns 0 if false, +1 if true, -1 if pt ON polygon boundary
-    int result = 0;
-    OutPt* startOp = op;
-
-    for( ; ; )
-    {
-        if( op->Next->Pt.Y == pt.Y )
-        {
-            if( (op->Next->Pt.X == pt.X) || ( op->Pt.Y == pt.Y
-                                              && ( (op->Next->Pt.X > pt.X) ==
-                                                   (op->Pt.X < pt.X) ) ) )
-                return -1;
-        }
-
-        if( (op->Pt.Y < pt.Y) != (op->Next->Pt.Y < pt.Y) )
-        {
-            if( op->Pt.X >= pt.X )
-            {
-                if( op->Next->Pt.X > pt.X )
-                    result = 1 - result;
-                else
-                {
-                    double d = (double) (op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) -
-                               (double) (op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y);
-
-                    if( !d )
-                        return -1;
-
-                    if( (d > 0) == (op->Next->Pt.Y > op->Pt.Y) )
-                        result = 1 - result;
-                }
-            }
-            else
-            {
-                if( op->Next->Pt.X > pt.X )
-                {
-                    double d = (double) (op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) -
-                               (double) (op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y);
-
-                    if( !d )
-                        return -1;
-
-                    if( (d > 0) == (op->Next->Pt.Y > op->Pt.Y) )
-                        result = 1 - result;
-                }
-            }
-        }
-
-        op = op->Next;
-
-        if( startOp == op )
-            break;
-    }
-
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Poly2ContainsPoly1( OutPt* OutPt1, OutPt* OutPt2 )
-{
-    OutPt* op = OutPt1;
-
-    do
-    {
-        // nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon
-        int res = PointInPolygon( op->Pt, OutPt2 );
-
-        if( res >= 0 )
-            return res > 0;
-
-        op = op->Next;
-    } while( op != OutPt1 );
-
-    return true;
-}
-
-
-// ----------------------------------------------------------------------
-
-bool SlopesEqual( const TEdge& e1, const TEdge& e2, bool UseFullInt64Range )
-{
-#ifndef use_int32
-
-    if( UseFullInt64Range )
-        return Int128Mul( e1.Top.Y - e1.Bot.Y, e2.Top.X - e2.Bot.X ) ==
-               Int128Mul( e1.Top.X - e1.Bot.X, e2.Top.Y - e2.Bot.Y );
-    else
-#endif
-    return (e1.Top.Y - e1.Bot.Y) * (e2.Top.X - e2.Bot.X) ==
-           (e1.Top.X - e1.Bot.X) * (e2.Top.Y - e2.Bot.Y);
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool SlopesEqual( const IntPoint pt1, const IntPoint pt2,
-        const IntPoint pt3, bool UseFullInt64Range )
-{
-#ifndef use_int32
-
-    if( UseFullInt64Range )
-        return Int128Mul( pt1.Y - pt2.Y,
-                pt2.X - pt3.X ) == Int128Mul( pt1.X - pt2.X, pt2.Y - pt3.Y );
-    else
-#endif
-    return (pt1.Y - pt2.Y) * (pt2.X - pt3.X) == (pt1.X - pt2.X) * (pt2.Y - pt3.Y);
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool SlopesEqual( const IntPoint pt1, const IntPoint pt2,
-        const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range )
-{
-#ifndef use_int32
-
-    if( UseFullInt64Range )
-        return Int128Mul( pt1.Y - pt2.Y,
-                pt3.X - pt4.X ) == Int128Mul( pt1.X - pt2.X, pt3.Y - pt4.Y );
-    else
-#endif
-    return (pt1.Y - pt2.Y) * (pt3.X - pt4.X) == (pt1.X - pt2.X) * (pt3.Y - pt4.Y);
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline bool IsHorizontal( TEdge& e )
-{
-    return e.Dx == HORIZONTAL;
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline double GetDx( const IntPoint pt1, const IntPoint pt2 )
-{
-    return (pt1.Y == pt2.Y) ?
-           HORIZONTAL : (double) (pt2.X - pt1.X) / (pt2.Y - pt1.Y);
-}
-
-
-// ---------------------------------------------------------------------------
-
-inline void SetDx( TEdge& e )
-{
-    cInt dy = (e.Top.Y - e.Bot.Y);
-
-    if( dy == 0 )
-        e.Dx = HORIZONTAL;
-    else
-        e.Dx = (double) (e.Top.X - e.Bot.X) / dy;
-}
-
-
-// ---------------------------------------------------------------------------
-
-inline void SwapSides( TEdge& Edge1, TEdge& Edge2 )
-{
-    EdgeSide Side = Edge1.Side;
-
-    Edge1.Side  = Edge2.Side;
-    Edge2.Side  = Side;
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline void SwapPolyIndexes( TEdge& Edge1, TEdge& Edge2 )
-{
-    int OutIdx = Edge1.OutIdx;
-
-    Edge1.OutIdx = Edge2.OutIdx;
-    Edge2.OutIdx = OutIdx;
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline cInt TopX( TEdge& edge, const cInt currentY )
-{
-    return ( currentY == edge.Top.Y ) ?
-           edge.Top.X : edge.Bot.X + Round( edge.Dx * (currentY - edge.Bot.Y) );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void IntersectPoint( TEdge& Edge1, TEdge& Edge2, IntPoint& ip )
-{
-#ifdef use_xyz
-    ip.Z = 0;
-#endif
-
-    double b1, b2;
-
-    if( Edge1.Dx == Edge2.Dx )
-    {
-        ip.Y = Edge1.Curr.Y;
-        ip.X = TopX( Edge1, ip.Y );
-        return;
-    }
-    else if( Edge1.Dx == 0 )
-    {
-        ip.X = Edge1.Bot.X;
-
-        if( IsHorizontal( Edge2 ) )
-            ip.Y = Edge2.Bot.Y;
-        else
-        {
-            b2 = Edge2.Bot.Y - (Edge2.Bot.X / Edge2.Dx);
-            ip.Y = Round( ip.X / Edge2.Dx + b2 );
-        }
-    }
-    else if( Edge2.Dx == 0 )
-    {
-        ip.X = Edge2.Bot.X;
-
-        if( IsHorizontal( Edge1 ) )
-            ip.Y = Edge1.Bot.Y;
-        else
-        {
-            b1 = Edge1.Bot.Y - (Edge1.Bot.X / Edge1.Dx);
-            ip.Y = Round( ip.X / Edge1.Dx + b1 );
-        }
-    }
-    else
-    {
-        b1  = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx;
-        b2  = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx;
-        double q = (b2 - b1) / (Edge1.Dx - Edge2.Dx);
-        ip.Y = Round( q );
-
-        if( std::fabs( Edge1.Dx ) < std::fabs( Edge2.Dx ) )
-            ip.X = Round( Edge1.Dx * q + b1 );
-        else
-            ip.X = Round( Edge2.Dx * q + b2 );
-    }
-
-    if( ip.Y < Edge1.Top.Y || ip.Y < Edge2.Top.Y )
-    {
-        if( Edge1.Top.Y > Edge2.Top.Y )
-            ip.Y = Edge1.Top.Y;
-        else
-            ip.Y = Edge2.Top.Y;
-
-        if( std::fabs( Edge1.Dx ) < std::fabs( Edge2.Dx ) )
-            ip.X = TopX( Edge1, ip.Y );
-        else
-            ip.X = TopX( Edge2, ip.Y );
-    }
-
-    // finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ...
-    if( ip.Y > Edge1.Curr.Y )
-    {
-        ip.Y = Edge1.Curr.Y;
-
-        // use the more vertical edge to derive X ...
-        if( std::fabs( Edge1.Dx ) > std::fabs( Edge2.Dx ) )
-            ip.X = TopX( Edge2, ip.Y );
-        else
-            ip.X = TopX( Edge1, ip.Y );
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ReversePolyPtLinks( OutPt* pp )
-{
-    if( !pp )
-        return;
-
-    OutPt* pp1, * pp2;
-    pp1 = pp;
-
-    do {
-        pp2 = pp1->Next;
-        pp1->Next = pp1->Prev;
-        pp1->Prev = pp2;
-        pp1 = pp2;
-    } while( pp1 != pp );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void DisposeOutPts( OutPt*& pp )
-{
-    if( pp == 0 )
-        return;
-
-    pp->Prev->Next = 0;
-
-    while( pp )
-    {
-        OutPt* tmpPp = pp;
-        pp = pp->Next;
-        delete tmpPp;
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline void InitEdge( TEdge* e, TEdge* eNext, TEdge* ePrev, const IntPoint& Pt )
-{
-    // This clears the C++ way
-    *e = TEdge( { 0 } );
-
-    e->Next = eNext;
-    e->Prev = ePrev;
-    e->Curr = Pt;
-    e->OutIdx = Unassigned;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void InitEdge2( TEdge& e, PolyType Pt )
-{
-    if( e.Curr.Y >= e.Next->Curr.Y )
-    {
-        e.Bot = e.Curr;
-        e.Top = e.Next->Curr;
-    }
-    else
-    {
-        e.Top = e.Curr;
-        e.Bot = e.Next->Curr;
-    }
-
-    SetDx( e );
-    e.PolyTyp = Pt;
-}
-
-
-// ------------------------------------------------------------------------------
-
-TEdge* RemoveEdge( TEdge* e )
-{
-    // removes e from double_linked_list (but without removing from memory)
-    e->Prev->Next = e->Next;
-    e->Next->Prev = e->Prev;
-    TEdge* result = e->Next;
-    e->Prev = 0; // flag as removed (see ClipperBase.Clear)
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline void ReverseHorizontal( TEdge& e )
-{
-    // swap horizontal edges' Top and Bottom x's so they follow the natural
-    // progression of the bounds - ie so their xbots will align with the
-    // adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
-    std::swap( e.Top.X, e.Bot.X );
-
-#ifdef use_xyz
-    std::swap( e.Top.Z, e.Bot.Z );
-#endif
-}
-
-
-// ------------------------------------------------------------------------------
-
-void SwapPoints( IntPoint& pt1, IntPoint& pt2 )
-{
-    IntPoint tmp = pt1;
-
-    pt1 = pt2;
-    pt2 = tmp;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool GetOverlapSegment( IntPoint pt1a, IntPoint pt1b, IntPoint pt2a,
-        IntPoint pt2b, IntPoint& pt1, IntPoint& pt2 )
-{
-    // precondition: segments are Collinear.
-    if( Abs( pt1a.X - pt1b.X ) > Abs( pt1a.Y - pt1b.Y ) )
-    {
-        if( pt1a.X > pt1b.X )
-            SwapPoints( pt1a, pt1b );
-
-        if( pt2a.X > pt2b.X )
-            SwapPoints( pt2a, pt2b );
-
-        if( pt1a.X > pt2a.X )
-            pt1 = pt1a;
-        else
-            pt1 = pt2a;
-
-        if( pt1b.X < pt2b.X )
-            pt2 = pt1b;
-        else
-            pt2 = pt2b;
-
-        return pt1.X < pt2.X;
-    }
-    else
-    {
-        if( pt1a.Y < pt1b.Y )
-            SwapPoints( pt1a, pt1b );
-
-        if( pt2a.Y < pt2b.Y )
-            SwapPoints( pt2a, pt2b );
-
-        if( pt1a.Y < pt2a.Y )
-            pt1 = pt1a;
-        else
-            pt1 = pt2a;
-
-        if( pt1b.Y > pt2b.Y )
-            pt2 = pt1b;
-        else
-            pt2 = pt2b;
-
-        return pt1.Y > pt2.Y;
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool FirstIsBottomPt( const OutPt* btmPt1, const OutPt* btmPt2 )
-{
-    OutPt* p = btmPt1->Prev;
-
-    while( (p->Pt == btmPt1->Pt) && (p != btmPt1) )
-        p = p->Prev;
-
-    double dx1p = std::fabs( GetDx( btmPt1->Pt, p->Pt ) );
-    p = btmPt1->Next;
-
-    while( (p->Pt == btmPt1->Pt) && (p != btmPt1) )
-        p = p->Next;
-
-    double dx1n = std::fabs( GetDx( btmPt1->Pt, p->Pt ) );
-
-    p = btmPt2->Prev;
-
-    while( (p->Pt == btmPt2->Pt) && (p != btmPt2) )
-        p = p->Prev;
-
-    double dx2p = std::fabs( GetDx( btmPt2->Pt, p->Pt ) );
-    p = btmPt2->Next;
-
-    while( (p->Pt == btmPt2->Pt) && (p != btmPt2) )
-        p = p->Next;
-
-    double dx2n = std::fabs( GetDx( btmPt2->Pt, p->Pt ) );
-
-    if( std::max( dx1p, dx1n ) == std::max( dx2p, dx2n )
-        && std::min( dx1p, dx1n ) == std::min( dx2p, dx2n ) )
-        return Area( btmPt1 ) > 0; // if otherwise identical use orientation
-    else
-        return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
-}
-
-
-// ------------------------------------------------------------------------------
-
-OutPt* GetBottomPt( OutPt* pp )
-{
-    OutPt* dups = 0;
-    OutPt* p = pp->Next;
-
-    while( p != pp )
-    {
-        if( p->Pt.Y > pp->Pt.Y )
-        {
-            pp = p;
-            dups = 0;
-        }
-        else if( p->Pt.Y == pp->Pt.Y && p->Pt.X <= pp->Pt.X )
-        {
-            if( p->Pt.X < pp->Pt.X )
-            {
-                dups = 0;
-                pp = p;
-            }
-            else
-            {
-                if( p->Next != pp && p->Prev != pp )
-                    dups = p;
-            }
-        }
-
-        p = p->Next;
-    }
-
-    if( dups )
-    {
-        // there appears to be at least 2 vertices at BottomPt so ...
-        while( dups != p )
-        {
-            if( !FirstIsBottomPt( p, dups ) )
-                pp = dups;
-
-            dups = dups->Next;
-
-            while( dups->Pt != pp->Pt )
-                dups = dups->Next;
-        }
-    }
-
-    return pp;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Pt2IsBetweenPt1AndPt3( const IntPoint pt1,
-        const IntPoint pt2, const IntPoint pt3 )
-{
-    if( (pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2) )
-        return false;
-    else if( pt1.X != pt3.X )
-        return (pt2.X > pt1.X) == (pt2.X < pt3.X);
-    else
-        return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y);
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool HorzSegmentsOverlap( cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b )
-{
-    if( seg1a > seg1b )
-        std::swap( seg1a, seg1b );
-
-    if( seg2a > seg2b )
-        std::swap( seg2a, seg2b );
-
-    return (seg1a < seg2b) && (seg2a < seg1b);
-}
-
-
-// ------------------------------------------------------------------------------
-// ClipperBase class methods ...
-// ------------------------------------------------------------------------------
-
-ClipperBase::ClipperBase()              // constructor
-{
-    m_CurrentLM = m_MinimaList.begin(); // begin() == end() here
-    m_UseFullRange = false;
-
-    // Avoid uninitialized vars:
-    m_PreserveCollinear = false;
-    m_HasOpenPaths = false;
-    m_ActiveEdges = nullptr;
-}
-
-
-// ------------------------------------------------------------------------------
-
-ClipperBase::~ClipperBase()    // destructor
-{
-    Clear();
-}
-
-
-// ------------------------------------------------------------------------------
-
-void RangeTest( const IntPoint& Pt, bool& useFullRange )
-{
-    if( useFullRange )
-    {
-        if( Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange )
-            throw clipperException( "Coordinate outside allowed range" );
-    }
-    else if( Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange )
-    {
-        useFullRange = true;
-        RangeTest( Pt, useFullRange );
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-TEdge* FindNextLocMin( TEdge* E )
-{
-    for( ; ; )
-    {
-        while( E->Bot != E->Prev->Bot || E->Curr == E->Top )
-            E = E->Next;
-
-        if( !IsHorizontal( *E ) && !IsHorizontal( *E->Prev ) )
-            break;
-
-        while( IsHorizontal( *E->Prev ) )
-            E = E->Prev;
-
-        TEdge* E2 = E;
-
-        while( IsHorizontal( *E ) )
-            E = E->Next;
-
-        if( E->Top.Y == E->Prev->Bot.Y )
-            continue;                         // ie just an intermediate horz.
-
-        if( E2->Prev->Bot.X < E->Bot.X )
-            E = E2;
-
-        break;
-    }
-
-    return E;
-}
-
-
-// ------------------------------------------------------------------------------
-
-TEdge* ClipperBase::ProcessBound( TEdge* E, bool NextIsForward )
-{
-    TEdge* Result = E;
-    TEdge* Horz = 0;
-
-    if( E->OutIdx == Skip )
-    {
-        // if edges still remain in the current bound beyond the skip edge then
-        // create another LocMin and call ProcessBound once more
-        if( NextIsForward )
-        {
-            while( E->Top.Y == E->Next->Bot.Y )
-                E = E->Next;
-
-            // don't include top horizontals when parsing a bound a second time,
-            // they will be contained in the opposite bound ...
-            while( E != Result && IsHorizontal( *E ) )
-                E = E->Prev;
-        }
-        else
-        {
-            while( E->Top.Y == E->Prev->Bot.Y )
-                E = E->Prev;
-
-            while( E != Result && IsHorizontal( *E ) )
-                E = E->Next;
-        }
-
-        if( E == Result )
-        {
-            if( NextIsForward )
-                Result = E->Next;
-            else
-                Result = E->Prev;
-        }
-        else
-        {
-            // there are more edges in the bound beyond result starting with E
-            if( NextIsForward )
-                E = Result->Next;
-            else
-                E = Result->Prev;
-
-            MinimaList::value_type locMin;
-            locMin.Y = E->Bot.Y;
-            locMin.LeftBound = 0;
-            locMin.RightBound = E;
-            E->WindDelta = 0;
-            Result = ProcessBound( E, NextIsForward );
-            m_MinimaList.push_back( locMin );
-        }
-
-        return Result;
-    }
-
-    TEdge* EStart;
-
-    if( IsHorizontal( *E ) )
-    {
-        // We need to be careful with open paths because this may not be a
-        // true local minima (ie E may be following a skip edge).
-        // Also, consecutive horz. edges may start heading left before going right.
-        if( NextIsForward )
-            EStart = E->Prev;
-        else
-            EStart = E->Next;
-
-        if( IsHorizontal( *EStart ) ) // ie an adjoining horizontal skip edge
-        {
-            if( EStart->Bot.X != E->Bot.X && EStart->Top.X != E->Bot.X )
-                ReverseHorizontal( *E );
-        }
-        else if( EStart->Bot.X != E->Bot.X )
-            ReverseHorizontal( *E );
-    }
-
-    EStart = E;
-
-    if( NextIsForward )
-    {
-        while( Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip )
-            Result = Result->Next;
-
-        if( IsHorizontal( *Result ) && Result->Next->OutIdx != Skip )
-        {
-            // nb: at the top of a bound, horizontals are added to the bound
-            // only when the preceding edge attaches to the horizontal's left vertex
-            // unless a Skip edge is encountered when that becomes the top divide
-            Horz = Result;
-
-            while( IsHorizontal( *Horz->Prev ) )
-                Horz = Horz->Prev;
-
-            if( Horz->Prev->Top.X > Result->Next->Top.X )
-                Result = Horz->Prev;
-        }
-
-        while( E != Result )
-        {
-            E->NextInLML = E->Next;
-
-            if( IsHorizontal( *E ) && E != EStart
-                && E->Bot.X != E->Prev->Top.X )
-                ReverseHorizontal( *E );
-
-            E = E->Next;
-        }
-
-        if( IsHorizontal( *E ) && E != EStart && E->Bot.X != E->Prev->Top.X )
-            ReverseHorizontal( *E );
-
-        Result = Result->Next; // move to the edge just beyond current bound
-    }
-    else
-    {
-        while( Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip )
-            Result = Result->Prev;
-
-        if( IsHorizontal( *Result ) && Result->Prev->OutIdx != Skip )
-        {
-            Horz = Result;
-
-            while( IsHorizontal( *Horz->Next ) )
-                Horz = Horz->Next;
-
-            if( Horz->Next->Top.X == Result->Prev->Top.X
-                || Horz->Next->Top.X > Result->Prev->Top.X )
-                Result = Horz->Next;
-        }
-
-        while( E != Result )
-        {
-            E->NextInLML = E->Prev;
-
-            if( IsHorizontal( *E ) && E != EStart && E->Bot.X != E->Next->Top.X )
-                ReverseHorizontal( *E );
-
-            E = E->Prev;
-        }
-
-        if( IsHorizontal( *E ) && E != EStart && E->Bot.X != E->Next->Top.X )
-            ReverseHorizontal( *E );
-
-        Result = Result->Prev; // move to the edge just beyond current bound
-    }
-
-    return Result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool ClipperBase::AddPath( const Path& pg, PolyType PolyTyp, bool Closed )
-{
-#ifdef use_lines
-
-    if( !Closed && PolyTyp == ptClip )
-        throw clipperException( "AddPath: Open paths must be subject." );
-
-#else
-
-    if( !Closed )
-        throw clipperException( "AddPath: Open paths have been disabled." );
-
-#endif
-
-    int highI = (int) pg.size() - 1;
-
-    if( Closed )
-        while( highI > 0 && (pg[highI] == pg[0]) )
-            --highI;
-
-
-    while( highI > 0 && (pg[highI] == pg[highI - 1]) )
-        --highI;
-
-    if( (Closed && highI < 2) || (!Closed && highI < 1) )
-        return false;
-
-    // create a new edge array ...
-    TEdge* edges = new TEdge[highI + 1];
-
-    bool IsFlat = true;
-    // 1. Basic (first) edge initialization ...
-    try
-    {
-        edges[1].Curr = pg[1];
-        RangeTest( pg[0], m_UseFullRange );
-        RangeTest( pg[highI], m_UseFullRange );
-        InitEdge( &edges[0], &edges[1], &edges[highI], pg[0] );
-        InitEdge( &edges[highI], &edges[0], &edges[highI - 1], pg[highI] );
-
-        for( int i = highI - 1; i >= 1; --i )
-        {
-            RangeTest( pg[i], m_UseFullRange );
-            InitEdge( &edges[i], &edges[i + 1], &edges[i - 1], pg[i] );
-        }
-    }
-    catch( ... )
-    {
-        delete [] edges;
-        throw; // range test fails
-    }
-    TEdge* eStart = &edges[0];
-
-    // 2. Remove duplicate vertices, and (when closed) collinear edges ...
-    TEdge* E = eStart, * eLoopStop = eStart;
-
-    for( ; ; )
-    {
-        // nb: allows matching start and end points when not Closed ...
-        if( E->Curr == E->Next->Curr && (Closed || E->Next != eStart) )
-        {
-            if( E == E->Next )
-                break;
-
-            if( E == eStart )
-                eStart = E->Next;
-
-            E = RemoveEdge( E );
-            eLoopStop = E;
-            continue;
-        }
-
-        if( E->Prev == E->Next )
-            break; // only two vertices
-        else if( Closed
-                 && SlopesEqual( E->Prev->Curr, E->Curr, E->Next->Curr, m_UseFullRange )
-                 && ( !m_PreserveCollinear
-                      || !Pt2IsBetweenPt1AndPt3( E->Prev->Curr, E->Curr, E->Next->Curr ) ) )
-        {
-            // Collinear edges are allowed for open paths but in closed paths
-            // the default is to merge adjacent collinear edges into a single edge.
-            // However, if the PreserveCollinear property is enabled, only overlapping
-            // collinear edges (ie spikes) will be removed from closed paths.
-            if( E == eStart )
-                eStart = E->Next;
-
-            E = RemoveEdge( E );
-            E = E->Prev;
-            eLoopStop = E;
-            continue;
-        }
-
-        E = E->Next;
-
-        if( (E == eLoopStop) || (!Closed && E->Next == eStart) )
-            break;
-    }
-
-    if( ( !Closed && (E == E->Next) ) || ( Closed && (E->Prev == E->Next) ) )
-    {
-        delete [] edges;
-        return false;
-    }
-
-    if( !Closed )
-    {
-        m_HasOpenPaths = true;
-        eStart->Prev->OutIdx = Skip;
-    }
-
-    // 3. Do second stage of edge initialization ...
-    E = eStart;
-
-    do
-    {
-        InitEdge2( *E, PolyTyp );
-        E = E->Next;
-
-        if( IsFlat && E->Curr.Y != eStart->Curr.Y )
-            IsFlat = false;
-    } while( E != eStart );
-
-    // 4. Finally, add edge bounds to LocalMinima list ...
-
-    // Totally flat paths must be handled differently when adding them
-    // to LocalMinima list to avoid endless loops etc ...
-    if( IsFlat )
-    {
-        if( Closed )
-        {
-            delete [] edges;
-            return false;
-        }
-
-        E->Prev->OutIdx = Skip;
-        MinimaList::value_type locMin;
-        locMin.Y = E->Bot.Y;
-        locMin.LeftBound = 0;
-        locMin.RightBound = E;
-        locMin.RightBound->Side = esRight;
-        locMin.RightBound->WindDelta = 0;
-
-        for( ; ; )
-        {
-            if( E->Bot.X != E->Prev->Top.X )
-                ReverseHorizontal( *E );
-
-            if( E->Next->OutIdx == Skip )
-                break;
-
-            E->NextInLML = E->Next;
-            E = E->Next;
-        }
-
-        m_MinimaList.push_back( locMin );
-        m_edges.push_back( edges );
-        return true;
-    }
-
-    m_edges.push_back( edges );
-    bool leftBoundIsForward;
-    TEdge* EMin = 0;
-
-    // workaround to avoid an endless loop in the while loop below when
-    // open paths have matching start and end points ...
-    if( E->Prev->Bot == E->Prev->Top )
-        E = E->Next;
-
-    for( ; ; )
-    {
-        E = FindNextLocMin( E );
-
-        if( E == EMin )
-            break;
-        else if( !EMin )
-            EMin = E;
-
-        // E and E.Prev now share a local minima (left aligned if horizontal).
-        // Compare their slopes to find which starts which bound ...
-        MinimaList::value_type locMin;
-        locMin.Y = E->Bot.Y;
-
-        if( E->Dx < E->Prev->Dx )
-        {
-            locMin.LeftBound = E->Prev;
-            locMin.RightBound = E;
-            leftBoundIsForward = false; // Q.nextInLML = Q.prev
-        }
-        else
-        {
-            locMin.LeftBound = E;
-            locMin.RightBound = E->Prev;
-            leftBoundIsForward = true; // Q.nextInLML = Q.next
-        }
-
-        if( !Closed )
-            locMin.LeftBound->WindDelta = 0;
-        else if( locMin.LeftBound->Next == locMin.RightBound )
-            locMin.LeftBound->WindDelta = -1;
-        else
-            locMin.LeftBound->WindDelta = 1;
-
-        locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta;
-
-        E = ProcessBound( locMin.LeftBound, leftBoundIsForward );
-
-        if( E->OutIdx == Skip )
-            E = ProcessBound( E, leftBoundIsForward );
-
-        TEdge* E2 = ProcessBound( locMin.RightBound, !leftBoundIsForward );
-
-        if( E2->OutIdx == Skip )
-            E2 = ProcessBound( E2, !leftBoundIsForward );
-
-        if( locMin.LeftBound->OutIdx == Skip )
-            locMin.LeftBound = 0;
-        else if( locMin.RightBound->OutIdx == Skip )
-            locMin.RightBound = 0;
-
-        m_MinimaList.push_back( locMin );
-
-        if( !leftBoundIsForward )
-            E = E2;
-    }
-
-    return true;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool ClipperBase::AddPaths( const Paths& ppg, PolyType PolyTyp, bool Closed )
-{
-    bool result = false;
-
-    for( Paths::size_type i = 0; i < ppg.size(); ++i )
-        if( AddPath( ppg[i], PolyTyp, Closed ) )
-            result = true;
-
-
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperBase::Clear()
-{
-    DisposeLocalMinimaList();
-
-    for( EdgeList::size_type i = 0; i < m_edges.size(); ++i )
-    {
-        TEdge* edges = m_edges[i];
-        delete [] edges;
-    }
-
-    m_edges.clear();
-    m_UseFullRange  = false;
-    m_HasOpenPaths  = false;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperBase::Reset()
-{
-    m_CurrentLM = m_MinimaList.begin();
-
-    if( m_CurrentLM == m_MinimaList.end() )
-        return;                                  // ie nothing to process
-
-    std::sort( m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter() );
-
-    m_Scanbeam = ScanbeamList(); // clears/resets priority_queue
-
-    // reset all edges ...
-    for( MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm )
-    {
-        InsertScanbeam( lm->Y );
-        TEdge* e = lm->LeftBound;
-
-        if( e )
-        {
-            e->Curr = e->Bot;
-            e->Side = esLeft;
-            e->OutIdx = Unassigned;
-        }
-
-        e = lm->RightBound;
-
-        if( e )
-        {
-            e->Curr = e->Bot;
-            e->Side = esRight;
-            e->OutIdx = Unassigned;
-        }
-    }
-
-    m_ActiveEdges = 0;
-    m_CurrentLM = m_MinimaList.begin();
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperBase::DisposeLocalMinimaList()
-{
-    m_MinimaList.clear();
-    m_CurrentLM = m_MinimaList.begin();
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool ClipperBase::PopLocalMinima( cInt Y, const LocalMinimum*& locMin )
-{
-    if( m_CurrentLM == m_MinimaList.end() || (*m_CurrentLM).Y != Y )
-        return false;
-
-    locMin = &(*m_CurrentLM);
-    ++m_CurrentLM;
-    return true;
-}
-
-
-// ------------------------------------------------------------------------------
-
-IntRect ClipperBase::GetBounds()
-{
-    IntRect result;
-    MinimaList::iterator lm = m_MinimaList.begin();
-
-    if( lm == m_MinimaList.end() )
-    {
-        result.left = result.top = result.right = result.bottom = 0;
-        return result;
-    }
-
-    result.left = lm->LeftBound->Bot.X;
-    result.top = lm->LeftBound->Bot.Y;
-    result.right = lm->LeftBound->Bot.X;
-    result.bottom = lm->LeftBound->Bot.Y;
-
-    while( lm != m_MinimaList.end() )
-    {
-        // todo - needs fixing for open paths
-        result.bottom = std::max( result.bottom, lm->LeftBound->Bot.Y );
-        TEdge* e = lm->LeftBound;
-
-        for( ; ; )
-        {
-            TEdge* bottomE = e;
-
-            while( e->NextInLML )
-            {
-                if( e->Bot.X < result.left )
-                    result.left = e->Bot.X;
-
-                if( e->Bot.X > result.right )
-                    result.right = e->Bot.X;
-
-                e = e->NextInLML;
-            }
-
-            result.left = std::min( result.left, e->Bot.X );
-            result.right = std::max( result.right, e->Bot.X );
-            result.left = std::min( result.left, e->Top.X );
-            result.right = std::max( result.right, e->Top.X );
-            result.top = std::min( result.top, e->Top.Y );
-
-            if( bottomE == lm->LeftBound )
-                e = lm->RightBound;
-            else
-                break;
-        }
-
-        ++lm;
-    }
-
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperBase::InsertScanbeam( const cInt Y )
-{
-    m_Scanbeam.push( Y );
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool ClipperBase::PopScanbeam( cInt& Y )
-{
-    if( m_Scanbeam.empty() )
-        return false;
-
-    Y = m_Scanbeam.top();
-    m_Scanbeam.pop();
-
-    while( !m_Scanbeam.empty() && Y == m_Scanbeam.top() )
-    {
-        m_Scanbeam.pop();
-    }                                                                        // Pop duplicates.
-
-    return true;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperBase::DisposeAllOutRecs()
-{
-    for( PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i )
-        DisposeOutRec( i );
-
-    m_PolyOuts.clear();
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperBase::DisposeOutRec( PolyOutList::size_type index )
-{
-    OutRec* outRec = m_PolyOuts[index];
-
-    if( outRec->Pts )
-        DisposeOutPts( outRec->Pts );
-
-    delete outRec;
-    m_PolyOuts[index] = 0;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperBase::DeleteFromAEL( TEdge* e )
-{
-    TEdge* AelPrev  = e->PrevInAEL;
-    TEdge* AelNext  = e->NextInAEL;
-
-    if( !AelPrev &&  !AelNext && (e != m_ActiveEdges) )
-        return;                                              // already deleted
-
-    if( AelPrev )
-        AelPrev->NextInAEL = AelNext;
-    else
-        m_ActiveEdges = AelNext;
-
-    if( AelNext )
-        AelNext->PrevInAEL = AelPrev;
-
-    e->NextInAEL = 0;
-    e->PrevInAEL = 0;
-}
-
-
-// ------------------------------------------------------------------------------
-
-OutRec* ClipperBase::CreateOutRec()
-{
-    OutRec* result = new OutRec;
-
-    result->IsHole  = false;
-    result->IsOpen  = false;
-    result->FirstLeft = 0;
-    result->Pts = 0;
-    result->BottomPt = 0;
-    result->PolyNd = 0;
-    m_PolyOuts.push_back( result );
-    result->Idx = (int) m_PolyOuts.size() - 1;
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperBase::SwapPositionsInAEL( TEdge* Edge1, TEdge* Edge2 )
-{
-    // check that one or other edge hasn't already been removed from AEL ...
-    if( Edge1->NextInAEL == Edge1->PrevInAEL
-        || Edge2->NextInAEL == Edge2->PrevInAEL )
-        return;
-
-    if( Edge1->NextInAEL == Edge2 )
-    {
-        TEdge* Next = Edge2->NextInAEL;
-
-        if( Next )
-            Next->PrevInAEL = Edge1;
-
-        TEdge* Prev = Edge1->PrevInAEL;
-
-        if( Prev )
-            Prev->NextInAEL = Edge2;
-
-        Edge2->PrevInAEL = Prev;
-        Edge2->NextInAEL = Edge1;
-        Edge1->PrevInAEL = Edge2;
-        Edge1->NextInAEL = Next;
-    }
-    else if( Edge2->NextInAEL == Edge1 )
-    {
-        TEdge* Next = Edge1->NextInAEL;
-
-        if( Next )
-            Next->PrevInAEL = Edge2;
-
-        TEdge* Prev = Edge2->PrevInAEL;
-
-        if( Prev )
-            Prev->NextInAEL = Edge1;
-
-        Edge1->PrevInAEL = Prev;
-        Edge1->NextInAEL = Edge2;
-        Edge2->PrevInAEL = Edge1;
-        Edge2->NextInAEL = Next;
-    }
-    else
-    {
-        TEdge* Next = Edge1->NextInAEL;
-        TEdge* Prev = Edge1->PrevInAEL;
-        Edge1->NextInAEL = Edge2->NextInAEL;
-
-        if( Edge1->NextInAEL )
-            Edge1->NextInAEL->PrevInAEL = Edge1;
-
-        Edge1->PrevInAEL = Edge2->PrevInAEL;
-
-        if( Edge1->PrevInAEL )
-            Edge1->PrevInAEL->NextInAEL = Edge1;
-
-        Edge2->NextInAEL = Next;
-
-        if( Edge2->NextInAEL )
-            Edge2->NextInAEL->PrevInAEL = Edge2;
-
-        Edge2->PrevInAEL = Prev;
-
-        if( Edge2->PrevInAEL )
-            Edge2->PrevInAEL->NextInAEL = Edge2;
-    }
-
-    if( !Edge1->PrevInAEL )
-        m_ActiveEdges = Edge1;
-    else if( !Edge2->PrevInAEL )
-        m_ActiveEdges = Edge2;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperBase::UpdateEdgeIntoAEL( TEdge*& e )
-{
-    if( !e->NextInLML )
-        throw clipperException( "UpdateEdgeIntoAEL: invalid call" );
-
-    e->NextInLML->OutIdx = e->OutIdx;
-    TEdge* AelPrev  = e->PrevInAEL;
-    TEdge* AelNext  = e->NextInAEL;
-
-    if( AelPrev )
-        AelPrev->NextInAEL = e->NextInLML;
-    else
-        m_ActiveEdges = e->NextInLML;
-
-    if( AelNext )
-        AelNext->PrevInAEL = e->NextInLML;
-
-    e->NextInLML->Side = e->Side;
-    e->NextInLML->WindDelta = e->WindDelta;
-    e->NextInLML->WindCnt   = e->WindCnt;
-    e->NextInLML->WindCnt2  = e->WindCnt2;
-    e = e->NextInLML;
-    e->Curr = e->Bot;
-    e->PrevInAEL = AelPrev;
-    e->NextInAEL = AelNext;
-
-    if( !IsHorizontal( *e ) )
-        InsertScanbeam( e->Top.Y );
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool ClipperBase::LocalMinimaPending()
-{
-    return m_CurrentLM != m_MinimaList.end();
-}
-
-
-// ------------------------------------------------------------------------------
-// TClipper methods ...
-// ------------------------------------------------------------------------------
-
-Clipper::Clipper( int initOptions ) : ClipperBase()    // constructor
-{
-    m_ExecuteLocked = false;
-    m_UseFullRange  = false;
-    m_ReverseOutput = ( (initOptions & ioReverseSolution) != 0 );
-    m_StrictSimple  = ( (initOptions & ioStrictlySimple) != 0 );
-    m_PreserveCollinear = ( (initOptions & ioPreserveCollinear) != 0 );
-    m_HasOpenPaths = false;
-
-    // Avoid uninitialized vars
-    m_ClipType = ctIntersection;
-    m_SortedEdges = nullptr;
-    m_ClipFillType = pftEvenOdd;
-    m_SubjFillType = pftEvenOdd;
-    m_UsingPolyTree = false;
-#ifdef use_xyz
-    m_ZFill = 0;
-#endif
-}
-
-
-// ------------------------------------------------------------------------------
-
-#ifdef use_xyz
-void Clipper::ZFillFunction( ZFillCallback zFillFunc )
-{
-    m_ZFill = zFillFunc;
-}
-
-
-// ------------------------------------------------------------------------------
-#endif
-
-bool Clipper::Execute( ClipType clipType, Paths& solution, PolyFillType fillType )
-{
-    return Execute( clipType, solution, fillType, fillType );
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::Execute( ClipType clipType, PolyTree& polytree, PolyFillType fillType )
-{
-    return Execute( clipType, polytree, fillType, fillType );
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::Execute( ClipType clipType, Paths& solution,
-        PolyFillType subjFillType, PolyFillType clipFillType )
-{
-    if( m_ExecuteLocked )
-        return false;
-
-    if( m_HasOpenPaths )
-        throw clipperException( "Error: PolyTree struct is needed for open path clipping." );
-
-    m_ExecuteLocked = true;
-    solution.resize( 0 );
-    m_SubjFillType  = subjFillType;
-    m_ClipFillType  = clipFillType;
-    m_ClipType = clipType;
-    m_UsingPolyTree = false;
-    bool succeeded = ExecuteInternal();
-
-    if( succeeded )
-        BuildResult( solution );
-
-    DisposeAllOutRecs();
-    m_ExecuteLocked = false;
-    return succeeded;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::Execute( ClipType clipType, PolyTree& polytree,
-        PolyFillType subjFillType, PolyFillType clipFillType )
-{
-    if( m_ExecuteLocked )
-        return false;
-
-    m_ExecuteLocked = true;
-    m_SubjFillType  = subjFillType;
-    m_ClipFillType  = clipFillType;
-    m_ClipType = clipType;
-    m_UsingPolyTree = true;
-    bool succeeded = ExecuteInternal();
-
-    if( succeeded )
-        BuildResult2( polytree );
-
-    DisposeAllOutRecs();
-    m_ExecuteLocked = false;
-    return succeeded;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::FixHoleLinkage( OutRec& outrec )
-{
-    // skip OutRecs that (a) contain outermost polygons or
-    // (b) already have the correct owner/child linkage ...
-    if( !outrec.FirstLeft
-        || (outrec.IsHole != outrec.FirstLeft->IsHole
-            && outrec.FirstLeft->Pts) )
-        return;
-
-    OutRec* orfl = outrec.FirstLeft;
-
-    while( orfl && ( (orfl->IsHole == outrec.IsHole) || !orfl->Pts ) )
-        orfl = orfl->FirstLeft;
-
-    outrec.FirstLeft = orfl;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::ExecuteInternal()
-{
-    bool succeeded = true;
-
-    try
-    {
-        Reset();
-        m_Maxima = MaximaList();
-        m_SortedEdges = 0;
-
-        succeeded = true;
-        cInt botY, topY;
-
-        if( !PopScanbeam( botY ) )
-            return false;
-
-        InsertLocalMinimaIntoAEL( botY );
-
-        while( PopScanbeam( topY ) || LocalMinimaPending() )
-        {
-            ProcessHorizontals();
-            ClearGhostJoins();
-
-            if( !ProcessIntersections( topY ) )
-            {
-                succeeded = false;
-                break;
-            }
-
-            ProcessEdgesAtTopOfScanbeam( topY );
-            botY = topY;
-            InsertLocalMinimaIntoAEL( botY );
-        }
-    }
-    catch( ... )
-    {
-        succeeded = false;
-    }
-
-    if( succeeded )
-    {
-        // fix orientations ...
-        for( PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i )
-        {
-            OutRec* outRec = m_PolyOuts[i];
-
-            if( !outRec->Pts || outRec->IsOpen )
-                continue;
-
-            if( (outRec->IsHole ^ m_ReverseOutput) == (Area( *outRec ) > 0) )
-                ReversePolyPtLinks( outRec->Pts );
-        }
-
-        if( !m_Joins.empty() )
-            JoinCommonEdges();
-
-        // unfortunately FixupOutPolygon() must be done after JoinCommonEdges()
-        for( PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i )
-        {
-            OutRec* outRec = m_PolyOuts[i];
-
-            if( !outRec->Pts )
-                continue;
-
-            if( outRec->IsOpen )
-                FixupOutPolyline( *outRec );
-            else
-                FixupOutPolygon( *outRec );
-        }
-
-        if( m_StrictSimple )
-            DoSimplePolygons();
-    }
-
-    ClearJoins();
-    ClearGhostJoins();
-    return succeeded;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::SetWindingCount( TEdge& edge )
-{
-    TEdge* e = edge.PrevInAEL;
-
-    // find the edge of the same polytype that immediately preceeds 'edge' in AEL
-    while( e  && ( (e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0) ) )
-        e = e->PrevInAEL;
-
-    if( !e )
-    {
-        if( edge.WindDelta == 0 )
-        {
-            PolyFillType pft = (edge.PolyTyp == ptSubject ? m_SubjFillType : m_ClipFillType);
-            edge.WindCnt = (pft == pftNegative ? -1 : 1);
-        }
-        else
-            edge.WindCnt = edge.WindDelta;
-
-        edge.WindCnt2 = 0;
-        e = m_ActiveEdges; // ie get ready to calc WindCnt2
-    }
-    else if( edge.WindDelta == 0 && m_ClipType != ctUnion )
-    {
-        edge.WindCnt = 1;
-        edge.WindCnt2 = e->WindCnt2;
-        e = e->NextInAEL; // ie get ready to calc WindCnt2
-    }
-    else if( IsEvenOddFillType( edge ) )
-    {
-        // EvenOdd filling ...
-        if( edge.WindDelta == 0 )
-        {
-            // are we inside a subj polygon ...
-            bool Inside = true;
-            TEdge* e2 = e->PrevInAEL;
-
-            while( e2 )
-            {
-                if( e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0 )
-                    Inside = !Inside;
-
-                e2 = e2->PrevInAEL;
-            }
-
-            edge.WindCnt = (Inside ? 0 : 1);
-        }
-        else
-        {
-            edge.WindCnt = edge.WindDelta;
-        }
-
-        edge.WindCnt2 = e->WindCnt2;
-        e = e->NextInAEL; // ie get ready to calc WindCnt2
-    }
-    else
-    {
-        // nonZero, Positive or Negative filling ...
-        if( e->WindCnt * e->WindDelta < 0 )
-        {
-            // prev edge is 'decreasing' WindCount (WC) toward zero
-            // so we're outside the previous polygon ...
-            if( Abs( e->WindCnt ) > 1 )
-            {
-                // outside prev poly but still inside another.
-                // when reversing direction of prev poly use the same WC
-                if( e->WindDelta * edge.WindDelta < 0 )
-                    edge.WindCnt = e->WindCnt;
-                // otherwise continue to 'decrease' WC ...
-                else
-                    edge.WindCnt = e->WindCnt + edge.WindDelta;
-            }
-            else
-                // now outside all polys of same polytype so set own WC ...
-                edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta);
-        }
-        else
-        {
-            // prev edge is 'increasing' WindCount (WC) away from zero
-            // so we're inside the previous polygon ...
-            if( edge.WindDelta == 0 )
-                edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1);
-            // if wind direction is reversing prev then use same WC
-            else if( e->WindDelta * edge.WindDelta < 0 )
-                edge.WindCnt = e->WindCnt;
-            // otherwise add to WC ...
-            else
-                edge.WindCnt = e->WindCnt + edge.WindDelta;
-        }
-
-        edge.WindCnt2 = e->WindCnt2;
-        e = e->NextInAEL; // ie get ready to calc WindCnt2
-    }
-
-    // update WindCnt2 ...
-    if( IsEvenOddAltFillType( edge ) )
-    {
-        // EvenOdd filling ...
-        while( e != &edge )
-        {
-            if( e->WindDelta != 0 )
-                edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0);
-
-            e = e->NextInAEL;
-        }
-    }
-    else
-    {
-        // nonZero, Positive or Negative filling ...
-        while( e != &edge )
-        {
-            edge.WindCnt2 += e->WindDelta;
-            e = e->NextInAEL;
-        }
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::IsEvenOddFillType( const TEdge& edge ) const
-{
-    if( edge.PolyTyp == ptSubject )
-        return m_SubjFillType == pftEvenOdd;
-    else
-        return m_ClipFillType == pftEvenOdd;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::IsEvenOddAltFillType( const TEdge& edge ) const
-{
-    if( edge.PolyTyp == ptSubject )
-        return m_ClipFillType == pftEvenOdd;
-    else
-        return m_SubjFillType == pftEvenOdd;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::IsContributing( const TEdge& edge ) const
-{
-    PolyFillType pft, pft2;
-
-    if( edge.PolyTyp == ptSubject )
-    {
-        pft = m_SubjFillType;
-        pft2 = m_ClipFillType;
-    }
-    else
-    {
-        pft = m_ClipFillType;
-        pft2 = m_SubjFillType;
-    }
-
-    switch( pft )
-    {
-    case pftEvenOdd:
-
-        // return false if a subj line has been flagged as inside a subj polygon
-        if( edge.WindDelta == 0 && edge.WindCnt != 1 )
-            return false;
-
-        break;
-
-    case pftNonZero:
-
-        if( Abs( edge.WindCnt ) != 1 )
-            return false;
-
-        break;
-
-    case pftPositive:
-
-        if( edge.WindCnt != 1 )
-            return false;
-
-        break;
-
-    default:    // pftNegative
-
-        if( edge.WindCnt != -1 )
-            return false;
-    }
-
-    switch( m_ClipType )
-    {
-    case ctIntersection:
-
-        switch( pft2 )
-        {
-        case pftEvenOdd:
-        case pftNonZero:
-            return edge.WindCnt2 != 0;
-
-        case pftPositive:
-            return edge.WindCnt2 > 0;
-
-        default:
-            return edge.WindCnt2 < 0;
-        }
-
-        break;
-
-    case ctUnion:
-
-        switch( pft2 )
-        {
-        case pftEvenOdd:
-        case pftNonZero:
-            return edge.WindCnt2 == 0;
-
-        case pftPositive:
-            return edge.WindCnt2 <= 0;
-
-        default:
-            return edge.WindCnt2 >= 0;
-        }
-
-        break;
-
-    case ctDifference:
-
-        if( edge.PolyTyp == ptSubject )
-            switch( pft2 )
-            {
-            case pftEvenOdd:
-            case pftNonZero:
-                return edge.WindCnt2 == 0;
-
-            case pftPositive:
-                return edge.WindCnt2 <= 0;
-
-            default:
-                return edge.WindCnt2 >= 0;
-            }
-
-
-        else
-            switch( pft2 )
-            {
-            case pftEvenOdd:
-            case pftNonZero:
-                return edge.WindCnt2 != 0;
-
-            case pftPositive:
-                return edge.WindCnt2 > 0;
-
-            default:
-                return edge.WindCnt2 < 0;
-            }
-
-
-        break;
-
-    case ctXor:
-
-        if( edge.WindDelta == 0 ) // XOr always contributing unless open
-            switch( pft2 )
-            {
-            case pftEvenOdd:
-            case pftNonZero:
-                return edge.WindCnt2 == 0;
-
-            case pftPositive:
-                return edge.WindCnt2 <= 0;
-
-            default:
-                return edge.WindCnt2 >= 0;
-            }
-
-
-        else
-            return true;
-
-        break;
-
-    default:
-        return true;
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-OutPt* Clipper::AddLocalMinPoly( TEdge* e1, TEdge* e2, const IntPoint& Pt )
-{
-    OutPt* result;
-    TEdge* e, * prevE;
-
-    if( IsHorizontal( *e2 ) || ( e1->Dx > e2->Dx ) )
-    {
-        result = AddOutPt( e1, Pt );
-        e2->OutIdx  = e1->OutIdx;
-        e1->Side    = esLeft;
-        e2->Side    = esRight;
-        e = e1;
-
-        if( e->PrevInAEL == e2 )
-            prevE = e2->PrevInAEL;
-        else
-            prevE = e->PrevInAEL;
-    }
-    else
-    {
-        result = AddOutPt( e2, Pt );
-        e1->OutIdx  = e2->OutIdx;
-        e1->Side    = esRight;
-        e2->Side    = esLeft;
-        e = e2;
-
-        if( e->PrevInAEL == e1 )
-            prevE = e1->PrevInAEL;
-        else
-            prevE = e->PrevInAEL;
-    }
-
-    if( prevE && prevE->OutIdx >= 0 && prevE->Top.Y < Pt.Y && e->Top.Y < Pt.Y )
-    {
-        cInt xPrev = TopX( *prevE, Pt.Y );
-        cInt xE = TopX( *e, Pt.Y );
-
-        if( xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0)
-            && SlopesEqual( IntPoint( xPrev, Pt.Y ), prevE->Top, IntPoint( xE, Pt.Y ), e->Top,
-                    m_UseFullRange ) )
-        {
-            OutPt* outPt = AddOutPt( prevE, Pt );
-            AddJoin( result, outPt, e->Top );
-        }
-    }
-
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::AddLocalMaxPoly( TEdge* e1, TEdge* e2, const IntPoint& Pt )
-{
-    AddOutPt( e1, Pt );
-
-    if( e2->WindDelta == 0 )
-        AddOutPt( e2, Pt );
-
-    if( e1->OutIdx == e2->OutIdx )
-    {
-        e1->OutIdx  = Unassigned;
-        e2->OutIdx  = Unassigned;
-    }
-    else if( e1->OutIdx < e2->OutIdx )
-        AppendPolygon( e1, e2 );
-    else
-        AppendPolygon( e2, e1 );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::AddEdgeToSEL( TEdge* edge )
-{
-    // SEL pointers in PEdge are reused to build a list of horizontal edges.
-    // However, we don't need to worry about order with horizontal edge processing.
-    if( !m_SortedEdges )
-    {
-        m_SortedEdges = edge;
-        edge->PrevInSEL = 0;
-        edge->NextInSEL = 0;
-    }
-    else
-    {
-        edge->NextInSEL = m_SortedEdges;
-        edge->PrevInSEL = 0;
-        m_SortedEdges->PrevInSEL = edge;
-        m_SortedEdges = edge;
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::PopEdgeFromSEL( TEdge*& edge )
-{
-    if( !m_SortedEdges )
-        return false;
-
-    edge = m_SortedEdges;
-    DeleteFromSEL( m_SortedEdges );
-    return true;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::CopyAELToSEL()
-{
-    TEdge* e = m_ActiveEdges;
-
-    m_SortedEdges = e;
-
-    while( e )
-    {
-        e->PrevInSEL = e->PrevInAEL;
-        e->NextInSEL = e->NextInAEL;
-        e = e->NextInAEL;
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::AddJoin( OutPt* op1, OutPt* op2, const IntPoint OffPt )
-{
-    Join* j = new Join;
-
-    j->OutPt1 = op1;
-    j->OutPt2 = op2;
-    j->OffPt = OffPt;
-    m_Joins.push_back( j );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::ClearJoins()
-{
-    for( JoinList::size_type i = 0; i < m_Joins.size(); i++ )
-        delete m_Joins[i];
-
-    m_Joins.resize( 0 );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::ClearGhostJoins()
-{
-    for( JoinList::size_type i = 0; i < m_GhostJoins.size(); i++ )
-        delete m_GhostJoins[i];
-
-    m_GhostJoins.resize( 0 );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::AddGhostJoin( OutPt* op, const IntPoint OffPt )
-{
-    Join* j = new Join;
-
-    j->OutPt1 = op;
-    j->OutPt2 = 0;
-    j->OffPt = OffPt;
-    m_GhostJoins.push_back( j );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::InsertLocalMinimaIntoAEL( const cInt botY )
-{
-    const LocalMinimum* lm;
-
-    while( PopLocalMinima( botY, lm ) )
-    {
-        TEdge* lb   = lm->LeftBound;
-        TEdge* rb   = lm->RightBound;
-
-        OutPt* Op1 = 0;
-
-        if( !lb )
-        {
-            // nb: don't insert LB into either AEL or SEL
-            InsertEdgeIntoAEL( rb, 0 );
-            SetWindingCount( *rb );
-
-            if( IsContributing( *rb ) )
-                Op1 = AddOutPt( rb, rb->Bot );
-        }
-        else if( !rb )
-        {
-            InsertEdgeIntoAEL( lb, 0 );
-            SetWindingCount( *lb );
-
-            if( IsContributing( *lb ) )
-                Op1 = AddOutPt( lb, lb->Bot );
-
-            InsertScanbeam( lb->Top.Y );
-        }
-        else
-        {
-            InsertEdgeIntoAEL( lb, 0 );
-            InsertEdgeIntoAEL( rb, lb );
-            SetWindingCount( *lb );
-            rb->WindCnt = lb->WindCnt;
-            rb->WindCnt2 = lb->WindCnt2;
-
-            if( IsContributing( *lb ) )
-                Op1 = AddLocalMinPoly( lb, rb, lb->Bot );
-
-            InsertScanbeam( lb->Top.Y );
-        }
-
-        if( rb )
-        {
-            if( IsHorizontal( *rb ) )
-            {
-                AddEdgeToSEL( rb );
-
-                if( rb->NextInLML )
-                    InsertScanbeam( rb->NextInLML->Top.Y );
-            }
-            else
-                InsertScanbeam( rb->Top.Y );
-        }
-
-        if( !lb || !rb )
-            continue;
-
-        // if any output polygons share an edge, they'll need joining later ...
-        if( Op1 && IsHorizontal( *rb )
-            && m_GhostJoins.size() > 0 && (rb->WindDelta != 0) )
-        {
-            for( JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i )
-            {
-                Join* jr = m_GhostJoins[i];
-
-                // if the horizontal Rb and a 'ghost' horizontal overlap, then convert
-                // the 'ghost' join to a real join ready for later ...
-                if( HorzSegmentsOverlap( jr->OutPt1->Pt.X, jr->OffPt.X, rb->Bot.X, rb->Top.X ) )
-                    AddJoin( jr->OutPt1, Op1, jr->OffPt );
-            }
-        }
-
-        if( lb->OutIdx >= 0 && lb->PrevInAEL
-            && lb->PrevInAEL->Curr.X == lb->Bot.X
-            && lb->PrevInAEL->OutIdx >= 0
-            && SlopesEqual( lb->PrevInAEL->Bot, lb->PrevInAEL->Top, lb->Curr, lb->Top,
-                    m_UseFullRange )
-            && (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0) )
-        {
-            OutPt* Op2 = AddOutPt( lb->PrevInAEL, lb->Bot );
-            AddJoin( Op1, Op2, lb->Top );
-        }
-
-        if( lb->NextInAEL != rb )
-        {
-            if( rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0
-                && SlopesEqual( rb->PrevInAEL->Curr, rb->PrevInAEL->Top, rb->Curr, rb->Top,
-                        m_UseFullRange )
-                && (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0) )
-            {
-                OutPt* Op2 = AddOutPt( rb->PrevInAEL, rb->Bot );
-                AddJoin( Op1, Op2, rb->Top );
-            }
-
-            TEdge* e = lb->NextInAEL;
-
-            if( e )
-            {
-                while( e != rb )
-                {
-                    // nb: For calculating winding counts etc, IntersectEdges() assumes
-                    // that param1 will be to the Right of param2 ABOVE the intersection ...
-                    IntersectEdges( rb, e, lb->Curr ); // order important here
-                    e = e->NextInAEL;
-                }
-            }
-        }
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::DeleteFromSEL( TEdge* e )
-{
-    TEdge* SelPrev  = e->PrevInSEL;
-    TEdge* SelNext  = e->NextInSEL;
-
-    if( !SelPrev &&  !SelNext && (e != m_SortedEdges) )
-        return;                                               // already deleted
-
-    if( SelPrev )
-        SelPrev->NextInSEL = SelNext;
-    else
-        m_SortedEdges = SelNext;
-
-    if( SelNext )
-        SelNext->PrevInSEL = SelPrev;
-
-    e->NextInSEL = 0;
-    e->PrevInSEL = 0;
-}
-
-
-// ------------------------------------------------------------------------------
-
-#ifdef use_xyz
-void Clipper::SetZ( IntPoint& pt, TEdge& e1, TEdge& e2 )
-{
-    if( pt.Z != 0 || !m_ZFill )
-        return;
-    else if( pt == e1.Bot )
-        pt.Z = e1.Bot.Z;
-    else if( pt == e1.Top )
-        pt.Z = e1.Top.Z;
-    else if( pt == e2.Bot )
-        pt.Z = e2.Bot.Z;
-    else if( pt == e2.Top )
-        pt.Z = e2.Top.Z;
-    else
-        m_ZFill( e1.Bot, e1.Top, e2.Bot, e2.Top, pt );
-}
-
-
-// ------------------------------------------------------------------------------
-#endif
-
-void Clipper::IntersectEdges( TEdge* e1, TEdge* e2, IntPoint& Pt )
-{
-    bool e1Contributing = ( e1->OutIdx >= 0 );
-    bool e2Contributing = ( e2->OutIdx >= 0 );
-
-#ifdef use_xyz
-    SetZ( Pt, *e1, *e2 );
-#endif
-
-#ifdef use_lines
-
-    // if either edge is on an OPEN path ...
-    if( e1->WindDelta == 0 || e2->WindDelta == 0 )
-    {
-        // ignore subject-subject open path intersections UNLESS they
-        // are both open paths, AND they are both 'contributing maximas' ...
-        if( e1->WindDelta == 0 && e2->WindDelta == 0 )
-            return;
-
-        // if intersecting a subj line with a subj poly ...
-        else if( e1->PolyTyp == e2->PolyTyp
-                 && e1->WindDelta != e2->WindDelta && m_ClipType == ctUnion )
-        {
-            if( e1->WindDelta == 0 )
-            {
-                if( e2Contributing )
-                {
-                    AddOutPt( e1, Pt );
-
-                    if( e1Contributing )
-                        e1->OutIdx = Unassigned;
-                }
-            }
-            else
-            {
-                if( e1Contributing )
-                {
-                    AddOutPt( e2, Pt );
-
-                    if( e2Contributing )
-                        e2->OutIdx = Unassigned;
-                }
-            }
-        }
-        else if( e1->PolyTyp != e2->PolyTyp )
-        {
-            // toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ...
-            if( (e1->WindDelta == 0) && abs( e2->WindCnt ) == 1
-                && (m_ClipType != ctUnion || e2->WindCnt2 == 0) )
-            {
-                AddOutPt( e1, Pt );
-
-                if( e1Contributing )
-                    e1->OutIdx = Unassigned;
-            }
-            else if( (e2->WindDelta == 0) && (abs( e1->WindCnt ) == 1)
-                     && (m_ClipType != ctUnion || e1->WindCnt2 == 0) )
-            {
-                AddOutPt( e2, Pt );
-
-                if( e2Contributing )
-                    e2->OutIdx = Unassigned;
-            }
-        }
-
-        return;
-    }
-
-#endif
-
-    // update winding counts...
-    // assumes that e1 will be to the Right of e2 ABOVE the intersection
-    if( e1->PolyTyp == e2->PolyTyp )
-    {
-        if( IsEvenOddFillType( *e1 ) )
-        {
-            int oldE1WindCnt = e1->WindCnt;
-            e1->WindCnt = e2->WindCnt;
-            e2->WindCnt = oldE1WindCnt;
-        }
-        else
-        {
-            if( e1->WindCnt + e2->WindDelta == 0 )
-                e1->WindCnt = -e1->WindCnt;
-            else
-                e1->WindCnt += e2->WindDelta;
-
-            if( e2->WindCnt - e1->WindDelta == 0 )
-                e2->WindCnt = -e2->WindCnt;
-            else
-                e2->WindCnt -= e1->WindDelta;
-        }
-    }
-    else
-    {
-        if( !IsEvenOddFillType( *e2 ) )
-            e1->WindCnt2 += e2->WindDelta;
-        else
-            e1->WindCnt2 = ( e1->WindCnt2 == 0 ) ? 1 : 0;
-
-        if( !IsEvenOddFillType( *e1 ) )
-            e2->WindCnt2 -= e1->WindDelta;
-        else
-            e2->WindCnt2 = ( e2->WindCnt2 == 0 ) ? 1 : 0;
-    }
-
-    PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
-
-    if( e1->PolyTyp == ptSubject )
-    {
-        e1FillType  = m_SubjFillType;
-        e1FillType2 = m_ClipFillType;
-    }
-    else
-    {
-        e1FillType  = m_ClipFillType;
-        e1FillType2 = m_SubjFillType;
-    }
-
-    if( e2->PolyTyp == ptSubject )
-    {
-        e2FillType  = m_SubjFillType;
-        e2FillType2 = m_ClipFillType;
-    }
-    else
-    {
-        e2FillType  = m_ClipFillType;
-        e2FillType2 = m_SubjFillType;
-    }
-
-    cInt e1Wc, e2Wc;
-
-    switch( e1FillType )
-    {
-    case pftPositive:
-        e1Wc = e1->WindCnt; break;
-
-    case pftNegative:
-        e1Wc = -e1->WindCnt; break;
-
-    default:
-        e1Wc = Abs( e1->WindCnt );
-    }
-
-    switch( e2FillType )
-    {
-    case pftPositive:
-        e2Wc = e2->WindCnt; break;
-
-    case pftNegative:
-        e2Wc = -e2->WindCnt; break;
-
-    default:
-        e2Wc = Abs( e2->WindCnt );
-    }
-
-    if( e1Contributing && e2Contributing )
-    {
-        if( (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1)
-            || (e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) )
-        {
-            AddLocalMaxPoly( e1, e2, Pt );
-        }
-        else
-        {
-            AddOutPt( e1, Pt );
-            AddOutPt( e2, Pt );
-            SwapSides( *e1, *e2 );
-            SwapPolyIndexes( *e1, *e2 );
-        }
-    }
-    else if( e1Contributing )
-    {
-        if( e2Wc == 0 || e2Wc == 1 )
-        {
-            AddOutPt( e1, Pt );
-            SwapSides( *e1, *e2 );
-            SwapPolyIndexes( *e1, *e2 );
-        }
-    }
-    else if( e2Contributing )
-    {
-        if( e1Wc == 0 || e1Wc == 1 )
-        {
-            AddOutPt( e2, Pt );
-            SwapSides( *e1, *e2 );
-            SwapPolyIndexes( *e1, *e2 );
-        }
-    }
-    else if( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1) )
-    {
-        // neither edge is currently contributing ...
-
-        cInt e1Wc2, e2Wc2;
-
-        switch( e1FillType2 )
-        {
-        case pftPositive:
-            e1Wc2 = e1->WindCnt2; break;
-
-        case pftNegative:
-            e1Wc2 = -e1->WindCnt2; break;
-
-        default:
-            e1Wc2 = Abs( e1->WindCnt2 );
-        }
-
-        switch( e2FillType2 )
-        {
-        case pftPositive:
-            e2Wc2 = e2->WindCnt2; break;
-
-        case pftNegative:
-            e2Wc2 = -e2->WindCnt2; break;
-
-        default:
-            e2Wc2 = Abs( e2->WindCnt2 );
-        }
-
-        if( e1->PolyTyp != e2->PolyTyp )
-        {
-            AddLocalMinPoly( e1, e2, Pt );
-        }
-        else if( e1Wc == 1 && e2Wc == 1 )
-            switch( m_ClipType )
-            {
-            case ctIntersection:
-
-                if( e1Wc2 > 0 && e2Wc2 > 0 )
-                    AddLocalMinPoly( e1, e2, Pt );
-
-                break;
-
-            case ctUnion:
-
-                if( e1Wc2 <= 0 && e2Wc2 <= 0 )
-                    AddLocalMinPoly( e1, e2, Pt );
-
-                break;
-
-            case ctDifference:
-
-                if( ( (e1->PolyTyp == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0) )
-                    || ( (e1->PolyTyp == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0) ) )
-                    AddLocalMinPoly( e1, e2, Pt );
-
-                break;
-
-            case ctXor:
-                AddLocalMinPoly( e1, e2, Pt );
-            }
-
-
-        else
-            SwapSides( *e1, *e2 );
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::SetHoleState( TEdge* e, OutRec* outrec )
-{
-    TEdge* e2 = e->PrevInAEL;
-    TEdge* eTmp = 0;
-
-    while( e2 )
-    {
-        if( e2->OutIdx >= 0 && e2->WindDelta != 0 )
-        {
-            if( !eTmp )
-                eTmp = e2;
-            else if( eTmp->OutIdx == e2->OutIdx )
-                eTmp = 0;
-        }
-
-        e2 = e2->PrevInAEL;
-    }
-
-    if( !eTmp )
-    {
-        outrec->FirstLeft = 0;
-        outrec->IsHole = false;
-    }
-    else
-    {
-        outrec->FirstLeft = m_PolyOuts[eTmp->OutIdx];
-        outrec->IsHole = !outrec->FirstLeft->IsHole;
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-OutRec* GetLowermostRec( OutRec* outRec1, OutRec* outRec2 )
-{
-    // work out which polygon fragment has the correct hole state ...
-    if( !outRec1->BottomPt )
-        outRec1->BottomPt = GetBottomPt( outRec1->Pts );
-
-    if( !outRec2->BottomPt )
-        outRec2->BottomPt = GetBottomPt( outRec2->Pts );
-
-    OutPt* OutPt1   = outRec1->BottomPt;
-    OutPt* OutPt2   = outRec2->BottomPt;
-
-    if( OutPt1->Pt.Y > OutPt2->Pt.Y )
-        return outRec1;
-    else if( OutPt1->Pt.Y < OutPt2->Pt.Y )
-        return outRec2;
-    else if( OutPt1->Pt.X < OutPt2->Pt.X )
-        return outRec1;
-    else if( OutPt1->Pt.X > OutPt2->Pt.X )
-        return outRec2;
-    else if( OutPt1->Next == OutPt1 )
-        return outRec2;
-    else if( OutPt2->Next == OutPt2 )
-        return outRec1;
-    else if( FirstIsBottomPt( OutPt1, OutPt2 ) )
-        return outRec1;
-    else
-        return outRec2;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool OutRec1RightOfOutRec2( OutRec* outRec1, OutRec* outRec2 )
-{
-    do
-    {
-        outRec1 = outRec1->FirstLeft;
-
-        if( outRec1 == outRec2 )
-            return true;
-    } while( outRec1 );
-
-    return false;
-}
-
-
-// ------------------------------------------------------------------------------
-
-OutRec* Clipper::GetOutRec( int Idx )
-{
-    OutRec* outrec = m_PolyOuts[Idx];
-
-    while( outrec != m_PolyOuts[outrec->Idx] )
-        outrec = m_PolyOuts[outrec->Idx];
-
-    return outrec;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::AppendPolygon( TEdge* e1, TEdge* e2 )
-{
-    // get the start and ends of both output polygons ...
-    OutRec* outRec1 = m_PolyOuts[e1->OutIdx];
-    OutRec* outRec2 = m_PolyOuts[e2->OutIdx];
-
-    OutRec* holeStateRec;
-
-    if( OutRec1RightOfOutRec2( outRec1, outRec2 ) )
-        holeStateRec = outRec2;
-    else if( OutRec1RightOfOutRec2( outRec2, outRec1 ) )
-        holeStateRec = outRec1;
-    else
-        holeStateRec = GetLowermostRec( outRec1, outRec2 );
-
-    // get the start and ends of both output polygons and
-    // join e2 poly onto e1 poly and delete pointers to e2 ...
-
-    OutPt* p1_lft   = outRec1->Pts;
-    OutPt* p1_rt    = p1_lft->Prev;
-    OutPt* p2_lft   = outRec2->Pts;
-    OutPt* p2_rt    = p2_lft->Prev;
-
-    // join e2 poly onto e1 poly and delete pointers to e2 ...
-    if(  e1->Side == esLeft )
-    {
-        if(  e2->Side == esLeft )
-        {
-            // z y x a b c
-            ReversePolyPtLinks( p2_lft );
-            p2_lft->Next = p1_lft;
-            p1_lft->Prev = p2_lft;
-            p1_rt->Next = p2_rt;
-            p2_rt->Prev = p1_rt;
-            outRec1->Pts = p2_rt;
-        }
-        else
-        {
-            // x y z a b c
-            p2_rt->Next = p1_lft;
-            p1_lft->Prev = p2_rt;
-            p2_lft->Prev = p1_rt;
-            p1_rt->Next = p2_lft;
-            outRec1->Pts = p2_lft;
-        }
-    }
-    else
-    {
-        if(  e2->Side == esRight )
-        {
-            // a b c z y x
-            ReversePolyPtLinks( p2_lft );
-            p1_rt->Next = p2_rt;
-            p2_rt->Prev = p1_rt;
-            p2_lft->Next = p1_lft;
-            p1_lft->Prev = p2_lft;
-        }
-        else
-        {
-            // a b c x y z
-            p1_rt->Next = p2_lft;
-            p2_lft->Prev = p1_rt;
-            p1_lft->Prev = p2_rt;
-            p2_rt->Next = p1_lft;
-        }
-    }
-
-    outRec1->BottomPt = 0;
-
-    if( holeStateRec == outRec2 )
-    {
-        if( outRec2->FirstLeft != outRec1 )
-            outRec1->FirstLeft = outRec2->FirstLeft;
-
-        outRec1->IsHole = outRec2->IsHole;
-    }
-
-    outRec2->Pts = 0;
-    outRec2->BottomPt = 0;
-    outRec2->FirstLeft = outRec1;
-
-    int OKIdx = e1->OutIdx;
-    int ObsoleteIdx = e2->OutIdx;
-
-    e1->OutIdx  = Unassigned; // nb: safe because we only get here via AddLocalMaxPoly
-    e2->OutIdx  = Unassigned;
-
-    TEdge* e = m_ActiveEdges;
-
-    while( e )
-    {
-        if( e->OutIdx == ObsoleteIdx )
-        {
-            e->OutIdx = OKIdx;
-            e->Side = e1->Side;
-            break;
-        }
-
-        e = e->NextInAEL;
-    }
-
-    outRec2->Idx = outRec1->Idx;
-}
-
-
-// ------------------------------------------------------------------------------
-
-OutPt* Clipper::AddOutPt( TEdge* e, const IntPoint& pt )
-{
-    if(  e->OutIdx < 0 )
-    {
-        OutRec* outRec = CreateOutRec();
-        outRec->IsOpen = (e->WindDelta == 0);
-        OutPt* newOp = new OutPt;
-        outRec->Pts = newOp;
-        newOp->Idx  = outRec->Idx;
-        newOp->Pt = pt;
-        newOp->Next = newOp;
-        newOp->Prev = newOp;
-
-        if( !outRec->IsOpen )
-            SetHoleState( e, outRec );
-
-        e->OutIdx = outRec->Idx;
-        return newOp;
-    }
-    else
-    {
-        OutRec* outRec = m_PolyOuts[e->OutIdx];
-        // OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most'
-        OutPt* op = outRec->Pts;
-
-        bool ToFront = (e->Side == esLeft);
-
-        if( ToFront && (pt == op->Pt) )
-            return op;
-        else if( !ToFront && (pt == op->Prev->Pt) )
-            return op->Prev;
-
-        OutPt* newOp = new OutPt;
-        newOp->Idx  = outRec->Idx;
-        newOp->Pt   = pt;
-        newOp->Next = op;
-        newOp->Prev = op->Prev;
-        newOp->Prev->Next = newOp;
-        op->Prev = newOp;
-
-        if( ToFront )
-            outRec->Pts = newOp;
-
-        return newOp;
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-OutPt* Clipper::GetLastOutPt( TEdge* e )
-{
-    OutRec* outRec = m_PolyOuts[e->OutIdx];
-
-    if( e->Side == esLeft )
-        return outRec->Pts;
-    else
-        return outRec->Pts->Prev;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::ProcessHorizontals()
-{
-    TEdge* horzEdge;
-
-    while( PopEdgeFromSEL( horzEdge ) )
-        ProcessHorizontal( horzEdge );
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline bool IsMinima( TEdge* e )
-{
-    return e  && (e->Prev->NextInLML != e) && (e->Next->NextInLML != e);
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline bool IsMaxima( TEdge* e, const cInt Y )
-{
-    return e && e->Top.Y == Y && !e->NextInLML;
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline bool IsIntermediate( TEdge* e, const cInt Y )
-{
-    return e->Top.Y == Y && e->NextInLML;
-}
-
-
-// ------------------------------------------------------------------------------
-
-TEdge* GetMaximaPair( TEdge* e )
-{
-    if( (e->Next->Top == e->Top) && !e->Next->NextInLML )
-        return e->Next;
-    else if( (e->Prev->Top == e->Top) && !e->Prev->NextInLML )
-        return e->Prev;
-    else
-        return 0;
-}
-
-
-// ------------------------------------------------------------------------------
-
-TEdge* GetMaximaPairEx( TEdge* e )
-{
-    // as GetMaximaPair() but returns 0 if MaxPair isn't in AEL (unless it's horizontal)
-    TEdge* result = GetMaximaPair( e );
-
-    if( result && ( result->OutIdx == Skip
-                    || ( result->NextInAEL == result->PrevInAEL && !IsHorizontal( *result ) ) ) )
-        return 0;
-
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::SwapPositionsInSEL( TEdge* Edge1, TEdge* Edge2 )
-{
-    if( !( Edge1->NextInSEL ) &&  !( Edge1->PrevInSEL ) )
-        return;
-
-    if( !( Edge2->NextInSEL ) &&  !( Edge2->PrevInSEL ) )
-        return;
-
-    if(  Edge1->NextInSEL == Edge2 )
-    {
-        TEdge* Next = Edge2->NextInSEL;
-
-        if( Next )
-            Next->PrevInSEL = Edge1;
-
-        TEdge* Prev = Edge1->PrevInSEL;
-
-        if( Prev )
-            Prev->NextInSEL = Edge2;
-
-        Edge2->PrevInSEL = Prev;
-        Edge2->NextInSEL = Edge1;
-        Edge1->PrevInSEL = Edge2;
-        Edge1->NextInSEL = Next;
-    }
-    else if(  Edge2->NextInSEL == Edge1 )
-    {
-        TEdge* Next = Edge1->NextInSEL;
-
-        if( Next )
-            Next->PrevInSEL = Edge2;
-
-        TEdge* Prev = Edge2->PrevInSEL;
-
-        if( Prev )
-            Prev->NextInSEL = Edge1;
-
-        Edge1->PrevInSEL = Prev;
-        Edge1->NextInSEL = Edge2;
-        Edge2->PrevInSEL = Edge1;
-        Edge2->NextInSEL = Next;
-    }
-    else
-    {
-        TEdge* Next = Edge1->NextInSEL;
-        TEdge* Prev = Edge1->PrevInSEL;
-        Edge1->NextInSEL = Edge2->NextInSEL;
-
-        if( Edge1->NextInSEL )
-            Edge1->NextInSEL->PrevInSEL = Edge1;
-
-        Edge1->PrevInSEL = Edge2->PrevInSEL;
-
-        if( Edge1->PrevInSEL )
-            Edge1->PrevInSEL->NextInSEL = Edge1;
-
-        Edge2->NextInSEL = Next;
-
-        if( Edge2->NextInSEL )
-            Edge2->NextInSEL->PrevInSEL = Edge2;
-
-        Edge2->PrevInSEL = Prev;
-
-        if( Edge2->PrevInSEL )
-            Edge2->PrevInSEL->NextInSEL = Edge2;
-    }
-
-    if( !Edge1->PrevInSEL )
-        m_SortedEdges = Edge1;
-    else if( !Edge2->PrevInSEL )
-        m_SortedEdges = Edge2;
-}
-
-
-// ------------------------------------------------------------------------------
-
-TEdge* GetNextInAEL( TEdge* e, Direction dir )
-{
-    return dir == dLeftToRight ? e->NextInAEL : e->PrevInAEL;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void GetHorzDirection( TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right )
-{
-    if( HorzEdge.Bot.X < HorzEdge.Top.X )
-    {
-        Left = HorzEdge.Bot.X;
-        Right = HorzEdge.Top.X;
-        Dir = dLeftToRight;
-    }
-    else
-    {
-        Left = HorzEdge.Top.X;
-        Right = HorzEdge.Bot.X;
-        Dir = dRightToLeft;
-    }
-}
-
-
-// ------------------------------------------------------------------------
-
-/*******************************************************************************
-* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or    *
-* Bottom of a scanbeam) are processed as if layered. The order in which HEs    *
-* are processed doesn't matter. HEs intersect with other HE Bot.Xs only [#]    *
-* (or they could intersect with Top.Xs only, ie EITHER Bot.Xs OR Top.Xs),      *
-* and with other non-horizontal edges [*]. Once these intersections are        *
-* processed, intermediate HEs then 'promote' the Edge above (NextInLML) into   *
-* the AEL. These 'promoted' edges may in turn intersect [%] with other HEs.    *
-*******************************************************************************/
-
-void Clipper::ProcessHorizontal( TEdge* horzEdge )
-{
-    Direction   dir;
-    cInt    horzLeft, horzRight;
-    bool    IsOpen = (horzEdge->WindDelta == 0);
-
-    GetHorzDirection( *horzEdge, dir, horzLeft, horzRight );
-
-    TEdge* eLastHorz = horzEdge, * eMaxPair = 0;
-
-    while( eLastHorz->NextInLML && IsHorizontal( *eLastHorz->NextInLML ) )
-        eLastHorz = eLastHorz->NextInLML;
-
-    if( !eLastHorz->NextInLML )
-        eMaxPair = GetMaximaPair( eLastHorz );
-
-    MaximaList::const_iterator maxIt;
-    MaximaList::const_reverse_iterator maxRit;
-
-    if( m_Maxima.size() > 0 )
-    {
-        // get the first maxima in range (X) ...
-        if( dir == dLeftToRight )
-        {
-            maxIt = m_Maxima.begin();
-
-            while( maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.X )
-                maxIt++;
-
-            if( maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.X )
-                maxIt = m_Maxima.end();
-        }
-        else
-        {
-            maxRit = m_Maxima.rbegin();
-
-            while( maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.X )
-                maxRit++;
-
-            if( maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.X )
-                maxRit = m_Maxima.rend();
-        }
-    }
-
-    OutPt* op1 = 0;
-
-    for( ; ; ) // loop through consec. horizontal edges
-    {
-        bool IsLastHorz = (horzEdge == eLastHorz);
-        TEdge* e = GetNextInAEL( horzEdge, dir );
-
-        while( e )
-        {
-            // this code block inserts extra coords into horizontal edges (in output
-            // polygons) whereever maxima touch these horizontal edges. This helps
-            // 'simplifying' polygons (ie if the Simplify property is set).
-            if( m_Maxima.size() > 0 )
-            {
-                if( dir == dLeftToRight )
-                {
-                    while( maxIt != m_Maxima.end() && *maxIt < e->Curr.X )
-                    {
-                        if( horzEdge->OutIdx >= 0 && !IsOpen )
-                            AddOutPt( horzEdge, IntPoint( *maxIt, horzEdge->Bot.Y ) );
-
-                        maxIt++;
-                    }
-                }
-                else
-                {
-                    while( maxRit != m_Maxima.rend() && *maxRit > e->Curr.X )
-                    {
-                        if( horzEdge->OutIdx >= 0 && !IsOpen )
-                            AddOutPt( horzEdge, IntPoint( *maxRit, horzEdge->Bot.Y ) );
-
-                        maxRit++;
-                    }
-                }
-            }
-
-            ;
-
-            if( (dir == dLeftToRight && e->Curr.X > horzRight)
-                || (dir == dRightToLeft && e->Curr.X < horzLeft) )
-                break;
-
-            // Also break if we've got to the end of an intermediate horizontal edge ...
-            // nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
-            if( e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML
-                && e->Dx < horzEdge->NextInLML->Dx )
-                break;
-
-            if( horzEdge->OutIdx >= 0 && !IsOpen ) // note: may be done multiple times
-            {
-#ifdef use_xyz
-
-                if( dir == dLeftToRight )
-                    SetZ( e->Curr, *horzEdge, *e );
-                else
-                    SetZ( e->Curr, *e, *horzEdge );
-
-#endif
-                op1 = AddOutPt( horzEdge, e->Curr );
-                TEdge* eNextHorz = m_SortedEdges;
-
-                while( eNextHorz )
-                {
-                    if( eNextHorz->OutIdx >= 0
-                        && HorzSegmentsOverlap( horzEdge->Bot.X,
-                                horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X ) )
-                    {
-                        OutPt* op2 = GetLastOutPt( eNextHorz );
-                        AddJoin( op2, op1, eNextHorz->Top );
-                    }
-
-                    eNextHorz = eNextHorz->NextInSEL;
-                }
-
-                AddGhostJoin( op1, horzEdge->Bot );
-            }
-
-            // OK, so far we're still in range of the horizontal Edge  but make sure
-            // we're at the last of consec. horizontals when matching with eMaxPair
-            if( e == eMaxPair && IsLastHorz )
-            {
-                if( horzEdge->OutIdx >= 0 )
-                    AddLocalMaxPoly( horzEdge, eMaxPair, horzEdge->Top );
-
-                DeleteFromAEL( horzEdge );
-                DeleteFromAEL( eMaxPair );
-                return;
-            }
-
-            if( dir == dLeftToRight )
-            {
-                IntPoint Pt = IntPoint( e->Curr.X, horzEdge->Curr.Y );
-                IntersectEdges( horzEdge, e, Pt );
-            }
-            else
-            {
-                IntPoint Pt = IntPoint( e->Curr.X, horzEdge->Curr.Y );
-                IntersectEdges( e, horzEdge, Pt );
-            }
-
-            TEdge* eNext = GetNextInAEL( e, dir );
-            SwapPositionsInAEL( horzEdge, e );
-            e = eNext;
-        }   // end while(e)
-
-        // Break out of loop if HorzEdge.NextInLML is not also horizontal ...
-        if( !horzEdge->NextInLML || !IsHorizontal( *horzEdge->NextInLML ) )
-            break;
-
-        UpdateEdgeIntoAEL( horzEdge );
-
-        if( horzEdge->OutIdx >= 0 )
-            AddOutPt( horzEdge, horzEdge->Bot );
-
-        GetHorzDirection( *horzEdge, dir, horzLeft, horzRight );
-    }   // end for (;;)
-
-    if( horzEdge->OutIdx >= 0 && !op1 )
-    {
-        op1 = GetLastOutPt( horzEdge );
-        TEdge* eNextHorz = m_SortedEdges;
-
-        while( eNextHorz )
-        {
-            if( eNextHorz->OutIdx >= 0
-                && HorzSegmentsOverlap( horzEdge->Bot.X,
-                        horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X ) )
-            {
-                OutPt* op2 = GetLastOutPt( eNextHorz );
-                AddJoin( op2, op1, eNextHorz->Top );
-            }
-
-            eNextHorz = eNextHorz->NextInSEL;
-        }
-
-        AddGhostJoin( op1, horzEdge->Top );
-    }
-
-    if( horzEdge->NextInLML )
-    {
-        if( horzEdge->OutIdx >= 0 )
-        {
-            op1 = AddOutPt( horzEdge, horzEdge->Top );
-            UpdateEdgeIntoAEL( horzEdge );
-
-            if( horzEdge->WindDelta == 0 )
-                return;
-
-            // nb: HorzEdge is no longer horizontal here
-            TEdge* ePrev = horzEdge->PrevInAEL;
-            TEdge* eNext = horzEdge->NextInAEL;
-
-            if( ePrev && ePrev->Curr.X == horzEdge->Bot.X
-                && ePrev->Curr.Y == horzEdge->Bot.Y && ePrev->WindDelta != 0
-                && ( ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y
-                     && SlopesEqual( *horzEdge, *ePrev, m_UseFullRange ) ) )
-            {
-                OutPt* op2 = AddOutPt( ePrev, horzEdge->Bot );
-                AddJoin( op1, op2, horzEdge->Top );
-            }
-            else if( eNext && eNext->Curr.X == horzEdge->Bot.X
-                     && eNext->Curr.Y == horzEdge->Bot.Y && eNext->WindDelta != 0
-                     && eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y
-                     && SlopesEqual( *horzEdge, *eNext, m_UseFullRange ) )
-            {
-                OutPt* op2 = AddOutPt( eNext, horzEdge->Bot );
-                AddJoin( op1, op2, horzEdge->Top );
-            }
-        }
-        else
-            UpdateEdgeIntoAEL( horzEdge );
-    }
-    else
-    {
-        if( horzEdge->OutIdx >= 0 )
-            AddOutPt( horzEdge, horzEdge->Top );
-
-        DeleteFromAEL( horzEdge );
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::ProcessIntersections( const cInt topY )
-{
-    if( !m_ActiveEdges )
-        return true;
-
-    try
-    {
-        BuildIntersectList( topY );
-        size_t IlSize = m_IntersectList.size();
-
-        if( IlSize == 0 )
-            return true;
-
-        if( IlSize == 1 || FixupIntersectionOrder() )
-            ProcessIntersectList();
-        else
-            return false;
-    }
-    catch( ... )
-    {
-        m_SortedEdges = 0;
-        DisposeIntersectNodes();
-        throw clipperException( "ProcessIntersections error" );
-    }
-    m_SortedEdges = 0;
-    return true;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::DisposeIntersectNodes()
-{
-    for( size_t i = 0; i < m_IntersectList.size(); ++i )
-        delete m_IntersectList[i];
-
-    m_IntersectList.clear();
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::BuildIntersectList( const cInt topY )
-{
-    if( !m_ActiveEdges )
-        return;
-
-    // prepare for sorting ...
-    TEdge* e = m_ActiveEdges;
-    m_SortedEdges = e;
-
-    while( e )
-    {
-        e->PrevInSEL = e->PrevInAEL;
-        e->NextInSEL = e->NextInAEL;
-        e->Curr.X = TopX( *e, topY );
-        e = e->NextInAEL;
-    }
-
-    // bubblesort ...
-    bool isModified;
-
-    do
-    {
-        isModified = false;
-        e = m_SortedEdges;
-
-        while( e->NextInSEL )
-        {
-            TEdge* eNext = e->NextInSEL;
-            IntPoint Pt;
-
-            if( e->Curr.X > eNext->Curr.X )
-            {
-                IntersectPoint( *e, *eNext, Pt );
-
-                if( Pt.Y < topY )
-                    Pt = IntPoint( TopX( *e, topY ), topY );
-
-                IntersectNode* newNode = new IntersectNode;
-                newNode->Edge1  = e;
-                newNode->Edge2  = eNext;
-                newNode->Pt = Pt;
-                m_IntersectList.push_back( newNode );
-
-                SwapPositionsInSEL( e, eNext );
-                isModified = true;
-            }
-            else
-                e = eNext;
-        }
-
-        if( e->PrevInSEL )
-            e->PrevInSEL->NextInSEL = 0;
-        else
-            break;
-    } while( isModified );
-
-    m_SortedEdges = 0; // important
-}
-
-
-// ------------------------------------------------------------------------------
-
-
-void Clipper::ProcessIntersectList()
-{
-    for( size_t i = 0; i < m_IntersectList.size(); ++i )
-    {
-        IntersectNode* iNode = m_IntersectList[i];
-        {
-            IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt );
-            SwapPositionsInAEL( iNode->Edge1, iNode->Edge2 );
-        }
-        delete iNode;
-    }
-
-    m_IntersectList.clear();
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool IntersectListSort( IntersectNode* node1, IntersectNode* node2 )
-{
-    return node2->Pt.Y < node1->Pt.Y;
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline bool EdgesAdjacent( const IntersectNode& inode )
-{
-    return (inode.Edge1->NextInSEL == inode.Edge2)
-           || (inode.Edge1->PrevInSEL == inode.Edge2);
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::FixupIntersectionOrder()
-{
-    // pre-condition: intersections are sorted Bottom-most first.
-    // Now it's crucial that intersections are made only between adjacent edges,
-    // so to ensure this the order of intersections may need adjusting ...
-    CopyAELToSEL();
-    std::sort( m_IntersectList.begin(), m_IntersectList.end(), IntersectListSort );
-    size_t cnt = m_IntersectList.size();
-
-    for( size_t i = 0; i < cnt; ++i )
-    {
-        if( !EdgesAdjacent( *m_IntersectList[i] ) )
-        {
-            size_t j = i + 1;
-
-            while( j < cnt && !EdgesAdjacent( *m_IntersectList[j] ) )
-                j++;
-
-            if( j == cnt )
-                return false;
-
-            std::swap( m_IntersectList[i], m_IntersectList[j] );
-        }
-
-        SwapPositionsInSEL( m_IntersectList[i]->Edge1, m_IntersectList[i]->Edge2 );
-    }
-
-    return true;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::DoMaxima( TEdge* e )
-{
-    TEdge* eMaxPair = GetMaximaPairEx( e );
-
-    if( !eMaxPair )
-    {
-        if( e->OutIdx >= 0 )
-            AddOutPt( e, e->Top );
-
-        DeleteFromAEL( e );
-        return;
-    }
-
-    TEdge* eNext = e->NextInAEL;
-
-    while( eNext && eNext != eMaxPair )
-    {
-        IntersectEdges( e, eNext, e->Top );
-        SwapPositionsInAEL( e, eNext );
-        eNext = e->NextInAEL;
-    }
-
-    if( e->OutIdx == Unassigned && eMaxPair->OutIdx == Unassigned )
-    {
-        DeleteFromAEL( e );
-        DeleteFromAEL( eMaxPair );
-    }
-    else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 )
-    {
-        if( e->OutIdx >= 0 )
-            AddLocalMaxPoly( e, eMaxPair, e->Top );
-
-        DeleteFromAEL( e );
-        DeleteFromAEL( eMaxPair );
-    }
-
-#ifdef use_lines
-    else if( e->WindDelta == 0 )
-    {
-        if( e->OutIdx >= 0 )
-        {
-            AddOutPt( e, e->Top );
-            e->OutIdx = Unassigned;
-        }
-
-        DeleteFromAEL( e );
-
-        if( eMaxPair->OutIdx >= 0 )
-        {
-            AddOutPt( eMaxPair, e->Top );
-            eMaxPair->OutIdx = Unassigned;
-        }
-
-        DeleteFromAEL( eMaxPair );
-    }
-#endif
-    else
-        throw clipperException( "DoMaxima error" );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::ProcessEdgesAtTopOfScanbeam( const cInt topY )
-{
-    TEdge* e = m_ActiveEdges;
-
-    while( e )
-    {
-        // 1. process maxima, treating them as if they're 'bent' horizontal edges,
-        // but exclude maxima with horizontal edges. nb: e can't be a horizontal.
-        bool IsMaximaEdge = IsMaxima( e, topY );
-
-        if( IsMaximaEdge )
-        {
-            TEdge* eMaxPair = GetMaximaPairEx( e );
-            IsMaximaEdge = ( !eMaxPair || !IsHorizontal( *eMaxPair ) );
-        }
-
-        if( IsMaximaEdge )
-        {
-            if( m_StrictSimple )
-                m_Maxima.push_back( e->Top.X );
-
-            TEdge* ePrev = e->PrevInAEL;
-            DoMaxima( e );
-
-            if( !ePrev )
-                e = m_ActiveEdges;
-            else
-                e = ePrev->NextInAEL;
-        }
-        else
-        {
-            // 2. promote horizontal edges, otherwise update Curr.X and Curr.Y ...
-            if( IsIntermediate( e, topY ) && IsHorizontal( *e->NextInLML ) )
-            {
-                UpdateEdgeIntoAEL( e );
-
-                if( e->OutIdx >= 0 )
-                    AddOutPt( e, e->Bot );
-
-                AddEdgeToSEL( e );
-            }
-            else
-            {
-                e->Curr.X = TopX( *e, topY );
-                e->Curr.Y = topY;
-#ifdef use_xyz
-                e->Curr.Z = topY == e->Top.Y ? e->Top.Z : (topY == e->Bot.Y ? e->Bot.Z : 0);
-#endif
-            }
-
-            // When StrictlySimple and 'e' is being touched by another edge, then
-            // make sure both edges have a vertex here ...
-            if( m_StrictSimple )
-            {
-                TEdge* ePrev = e->PrevInAEL;
-
-                if( (e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0)
-                    && (ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0) )
-                {
-                    IntPoint pt = e->Curr;
-#ifdef use_xyz
-                    SetZ( pt, *ePrev, *e );
-#endif
-                    OutPt* op   = AddOutPt( ePrev, pt );
-                    OutPt* op2  = AddOutPt( e, pt );
-                    AddJoin( op, op2, pt ); // StrictlySimple (type-3) join
-                }
-            }
-
-            e = e->NextInAEL;
-        }
-    }
-
-    // 3. Process horizontals at the Top of the scanbeam ...
-    m_Maxima.sort();
-    ProcessHorizontals();
-    m_Maxima.clear();
-
-    // 4. Promote intermediate vertices ...
-    e = m_ActiveEdges;
-
-    while( e )
-    {
-        if( IsIntermediate( e, topY ) )
-        {
-            OutPt* op = 0;
-
-            if( e->OutIdx >= 0 )
-                op = AddOutPt( e, e->Top );
-
-            UpdateEdgeIntoAEL( e );
-
-            // if output polygons share an edge, they'll need joining later ...
-            TEdge* ePrev = e->PrevInAEL;
-            TEdge* eNext = e->NextInAEL;
-
-            if( ePrev && ePrev->Curr.X == e->Bot.X
-                && ePrev->Curr.Y == e->Bot.Y && op
-                && ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y
-                && SlopesEqual( e->Curr, e->Top, ePrev->Curr, ePrev->Top, m_UseFullRange )
-                && (e->WindDelta != 0) && (ePrev->WindDelta != 0) )
-            {
-                OutPt* op2 = AddOutPt( ePrev, e->Bot );
-                AddJoin( op, op2, e->Top );
-            }
-            else if( eNext && eNext->Curr.X == e->Bot.X
-                     && eNext->Curr.Y == e->Bot.Y && op
-                     && eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y
-                     && SlopesEqual( e->Curr, e->Top, eNext->Curr, eNext->Top, m_UseFullRange )
-                     && (e->WindDelta != 0) && (eNext->WindDelta != 0) )
-            {
-                OutPt* op2 = AddOutPt( eNext, e->Bot );
-                AddJoin( op, op2, e->Top );
-            }
-        }
-
-        e = e->NextInAEL;
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::FixupOutPolyline( OutRec& outrec )
-{
-    OutPt* pp = outrec.Pts;
-    OutPt* lastPP = pp->Prev;
-
-    while( pp != lastPP )
-    {
-        pp = pp->Next;
-
-        if( pp->Pt == pp->Prev->Pt )
-        {
-            if( pp == lastPP )
-                lastPP = pp->Prev;
-
-            OutPt* tmpPP = pp->Prev;
-            tmpPP->Next = pp->Next;
-            pp->Next->Prev = tmpPP;
-            delete pp;
-            pp = tmpPP;
-        }
-    }
-
-    if( pp == pp->Prev )
-    {
-        DisposeOutPts( pp );
-        outrec.Pts = 0;
-        return;
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::FixupOutPolygon( OutRec& outrec )
-{
-    // FixupOutPolygon() - removes duplicate points and simplifies consecutive
-    // parallel edges by removing the middle vertex.
-    OutPt* lastOK = 0;
-
-    outrec.BottomPt = 0;
-    OutPt* pp = outrec.Pts;
-    bool preserveCol = m_PreserveCollinear || m_StrictSimple;
-
-    for( ; ; )
-    {
-        if( pp->Prev == pp || pp->Prev == pp->Next )
-        {
-            DisposeOutPts( pp );
-            outrec.Pts = 0;
-            return;
-        }
-
-        // test for duplicate points and collinear edges ...
-        if( (pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt)
-            || ( SlopesEqual( pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange )
-                 && ( !preserveCol
-                      || !Pt2IsBetweenPt1AndPt3( pp->Prev->Pt, pp->Pt, pp->Next->Pt ) ) ) )
-        {
-            lastOK = 0;
-            OutPt* tmp = pp;
-            pp->Prev->Next  = pp->Next;
-            pp->Next->Prev  = pp->Prev;
-            pp = pp->Prev;
-            delete tmp;
-        }
-        else if( pp == lastOK )
-            break;
-        else
-        {
-            if( !lastOK )
-                lastOK = pp;
-
-            pp = pp->Next;
-        }
-    }
-
-    outrec.Pts = pp;
-}
-
-
-// ------------------------------------------------------------------------------
-
-int PointCount( OutPt* Pts )
-{
-    if( !Pts )
-        return 0;
-
-    int result = 0;
-    OutPt* p = Pts;
-
-    do
-    {
-        result++;
-        p = p->Next;
-    } while( p != Pts );
-
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::BuildResult( Paths& polys )
-{
-    polys.reserve( m_PolyOuts.size() );
-
-    for( PolyOutList::size_type ii = 0; ii < m_PolyOuts.size(); ++ii )
-    {
-        if( !m_PolyOuts[ii]->Pts )
-            continue;
-
-        Path pg;
-        OutPt* p = m_PolyOuts[ii]->Pts->Prev;
-        int cnt = PointCount( p );
-
-        if( cnt < 2 )
-            continue;
-
-        pg.reserve( cnt );
-
-        for( int jj = 0; jj < cnt; ++jj )
-        {
-            pg.push_back( p->Pt );
-            p = p->Prev;
-        }
-
-        polys.push_back( pg );
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::BuildResult2( PolyTree& polytree )
-{
-    polytree.Clear();
-    polytree.AllNodes.reserve( m_PolyOuts.size() );
-
-    // add each output polygon/contour to polytree ...
-    for( PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++ )
-    {
-        OutRec* outRec = m_PolyOuts[i];
-        int cnt = PointCount( outRec->Pts );
-
-        if( (outRec->IsOpen && cnt < 2) || (!outRec->IsOpen && cnt < 3) )
-            continue;
-
-        FixHoleLinkage( *outRec );
-        PolyNode* pn = new PolyNode();
-        // nb: polytree takes ownership of all the PolyNodes
-        polytree.AllNodes.push_back( pn );
-        outRec->PolyNd = pn;
-        pn->Parent  = 0;
-        pn->Index   = 0;
-        pn->Contour.reserve( cnt );
-        OutPt* op = outRec->Pts->Prev;
-
-        for( int j = 0; j < cnt; j++ )
-        {
-            pn->Contour.push_back( op->Pt );
-            op = op->Prev;
-        }
-    }
-
-    // fixup PolyNode links etc ...
-    polytree.Childs.reserve( m_PolyOuts.size() );
-
-    for( PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++ )
-    {
-        OutRec* outRec = m_PolyOuts[i];
-
-        if( !outRec->PolyNd )
-            continue;
-
-        if( outRec->IsOpen )
-        {
-            outRec->PolyNd->m_IsOpen = true;
-            polytree.AddChild( *outRec->PolyNd );
-        }
-        else if( outRec->FirstLeft && outRec->FirstLeft->PolyNd )
-            outRec->FirstLeft->PolyNd->AddChild( *outRec->PolyNd );
-        else
-            polytree.AddChild( *outRec->PolyNd );
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void SwapIntersectNodes( IntersectNode& int1, IntersectNode& int2 )
-{
-    // just swap the contents (because fIntersectNodes is a single-linked-list)
-    IntersectNode inode = int1; // gets a copy of Int1
-
-    int1.Edge1  = int2.Edge1;
-    int1.Edge2  = int2.Edge2;
-    int1.Pt = int2.Pt;
-    int2.Edge1  = inode.Edge1;
-    int2.Edge2  = inode.Edge2;
-    int2.Pt = inode.Pt;
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline bool E2InsertsBeforeE1( TEdge& e1, TEdge& e2 )
-{
-    if( e2.Curr.X == e1.Curr.X )
-    {
-        if( e2.Top.Y > e1.Top.Y )
-            return e2.Top.X < TopX( e1, e2.Top.Y );
-        else
-            return e1.Top.X > TopX( e2, e1.Top.Y );
-    }
-    else
-        return e2.Curr.X < e1.Curr.X;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool GetOverlap( const cInt a1, const cInt a2, const cInt b1, const cInt b2,
-        cInt& Left, cInt& Right )
-{
-    if( a1 < a2 )
-    {
-        if( b1 < b2 )
-        {
-            Left = std::max( a1, b1 ); Right = std::min( a2, b2 );
-        }
-        else
-        {
-            Left = std::max( a1, b2 ); Right = std::min( a2, b1 );
-        }
-    }
-    else
-    {
-        if( b1 < b2 )
-        {
-            Left = std::max( a2, b1 ); Right = std::min( a1, b2 );
-        }
-        else
-        {
-            Left = std::max( a2, b2 ); Right = std::min( a1, b1 );
-        }
-    }
-
-    return Left < Right;
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline void UpdateOutPtIdxs( OutRec& outrec )
-{
-    OutPt* op = outrec.Pts;
-
-    do
-    {
-        op->Idx = outrec.Idx;
-        op = op->Prev;
-    } while( op != outrec.Pts );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::InsertEdgeIntoAEL( TEdge* edge, TEdge* startEdge )
-{
-    if( !m_ActiveEdges )
-    {
-        edge->PrevInAEL = 0;
-        edge->NextInAEL = 0;
-        m_ActiveEdges = edge;
-    }
-    else if( !startEdge && E2InsertsBeforeE1( *m_ActiveEdges, *edge ) )
-    {
-        edge->PrevInAEL = 0;
-        edge->NextInAEL = m_ActiveEdges;
-        m_ActiveEdges->PrevInAEL = edge;
-        m_ActiveEdges = edge;
-    }
-    else
-    {
-        if( !startEdge )
-            startEdge = m_ActiveEdges;
-
-        while( startEdge->NextInAEL
-               && !E2InsertsBeforeE1( *startEdge->NextInAEL, *edge ) )
-            startEdge = startEdge->NextInAEL;
-
-        edge->NextInAEL = startEdge->NextInAEL;
-
-        if( startEdge->NextInAEL )
-            startEdge->NextInAEL->PrevInAEL = edge;
-
-        edge->PrevInAEL = startEdge;
-        startEdge->NextInAEL = edge;
-    }
-}
-
-
-// ----------------------------------------------------------------------
-
-OutPt* DupOutPt( OutPt* outPt, bool InsertAfter )
-{
-    OutPt* result = new OutPt;
-
-    result->Pt  = outPt->Pt;
-    result->Idx = outPt->Idx;
-
-    if( InsertAfter )
-    {
-        result->Next = outPt->Next;
-        result->Prev = outPt;
-        outPt->Next->Prev = result;
-        outPt->Next = result;
-    }
-    else
-    {
-        result->Prev = outPt->Prev;
-        result->Next = outPt;
-        outPt->Prev->Next = result;
-        outPt->Prev = result;
-    }
-
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool JoinHorz( OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b,
-        const IntPoint Pt, bool DiscardLeft )
-{
-    Direction Dir1 = (op1->Pt.X > op1b->Pt.X ? dRightToLeft : dLeftToRight);
-    Direction Dir2 = (op2->Pt.X > op2b->Pt.X ? dRightToLeft : dLeftToRight);
-
-    if( Dir1 == Dir2 )
-        return false;
-
-    // When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we
-    // want Op1b to be on the Right. (And likewise with Op2 and Op2b.)
-    // So, to facilitate this while inserting Op1b and Op2b ...
-    // when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b,
-    // otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.)
-    if( Dir1 == dLeftToRight )
-    {
-        while( op1->Next->Pt.X <= Pt.X
-               && op1->Next->Pt.X >= op1->Pt.X && op1->Next->Pt.Y == Pt.Y )
-            op1 = op1->Next;
-
-        if( DiscardLeft && (op1->Pt.X != Pt.X) )
-            op1 = op1->Next;
-
-        op1b = DupOutPt( op1, !DiscardLeft );
-
-        if( op1b->Pt != Pt )
-        {
-            op1 = op1b;
-            op1->Pt = Pt;
-            op1b = DupOutPt( op1, !DiscardLeft );
-        }
-    }
-    else
-    {
-        while( op1->Next->Pt.X >= Pt.X
-               && op1->Next->Pt.X <= op1->Pt.X && op1->Next->Pt.Y == Pt.Y )
-            op1 = op1->Next;
-
-        if( !DiscardLeft && (op1->Pt.X != Pt.X) )
-            op1 = op1->Next;
-
-        op1b = DupOutPt( op1, DiscardLeft );
-
-        if( op1b->Pt != Pt )
-        {
-            op1 = op1b;
-            op1->Pt = Pt;
-            op1b = DupOutPt( op1, DiscardLeft );
-        }
-    }
-
-    if( Dir2 == dLeftToRight )
-    {
-        while( op2->Next->Pt.X <= Pt.X
-               && op2->Next->Pt.X >= op2->Pt.X && op2->Next->Pt.Y == Pt.Y )
-            op2 = op2->Next;
-
-        if( DiscardLeft && (op2->Pt.X != Pt.X) )
-            op2 = op2->Next;
-
-        op2b = DupOutPt( op2, !DiscardLeft );
-
-        if( op2b->Pt != Pt )
-        {
-            op2 = op2b;
-            op2->Pt = Pt;
-            op2b = DupOutPt( op2, !DiscardLeft );
-        }
-
-        ;
-    }
-    else
-    {
-        while( op2->Next->Pt.X >= Pt.X
-               && op2->Next->Pt.X <= op2->Pt.X && op2->Next->Pt.Y == Pt.Y )
-            op2 = op2->Next;
-
-        if( !DiscardLeft && (op2->Pt.X != Pt.X) )
-            op2 = op2->Next;
-
-        op2b = DupOutPt( op2, DiscardLeft );
-
-        if( op2b->Pt != Pt )
-        {
-            op2 = op2b;
-            op2->Pt = Pt;
-            op2b = DupOutPt( op2, DiscardLeft );
-        }
-
-        ;
-    }
-
-    ;
-
-    if( (Dir1 == dLeftToRight) == DiscardLeft )
-    {
-        op1->Prev = op2;
-        op2->Next = op1;
-        op1b->Next  = op2b;
-        op2b->Prev  = op1b;
-    }
-    else
-    {
-        op1->Next = op2;
-        op2->Prev = op1;
-        op1b->Prev  = op2b;
-        op2b->Next  = op1b;
-    }
-
-    return true;
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool Clipper::JoinPoints( Join* j, OutRec* outRec1, OutRec* outRec2 )
-{
-    OutPt* op1  = j->OutPt1, * op1b;
-    OutPt* op2  = j->OutPt2, * op2b;
-
-    // There are 3 kinds of joins for output polygons ...
-    // 1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere
-    // along (horizontal) collinear edges (& Join.OffPt is on the same horizontal).
-    // 2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same
-    // location at the Bottom of the overlapping segment (& Join.OffPt is above).
-    // 3. StrictSimple joins where edges touch but are not collinear and where
-    // Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point.
-    bool isHorizontal = (j->OutPt1->Pt.Y == j->OffPt.Y);
-
-    if( isHorizontal  && (j->OffPt == j->OutPt1->Pt)
-        && (j->OffPt == j->OutPt2->Pt) )
-    {
-        // Strictly Simple join ...
-        if( outRec1 != outRec2 )
-            return false;
-
-        op1b = j->OutPt1->Next;
-
-        while( op1b != op1 && (op1b->Pt == j->OffPt) )
-            op1b = op1b->Next;
-
-        bool reverse1 = (op1b->Pt.Y > j->OffPt.Y);
-        op2b = j->OutPt2->Next;
-
-        while( op2b != op2 && (op2b->Pt == j->OffPt) )
-            op2b = op2b->Next;
-
-        bool reverse2 = (op2b->Pt.Y > j->OffPt.Y);
-
-        if( reverse1 == reverse2 )
-            return false;
-
-        if( reverse1 )
-        {
-            op1b = DupOutPt( op1, false );
-            op2b = DupOutPt( op2, true );
-            op1->Prev = op2;
-            op2->Next = op1;
-            op1b->Next  = op2b;
-            op2b->Prev  = op1b;
-            j->OutPt1   = op1;
-            j->OutPt2   = op1b;
-            return true;
-        }
-        else
-        {
-            op1b = DupOutPt( op1, true );
-            op2b = DupOutPt( op2, false );
-            op1->Next = op2;
-            op2->Prev = op1;
-            op1b->Prev  = op2b;
-            op2b->Next  = op1b;
-            j->OutPt1   = op1;
-            j->OutPt2   = op1b;
-            return true;
-        }
-    }
-    else if( isHorizontal )
-    {
-        // treat horizontal joins differently to non-horizontal joins since with
-        // them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt
-        // may be anywhere along the horizontal edge.
-        op1b = op1;
-
-        while( op1->Prev->Pt.Y == op1->Pt.Y && op1->Prev != op1b && op1->Prev != op2 )
-            op1 = op1->Prev;
-
-        while( op1b->Next->Pt.Y == op1b->Pt.Y && op1b->Next != op1 && op1b->Next != op2 )
-            op1b = op1b->Next;
-
-        if( op1b->Next == op1 || op1b->Next == op2 )
-            return false;                                     // a flat 'polygon'
-
-        op2b = op2;
-
-        while( op2->Prev->Pt.Y == op2->Pt.Y && op2->Prev != op2b && op2->Prev != op1b )
-            op2 = op2->Prev;
-
-        while( op2b->Next->Pt.Y == op2b->Pt.Y && op2b->Next != op2 && op2b->Next != op1 )
-            op2b = op2b->Next;
-
-        if( op2b->Next == op2 || op2b->Next == op1 )
-            return false;                                     // a flat 'polygon'
-
-        cInt Left, Right;
-
-        // Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges
-        if( !GetOverlap( op1->Pt.X, op1b->Pt.X, op2->Pt.X, op2b->Pt.X, Left, Right ) )
-            return false;
-
-        // DiscardLeftSide: when overlapping edges are joined, a spike will created
-        // which needs to be cleaned up. However, we don't want Op1 or Op2 caught up
-        // on the discard Side as either may still be needed for other joins ...
-        IntPoint Pt;
-        bool DiscardLeftSide;
-
-        if( op1->Pt.X >= Left && op1->Pt.X <= Right )
-        {
-            Pt = op1->Pt; DiscardLeftSide = (op1->Pt.X > op1b->Pt.X);
-        }
-        else if( op2->Pt.X >= Left&& op2->Pt.X <= Right )
-        {
-            Pt = op2->Pt; DiscardLeftSide = (op2->Pt.X > op2b->Pt.X);
-        }
-        else if( op1b->Pt.X >= Left && op1b->Pt.X <= Right )
-        {
-            Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.X > op1->Pt.X;
-        }
-        else
-        {
-            Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.X > op2->Pt.X);
-        }
-
-        j->OutPt1 = op1; j->OutPt2 = op2;
-        return JoinHorz( op1, op1b, op2, op2b, Pt, DiscardLeftSide );
-    }
-    else
-    {
-        // nb: For non-horizontal joins ...
-        // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y
-        // 2. Jr.OutPt1.Pt > Jr.OffPt.Y
-
-        // make sure the polygons are correctly oriented ...
-        op1b = op1->Next;
-
-        while( (op1b->Pt == op1->Pt) && (op1b != op1) )
-            op1b = op1b->Next;
-
-        bool Reverse1 = ( (op1b->Pt.Y > op1->Pt.Y)
-                          || !SlopesEqual( op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange ) );
-
-        if( Reverse1 )
-        {
-            op1b = op1->Prev;
-
-            while( (op1b->Pt == op1->Pt) && (op1b != op1) )
-                op1b = op1b->Prev;
-
-            if( (op1b->Pt.Y > op1->Pt.Y)
-                || !SlopesEqual( op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange ) )
-                return false;
-        }
-
-        ;
-        op2b = op2->Next;
-
-        while( (op2b->Pt == op2->Pt) && (op2b != op2) )
-            op2b = op2b->Next;
-
-        bool Reverse2 = ( (op2b->Pt.Y > op2->Pt.Y)
-                          || !SlopesEqual( op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange ) );
-
-        if( Reverse2 )
-        {
-            op2b = op2->Prev;
-
-            while( (op2b->Pt == op2->Pt) && (op2b != op2) )
-                op2b = op2b->Prev;
-
-            if( (op2b->Pt.Y > op2->Pt.Y)
-                || !SlopesEqual( op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange ) )
-                return false;
-        }
-
-        if( (op1b == op1) || (op2b == op2) || (op1b == op2b)
-            || ( (outRec1 == outRec2) && (Reverse1 == Reverse2) ) )
-            return false;
-
-        if( Reverse1 )
-        {
-            op1b = DupOutPt( op1, false );
-            op2b = DupOutPt( op2, true );
-            op1->Prev = op2;
-            op2->Next = op1;
-            op1b->Next  = op2b;
-            op2b->Prev  = op1b;
-            j->OutPt1   = op1;
-            j->OutPt2   = op1b;
-            return true;
-        }
-        else
-        {
-            op1b = DupOutPt( op1, true );
-            op2b = DupOutPt( op2, false );
-            op1->Next = op2;
-            op2->Prev = op1;
-            op1b->Prev  = op2b;
-            op2b->Next  = op1b;
-            j->OutPt1   = op1;
-            j->OutPt2   = op1b;
-            return true;
-        }
-    }
-}
-
-
-// ----------------------------------------------------------------------
-
-static OutRec* ParseFirstLeft( OutRec* FirstLeft )
-{
-    while( FirstLeft && !FirstLeft->Pts )
-        FirstLeft = FirstLeft->FirstLeft;
-
-    return FirstLeft;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Clipper::FixupFirstLefts1( OutRec* OldOutRec, OutRec* NewOutRec )
-{
-    // tests if NewOutRec contains the polygon before reassigning FirstLeft
-    for( PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i )
-    {
-        OutRec* outRec = m_PolyOuts[i];
-        OutRec* firstLeft = ParseFirstLeft( outRec->FirstLeft );
-
-        if( outRec->Pts  && firstLeft == OldOutRec )
-        {
-            if( Poly2ContainsPoly1( outRec->Pts, NewOutRec->Pts ) )
-                outRec->FirstLeft = NewOutRec;
-        }
-    }
-}
-
-
-// ----------------------------------------------------------------------
-
-void Clipper::FixupFirstLefts2( OutRec* InnerOutRec, OutRec* OuterOutRec )
-{
-    // A polygon has split into two such that one is now the inner of the other.
-    // It's possible that these polygons now wrap around other polygons, so check
-    // every polygon that's also contained by OuterOutRec's FirstLeft container
-    // (including 0) to see if they've become inner to the new inner polygon ...
-    OutRec* orfl = OuterOutRec->FirstLeft;
-
-    for( PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i )
-    {
-        OutRec* outRec = m_PolyOuts[i];
-
-        if( !outRec->Pts || outRec == OuterOutRec || outRec == InnerOutRec )
-            continue;
-
-        OutRec* firstLeft = ParseFirstLeft( outRec->FirstLeft );
-
-        if( firstLeft != orfl && firstLeft != InnerOutRec && firstLeft != OuterOutRec )
-            continue;
-
-        if( Poly2ContainsPoly1( outRec->Pts, InnerOutRec->Pts ) )
-            outRec->FirstLeft = InnerOutRec;
-        else if( Poly2ContainsPoly1( outRec->Pts, OuterOutRec->Pts ) )
-            outRec->FirstLeft = OuterOutRec;
-        else if( outRec->FirstLeft == InnerOutRec || outRec->FirstLeft == OuterOutRec )
-            outRec->FirstLeft = orfl;
-    }
-}
-
-
-// ----------------------------------------------------------------------
-void Clipper::FixupFirstLefts3( OutRec* OldOutRec, OutRec* NewOutRec )
-{
-    // reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon
-    for( PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i )
-    {
-        OutRec* outRec = m_PolyOuts[i];
-        OutRec* firstLeft = ParseFirstLeft( outRec->FirstLeft );
-
-        if( outRec->Pts && firstLeft == OldOutRec )
-            outRec->FirstLeft = NewOutRec;
-    }
-}
-
-
-// ----------------------------------------------------------------------
-
-void Clipper::JoinCommonEdges()
-{
-    for( JoinList::size_type i = 0; i < m_Joins.size(); i++ )
-    {
-        Join* join = m_Joins[i];
-
-        OutRec* outRec1 = GetOutRec( join->OutPt1->Idx );
-        OutRec* outRec2 = GetOutRec( join->OutPt2->Idx );
-
-        if( !outRec1->Pts || !outRec2->Pts )
-            continue;
-
-        if( outRec1->IsOpen || outRec2->IsOpen )
-            continue;
-
-        // get the polygon fragment with the correct hole state (FirstLeft)
-        // before calling JoinPoints() ...
-        OutRec* holeStateRec;
-
-        if( outRec1 == outRec2 )
-            holeStateRec = outRec1;
-        else if( OutRec1RightOfOutRec2( outRec1, outRec2 ) )
-            holeStateRec = outRec2;
-        else if( OutRec1RightOfOutRec2( outRec2, outRec1 ) )
-            holeStateRec = outRec1;
-        else
-            holeStateRec = GetLowermostRec( outRec1, outRec2 );
-
-        if( !JoinPoints( join, outRec1, outRec2 ) )
-            continue;
-
-        if( outRec1 == outRec2 )
-        {
-            // instead of joining two polygons, we've just created a new one by
-            // splitting one polygon into two.
-            outRec1->Pts = join->OutPt1;
-            outRec1->BottomPt = 0;
-            outRec2 = CreateOutRec();
-            outRec2->Pts = join->OutPt2;
-
-            // update all OutRec2.Pts Idx's ...
-            UpdateOutPtIdxs( *outRec2 );
-
-            if( Poly2ContainsPoly1( outRec2->Pts, outRec1->Pts ) )
-            {
-                // outRec1 contains outRec2 ...
-                outRec2->IsHole = !outRec1->IsHole;
-                outRec2->FirstLeft = outRec1;
-
-                if( m_UsingPolyTree )
-                    FixupFirstLefts2( outRec2, outRec1 );
-
-                if( (outRec2->IsHole ^ m_ReverseOutput) == (Area( *outRec2 ) > 0) )
-                    ReversePolyPtLinks( outRec2->Pts );
-            }
-            else if( Poly2ContainsPoly1( outRec1->Pts, outRec2->Pts ) )
-            {
-                // outRec2 contains outRec1 ...
-                outRec2->IsHole = outRec1->IsHole;
-                outRec1->IsHole = !outRec2->IsHole;
-                outRec2->FirstLeft  = outRec1->FirstLeft;
-                outRec1->FirstLeft  = outRec2;
-
-                if( m_UsingPolyTree )
-                    FixupFirstLefts2( outRec1, outRec2 );
-
-                if( (outRec1->IsHole ^ m_ReverseOutput) == (Area( *outRec1 ) > 0) )
-                    ReversePolyPtLinks( outRec1->Pts );
-            }
-            else
-            {
-                // the 2 polygons are completely separate ...
-                outRec2->IsHole = outRec1->IsHole;
-                outRec2->FirstLeft = outRec1->FirstLeft;
-
-                // fixup FirstLeft pointers that may need reassigning to OutRec2
-                if( m_UsingPolyTree )
-                    FixupFirstLefts1( outRec1, outRec2 );
-            }
-        }
-        else
-        {
-            // joined 2 polygons together ...
-
-            outRec2->Pts = 0;
-            outRec2->BottomPt = 0;
-            outRec2->Idx = outRec1->Idx;
-
-            outRec1->IsHole = holeStateRec->IsHole;
-
-            if( holeStateRec == outRec2 )
-                outRec1->FirstLeft = outRec2->FirstLeft;
-
-            outRec2->FirstLeft = outRec1;
-
-            if( m_UsingPolyTree )
-                FixupFirstLefts3( outRec2, outRec1 );
-        }
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-// ClipperOffset support functions ...
-// ------------------------------------------------------------------------------
-
-DoublePoint GetUnitNormal( const IntPoint& pt1, const IntPoint& pt2 )
-{
-    if( pt2.X == pt1.X && pt2.Y == pt1.Y )
-        return DoublePoint( 0, 0 );
-
-    double Dx   = (double) (pt2.X - pt1.X);
-    double dy   = (double) (pt2.Y - pt1.Y);
-    double f    = 1 * 1.0 / std::sqrt( Dx * Dx + dy * dy );
-    Dx  *= f;
-    dy  *= f;
-    return DoublePoint( dy, -Dx );
-}
-
-
-// ------------------------------------------------------------------------------
-// ClipperOffset class
-// ------------------------------------------------------------------------------
-
-ClipperOffset::ClipperOffset( double miterLimit, double arcTolerance )
-{
-    this->MiterLimit = miterLimit;
-    this->ArcTolerance = arcTolerance;
-    m_lowest.X = -1;
-
-    //Avoid uninitialized vars:
-    MiterFallback = jtSquare;
-    m_delta = 1.0;
-    m_sinA = 0.0;
-    m_sin = 0.0;
-    m_cos = 0.0;
-    m_miterLim = 1.0;
-    m_StepsPerRad = 1.0;
-}
-
-
-// ------------------------------------------------------------------------------
-
-ClipperOffset::~ClipperOffset()
-{
-    Clear();
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::Clear()
-{
-    for( int i = 0; i < m_polyNodes.ChildCount(); ++i )
-        delete m_polyNodes.Childs[i];
-
-    m_polyNodes.Childs.clear();
-    m_lowest.X = -1;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::AddPath( const Path& path, JoinType joinType, EndType endType )
-{
-    int highI = (int) path.size() - 1;
-
-    if( highI < 0 )
-        return;
-
-    PolyNode* newNode = new PolyNode();
-    newNode->m_jointype = joinType;
-    newNode->m_endtype  = endType;
-
-    // strip duplicate points from path and also get index to the lowest point ...
-    if( endType == etClosedLine || endType == etClosedPolygon )
-        while( highI > 0 && path[0] == path[highI] )
-            highI--;
-
-
-    newNode->Contour.reserve( highI + 1 );
-    newNode->Contour.push_back( path[0] );
-    int j = 0, k = 0;
-
-    for( int i = 1; i <= highI; i++ )
-        if( newNode->Contour[j] != path[i] )
-        {
-            j++;
-            newNode->Contour.push_back( path[i] );
-
-            if( path[i].Y > newNode->Contour[k].Y
-                || (path[i].Y == newNode->Contour[k].Y
-                    && path[i].X < newNode->Contour[k].X) )
-                k = j;
-        }
-
-
-    if( endType == etClosedPolygon && j < 2 )
-    {
-        delete newNode;
-        return;
-    }
-
-    m_polyNodes.AddChild( *newNode );
-
-    // if this path's lowest pt is lower than all the others then update m_lowest
-    if( endType != etClosedPolygon )
-        return;
-
-    if( m_lowest.X < 0 )
-        m_lowest = IntPoint( m_polyNodes.ChildCount() - 1, k );
-    else
-    {
-        IntPoint ip = m_polyNodes.Childs[(int) m_lowest.X]->Contour[(int) m_lowest.Y];
-
-        if( newNode->Contour[k].Y > ip.Y
-            || (newNode->Contour[k].Y == ip.Y
-                && newNode->Contour[k].X < ip.X) )
-            m_lowest = IntPoint( m_polyNodes.ChildCount() - 1, k );
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::AddPaths( const Paths& paths, JoinType joinType, EndType endType )
-{
-    for( Paths::size_type i = 0; i < paths.size(); ++i )
-        AddPath( paths[i], joinType, endType );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::FixOrientations()
-{
-    // fixup orientations of all closed paths if the orientation of the
-    // closed path with the lowermost vertex is wrong ...
-    if( m_lowest.X >= 0
-        && !Orientation( m_polyNodes.Childs[(int) m_lowest.X]->Contour ) )
-    {
-        for( int i = 0; i < m_polyNodes.ChildCount(); ++i )
-        {
-            PolyNode& node = *m_polyNodes.Childs[i];
-
-            if( node.m_endtype == etClosedPolygon
-                || ( node.m_endtype == etClosedLine && Orientation( node.Contour ) ) )
-                ReversePath( node.Contour );
-        }
-    }
-    else
-    {
-        for( int i = 0; i < m_polyNodes.ChildCount(); ++i )
-        {
-            PolyNode& node = *m_polyNodes.Childs[i];
-
-            if( node.m_endtype == etClosedLine && !Orientation( node.Contour ) )
-                ReversePath( node.Contour );
-        }
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::Execute( Paths& solution, double delta )
-{
-    solution.clear();
-    FixOrientations();
-    DoOffset( delta );
-
-    // now clean up 'corners' ...
-    Clipper clpr;
-    clpr.AddPaths( m_destPolys, ptSubject, true );
-
-    if( delta > 0 )
-    {
-        clpr.Execute( ctUnion, solution, pftPositive, pftPositive );
-    }
-    else
-    {
-        IntRect r = clpr.GetBounds();
-        Path outer( 4 );
-        outer[0] = IntPoint( r.left - 10, r.bottom + 10 );
-        outer[1] = IntPoint( r.right + 10, r.bottom + 10 );
-        outer[2] = IntPoint( r.right + 10, r.top - 10 );
-        outer[3] = IntPoint( r.left - 10, r.top - 10 );
-
-        clpr.AddPath( outer, ptSubject, true );
-        clpr.ReverseSolution( true );
-        clpr.Execute( ctUnion, solution, pftNegative, pftNegative );
-
-        if( solution.size() > 0 )
-            solution.erase( solution.begin() );
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::Execute( PolyTree& solution, double delta )
-{
-    solution.Clear();
-    FixOrientations();
-    DoOffset( delta );
-
-    // now clean up 'corners' ...
-    Clipper clpr;
-    clpr.AddPaths( m_destPolys, ptSubject, true );
-
-    if( delta > 0 )
-    {
-        clpr.Execute( ctUnion, solution, pftPositive, pftPositive );
-    }
-    else
-    {
-        IntRect r = clpr.GetBounds();
-        Path outer( 4 );
-        outer[0] = IntPoint( r.left - 10, r.bottom + 10 );
-        outer[1] = IntPoint( r.right + 10, r.bottom + 10 );
-        outer[2] = IntPoint( r.right + 10, r.top - 10 );
-        outer[3] = IntPoint( r.left - 10, r.top - 10 );
-
-        clpr.AddPath( outer, ptSubject, true );
-        clpr.ReverseSolution( true );
-        clpr.Execute( ctUnion, solution, pftNegative, pftNegative );
-
-        // remove the outer PolyNode rectangle ...
-        if( solution.ChildCount() == 1 && solution.Childs[0]->ChildCount() > 0 )
-        {
-            PolyNode* outerNode = solution.Childs[0];
-            solution.Childs.reserve( outerNode->ChildCount() );
-            solution.Childs[0] = outerNode->Childs[0];
-            solution.Childs[0]->Parent = outerNode->Parent;
-
-            for( int i = 1; i < outerNode->ChildCount(); ++i )
-                solution.AddChild( *outerNode->Childs[i] );
-        }
-        else
-            solution.Clear();
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::DoOffset( double delta )
-{
-    m_destPolys.clear();
-    m_delta = delta;
-
-    // if Zero offset, just copy any CLOSED polygons to m_p and return ...
-    if( NEAR_ZERO( delta ) )
-    {
-        m_destPolys.reserve( m_polyNodes.ChildCount() );
-
-        for( int i = 0; i < m_polyNodes.ChildCount(); i++ )
-        {
-            PolyNode& node = *m_polyNodes.Childs[i];
-
-            if( node.m_endtype == etClosedPolygon )
-                m_destPolys.push_back( node.Contour );
-        }
-
-        return;
-    }
-
-    // see offset_triginometry3.svg in the documentation folder ...
-    if( MiterLimit > 2 )
-        m_miterLim = 2 / (MiterLimit * MiterLimit);
-    else
-        m_miterLim = 0.5;
-
-    double y;
-
-    if( ArcTolerance <= 0.0 )
-        y = def_arc_tolerance;
-    else if( ArcTolerance > std::fabs( delta ) * def_arc_tolerance )
-        y = std::fabs( delta ) * def_arc_tolerance;
-    else
-        y = ArcTolerance;
-
-    // see offset_triginometry2.svg in the documentation folder ...
-    double steps = pi / std::acos( 1 - y / std::fabs( delta ) );
-
-    if( steps > std::fabs( delta ) * pi )
-        steps = std::fabs( delta ) * pi; // ie excessive precision check
-
-    m_sin = std::sin( two_pi / steps );
-    m_cos = std::cos( two_pi / steps );
-    m_StepsPerRad = steps / two_pi;
-
-    if( delta < 0.0 )
-        m_sin = -m_sin;
-
-    m_destPolys.reserve( m_polyNodes.ChildCount() * 2 );
-
-    for( int i = 0; i < m_polyNodes.ChildCount(); i++ )
-    {
-        PolyNode& node = *m_polyNodes.Childs[i];
-        m_srcPoly = node.Contour;
-
-        int len = (int) m_srcPoly.size();
-
-        if( len == 0 || ( delta <= 0 && (len < 3 || node.m_endtype != etClosedPolygon) ) )
-            continue;
-
-        m_destPoly.clear();
-
-        if( len == 1 )
-        {
-            if( node.m_jointype == jtRound )
-            {
-                double X = 1.0, Y = 0.0;
-
-                for( cInt j = 1; j <= steps; j++ )
-                {
-                    m_destPoly.emplace_back( Round( m_srcPoly[0].X + X * delta ),
-                                             Round( m_srcPoly[0].Y + Y * delta ) );
-                    double X2 = X;
-                    X = X * m_cos - m_sin * Y;
-                    Y = X2 * m_sin + Y * m_cos;
-                }
-            }
-            else
-            {
-                double X = -1.0, Y = -1.0;
-
-                for( int j = 0; j < 4; ++j )
-                {
-                    m_destPoly.emplace_back( Round( m_srcPoly[0].X + X * delta ),
-                                             Round( m_srcPoly[0].Y + Y * delta ) );
-
-                    if( X < 0 )
-                        X = 1;
-                    else if( Y < 0 )
-                        Y = 1;
-                    else
-                        X = -1;
-                }
-            }
-
-            m_destPolys.push_back( m_destPoly );
-            continue;
-        }
-
-        // build m_normals ...
-        m_normals.clear();
-        m_normals.reserve( len );
-
-        for( int j = 0; j < len - 1; ++j )
-            m_normals.push_back( GetUnitNormal( m_srcPoly[j], m_srcPoly[j + 1] ) );
-
-        if( node.m_endtype == etClosedLine || node.m_endtype == etClosedPolygon )
-            m_normals.push_back( GetUnitNormal( m_srcPoly[len - 1], m_srcPoly[0] ) );
-        else
-            m_normals.emplace_back( m_normals[len - 2] );
-
-        if( node.m_endtype == etClosedPolygon )
-        {
-            int k = len - 1;
-
-            for( int j = 0; j < len; ++j )
-                OffsetPoint( j, k, node.m_jointype );
-
-            m_destPolys.push_back( m_destPoly );
-        }
-        else if( node.m_endtype == etClosedLine )
-        {
-            int k = len - 1;
-
-            for( int j = 0; j < len; ++j )
-                OffsetPoint( j, k, node.m_jointype );
-
-            m_destPolys.push_back( m_destPoly );
-            m_destPoly.clear();
-            // re-build m_normals ...
-            DoublePoint n = m_normals[len - 1];
-
-            for( int j = len - 1; j > 0; j-- )
-                m_normals[j] = DoublePoint( -m_normals[j - 1].X, -m_normals[j - 1].Y );
-
-            m_normals[0] = DoublePoint( -n.X, -n.Y );
-            k = 0;
-
-            for( int j = len - 1; j >= 0; j-- )
-                OffsetPoint( j, k, node.m_jointype );
-
-            m_destPolys.push_back( m_destPoly );
-        }
-        else
-        {
-            int k = 0;
-
-            for( int j = 1; j < len - 1; ++j )
-                OffsetPoint( j, k, node.m_jointype );
-
-            IntPoint pt1;
-
-            if( node.m_endtype == etOpenButt )
-            {
-                int j = len - 1;
-                pt1 = IntPoint( (cInt) Round( m_srcPoly[j].X + m_normals[j].X *
-                                delta ), (cInt) Round( m_srcPoly[j].Y + m_normals[j].Y * delta ) );
-                m_destPoly.push_back( pt1 );
-                pt1 = IntPoint( (cInt) Round( m_srcPoly[j].X - m_normals[j].X *
-                                delta ), (cInt) Round( m_srcPoly[j].Y - m_normals[j].Y * delta ) );
-                m_destPoly.push_back( pt1 );
-            }
-            else
-            {
-                int j = len - 1;
-                k = len - 2;
-                m_sinA = 0;
-                m_normals[j] = DoublePoint( -m_normals[j].X, -m_normals[j].Y );
-
-                if( node.m_endtype == etOpenSquare )
-                    DoSquare( j, k );
-                else
-                    DoRound( j, k );
-            }
-
-            // re-build m_normals ...
-            for( int j = len - 1; j > 0; j-- )
-                m_normals[j] = DoublePoint( -m_normals[j - 1].X, -m_normals[j - 1].Y );
-
-            m_normals[0] = DoublePoint( -m_normals[1].X, -m_normals[1].Y );
-
-            k = len - 1;
-
-            for( int j = k - 1; j > 0; --j )
-                OffsetPoint( j, k, node.m_jointype );
-
-            if( node.m_endtype == etOpenButt )
-            {
-                pt1 = IntPoint( (cInt) Round( m_srcPoly[0].X - m_normals[0].X * delta ),
-                        (cInt) Round( m_srcPoly[0].Y - m_normals[0].Y * delta ) );
-                m_destPoly.push_back( pt1 );
-                pt1 = IntPoint( (cInt) Round( m_srcPoly[0].X + m_normals[0].X * delta ),
-                        (cInt) Round( m_srcPoly[0].Y + m_normals[0].Y * delta ) );
-                m_destPoly.push_back( pt1 );
-            }
-            else
-            {
-                k = 1;
-                m_sinA = 0;
-
-                if( node.m_endtype == etOpenSquare )
-                    DoSquare( 0, 1 );
-                else
-                    DoRound( 0, 1 );
-            }
-
-            m_destPolys.push_back( m_destPoly );
-        }
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::OffsetPoint( int j, int& k, JoinType jointype )
-{
-    // cross product ...
-    m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y);
-
-    if( std::fabs( m_sinA * m_delta ) < 1.0 )
-    {
-        // dot product ...
-        double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y );
-
-        if( cosA > 0 ) // angle => 0 degrees
-        {
-            m_destPoly.emplace_back( Round( m_srcPoly[j].X + m_normals[k].X * m_delta ),
-                                     Round( m_srcPoly[j].Y + m_normals[k].Y * m_delta ) );
-            return;
-        }
-
-        // else angle => 180 degrees
-    }
-    else if( m_sinA > 1.0 )
-        m_sinA = 1.0;
-    else if( m_sinA < -1.0 )
-        m_sinA = -1.0;
-
-    if( m_sinA * m_delta < 0 )
-    {
-        m_destPoly.emplace_back( Round( m_srcPoly[j].X + m_normals[k].X * m_delta ),
-                                 Round( m_srcPoly[j].Y + m_normals[k].Y * m_delta ) );
-        m_destPoly.push_back( m_srcPoly[j] );
-        m_destPoly.emplace_back( Round( m_srcPoly[j].X + m_normals[j].X * m_delta ),
-                                 Round( m_srcPoly[j].Y + m_normals[j].Y * m_delta ) );
-    }
-    else
-        switch( jointype )
-        {
-        case jtMiter:
-        {
-            double r = 1 + (m_normals[j].X * m_normals[k].X +
-                            m_normals[j].Y * m_normals[k].Y);
-
-            if( r >= m_miterLim )
-                DoMiter( j, k, r );
-            else if( MiterFallback == jtRound )
-                DoRound( j, k );
-            else
-                DoSquare( j, k );
-
-            break;
-        }
-
-        case jtSquare:
-            DoSquare( j, k ); break;
-
-        case jtRound:
-            DoRound( j, k ); break;
-        }
-
-
-    k = j;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::DoSquare( int j, int k )
-{
-    double dx = std::tan( std::atan2( m_sinA,
-                    m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y ) / 4 );
-
-    m_destPoly.push_back( IntPoint(
-                    Round( m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx) ),
-                    Round( m_srcPoly[j].Y + m_delta * (m_normals[k].Y + m_normals[k].X * dx) ) ) );
-    m_destPoly.push_back( IntPoint(
-                    Round( m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx) ),
-                    Round( m_srcPoly[j].Y + m_delta * (m_normals[j].Y - m_normals[j].X * dx) ) ) );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::DoMiter( int j, int k, double r )
-{
-    double q = m_delta / r;
-
-    m_destPoly.emplace_back( Round( m_srcPoly[j].X + ( m_normals[k].X + m_normals[j].X ) * q ),
-                             Round( m_srcPoly[j].Y + ( m_normals[k].Y + m_normals[j].Y ) * q ) );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClipperOffset::DoRound( int j, int k )
-{
-    double a = std::atan2( m_sinA,
-            m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y );
-    double steps = m_StepsPerRad * std::fabs( a );
-    int    takenSteps = std::max((int) std::floor( steps ), 1 );
-
-    double X = m_normals[k].X, Y = m_normals[k].Y, X2;
-
-    for( int i = 0; i < takenSteps; ++i )
-    {
-        m_destPoly.emplace_back( Round( m_srcPoly[j].X + X * m_delta ),
-                                 Round( m_srcPoly[j].Y + Y * m_delta ) );
-        X2  = X;
-        X   = X * m_cos - m_sin * Y;
-        Y   = X2 * m_sin + Y * m_cos;
-    }
-
-    // A 10% error on chord length won't make much error difference, and it keeps us
-    // from generating geometrically noisy solutions.
-    if( steps > takenSteps + 0.1 )
-    {
-        m_destPoly.emplace_back( Round( m_srcPoly[j].X + X * m_delta ),
-                                 Round( m_srcPoly[j].Y + Y * m_delta ) );
-    }
-
-    m_destPoly.emplace_back( Round( m_srcPoly[j].X + m_normals[j].X * m_delta ),
-                             Round( m_srcPoly[j].Y + m_normals[j].Y * m_delta ) );
-}
-
-
-// ------------------------------------------------------------------------------
-// Miscellaneous public functions
-// ------------------------------------------------------------------------------
-
-void Clipper::DoSimplePolygons()
-{
-    PolyOutList::size_type i = 0;
-
-    while( i < m_PolyOuts.size() )
-    {
-        OutRec* outrec = m_PolyOuts[i++];
-        OutPt*  op = outrec->Pts;
-
-        if( !op || outrec->IsOpen )
-            continue;
-
-        do  // for each Pt in Polygon until duplicate found do ...
-        {
-            OutPt* op2 = op->Next;
-
-            while( op2 != outrec->Pts )
-            {
-                if( (op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op )
-                {
-                    // split the polygon into two ...
-                    OutPt* op3  = op->Prev;
-                    OutPt* op4  = op2->Prev;
-                    op->Prev = op4;
-                    op4->Next = op;
-                    op2->Prev = op3;
-                    op3->Next = op2;
-
-                    outrec->Pts = op;
-                    OutRec* outrec2 = CreateOutRec();
-                    outrec2->Pts = op2;
-                    UpdateOutPtIdxs( *outrec2 );
-
-                    if( Poly2ContainsPoly1( outrec2->Pts, outrec->Pts ) )
-                    {
-                        // OutRec2 is contained by OutRec1 ...
-                        outrec2->IsHole = !outrec->IsHole;
-                        outrec2->FirstLeft = outrec;
-
-                        if( m_UsingPolyTree )
-                            FixupFirstLefts2( outrec2, outrec );
-                    }
-                    else
-                        if( Poly2ContainsPoly1( outrec->Pts, outrec2->Pts ) )
-                        {
-                            // OutRec1 is contained by OutRec2 ...
-                            outrec2->IsHole = outrec->IsHole;
-                            outrec->IsHole  = !outrec2->IsHole;
-                            outrec2->FirstLeft  = outrec->FirstLeft;
-                            outrec->FirstLeft   = outrec2;
-
-                            if( m_UsingPolyTree )
-                                FixupFirstLefts2( outrec, outrec2 );
-                        }
-                        else
-                        {
-                            // the 2 polygons are separate ...
-                            outrec2->IsHole = outrec->IsHole;
-                            outrec2->FirstLeft = outrec->FirstLeft;
-
-                            if( m_UsingPolyTree )
-                                FixupFirstLefts1( outrec, outrec2 );
-                        }
-
-
-                    op2 = op; // ie get ready for the Next iteration
-                }
-
-                op2 = op2->Next;
-            }
-
-            op = op->Next;
-        } while( op != outrec->Pts );
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ReversePath( Path& p )
-{
-    std::reverse( p.begin(), p.end() );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ReversePaths( Paths& p )
-{
-    for( Paths::size_type i = 0; i < p.size(); ++i )
-        ReversePath( p[i] );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void SimplifyPolygon( const Path& in_poly, Paths& out_polys, PolyFillType fillType )
-{
-    Clipper c;
-
-    c.StrictlySimple( true );
-    c.AddPath( in_poly, ptSubject, true );
-    c.Execute( ctUnion, out_polys, fillType, fillType );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void SimplifyPolygons( const Paths& in_polys, Paths& out_polys, PolyFillType fillType )
-{
-    Clipper c;
-
-    c.StrictlySimple( true );
-    c.AddPaths( in_polys, ptSubject, true );
-    c.Execute( ctUnion, out_polys, fillType, fillType );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void SimplifyPolygons( Paths& polys, PolyFillType fillType )
-{
-    SimplifyPolygons( polys, polys, fillType );
-}
-
-
-// ------------------------------------------------------------------------------
-
-inline double DistanceSqrd( const IntPoint& pt1, const IntPoint& pt2 )
-{
-    double Dx   = ( (double) pt1.X - pt2.X );
-    double dy   = ( (double) pt1.Y - pt2.Y );
-
-    return Dx * Dx + dy * dy;
-}
-
-
-// ------------------------------------------------------------------------------
-
-double DistanceFromLineSqrd( const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2 )
-{
-    // The equation of a line in general form (Ax + By + C = 0)
-    // given 2 points (x¹,y¹) & (x²,y²) is ...
-    // (y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0
-    // A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹
-    // perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²)
-    // see http://en.wikipedia.org/wiki/Perpendicular_distance
-    double A = double(ln1.Y - ln2.Y);
-    double B = double(ln2.X - ln1.X);
-    double C = A * ln1.X + B * ln1.Y;
-
-    C = A * pt.X + B * pt.Y - C;
-    return (C * C) / (A * A + B * B);
-}
-
-
-// ---------------------------------------------------------------------------
-
-bool SlopesNearCollinear( const IntPoint& pt1,
-        const IntPoint& pt2, const IntPoint& pt3, double distSqrd )
-{
-    // this function is more accurate when the point that's geometrically
-    // between the other 2 points is the one that's tested for distance.
-    // ie makes it more likely to pick up 'spikes' ...
-    if( Abs( pt1.X - pt2.X ) > Abs( pt1.Y - pt2.Y ) )
-    {
-        if( (pt1.X > pt2.X) == (pt1.X < pt3.X) )
-            return DistanceFromLineSqrd( pt1, pt2, pt3 ) < distSqrd;
-        else if( (pt2.X > pt1.X) == (pt2.X < pt3.X) )
-            return DistanceFromLineSqrd( pt2, pt1, pt3 ) < distSqrd;
-        else
-            return DistanceFromLineSqrd( pt3, pt1, pt2 ) < distSqrd;
-    }
-    else
-    {
-        if( (pt1.Y > pt2.Y) == (pt1.Y < pt3.Y) )
-            return DistanceFromLineSqrd( pt1, pt2, pt3 ) < distSqrd;
-        else if( (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y) )
-            return DistanceFromLineSqrd( pt2, pt1, pt3 ) < distSqrd;
-        else
-            return DistanceFromLineSqrd( pt3, pt1, pt2 ) < distSqrd;
-    }
-}
-
-
-// ------------------------------------------------------------------------------
-
-bool PointsAreClose( IntPoint pt1, IntPoint pt2, double distSqrd )
-{
-    double Dx   = (double) pt1.X - pt2.X;
-    double dy   = (double) pt1.Y - pt2.Y;
-
-    return (Dx * Dx) + (dy * dy) <= distSqrd;
-}
-
-
-// ------------------------------------------------------------------------------
-
-OutPt* ExcludeOp( OutPt* op )
-{
-    OutPt* result = op->Prev;
-
-    result->Next = op->Next;
-    op->Next->Prev = result;
-    result->Idx = 0;
-    return result;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void CleanPolygon( const Path& in_poly, Path& out_poly, double distance )
-{
-    // distance = proximity in units/pixels below which vertices
-    // will be stripped. Default ~= sqrt(2).
-
-    size_t size = in_poly.size();
-
-    if( size == 0 )
-    {
-        out_poly.clear();
-        return;
-    }
-
-    OutPt* outPts = new OutPt[size];
-
-    for( size_t i = 0; i < size; ++i )
-    {
-        outPts[i].Pt = in_poly[i];
-        outPts[i].Next = &outPts[(i + 1) % size];
-        outPts[i].Next->Prev = &outPts[i];
-        outPts[i].Idx = 0;
-    }
-
-    double distSqrd = distance * distance;
-    OutPt* op = &outPts[0];
-
-    while( op->Idx == 0 && op->Next != op->Prev )
-    {
-        if( PointsAreClose( op->Pt, op->Prev->Pt, distSqrd ) )
-        {
-            op = ExcludeOp( op );
-            size--;
-        }
-        else if( PointsAreClose( op->Prev->Pt, op->Next->Pt, distSqrd ) )
-        {
-            ExcludeOp( op->Next );
-            op = ExcludeOp( op );
-            size -= 2;
-        }
-        else if( SlopesNearCollinear( op->Prev->Pt, op->Pt, op->Next->Pt, distSqrd ) )
-        {
-            op = ExcludeOp( op );
-            size--;
-        }
-        else
-        {
-            op->Idx = 1;
-            op = op->Next;
-        }
-    }
-
-    if( size < 3 )
-        size = 0;
-
-    out_poly.resize( size );
-
-    for( size_t i = 0; i < size; ++i )
-    {
-        out_poly[i] = op->Pt;
-        op = op->Next;
-    }
-
-    delete [] outPts;
-}
-
-
-// ------------------------------------------------------------------------------
-
-void CleanPolygon( Path& poly, double distance )
-{
-    CleanPolygon( poly, poly, distance );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void CleanPolygons( const Paths& in_polys, Paths& out_polys, double distance )
-{
-    out_polys.resize( in_polys.size() );
-
-    for( Paths::size_type i = 0; i < in_polys.size(); ++i )
-        CleanPolygon( in_polys[i], out_polys[i], distance );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void CleanPolygons( Paths& polys, double distance )
-{
-    CleanPolygons( polys, polys, distance );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void Minkowski( const Path& poly, const Path& path,
-        Paths& solution, bool isSum, bool isClosed )
-{
-    int delta = (isClosed ? 1 : 0);
-    size_t polyCnt  = poly.size();
-    size_t pathCnt  = path.size();
-    Paths pp;
-
-    pp.reserve( pathCnt );
-
-    if( isSum )
-        for( size_t i = 0; i < pathCnt; ++i )
-        {
-            Path p;
-            p.reserve( polyCnt );
-
-            for( size_t j = 0; j < poly.size(); ++j )
-                p.emplace_back( path[i].X + poly[j].X, path[i].Y + poly[j].Y );
-
-            pp.push_back( p );
-        }
-
-
-    else
-        for( size_t i = 0; i < pathCnt; ++i )
-        {
-            Path p;
-            p.reserve( polyCnt );
-
-            for( size_t j = 0; j < poly.size(); ++j )
-                p.emplace_back( path[i].X - poly[j].X, path[i].Y - poly[j].Y );
-
-            pp.push_back( p );
-        }
-
-
-
-    solution.clear();
-    solution.reserve( (pathCnt + delta) * (polyCnt + 1) );
-
-    for( size_t i = 0; i < pathCnt - 1 + delta; ++i )
-        for( size_t j = 0; j < polyCnt; ++j )
-        {
-            Path quad;
-            quad.reserve( 4 );
-            quad.push_back( pp[i % pathCnt][j % polyCnt] );
-            quad.push_back( pp[(i + 1) % pathCnt][j % polyCnt] );
-            quad.push_back( pp[(i + 1) % pathCnt][(j + 1) % polyCnt] );
-            quad.push_back( pp[i % pathCnt][(j + 1) % polyCnt] );
-
-            if( !Orientation( quad ) )
-                ReversePath( quad );
-
-            solution.push_back( quad );
-        }
-
-
-}
-
-
-// ------------------------------------------------------------------------------
-
-void MinkowskiSum( const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed )
-{
-    Minkowski( pattern, path, solution, true, pathIsClosed );
-    Clipper c;
-    c.AddPaths( solution, ptSubject, true );
-    c.Execute( ctUnion, solution, pftNonZero, pftNonZero );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void TranslatePath( const Path& input, Path& output, const IntPoint delta )
-{
-    // precondition: input != output
-    output.resize( input.size() );
-
-    for( size_t i = 0; i < input.size(); ++i )
-        output[i] = IntPoint( input[i].X + delta.X, input[i].Y + delta.Y );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void MinkowskiSum( const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed )
-{
-    Clipper c;
-
-    for( size_t i = 0; i < paths.size(); ++i )
-    {
-        Paths tmp;
-        Minkowski( pattern, paths[i], tmp, true, pathIsClosed );
-        c.AddPaths( tmp, ptSubject, true );
-
-        if( pathIsClosed )
-        {
-            Path tmp2;
-            TranslatePath( paths[i], tmp2, pattern[0] );
-            c.AddPath( tmp2, ptClip, true );
-        }
-    }
-
-    c.Execute( ctUnion, solution, pftNonZero, pftNonZero );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void MinkowskiDiff( const Path& poly1, const Path& poly2, Paths& solution )
-{
-    Minkowski( poly1, poly2, solution, false, true );
-    Clipper c;
-    c.AddPaths( solution, ptSubject, true );
-    c.Execute( ctUnion, solution, pftNonZero, pftNonZero );
-}
-
-
-// ------------------------------------------------------------------------------
-
-enum NodeType
-{
-    ntAny, ntOpen, ntClosed
-};
-
-void AddPolyNodeToPaths( const PolyNode& polynode, NodeType nodetype, Paths& paths )
-{
-    bool match = true;
-
-    if( nodetype == ntClosed )
-        match = !polynode.IsOpen();
-    else if( nodetype == ntOpen )
-        return;
-
-    if( !polynode.Contour.empty() && match )
-        paths.push_back( polynode.Contour );
-
-    for( int i = 0; i < polynode.ChildCount(); ++i )
-        AddPolyNodeToPaths( *polynode.Childs[i], nodetype, paths );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void PolyTreeToPaths( const PolyTree& polytree, Paths& paths )
-{
-    paths.resize( 0 );
-    paths.reserve( polytree.Total() );
-    AddPolyNodeToPaths( polytree, ntAny, paths );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void ClosedPathsFromPolyTree( const PolyTree& polytree, Paths& paths )
-{
-    paths.resize( 0 );
-    paths.reserve( polytree.Total() );
-    AddPolyNodeToPaths( polytree, ntClosed, paths );
-}
-
-
-// ------------------------------------------------------------------------------
-
-void OpenPathsFromPolyTree( PolyTree& polytree, Paths& paths )
-{
-    paths.resize( 0 );
-    paths.reserve( polytree.Total() );
-
-    // Open paths are top level only, so ...
-    for( int i = 0; i < polytree.ChildCount(); ++i )
-        if( polytree.Childs[i]->IsOpen() )
-            paths.push_back( polytree.Childs[i]->Contour );
-
-
-}
-
-
-// ------------------------------------------------------------------------------
-
-std::ostream& operator <<( std::ostream& s, const IntPoint& p )
-{
-    s << "(" << p.X << "," << p.Y << ")";
-    return s;
-}
-
-
-// ------------------------------------------------------------------------------
-
-std::ostream& operator <<( std::ostream& s, const Path& p )
-{
-    if( p.empty() )
-        return s;
-
-    Path::size_type last = p.size() - 1;
-
-    for( Path::size_type i = 0; i < last; i++ )
-        s << "(" << p[i].X << "," << p[i].Y << "), ";
-
-    s << "(" << p[last].X << "," << p[last].Y << ")\n";
-    return s;
-}
-
-
-// ------------------------------------------------------------------------------
-
-std::ostream& operator <<( std::ostream& s, const Paths& p )
-{
-    for( Paths::size_type i = 0; i < p.size(); i++ )
-        s << p[i];
-
-    s << "\n";
-    return s;
-}
-
-
-// ------------------------------------------------------------------------------
-}    // ClipperLib namespace
diff --git a/thirdparty/clipper/clipper.hpp b/thirdparty/clipper/clipper.hpp
deleted file mode 100644
index b5d0ee945b..0000000000
--- a/thirdparty/clipper/clipper.hpp
+++ /dev/null
@@ -1,457 +0,0 @@
-/*******************************************************************************
-*                                                                              *
-* Author    :  Angus Johnson                                                   *
-* Version   :  6.4.2                                                           *
-* Date      :  27 February 2017                                                *
-* Website   :  http://www.angusj.com                                           *
-* Copyright :  Angus Johnson 2010-2017                                         *
-*                                                                              *
-* License:                                                                     *
-* Use, modification & distribution is subject to Boost Software License Ver 1. *
-* http://www.boost.org/LICENSE_1_0.txt                                         *
-*                                                                              *
-* Attributions:                                                                *
-* The code in this library is an extension of Bala Vatti's clipping algorithm: *
-* "A generic solution to polygon clipping"                                     *
-* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.             *
-* http://portal.acm.org/citation.cfm?id=129906                                 *
-*                                                                              *
-* Computer graphics and geometric modeling: implementation and algorithms      *
-* By Max K. Agoston                                                            *
-* Springer; 1 edition (January 4, 2005)                                        *
-* http://books.google.com/books?q=vatti+clipping+agoston                       *
-*                                                                              *
-* See also:                                                                    *
-* "Polygon Offsetting by Computing Winding Numbers"                            *
-* Paper no. DETC2005-85513 pp. 565-575                                         *
-* ASME 2005 International Design Engineering Technical Conferences             *
-* and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
-* September 24-28, 2005 , Long Beach, California, USA                          *
-* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
-*                                                                              *
-*******************************************************************************/
-
-#ifndef clipper_hpp
-#define clipper_hpp
-
-#define CLIPPER_VERSION "6.4.2"
-
-// use_int32: When enabled 32bit ints are used instead of 64bit ints. This
-// improve performance but coordinate values are limited to the range +/- 46340
-// #define use_int32
-
-// use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
-#define use_xyz
-
-// use_lines: Enables line clipping. Adds a very minor cost to performance.
-#define use_lines
-
-// use_deprecated: Enables temporary support for the obsolete functions
-// #define use_deprecated
-
-#include <functional>
-#include <vector>
-#include <list>
-#include <set>
-#include <stdexcept>
-#include <cstring>
-#include <cstdlib>
-#include <ostream>
-#include <functional>
-#include <queue>
-
-namespace ClipperLib {
-enum ClipType
-{
-    ctIntersection, ctUnion, ctDifference, ctXor
-};
-enum PolyType
-{
-    ptSubject, ptClip
-};
-// By far the most widely used winding rules for polygon filling are
-// EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
-// Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
-// see http://glprogramming.com/red/chapter11.html
-enum PolyFillType
-{
-    pftEvenOdd, pftNonZero, pftPositive, pftNegative
-};
-
-#ifdef use_int32
-typedef int cInt;
-static cInt const loRange   = 0x7FFF;
-static cInt const hiRange   = 0x7FFF;
-#else
-typedef signed long long cInt;
-static cInt const loRange   = 0x3FFFFFFF;
-static cInt const hiRange   = 0x3FFFFFFFFFFFFFFFLL;
-typedef signed long long    long64;    // used by Int128 class
-typedef unsigned long long  ulong64;
-
-#endif
-
-struct IntPoint
-{
-    cInt X;
-    cInt Y;
-#ifdef use_xyz
-    cInt Z;
-    IntPoint( cInt x = 0, cInt y = 0, cInt z = 0 ) : X( x ), Y( y ), Z( z ) {};
-#else
-    IntPoint( cInt x = 0, cInt y = 0 ) : X( x ), Y( y ) {};
-#endif
-
-    friend inline bool operator==( const IntPoint& a, const IntPoint& b )
-    {
-        return a.X == b.X && a.Y == b.Y;
-    }
-
-    friend inline bool operator!=( const IntPoint& a, const IntPoint& b )
-    {
-        return a.X != b.X  || a.Y != b.Y;
-    }
-};
-// ------------------------------------------------------------------------------
-
-typedef std::vector<IntPoint>   Path;
-typedef std::vector<Path>       Paths;
-
-inline Path& operator <<( Path& poly, const IntPoint& p )
-{
-    poly.push_back( p ); return poly;
-}
-
-
-inline Paths& operator <<( Paths& polys, const Path& p )
-{
-    polys.push_back( p ); return polys;
-}
-
-
-std::ostream&   operator <<( std::ostream& s, const IntPoint& p );
-std::ostream&   operator <<( std::ostream& s, const Path& p );
-std::ostream&   operator <<( std::ostream& s, const Paths& p );
-
-struct DoublePoint
-{
-    double X;
-    double Y;
-    DoublePoint( double x = 0, double y = 0 ) : X( x ), Y( y ) {}
-    DoublePoint( IntPoint ip ) : X( (double) ip.X ), Y( (double) ip.Y ) {}
-};
-// ------------------------------------------------------------------------------
-
-#ifdef use_xyz
-typedef std::function<void( IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top,
-                            IntPoint& pt )> ZFillCallback;
-#endif
-
-enum InitOptions
-{
-    ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4
-};
-enum JoinType
-{
-    jtSquare, jtRound, jtMiter
-};
-enum EndType
-{
-    etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound
-};
-
-class PolyNode;
-typedef std::vector<PolyNode*> PolyNodes;
-
-class PolyNode
-{
-public:
-    PolyNode();
-    virtual ~PolyNode() {};
-    Path Contour;
-    PolyNodes Childs;
-    PolyNode* Parent;
-    PolyNode*   GetNext() const;
-    bool        IsHole() const;
-    bool        IsOpen() const;
-    int         ChildCount() const;
-
-private:
-    // PolyNode& operator =(PolyNode& other);
-    unsigned Index;    // node index in Parent.Childs
-    bool m_IsOpen;
-    JoinType m_jointype;
-    EndType m_endtype;
-    PolyNode*   GetNextSiblingUp() const;
-    void        AddChild( PolyNode& child );
-
-    friend class Clipper;    // to access Index
-    friend class ClipperOffset;
-};
-
-class PolyTree : public PolyNode
-{
-public:
-    ~PolyTree() { Clear(); };
-    PolyNode*   GetFirst() const;
-    void        Clear();
-    int         Total() const;
-
-private:
-    // PolyTree& operator =(PolyTree& other);
-    PolyNodes AllNodes;
-    friend class Clipper;    // to access AllNodes
-};
-
-bool    Orientation( const Path& poly );
-double  Area( const Path& poly );
-int     PointInPolygon( const IntPoint& pt, const Path& path );
-
-void SimplifyPolygon( const Path& in_poly, Paths& out_polys,
-        PolyFillType fillType = pftEvenOdd );
-void SimplifyPolygons( const Paths& in_polys,
-        Paths& out_polys,
-        PolyFillType fillType = pftEvenOdd );
-void SimplifyPolygons( Paths& polys, PolyFillType fillType = pftEvenOdd );
-
-void    CleanPolygon( const Path& in_poly, Path& out_poly, double distance = 1.415 );
-void    CleanPolygon( Path& poly, double distance = 1.415 );
-void    CleanPolygons( const Paths& in_polys, Paths& out_polys, double distance = 1.415 );
-void    CleanPolygons( Paths& polys, double distance = 1.415 );
-
-void    MinkowskiSum( const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed );
-void    MinkowskiSum( const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed );
-void    MinkowskiDiff( const Path& poly1, const Path& poly2, Paths& solution );
-
-void    PolyTreeToPaths( const PolyTree& polytree, Paths& paths );
-void    ClosedPathsFromPolyTree( const PolyTree& polytree, Paths& paths );
-void    OpenPathsFromPolyTree( PolyTree& polytree, Paths& paths );
-
-void    ReversePath( Path& p );
-void    ReversePaths( Paths& p );
-
-struct IntRect
-{
-    cInt left; cInt top; cInt right; cInt bottom;
-};
-
-// enums that are used internally ...
-enum EdgeSide
-{
-    esLeft = 1, esRight = 2
-};
-
-// forward declarations (for stuff used internally) ...
-struct TEdge;
-struct IntersectNode;
-struct LocalMinimum;
-struct OutPt;
-struct OutRec;
-struct Join;
-
-typedef std::vector <OutRec*>           PolyOutList;
-typedef std::vector <TEdge*>            EdgeList;
-typedef std::vector <Join*>             JoinList;
-typedef std::vector <IntersectNode*>    IntersectList;
-
-// ------------------------------------------------------------------------------
-
-// ClipperBase is the ancestor to the Clipper class. It should not be
-// instantiated directly. This class simply abstracts the conversion of sets of
-// polygon coordinates into edge objects that are stored in a LocalMinima list.
-class ClipperBase
-{
-public:
-    ClipperBase();
-    virtual ~ClipperBase();
-    virtual bool    AddPath( const Path& pg, PolyType PolyTyp, bool Closed );
-    bool            AddPaths( const Paths& ppg, PolyType PolyTyp, bool Closed );
-    virtual void    Clear();
-    IntRect         GetBounds();
-
-    bool PreserveCollinear() { return m_PreserveCollinear; };
-    void PreserveCollinear( bool value ) { m_PreserveCollinear = value; };
-
-protected:
-    void            DisposeLocalMinimaList();
-    TEdge*          AddBoundsToLML( TEdge* e, bool IsClosed );
-    virtual void    Reset();
-    TEdge*          ProcessBound( TEdge* E, bool IsClockwise );
-    void            InsertScanbeam( const cInt Y );
-    bool            PopScanbeam( cInt& Y );
-    bool            LocalMinimaPending();
-    bool            PopLocalMinima( cInt Y, const LocalMinimum*& locMin );
-    OutRec*         CreateOutRec();
-    void            DisposeAllOutRecs();
-    void            DisposeOutRec( PolyOutList::size_type index );
-    void            SwapPositionsInAEL( TEdge* edge1, TEdge* edge2 );
-    void            DeleteFromAEL( TEdge* e );
-    void            UpdateEdgeIntoAEL( TEdge*& e );
-
-    typedef std::vector<LocalMinimum> MinimaList;
-    MinimaList::iterator m_CurrentLM;
-    MinimaList m_MinimaList;
-
-    bool m_UseFullRange;
-    EdgeList    m_edges;
-    bool    m_PreserveCollinear;
-    bool    m_HasOpenPaths;
-    PolyOutList m_PolyOuts;
-    TEdge* m_ActiveEdges;
-
-    typedef std::priority_queue<cInt> ScanbeamList;
-    ScanbeamList m_Scanbeam;
-};
-// ------------------------------------------------------------------------------
-
-class Clipper : public virtual ClipperBase
-{
-public:
-    Clipper( int initOptions = 0 );
-    bool Execute( ClipType clipType,
-            Paths& solution,
-            PolyFillType fillType = pftEvenOdd );
-    bool Execute( ClipType clipType,
-            Paths& solution,
-            PolyFillType subjFillType,
-            PolyFillType clipFillType );
-    bool Execute( ClipType clipType,
-            PolyTree& polytree,
-            PolyFillType fillType = pftEvenOdd );
-    bool Execute( ClipType clipType,
-            PolyTree& polytree,
-            PolyFillType subjFillType,
-            PolyFillType clipFillType );
-
-    bool ReverseSolution() { return m_ReverseOutput; };
-    void ReverseSolution( bool value ) { m_ReverseOutput = value; };
-    bool StrictlySimple() { return m_StrictSimple; };
-    void StrictlySimple( bool value ) { m_StrictSimple = value; };
-    // set the callback function for z value filling on intersections (otherwise Z is 0)
-#ifdef use_xyz
-    void ZFillFunction( ZFillCallback zFillFunc );
-
-#endif
-
-protected:
-    virtual bool ExecuteInternal();
-
-private:
-    JoinList m_Joins;
-    JoinList m_GhostJoins;
-    IntersectList m_IntersectList;
-    ClipType m_ClipType;
-    typedef std::list<cInt> MaximaList;
-    MaximaList m_Maxima;
-    TEdge* m_SortedEdges;
-    bool m_ExecuteLocked;
-    PolyFillType m_ClipFillType;
-    PolyFillType m_SubjFillType;
-    bool m_ReverseOutput;
-    bool m_UsingPolyTree;
-    bool m_StrictSimple;
-#ifdef use_xyz
-    ZFillCallback m_ZFill; // custom callback
-#endif
-    void    SetWindingCount( TEdge& edge );
-    bool    IsEvenOddFillType( const TEdge& edge ) const;
-    bool    IsEvenOddAltFillType( const TEdge& edge ) const;
-    void    InsertLocalMinimaIntoAEL( const cInt botY );
-    void    InsertEdgeIntoAEL( TEdge* edge, TEdge* startEdge );
-    void    AddEdgeToSEL( TEdge* edge );
-    bool    PopEdgeFromSEL( TEdge*& edge );
-    void    CopyAELToSEL();
-    void    DeleteFromSEL( TEdge* e );
-    void    SwapPositionsInSEL( TEdge* edge1, TEdge* edge2 );
-    bool    IsContributing( const TEdge& edge ) const;
-    bool    IsTopHorz( const cInt XPos );
-    void    DoMaxima( TEdge* e );
-    void    ProcessHorizontals();
-    void    ProcessHorizontal( TEdge* horzEdge );
-    void    AddLocalMaxPoly( TEdge* e1, TEdge* e2, const IntPoint& pt );
-    OutPt*  AddLocalMinPoly( TEdge* e1, TEdge* e2, const IntPoint& pt );
-    OutRec* GetOutRec( int idx );
-    void    AppendPolygon( TEdge* e1, TEdge* e2 );
-    void    IntersectEdges( TEdge* e1, TEdge* e2, IntPoint& pt );
-    OutPt*  AddOutPt( TEdge* e, const IntPoint& pt );
-    OutPt*  GetLastOutPt( TEdge* e );
-    bool    ProcessIntersections( const cInt topY );
-    void    BuildIntersectList( const cInt topY );
-    void    ProcessIntersectList();
-    void    ProcessEdgesAtTopOfScanbeam( const cInt topY );
-    void    BuildResult( Paths& polys );
-    void    BuildResult2( PolyTree& polytree );
-    void    SetHoleState( TEdge* e, OutRec* outrec );
-    void    DisposeIntersectNodes();
-    bool    FixupIntersectionOrder();
-    void    FixupOutPolygon( OutRec& outrec );
-    void    FixupOutPolyline( OutRec& outrec );
-    bool    IsHole( TEdge* e );
-    bool    FindOwnerFromSplitRecs( OutRec& outRec, OutRec*& currOrfl );
-    void    FixHoleLinkage( OutRec& outrec );
-    void    AddJoin( OutPt* op1, OutPt* op2, const IntPoint offPt );
-    void    ClearJoins();
-    void    ClearGhostJoins();
-    void    AddGhostJoin( OutPt* op, const IntPoint offPt );
-    bool    JoinPoints( Join* j, OutRec* outRec1, OutRec* outRec2 );
-    void    JoinCommonEdges();
-    void    DoSimplePolygons();
-    void    FixupFirstLefts1( OutRec* OldOutRec, OutRec* NewOutRec );
-    void    FixupFirstLefts2( OutRec* InnerOutRec, OutRec* OuterOutRec );
-    void    FixupFirstLefts3( OutRec* OldOutRec, OutRec* NewOutRec );
-
-#ifdef use_xyz
-    void SetZ( IntPoint& pt, TEdge& e1, TEdge& e2 );
-
-#endif
-};
-// ------------------------------------------------------------------------------
-
-class ClipperOffset
-{
-public:
-    ClipperOffset( double miterLimit = 2.0, double roundPrecision = 0.25 );
-    ~ClipperOffset();
-    void    AddPath( const Path& path, JoinType joinType, EndType endType );
-    void    AddPaths( const Paths& paths, JoinType joinType, EndType endType );
-    void    Execute( Paths& solution, double delta );
-    void    Execute( PolyTree& solution, double delta );
-    void    Clear();
-
-    double MiterLimit;
-    JoinType MiterFallback;
-    double ArcTolerance;
-
-private:
-    Paths m_destPolys;
-    Path m_srcPoly;
-    Path m_destPoly;
-    std::vector<DoublePoint> m_normals;
-    double m_delta, m_sinA, m_sin, m_cos;
-    double m_miterLim, m_StepsPerRad;
-    IntPoint m_lowest;
-    PolyNode m_polyNodes;
-
-    void    FixOrientations();
-    void    DoOffset( double delta );
-    void    OffsetPoint( int j, int& k, JoinType jointype );
-    void    DoSquare( int j, int k );
-    void    DoMiter( int j, int k, double r );
-    void    DoRound( int j, int k );
-};
-// ------------------------------------------------------------------------------
-
-class clipperException : public std::exception
-{
-public:
-    clipperException( const char* description ) : m_descr( description ) {}
-    virtual ~clipperException() throw() {}
-    virtual const char* what() const throw()override { return m_descr.c_str(); }
-
-private:
-    std::string m_descr;
-};
-// ------------------------------------------------------------------------------
-}       // ClipperLib namespace
-
-#endif  // clipper_hpp