diff --git a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp
index c4c1f2a31c..3748459fa9 100644
--- a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp
+++ b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp
@@ -722,11 +722,9 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
 void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aContainer,
                                          PCB_LAYER_ID aLayerId )
 {
-    // Copy the polys list because we have to simplify it
-    SHAPE_POLY_SET polyList = SHAPE_POLY_SET( *aZone->GetFilledPolysList( aLayerId ) );
-
     // This convert the poly in outline and holes
-    ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aZone );
+    ConvertPolygonToTriangles( *aZone->GetFilledPolysList( aLayerId ), *aContainer,
+                               m_biuTo3Dunits, *aZone );
 }
 
 
diff --git a/3d-viewer/3d_rendering/opengl/create_scene.cpp b/3d-viewer/3d_rendering/opengl/create_scene.cpp
index df3f275aa0..d2bd22d044 100644
--- a/3d-viewer/3d_rendering/opengl/create_scene.cpp
+++ b/3d-viewer/3d_rendering/opengl/create_scene.cpp
@@ -395,9 +395,8 @@ OPENGL_RENDER_LIST* RENDER_3D_OPENGL::createBoard( const SHAPE_POLY_SET& aBoardP
 {
     OPENGL_RENDER_LIST* dispLists = nullptr;
     CONTAINER_2D boardContainer;
-    SHAPE_POLY_SET brd_outlines = aBoardPoly;
 
-    ConvertPolygonToTriangles( brd_outlines, boardContainer, m_boardAdapter.BiuTo3dUnits(),
+    ConvertPolygonToTriangles( aBoardPoly, boardContainer, m_boardAdapter.BiuTo3dUnits(),
                                (const BOARD_ITEM &)*m_boardAdapter.GetBoard() );
 
     const LIST_OBJECT2D& listBoardObject2d = boardContainer.GetList();
@@ -481,7 +480,7 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
         m_antiBoard = createBoard( m_antiBoardPolys );
     }
 
-    SHAPE_POLY_SET board_poly_with_holes = m_boardAdapter.GetBoardPoly();
+    SHAPE_POLY_SET board_poly_with_holes = m_boardAdapter.GetBoardPoly().CloneDropTriangulation();
     board_poly_with_holes.BooleanSubtract( m_boardAdapter.GetThroughHoleOdPolys(),
                                            SHAPE_POLY_SET::PM_FAST );
     board_poly_with_holes.BooleanSubtract( m_boardAdapter.GetOuterNonPlatedThroughHolePoly(),
@@ -496,11 +495,13 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
     if( aStatusReporter )
         aStatusReporter->Report( _( "Load OpenGL: holes and vias" ) );
 
-    SHAPE_POLY_SET outerPolyTHT = m_boardAdapter.GetThroughHoleOdPolys();
+    SHAPE_POLY_SET outerPolyTHT = m_boardAdapter.GetThroughHoleOdPolys().CloneDropTriangulation();
 
     if( m_boardAdapter.m_Cfg->m_Render.realistic )
+    {
         outerPolyTHT.BooleanIntersection( m_boardAdapter.GetBoardPoly(),
                                           SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
+    }
 
     m_outerThroughHoles = generateHoles( m_boardAdapter.GetThroughHoleOds().GetList(),
                                          outerPolyTHT, 1.0f, 0.0f, false,
@@ -630,9 +631,12 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
     if( m_boardAdapter.m_Cfg->m_Render.renderPlatedPadsAsPlated
             && m_boardAdapter.m_Cfg->m_Render.realistic )
     {
-        if( m_boardAdapter.GetFrontPlatedPadPolys() )
+        const SHAPE_POLY_SET* frontPlatedPadPolys = m_boardAdapter.GetFrontPlatedPadPolys();
+        const SHAPE_POLY_SET* backPlatedPadPolys = m_boardAdapter.GetBackPlatedPadPolys();
+
+        if( frontPlatedPadPolys )
         {
-            SHAPE_POLY_SET polySubtracted = *m_boardAdapter.GetFrontPlatedPadPolys();
+            SHAPE_POLY_SET polySubtracted = frontPlatedPadPolys->CloneDropTriangulation();
             polySubtracted.BooleanIntersection( m_boardAdapter.GetBoardPoly(),
                                                 SHAPE_POLY_SET::PM_FAST );
             polySubtracted.BooleanSubtract( m_boardAdapter.GetThroughHoleOdPolys(),
@@ -648,9 +652,9 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
                 m_layers[F_Cu] = generateEmptyLayerList( F_Cu );
         }
 
-        if( m_boardAdapter.GetBackPlatedPadPolys() )
+        if( backPlatedPadPolys )
         {
-            SHAPE_POLY_SET polySubtracted = *m_boardAdapter.GetBackPlatedPadPolys();
+            SHAPE_POLY_SET polySubtracted = backPlatedPadPolys->CloneDropTriangulation();
             polySubtracted.BooleanIntersection( m_boardAdapter.GetBoardPoly(),
                                                 SHAPE_POLY_SET::PM_FAST );
             polySubtracted.BooleanSubtract( m_boardAdapter.GetThroughHoleOdPolys(),
diff --git a/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.cpp b/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.cpp
index b72071c6c1..688712c563 100644
--- a/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.cpp
+++ b/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.cpp
@@ -118,14 +118,14 @@ bool TRIANGLE_2D::IsPointInside( const SFVEC2F& aPoint ) const
 }
 
 
-void ConvertPolygonToTriangles( SHAPE_POLY_SET& aPolyList, CONTAINER_2D_BASE& aDstContainer,
+void ConvertPolygonToTriangles( const SHAPE_POLY_SET& aPolyList, CONTAINER_2D_BASE& aDstContainer,
                                 float aBiuTo3dUnitsScale, const BOARD_ITEM& aBoardItem )
 {
     VECTOR2I a;
     VECTOR2I b;
     VECTOR2I c;
 
-    aPolyList.CacheTriangulation( false );
+    const_cast<SHAPE_POLY_SET&>( aPolyList ).CacheTriangulation( false );
     const double conver_d = (double)aBiuTo3dUnitsScale;
 
     for( unsigned int j = 0; j < aPolyList.TriangulatedPolyCount(); j++ )
diff --git a/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.h b/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.h
index 06d79f5ab7..e3b7ffe25f 100644
--- a/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.h
+++ b/3d-viewer/3d_rendering/raytracing/shapes2D/triangle_2d.h
@@ -64,6 +64,6 @@ private:
 };
 
 
-void ConvertPolygonToTriangles( SHAPE_POLY_SET& aPolyList, CONTAINER_2D_BASE& aDstContainer,
+void ConvertPolygonToTriangles( const SHAPE_POLY_SET& aPolyList, CONTAINER_2D_BASE& aDstContainer,
                                 float aBiuTo3dUnitsScale, const BOARD_ITEM& aBoardItem );
 #endif // _TRIANGLE_2D_H_
diff --git a/common/drawing_sheet/ds_data_item.cpp b/common/drawing_sheet/ds_data_item.cpp
index 124e4c61cf..6a597cc413 100644
--- a/common/drawing_sheet/ds_data_item.cpp
+++ b/common/drawing_sheet/ds_data_item.cpp
@@ -417,6 +417,7 @@ void DS_DATA_ITEM_POLYGONS::SyncDrawItems( DS_DRAW_ITEM_LIST* aCollector, KIGFX:
 
         // Transfer all outlines (basic polygons)
         SHAPE_POLY_SET& polygons = poly_shape->GetPolygons();
+
         for( int kk = 0; kk < GetPolyCount(); kk++ )
         {
             // Create new outline
diff --git a/common/plotters/GERBER_plotter.cpp b/common/plotters/GERBER_plotter.cpp
index 63f53f82cb..3300bf712c 100644
--- a/common/plotters/GERBER_plotter.cpp
+++ b/common/plotters/GERBER_plotter.cpp
@@ -1696,7 +1696,7 @@ void GERBER_PLOTTER::FlashPadCustom( const VECTOR2I& aPadPos, const VECTOR2I& aS
     if( aData )
         gbr_metadata = *static_cast<GBR_METADATA*>( aData );
 
-    SHAPE_POLY_SET polyshape = *aPolygons;
+    SHAPE_POLY_SET polyshape = aPolygons->CloneDropTriangulation();
 
     if( aTraceMode != FILLED )
     {
diff --git a/gerbview/export_to_pcbnew.cpp b/gerbview/export_to_pcbnew.cpp
index 364e1ca983..5d0ca03aba 100644
--- a/gerbview/export_to_pcbnew.cpp
+++ b/gerbview/export_to_pcbnew.cpp
@@ -476,7 +476,7 @@ void GBR_TO_PCB_EXPORTER::writePcbHeader( const int* aLayerLookUpTable )
 void GBR_TO_PCB_EXPORTER::writePcbPolygon( const SHAPE_POLY_SET& aPolys, int aLayer,
                                            const VECTOR2I& aOffset )
 {
-    SHAPE_POLY_SET polys = aPolys;
+    SHAPE_POLY_SET polys = aPolys.CloneDropTriangulation();
 
     // Cleanup the polygon
     polys.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
@@ -523,7 +523,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_Polygon;
+    SHAPE_POLY_SET polys = aGbrItem->m_Polygon.CloneDropTriangulation();
     polys.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
 
     if( polys.OutlineCount() == 0 )
diff --git a/libs/kimath/include/geometry/shape_poly_set.h b/libs/kimath/include/geometry/shape_poly_set.h
index 73284ee5d3..528bd4fe5b 100644
--- a/libs/kimath/include/geometry/shape_poly_set.h
+++ b/libs/kimath/include/geometry/shape_poly_set.h
@@ -536,6 +536,8 @@ public:
     /// @copydoc SHAPE::Clone()
     SHAPE* Clone() const override;
 
+    SHAPE_POLY_SET CloneDropTriangulation() const;
+
     ///< Creates a new empty polygon in the set and returns its index
     int NewOutline();
 
@@ -1366,6 +1368,10 @@ public:
     static const SHAPE_POLY_SET BuildPolysetFromOrientedPaths( const std::vector<SHAPE_LINE_CHAIN>& aPaths, bool aReverseOrientation = false, bool aEvenOdd = false );
 
 private:
+    enum DROP_TRIANGULATION_FLAG { SINGLETON };
+
+    SHAPE_POLY_SET( const SHAPE_POLY_SET& aOther, DROP_TRIANGULATION_FLAG );
+
     void fractureSingle( POLYGON& paths );
     void unfractureSingle ( POLYGON& path );
     void importTree( ClipperLib::PolyTree*               tree,
diff --git a/libs/kimath/src/geometry/shape_poly_set.cpp b/libs/kimath/src/geometry/shape_poly_set.cpp
index ee15873c35..c2eae1b368 100644
--- a/libs/kimath/src/geometry/shape_poly_set.cpp
+++ b/libs/kimath/src/geometry/shape_poly_set.cpp
@@ -108,6 +108,16 @@ SHAPE_POLY_SET::SHAPE_POLY_SET( const SHAPE_POLY_SET& aOther ) :
 }
 
 
+SHAPE_POLY_SET::SHAPE_POLY_SET( const SHAPE_POLY_SET& aOther, DROP_TRIANGULATION_FLAG ) :
+    SHAPE( aOther ),
+    m_polys( aOther.m_polys )
+{
+    m_triangulationValid = false;
+    m_hash = MD5_HASH();
+    m_triangulatedPolys.clear();
+}
+
+
 SHAPE_POLY_SET::~SHAPE_POLY_SET()
 {
 }
@@ -119,6 +129,12 @@ SHAPE* SHAPE_POLY_SET::Clone() const
 }
 
 
+SHAPE_POLY_SET SHAPE_POLY_SET::CloneDropTriangulation() const
+{
+    return SHAPE_POLY_SET( *this, DROP_TRIANGULATION_FLAG::SINGLETON );
+}
+
+
 bool SHAPE_POLY_SET::GetRelativeIndices( int aGlobalIdx,
                                          SHAPE_POLY_SET::VERTEX_INDEX* aRelativeIndices ) const
 {
diff --git a/pcbnew/autorouter/ar_autoplacer.cpp b/pcbnew/autorouter/ar_autoplacer.cpp
index 1dd6a6ada1..7ea7d6e8b1 100644
--- a/pcbnew/autorouter/ar_autoplacer.cpp
+++ b/pcbnew/autorouter/ar_autoplacer.cpp
@@ -145,7 +145,7 @@ bool AR_AUTOPLACER::fillMatrix()
     VECTOR2I coord_orgin = m_matrix.GetBrdCoordOrigin(); // Board coordinate of matruix cell (0,0)
 
     // Create a single board outline:
-    SHAPE_POLY_SET brd_shape = m_boardShape;
+    SHAPE_POLY_SET brd_shape = m_boardShape.CloneDropTriangulation();
     brd_shape.Fracture( SHAPE_POLY_SET::PM_FAST );
     const SHAPE_LINE_CHAIN& outline = brd_shape.Outline(0);
     const BOX2I& rect = outline.BBox();
@@ -800,7 +800,7 @@ void AR_AUTOPLACER::drawPlacementRoutingMatrix( )
     m_overlay->SetIsFill( true );
     m_overlay->SetIsStroke( false );
 
-    SHAPE_POLY_SET freeArea = m_topFreeArea;
+    SHAPE_POLY_SET freeArea = m_topFreeArea.CloneDropTriangulation();
     freeArea.Fracture( SHAPE_POLY_SET::PM_FAST );
 
     // Draw the free polygon areas, top side:
diff --git a/pcbnew/convert_shape_list_to_polygon.cpp b/pcbnew/convert_shape_list_to_polygon.cpp
index 0cbce66cb6..52d36ecfc4 100644
--- a/pcbnew/convert_shape_list_to_polygon.cpp
+++ b/pcbnew/convert_shape_list_to_polygon.cpp
@@ -244,9 +244,9 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aSegList, SHAPE_POLY_SET&
 
         case SHAPE_T::POLY:
             {
-                const SHAPE_POLY_SET poly = graphic->GetPolyShape();
-                EDA_ANGLE            orientation = ANGLE_0;
-                VECTOR2I             offset = VECTOR2I( 0, 0 );
+                const SHAPE_POLY_SET& poly = graphic->GetPolyShape();
+                EDA_ANGLE             orientation = ANGLE_0;
+                VECTOR2I              offset = VECTOR2I( 0, 0 );
 
                 if( graphic->GetParentFootprint() )
                 {
@@ -946,7 +946,7 @@ bool isCopperOutside( const FOOTPRINT* aMod, SHAPE_POLY_SET& aShape )
 
     for( PAD* pad : aMod->Pads() )
     {
-        SHAPE_POLY_SET poly = aShape;
+        SHAPE_POLY_SET poly = aShape.CloneDropTriangulation();
 
         poly.BooleanIntersection( *pad->GetEffectivePolygon(), SHAPE_POLY_SET::PM_FAST );
 
diff --git a/pcbnew/drc/drc_test_provider_disallow.cpp b/pcbnew/drc/drc_test_provider_disallow.cpp
index 462dfd5602..25ab38395e 100644
--- a/pcbnew/drc/drc_test_provider_disallow.cpp
+++ b/pcbnew/drc/drc_test_provider_disallow.cpp
@@ -130,7 +130,7 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
                             // enough to 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();
+                            SHAPE_POLY_SET areaPoly = ruleArea->Outline()->CloneDropTriangulation();
                             areaPoly.Deflate( epsilon, 0, SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS );
 
                             DRC_RTREE* zoneRTree = board->m_CopperZoneRTrees[ copperZone ].get();
diff --git a/pcbnew/drc/drc_test_provider_library_parity.cpp b/pcbnew/drc/drc_test_provider_library_parity.cpp
index 28e4e23eb5..708e068df9 100644
--- a/pcbnew/drc/drc_test_provider_library_parity.cpp
+++ b/pcbnew/drc/drc_test_provider_library_parity.cpp
@@ -294,11 +294,17 @@ bool zonesNeedUpdate( const FP_ZONE* a, const FP_ZONE* b )
 
     TEST( a->Outline()->TotalVertices(), b->Outline()->TotalVertices() );
 
+    // The footprint's zone will be in board position, so we must translate & rotate the library
+    // footprint's zone to match.
+    FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( a->GetParentFootprint() );
+    const SHAPE_POLY_SET& aPoly = *a->Outline();
+    SHAPE_POLY_SET        bPoly = b->Outline()->CloneDropTriangulation();
+
+    bPoly.Rotate( parentFootprint->GetOrientation() );
+    bPoly.Move( parentFootprint->GetPosition() );
+
     for( int ii = 0; ii < a->Outline()->TotalVertices(); ++ii )
-    {
-        TEST( a->Outline()->CVertex( ii ) - a->GetParent()->GetPosition(),
-              b->Outline()->CVertex( ii ) - b->GetParent()->GetPosition() );
-    }
+        TEST( aPoly.CVertex( ii ), bPoly.CVertex( ii ) );
 
     return false;
 }
diff --git a/pcbnew/drc/drc_test_provider_mechanical_clearance.cpp b/pcbnew/drc/drc_test_provider_mechanical_clearance.cpp
index 0cc3817df1..1fc4956e00 100644
--- a/pcbnew/drc/drc_test_provider_mechanical_clearance.cpp
+++ b/pcbnew/drc/drc_test_provider_mechanical_clearance.cpp
@@ -516,7 +516,7 @@ void DRC_TEST_PROVIDER_MECHANICAL_CLEARANCE::testZoneLayer( ZONE* aZone, PCB_LAY
 {
     int            epsilon = m_board->GetDesignSettings().GetDRCEpsilon();
     int            clearance = aConstraint.GetValue().Min();
-    SHAPE_POLY_SET fill = *aZone->GetFilledPolysList( aLayer );
+    SHAPE_POLY_SET fill = aZone->GetFilledPolysList( aLayer )->CloneDropTriangulation();
 
     if( aConstraint.GetSeverity() == RPT_SEVERITY_IGNORE || clearance - epsilon <= 0 )
         return;
diff --git a/pcbnew/drc/drc_test_provider_sliver_checker.cpp b/pcbnew/drc/drc_test_provider_sliver_checker.cpp
index be42b111de..451a0ec4f2 100644
--- a/pcbnew/drc/drc_test_provider_sliver_checker.cpp
+++ b/pcbnew/drc/drc_test_provider_sliver_checker.cpp
@@ -125,6 +125,7 @@ bool DRC_TEST_PROVIDER_SLIVER_CHECKER::Run()
                     {
                         PCB_LAYER_ID    layer = copperLayers[i];
                         SHAPE_POLY_SET& poly = layerPolys[i];
+                        SHAPE_POLY_SET  fill;
 
                         forEachGeometryItem( s_allBasicItems, LSET().set( layer ),
                                 [&]( BOARD_ITEM* item ) -> bool
@@ -135,11 +136,11 @@ bool DRC_TEST_PROVIDER_SLIVER_CHECKER::Run()
 
                                         if( !zone->GetIsRuleArea() )
                                         {
-                                            SHAPE_POLY_SET layerPoly = *zone->GetFill( layer );
-                                            layerPoly.Unfracture( SHAPE_POLY_SET::PM_FAST );
+                                            fill = zone->GetFill( layer )->CloneDropTriangulation();
+                                            fill.Unfracture( SHAPE_POLY_SET::PM_FAST );
 
-                                            for( int jj = 0; jj < layerPoly.OutlineCount(); ++jj )
-                                                poly.AddOutline( layerPoly.Outline( jj ) );
+                                            for( int jj = 0; jj < fill.OutlineCount(); ++jj )
+                                                poly.AddOutline( fill.Outline( jj ) );
 
                                             // Report progress on board zones only.  Everything
                                             // else is in the noise.
diff --git a/pcbnew/drc/drc_test_provider_text_dims.cpp b/pcbnew/drc/drc_test_provider_text_dims.cpp
index b97d4df0d3..681eb8f566 100644
--- a/pcbnew/drc/drc_test_provider_text_dims.cpp
+++ b/pcbnew/drc/drc_test_provider_text_dims.cpp
@@ -169,7 +169,7 @@ bool DRC_TEST_PROVIDER_TEXT_DIMS::Run()
                         for( ii = 0; ii < outlineCount; ++ii )
                             holeCount += outlineGlyph->HoleCount( ii );
 
-                        SHAPE_POLY_SET poly = *outlineGlyph;
+                        SHAPE_POLY_SET poly = outlineGlyph->CloneDropTriangulation();
                         poly.Deflate( constraint.Value().Min() / 2, 16 );
                         poly.Simplify( SHAPE_POLY_SET::PM_FAST );
 
diff --git a/pcbnew/exporters/export_hyperlynx.cpp b/pcbnew/exporters/export_hyperlynx.cpp
index f407f7f17d..21f49166ec 100644
--- a/pcbnew/exporters/export_hyperlynx.cpp
+++ b/pcbnew/exporters/export_hyperlynx.cpp
@@ -485,45 +485,51 @@ bool HYPERLYNX_EXPORTER::writeNetObjects( const std::vector<BOARD_ITEM*>& aObjec
             for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
             {
                 const wxString layerName   = m_board->GetLayerName( layer );
-                SHAPE_POLY_SET filledShape = *zone->GetFilledPolysList( layer );
+                SHAPE_POLY_SET fill = zone->GetFilledPolysList( layer )->CloneDropTriangulation();
 
-                filledShape.Simplify( SHAPE_POLY_SET::PM_FAST );
+                fill.Simplify( SHAPE_POLY_SET::PM_FAST );
 
-                for( int i = 0; i < filledShape.OutlineCount(); i++ )
+                for( int i = 0; i < fill.OutlineCount(); i++ )
                 {
-                    const SHAPE_LINE_CHAIN& outl = filledShape.COutline( i );
+                    const SHAPE_LINE_CHAIN& outl = fill.COutline( i );
 
                     auto p0 = outl.CPoint( 0 );
                     m_out->Print( 1, "{POLYGON T=POUR L=\"%s\" ID=%d X=%.10f Y=%.10f\n",
-                            (const char*) layerName.c_str(), m_polyId, iu2hyp( p0.x ),
-                            iu2hyp( p0.y ) );
+                                  (const char*) layerName.c_str(),
+                                  m_polyId,
+                                  iu2hyp( p0.x ),
+                                  iu2hyp( p0.y ) );
 
                     for( int v = 0; v < outl.PointCount(); v++ )
                     {
-                        m_out->Print( 2, "(LINE X=%.10f Y=%.10f)\n", iu2hyp( outl.CPoint( v ).x ),
-                                iu2hyp( outl.CPoint( v ).y ) );
+                        m_out->Print( 2, "(LINE X=%.10f Y=%.10f)\n",
+                                      iu2hyp( outl.CPoint( v ).x ),
+                                      iu2hyp( outl.CPoint( v ).y ) );
                     }
 
                     m_out->Print( 2, "(LINE X=%.10f Y=%.10f)\n", iu2hyp( p0.x ), iu2hyp( p0.y ) );
                     m_out->Print( 1, "}\n" );
 
-                    for( int h = 0; h < filledShape.HoleCount( i ); h++ )
+                    for( int h = 0; h < fill.HoleCount( i ); h++ )
                     {
-                        const SHAPE_LINE_CHAIN& holeShape = filledShape.CHole( i, h );
+                        const SHAPE_LINE_CHAIN& holeShape = fill.CHole( i, h );
                         VECTOR2I                ph0       = holeShape.CPoint( 0 );
 
-                        m_out->Print( 1, "{POLYVOID ID=%d X=%.10f Y=%.10f\n", m_polyId,
-                                iu2hyp( ph0.x ), iu2hyp( ph0.y ) );
+                        m_out->Print( 1, "{POLYVOID ID=%d X=%.10f Y=%.10f\n",
+                                      m_polyId,
+                                      iu2hyp( ph0.x ),
+                                      iu2hyp( ph0.y ) );
 
                         for( int v = 0; v < holeShape.PointCount(); v++ )
                         {
                             m_out->Print( 2, "(LINE X=%.10f Y=%.10f)\n",
-                                    iu2hyp( holeShape.CPoint( v ).x ),
-                                    iu2hyp( holeShape.CPoint( v ).y ) );
+                                          iu2hyp( holeShape.CPoint( v ).x ),
+                                          iu2hyp( holeShape.CPoint( v ).y ) );
                         }
 
                         m_out->Print( 2, "(LINE X=%.10f Y=%.10f)\n",
-                                iu2hyp( ph0.x ), iu2hyp( ph0.y ) );
+                                      iu2hyp( ph0.x ),
+                                      iu2hyp( ph0.y ) );
                         m_out->Print( 1, "}\n" );
                     }
 
diff --git a/pcbnew/footprint.cpp b/pcbnew/footprint.cpp
index 70f6f23513..2a190e355d 100644
--- a/pcbnew/footprint.cpp
+++ b/pcbnew/footprint.cpp
@@ -894,7 +894,7 @@ SHAPE_POLY_SET FOOTPRINT::GetBoundingHull() const
     {
         for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
         {
-            SHAPE_POLY_SET layerPoly = *zone->GetFilledPolysList( layer );
+            const SHAPE_POLY_SET& layerPoly = *zone->GetFilledPolysList( layer );
 
             for( int ii = 0; ii < layerPoly.OutlineCount(); ii++ )
             {
diff --git a/pcbnew/pcb_expr_evaluator.cpp b/pcbnew/pcb_expr_evaluator.cpp
index 95545a63f3..23dc60118d 100644
--- a/pcbnew/pcb_expr_evaluator.cpp
+++ b/pcbnew/pcb_expr_evaluator.cpp
@@ -452,7 +452,7 @@ bool calcIsInsideArea( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, PCB_EXPR_CO
     // Collisions include touching, so we need to deflate outline by enough to exclude it.
     // This is particularly important for detecting copper fills as they will be exactly
     // touching along the entire exclusion border.
-    SHAPE_POLY_SET areaOutline = *aArea->Outline();
+    SHAPE_POLY_SET areaOutline = aArea->Outline()->CloneDropTriangulation();
     areaOutline.Deflate( board->GetDesignSettings().GetDRCEpsilon(), 0,
                          SHAPE_POLY_SET::ALLOW_ACUTE_CORNERS );
 
@@ -498,7 +498,7 @@ bool calcIsInsideArea( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, PCB_EXPR_CO
 
         if( ( aArea->GetLayerSet() & LSET::FrontMask() ).any() )
         {
-            SHAPE_POLY_SET courtyard = footprint->GetPolyCourtyard( F_CrtYd );
+            const SHAPE_POLY_SET& courtyard = footprint->GetPolyCourtyard( F_CrtYd );
 
             if( courtyard.OutlineCount() == 0 )
             {
@@ -515,7 +515,7 @@ bool calcIsInsideArea( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, PCB_EXPR_CO
 
         if( ( aArea->GetLayerSet() & LSET::BackMask() ).any() )
         {
-            SHAPE_POLY_SET courtyard = footprint->GetPolyCourtyard( B_CrtYd );
+            const SHAPE_POLY_SET& courtyard = footprint->GetPolyCourtyard( B_CrtYd );
 
             if( courtyard.OutlineCount() == 0 )
             {
diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp
index a7205992cb..6ebf197bf2 100644
--- a/pcbnew/pcb_painter.cpp
+++ b/pcbnew/pcb_painter.cpp
@@ -546,7 +546,7 @@ bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
 
             if( fp )
             {
-                SHAPE_POLY_SET convex = fp->GetBoundingHull();
+                const SHAPE_POLY_SET& convex = fp->GetBoundingHull();
 
                 m_gal->DrawPolyline( convex.COutline( 0 ) );
             }
@@ -1953,7 +1953,7 @@ void PCB_PAINTER::draw( const FOOTPRINT* aFootprint, int aLayer )
         m_gal->SetIsStroke( false );
         m_gal->SetFillColor( color );
 
-        SHAPE_POLY_SET poly = aFootprint->GetBoundingHull();
+        const SHAPE_POLY_SET& poly = aFootprint->GetBoundingHull();
         m_gal->DrawPolygon( poly );
     }
 }
diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp
index c9f88b15e3..272e734ced 100644
--- a/pcbnew/plot_board_layers.cpp
+++ b/pcbnew/plot_board_layers.cpp
@@ -614,7 +614,7 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
             if( !aLayerMask[layer] )
                 continue;
 
-            SHAPE_POLY_SET mainArea = *zone->GetFilledPolysList( layer );
+            SHAPE_POLY_SET mainArea = zone->GetFilledPolysList( layer )->CloneDropTriangulation();
             SHAPE_POLY_SET islands;
 
             for( int i = mainArea.OutlineCount() - 1; i >= 0; i-- )
diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp
index 0c586c7f71..366a5763a3 100644
--- a/pcbnew/plot_brditems_plotter.cpp
+++ b/pcbnew/plot_brditems_plotter.cpp
@@ -1013,7 +1013,7 @@ void BRDITEMS_PLOTTER::PlotPcbShape( const PCB_SHAPE* aShape )
                     // ( for the future or to show a non expected shape )
                     // This must be simplified and fractured to prevent overlapping polygons
                     // from generating invalid Gerber files
-                    SHAPE_POLY_SET tmpPoly = SHAPE_POLY_SET( aShape->GetPolyShape() );
+                    SHAPE_POLY_SET tmpPoly = aShape->GetPolyShape().CloneDropTriangulation();
                     tmpPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
                     FILL_T fill = aShape->IsFilled() ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL;
 
diff --git a/pcbnew/zone.cpp b/pcbnew/zone.cpp
index 292ed91a0d..ac60d2a9a5 100644
--- a/pcbnew/zone.cpp
+++ b/pcbnew/zone.cpp
@@ -1060,7 +1060,7 @@ bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer
 
     // Processing of arc shapes in zones is not yet supported because Clipper can't do boolean
     // operations on them.  The poly outline must be converted to segments first.
-    SHAPE_POLY_SET flattened = *m_Poly;
+    SHAPE_POLY_SET flattened = m_Poly->CloneDropTriangulation();
     flattened.ClearArcs();
 
     if( GetIsRuleArea() )
@@ -1132,22 +1132,19 @@ bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer
 
     for( ZONE* zone : interactingZones )
     {
-        SHAPE_POLY_SET flattened_outline = *zone->Outline();
+        SHAPE_POLY_SET flattened_outline = zone->Outline()->CloneDropTriangulation();
         flattened_outline.ClearArcs();
         aSmoothedPoly.BooleanAdd( flattened_outline, SHAPE_POLY_SET::PM_FAST );
     }
 
     if( aBoardOutline )
-    {
-        SHAPE_POLY_SET poly = *aBoardOutline;
-        aSmoothedPoly.BooleanIntersection( poly, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
-    }
+        aSmoothedPoly.BooleanIntersection( *aBoardOutline, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
 
     smooth( aSmoothedPoly );
 
     if( aSmoothedPolyWithApron )
     {
-        SHAPE_POLY_SET poly = *maxExtents;
+        SHAPE_POLY_SET poly = maxExtents->CloneDropTriangulation();
         poly.Inflate( m_ZoneMinThickness, 64 );
         *aSmoothedPolyWithApron = aSmoothedPoly;
         aSmoothedPolyWithApron->BooleanIntersection( poly, SHAPE_POLY_SET::PM_FAST );
diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp
index 75f4bf896b..6719a84553 100644
--- a/pcbnew/zone_filler.cpp
+++ b/pcbnew/zone_filler.cpp
@@ -921,7 +921,7 @@ void ZONE_FILLER::subtractHigherPriorityZones( const ZONE* aZone, PCB_LAYER_ID a
                     // Processing of arc shapes in zones is not yet supported because Clipper
                     // can't do boolean operations on them.  The poly outline must be converted to
                     // segments first.
-                    SHAPE_POLY_SET outline = *aKnockout->Outline();
+                    SHAPE_POLY_SET outline = aKnockout->Outline()->CloneDropTriangulation();
                     outline.ClearArcs();
 
                     aRawFill.BooleanSubtract( outline, SHAPE_POLY_SET::PM_FAST );
@@ -1034,7 +1034,7 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA
     // Create a temporary zone that we can hit-test spoke-ends against.  It's only temporary
     // 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;
+    SHAPE_POLY_SET testAreas = aFillPolys.CloneDropTriangulation();
     testAreas.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
     DUMP_POLYS_TO_COPPER_LAYER( testAreas, In4_Cu, wxT( "minus-clearance-holes" ) );
 
@@ -1395,7 +1395,7 @@ bool ZONE_FILLER::addHatchFillTypeOnZone( const ZONE* aZone, PCB_LAYER_ID aLayer
     int linethickness = thickness - aZone->GetMinThickness();
     int gridsize = thickness + aZone->GetHatchGap();
 
-    SHAPE_POLY_SET filledPolys = aFillPolys;
+    SHAPE_POLY_SET filledPolys = aFillPolys.CloneDropTriangulation();
     // Use a area that contains the rotated bbox by orientation, and after rotate the result
     // by -orientation.
     if( !aZone->GetHatchOrientation().IsZero() )
@@ -1517,12 +1517,12 @@ bool ZONE_FILLER::addHatchFillTypeOnZone( const ZONE* aZone, PCB_LAYER_ID aLayer
 
     // The fill has already been deflated to ensure GetMinThickness() so we just have to
     // account for anything beyond that.
-    SHAPE_POLY_SET deflatedFilledPolys = aFillPolys;
+    SHAPE_POLY_SET deflatedFilledPolys = aFillPolys.CloneDropTriangulation();
     deflatedFilledPolys.Deflate( outline_margin - aZone->GetMinThickness(), 16 );
     holes.BooleanIntersection( deflatedFilledPolys, SHAPE_POLY_SET::PM_FAST );
     DUMP_POLYS_TO_COPPER_LAYER( holes, In11_Cu, wxT( "fill-clipped-hatch-holes" ) );
 
-    SHAPE_POLY_SET deflatedOutline = *aZone->Outline();
+    SHAPE_POLY_SET deflatedOutline = aZone->Outline()->CloneDropTriangulation();
     deflatedOutline.Deflate( outline_margin, 16 );
     holes.BooleanIntersection( deflatedOutline, SHAPE_POLY_SET::PM_FAST );
     DUMP_POLYS_TO_COPPER_LAYER( holes, In12_Cu, wxT( "outline-clipped-hatch-holes" ) );