From bc484784fc00f1e971c2034a1aeeb31cc338a7c5 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sat, 12 Dec 2020 15:14:41 +0000 Subject: [PATCH] Make sure zones are triangulated for DRC. Normally this happens as a side-effect of rendering them but if done from a script (or test case) this won't happen. Fixes https://gitlab.com/kicad/code/kicad/issues/6635 --- libs/kimath/src/geometry/shape_poly_set.cpp | 29 ++++++++++++--------- pcbnew/drc/drc_engine.cpp | 6 +++++ pcbnew/zone.h | 9 ++++--- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/libs/kimath/src/geometry/shape_poly_set.cpp b/libs/kimath/src/geometry/shape_poly_set.cpp index e629d72625..6df5657f04 100644 --- a/libs/kimath/src/geometry/shape_poly_set.cpp +++ b/libs/kimath/src/geometry/shape_poly_set.cpp @@ -1609,7 +1609,7 @@ void SHAPE_POLY_SET::Move( const VECTOR2I& aVector ) path.Move( aVector ); } - for( auto& tri : m_triangulatedPolys ) + for( std::unique_ptr& tri : m_triangulatedPolys ) tri->Move( aVector ); m_hash = checksum(); @@ -1621,9 +1621,7 @@ void SHAPE_POLY_SET::Mirror( bool aX, bool aY, const VECTOR2I& aRef ) for( POLYGON& poly : m_polys ) { for( SHAPE_LINE_CHAIN& path : poly ) - { path.Mirror( aX, aY, aRef ); - } } } @@ -1745,7 +1743,7 @@ SEG::ecoord SHAPE_POLY_SET::SquaredDistance( VECTOR2I aPoint, VECTOR2I* aNearest { SEG::ecoord currentDistance_sq; SEG::ecoord minDistance_sq = VECTOR2I::ECOORD_MAX; - VECTOR2I nearest; + VECTOR2I nearest; // Iterate through all the polygons and get the minimum distance. for( unsigned int polygonIdx = 0; polygonIdx < m_polys.size(); polygonIdx++ ) @@ -1770,13 +1768,13 @@ SEG::ecoord SHAPE_POLY_SET::SquaredDistance( const SEG& aSegment, VECTOR2I* aNea { SEG::ecoord currentDistance_sq; SEG::ecoord minDistance_sq = VECTOR2I::ECOORD_MAX; - VECTOR2I nearest; + VECTOR2I nearest; // Iterate through all the polygons and get the minimum distance. for( unsigned int polygonIdx = 0; polygonIdx < m_polys.size(); polygonIdx++ ) { currentDistance_sq = SquaredDistanceToPolygon( aSegment, polygonIdx, - aNearest ? &nearest : nullptr ); + aNearest ? &nearest : nullptr ); if( currentDistance_sq < minDistance_sq ) { @@ -1997,8 +1995,10 @@ SHAPE_POLY_SET &SHAPE_POLY_SET::operator=( const SHAPE_POLY_SET& aOther ) if( aOther.IsTriangulationUpToDate() ) { for( unsigned i = 0; i < aOther.TriangulatedPolyCount(); i++ ) - m_triangulatedPolys.push_back( - std::make_unique( *aOther.TriangulatedPolygon( i ) ) ); + { + const TRIANGULATED_POLYGON* poly = aOther.TriangulatedPolygon( i ); + m_triangulatedPolys.push_back( std::make_unique( *poly ) ); + } m_hash = aOther.GetHash(); m_triangulationValid = true; @@ -2024,14 +2024,14 @@ bool SHAPE_POLY_SET::IsTriangulationUpToDate() const if( !m_hash.IsValid() ) return false; - auto hash = checksum(); + MD5_HASH hash = checksum(); return hash == m_hash; } -static void partitionPolyIntoRegularCellGrid( - const SHAPE_POLY_SET& aPoly, int aSize, SHAPE_POLY_SET& aOut ) +static void partitionPolyIntoRegularCellGrid( const SHAPE_POLY_SET& aPoly, int aSize, + SHAPE_POLY_SET& aOut ) { BOX2I bb = aPoly.BBox(); @@ -2057,6 +2057,7 @@ static void partitionPolyIntoRegularCellGrid( SHAPE_POLY_SET ps1( aPoly ), ps2( aPoly ), maskSetOdd, maskSetEven; for( int yy = 0; yy < n_cells_y; yy++ ) + { for( int xx = 0; xx < n_cells_x; xx++ ) { VECTOR2I p; @@ -2082,6 +2083,7 @@ static void partitionPolyIntoRegularCellGrid( else maskSetEven.AddOutline( mask ); } + } ps1.BooleanIntersection( maskSetOdd, SHAPE_POLY_SET::PM_FAST ); ps2.BooleanIntersection( maskSetEven, SHAPE_POLY_SET::PM_FAST ); @@ -2089,10 +2091,9 @@ static void partitionPolyIntoRegularCellGrid( ps2.Fracture( SHAPE_POLY_SET::PM_FAST ); aOut = ps1; + for( int i = 0; i < ps2.OutlineCount(); i++ ) - { aOut.AddOutline( ps2.COutline( i ) ); - } if( !aOut.OutlineCount() ) aOut = aPoly; @@ -2124,8 +2125,10 @@ void SHAPE_POLY_SET::CacheTriangulation( bool aPartition ) SHAPE_POLY_SET tmpSet; if( aPartition ) + { // This partitions into regularly-sized grids (1cm in pcbnew) partitionPolyIntoRegularCellGrid( *this, 1e7, tmpSet ); + } else { tmpSet = *this; diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index 13f100f095..22577eeef3 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -677,12 +677,18 @@ void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aT } for( ZONE* zone : m_board->Zones() ) + { zone->CacheBoundingBox(); + zone->CacheTriangulation(); + } for( FOOTPRINT* footprint : m_board->Footprints() ) { for( ZONE* zone : footprint->Zones() ) + { zone->CacheBoundingBox(); + zone->CacheTriangulation(); + } footprint->BuildPolyCourtyards(); } diff --git a/pcbnew/zone.h b/pcbnew/zone.h index af180d190e..7e8dd62306 100644 --- a/pcbnew/zone.h +++ b/pcbnew/zone.h @@ -321,7 +321,8 @@ public: void SetOutline( SHAPE_POLY_SET* aOutline ) { m_Poly = aOutline; } // @copydoc BOARD_ITEM::GetEffectiveShape - virtual std::shared_ptr GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override; + virtual std::shared_ptr + GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override; /** * Function HitTest @@ -350,10 +351,10 @@ public: * @return true if aRefPos is inside a zone cutout */ bool HitTestCutout( const VECTOR2I& aRefPos, int* aOutlineIdx = nullptr, - int* aHoleIdx = nullptr ) const; + int* aHoleIdx = nullptr ) const; bool HitTestCutout( const wxPoint& aRefPos, int* aOutlineIdx = nullptr, - int* aHoleIdx = nullptr ) const + int* aHoleIdx = nullptr ) const { return HitTestCutout( VECTOR2I( aRefPos.x, aRefPos.y ), aOutlineIdx, aHoleIdx ); } @@ -587,7 +588,9 @@ public: } } else + { throw( std::out_of_range( "aCornerIndex-th vertex does not exist" ) ); + } } /**