From d6dd58fff9e84db17519ee324cf7818b30ae5da9 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sat, 25 Mar 2023 10:44:46 +0000 Subject: [PATCH] Keep track of single-pad-islands so we can discount spokes to them. --- pcbnew/board.cpp | 1 + pcbnew/board.h | 2 + pcbnew/connectivity/connectivity_algo.cpp | 64 ++++------- pcbnew/connectivity/connectivity_algo.h | 13 +-- pcbnew/connectivity/connectivity_data.cpp | 14 +-- pcbnew/connectivity/connectivity_data.h | 26 +---- pcbnew/connectivity/connectivity_items.cpp | 17 +++ pcbnew/connectivity/connectivity_items.h | 2 + pcbnew/drc/drc_cache_generator.cpp | 19 +++- pcbnew/drc/drc_test_provider_connectivity.cpp | 38 ++----- .../drc_test_provider_zone_connections.cpp | 28 ++++- pcbnew/zone.h | 18 +++ pcbnew/zone_filler.cpp | 106 +++++++++--------- 13 files changed, 174 insertions(+), 174 deletions(-) diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index 96e15c1cd2..964a7fc408 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -263,6 +263,7 @@ void BOARD::IncrementTimeStamp() m_DRCMaxPhysicalClearance = 0; m_DRCZones.clear(); m_DRCCopperZones.clear(); + m_ZoneIsolatedIslandsMap.clear(); m_CopperZoneRTreeCache.clear(); m_CopperItemRTreeCache = std::make_unique(); } diff --git a/pcbnew/board.h b/pcbnew/board.h index 2d64f8cbac..d727d5489d 100644 --- a/pcbnew/board.h +++ b/pcbnew/board.h @@ -60,6 +60,7 @@ class CONNECTIVITY_DATA; class COMPONENT; class PROJECT; class PROGRESS_REPORTER; +struct ISOLATED_ISLANDS; // The default value for m_outlinesChainingEpsilon to convert a board outlines to polygons // It is the max dist between 2 end points to see them connected @@ -1177,6 +1178,7 @@ public: int m_DRCMaxClearance; int m_DRCMaxPhysicalClearance; ZONE* m_SolderMask; + std::map> m_ZoneIsolatedIslandsMap; private: // The default copy constructor & operator= are inadequate, diff --git a/pcbnew/connectivity/connectivity_algo.cpp b/pcbnew/connectivity/connectivity_algo.cpp index 49cfab806e..528ce9d916 100644 --- a/pcbnew/connectivity/connectivity_algo.cpp +++ b/pcbnew/connectivity/connectivity_algo.cpp @@ -613,53 +613,26 @@ void CN_CONNECTIVITY_ALGO::PropagateNets( BOARD_COMMIT* aCommit ) } -void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE* aZone, PCB_LAYER_ID aLayer, - std::vector& aIslands ) -{ - if( aZone->GetFilledPolysList( aLayer )->IsEmpty() ) - return; - - aIslands.clear(); - - Remove( aZone ); - Add( aZone ); - - m_connClusters = SearchClusters( CSM_CONNECTIVITY_CHECK ); - - for( const std::shared_ptr& cluster : m_connClusters ) - { - if( cluster->Contains( aZone ) && cluster->IsOrphaned() ) - { - for( CN_ITEM* z : *cluster ) - { - if( z->Parent() == aZone && z->Layer() == aLayer ) - aIslands.push_back( static_cast(z)->SubpolyIndex() ); - } - } - } - - wxLogTrace( wxT( "CN" ), wxT( "Found %u isolated islands\n" ), (unsigned) aIslands.size() ); -} - -void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector& aZones, - bool aConnectivityAlreadyRebuilt ) +void CN_CONNECTIVITY_ALGO::FillIsolatedIslandsMap( + std::map>& aMap, + bool aConnectivityAlreadyRebuilt ) { int progressDelta = 50; int ii = 0; - progressDelta = std::max( progressDelta, (int) aZones.size() / 4 ); + progressDelta = std::max( progressDelta, (int) aMap.size() / 4 ); if( !aConnectivityAlreadyRebuilt ) { - for( CN_ZONE_ISOLATED_ISLAND_LIST& z : aZones ) + for( const auto& [ zone, islands ] : aMap ) { - Remove( z.m_zone ); - Add( z.m_zone ); + Remove( zone ); + Add( zone ); ii++; if( m_progressReporter && ( ii % progressDelta ) == 0 ) { - m_progressReporter->SetCurrentProgress( (double) ii / (double) aZones.size() ); + m_progressReporter->SetCurrentProgress( (double) ii / (double) aMap.size() ); m_progressReporter->KeepRefreshing( false ); } @@ -670,24 +643,25 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vectorGetLayerSet().Seq() ) + for( auto& [ layer, layerIslands ] : zoneIslands ) { - if( zone.m_zone->GetFilledPolysList( layer )->IsEmpty() ) + if( zone->GetFilledPolysList( layer )->IsEmpty() ) continue; for( const std::shared_ptr& cluster : m_connClusters ) { - if( cluster->Contains( zone.m_zone ) && cluster->IsOrphaned() ) + for( CN_ITEM* item : *cluster ) { - for( CN_ITEM* z : *cluster ) + if( item->Parent() == zone && item->Layer() == layer ) { - if( z->Parent() == zone.m_zone && z->Layer() == layer ) - { - zone.m_islands[layer].push_back( - static_cast( z )->SubpolyIndex() ); - } + CN_ZONE_LAYER* z = static_cast( item ); + + if( cluster->IsOrphaned() ) + layerIslands.m_IsolatedOutlines.push_back( z->SubpolyIndex() ); + else if( z->HasSingleConnection() ) + layerIslands.m_SingleConnectionOutlines.push_back( z->SubpolyIndex() ); } } } diff --git a/pcbnew/connectivity/connectivity_algo.h b/pcbnew/connectivity/connectivity_algo.h index f903a98ad8..14ace5a782 100644 --- a/pcbnew/connectivity/connectivity_algo.h +++ b/pcbnew/connectivity/connectivity_algo.h @@ -221,18 +221,11 @@ public: */ void PropagateNets( BOARD_COMMIT* aCommit = nullptr ); - void FindIsolatedCopperIslands( ZONE* aZone, PCB_LAYER_ID aLayer, std::vector& aIslands ); - /** - * Find the copper islands that are not connected to a net. - * - * These are added to the m_islands vector. - * N.B. This must be called after aZones has been refreshed. - * - * @param: aZones is the set of zones to search for islands. + * Fill in the isolated islands map with copper islands that are not connected to a net. */ - void FindIsolatedCopperIslands( std::vector& aZones, - bool aConnectivityAlreadyRebuilt ); + void FillIsolatedIslandsMap( std::map>& aMap, + bool aConnectivityAlreadyRebuilt ); const CLUSTERS& GetClusters(); diff --git a/pcbnew/connectivity/connectivity_data.cpp b/pcbnew/connectivity/connectivity_data.cpp index 3f4ad79247..799c4b8ffd 100644 --- a/pcbnew/connectivity/connectivity_data.cpp +++ b/pcbnew/connectivity/connectivity_data.cpp @@ -309,18 +309,10 @@ int CONNECTIVITY_DATA::GetNetCount() const } -void CONNECTIVITY_DATA::FindIsolatedCopperIslands( ZONE* aZone, std::vector& aIslands ) +void CONNECTIVITY_DATA::FillIsolatedIslandsMap( std::map>& aMap, + bool aConnectivityAlreadyRebuilt ) { - // TODO(JE) ZONES -#if 0 - m_connAlgo->FindIsolatedCopperIslands( aZone, aIslands ); -#endif -} - -void CONNECTIVITY_DATA::FindIsolatedCopperIslands( std::vector& aZones, - bool aConnectivityAlreadyRebuilt ) -{ - m_connAlgo->FindIsolatedCopperIslands( aZones, aConnectivityAlreadyRebuilt ); + m_connAlgo->FillIsolatedIslandsMap( aMap, aConnectivityAlreadyRebuilt ); } diff --git a/pcbnew/connectivity/connectivity_data.h b/pcbnew/connectivity/connectivity_data.h index 97f6397c92..85e0ea742b 100644 --- a/pcbnew/connectivity/connectivity_data.h +++ b/pcbnew/connectivity/connectivity_data.h @@ -64,21 +64,6 @@ struct CN_DISJOINT_NET_ENTRY }; -/** - * A structure used for calculating isolated islands on a given zone across all its layers - */ -struct CN_ZONE_ISOLATED_ISLAND_LIST -{ - CN_ZONE_ISOLATED_ISLAND_LIST( ZONE* aZone ) : - m_zone( aZone ) - {} - - ZONE* m_zone; - - std::map> m_islands; -}; - - struct RN_DYNAMIC_LINE { int netCode; @@ -176,14 +161,11 @@ public: void PropagateNets( BOARD_COMMIT* aCommit = nullptr ); /** - * Function FindIsolatedCopperIslands() - * Searches for copper islands in zone aZone that are not connected to any pad. - * @param aZone zone to test - * @param aIslands list of islands that have no connections (outline indices in the polygon set) + * Fill the isolate islands list for each layer of each zone. Isolated islands are individual + * polygons in a zone fill that don't connect to a net. */ - void FindIsolatedCopperIslands( ZONE* aZone, std::vector& aIslands ); - void FindIsolatedCopperIslands( std::vector& aZones, - bool aConnectivityAlreadyRebuilt = false ); + void FillIsolatedIslandsMap( std::map>& aMap, + bool aConnectivityAlreadyRebuilt = false ); /** * Function RecalculateRatsnest() diff --git a/pcbnew/connectivity/connectivity_items.cpp b/pcbnew/connectivity/connectivity_items.cpp index 1803fb928e..da635f2ca5 100644 --- a/pcbnew/connectivity/connectivity_items.cpp +++ b/pcbnew/connectivity/connectivity_items.cpp @@ -109,6 +109,23 @@ const VECTOR2I CN_ZONE_LAYER::GetAnchor( int n ) const } +bool CN_ZONE_LAYER::HasSingleConnection() +{ + int count = 0; + + for( CN_ITEM* item : ConnectedItems() ) + { + if( item->Valid() ) + count++; + + if( count > 1 ) + break; + } + + return count == 1; +} + + void CN_ITEM::RemoveInvalidRefs() { for( auto it = m_connected.begin(); it != m_connected.end(); /* increment in loop */ ) diff --git a/pcbnew/connectivity/connectivity_items.h b/pcbnew/connectivity/connectivity_items.h index b52b33b735..36a4925de0 100644 --- a/pcbnew/connectivity/connectivity_items.h +++ b/pcbnew/connectivity/connectivity_items.h @@ -387,6 +387,8 @@ public: return collision; } + bool HasSingleConnection(); + private: int m_subpolyIndex; PCB_LAYER_ID m_layer; diff --git a/pcbnew/drc/drc_cache_generator.cpp b/pcbnew/drc/drc_cache_generator.cpp index 652ca5d265..c0f903dd03 100644 --- a/pcbnew/drc/drc_cache_generator.cpp +++ b/pcbnew/drc/drc_cache_generator.cpp @@ -26,7 +26,7 @@ #include #include #include - +#include #include #include #include @@ -201,6 +201,23 @@ bool DRC_CACHE_GENERATOR::Run() } } + m_board->m_ZoneIsolatedIslandsMap.clear(); + + for( ZONE* zone : m_board->Zones() ) + { + if( !zone->GetIsRuleArea() ) + { + for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) + m_board->m_ZoneIsolatedIslandsMap[ zone ][ layer ] = ISOLATED_ISLANDS(); + } + } + + std::shared_ptr connectivity = m_board->GetConnectivity(); + + connectivity->ClearRatsnest(); + connectivity->Build( m_board, m_drcEngine->GetProgressReporter() ); + connectivity->FillIsolatedIslandsMap( m_board->m_ZoneIsolatedIslandsMap, true ); + return !m_drcEngine->IsCancelled(); } diff --git a/pcbnew/drc/drc_test_provider_connectivity.cpp b/pcbnew/drc/drc_test_provider_connectivity.cpp index 562c513337..111f512478 100644 --- a/pcbnew/drc/drc_test_provider_connectivity.cpp +++ b/pcbnew/drc/drc_test_provider_connectivity.cpp @@ -26,7 +26,7 @@ #include #include - +#include #include #include #include @@ -71,25 +71,12 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() if( !reportPhase( _( "Checking pad, via and zone connections..." ) ) ) return false; // DRC cancelled - BOARD* board = m_drcEngine->GetBoard(); - - std::shared_ptr connectivity = board->GetConnectivity(); - std::vector islandsList; - - for( ZONE* zone : board->Zones() ) - { - if( !zone->GetIsRuleArea() ) - islandsList.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST( zone ) ); - } - - // Rebuild (from scratch, ignoring dirty flags) just in case. This really needs to be reliable. - connectivity->ClearRatsnest(); - connectivity->Build( board, m_drcEngine->GetProgressReporter() ); - connectivity->FindIsolatedCopperIslands( islandsList, true ); + BOARD* board = m_drcEngine->GetBoard(); + std::shared_ptr connectivity = board->GetConnectivity(); int progressDelta = 250; int ii = 0; - int count = board->Tracks().size() + islandsList.size(); + int count = board->Tracks().size() + board->m_ZoneIsolatedIslandsMap.size(); ii += count; // We gave half of this phase to CONNECTIVITY_DATA::Build() count += count; @@ -122,7 +109,7 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() } /* test starved zones */ - for( CN_ZONE_ISOLATED_ISLAND_LIST& zone : islandsList ) + for( const auto& [ zone, zoneIslands ] : board->m_ZoneIsolatedIslandsMap ) { if( m_drcEngine->IsErrorLimitExceeded( DRCE_ISOLATED_COPPER ) ) break; @@ -130,21 +117,18 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run() if( !reportProgress( ii++, count, progressDelta ) ) return false; // DRC cancelled - for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() ) + for( const auto& [ layer, layerIslands ] : zoneIslands ) { - if( !zone.m_islands.count( layer ) ) - continue; - - std::shared_ptr poly = zone.m_zone->GetFilledPolysList( layer ); - - for( int idx : zone.m_islands.at( layer ) ) + for( int polyIdx : layerIslands.m_IsolatedOutlines ) { if( m_drcEngine->IsErrorLimitExceeded( DRCE_ISOLATED_COPPER ) ) break; + std::shared_ptr poly = zone->GetFilledPolysList( layer ); + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_ISOLATED_COPPER ); - drcItem->SetItems( zone.m_zone ); - reportViolation( drcItem, poly->Outline( idx ).CPoint( 0 ), layer ); + drcItem->SetItems( zone ); + reportViolation( drcItem, poly->Outline( polyIdx ).CPoint( 0 ), layer ); } } } diff --git a/pcbnew/drc/drc_test_provider_zone_connections.cpp b/pcbnew/drc/drc_test_provider_zone_connections.cpp index e90c216b4b..737e02e159 100644 --- a/pcbnew/drc/drc_test_provider_zone_connections.cpp +++ b/pcbnew/drc/drc_test_provider_zone_connections.cpp @@ -81,6 +81,17 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I DRC_CONSTRAINT constraint; const std::shared_ptr& zoneFill = aZone->GetFilledPolysList( aLayer ); + ISOLATED_ISLANDS isolatedIslands; + + auto zoneIter = board->m_ZoneIsolatedIslandsMap.find( aZone ); + + if( zoneIter != board->m_ZoneIsolatedIslandsMap.end() ) + { + auto layerIter = zoneIter->second.find( aLayer ); + + if( layerIter != zoneIter->second.end() ) + isolatedIslands = layerIter->second; + } for( FOOTPRINT* footprint : board->Footprints() ) { @@ -132,7 +143,15 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I std::vector intersections; for( int jj = 0; jj < zoneFill->OutlineCount(); ++jj ) + { + // If we connect to an island that only connects to a single item then we *are* + // that item. Thermal spokes to this (otherwise isolated) island don't provide + // electrical connectivity to anything, so we don't count them. + if( alg::contains( isolatedIslands.m_SingleConnectionOutlines, jj ) ) + continue; + zoneFill->Outline( jj ).Intersect( padOutline, intersections, true, &padBBox ); + } int spokes = intersections.size() / 2; @@ -198,10 +217,13 @@ bool DRC_TEST_PROVIDER_ZONE_CONNECTIONS::Run() for( ZONE* zone : board->m_DRCCopperZones ) { - for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) + if( !zone->IsTeardropArea() ) { - zoneLayers.push_back( { zone, layer } ); - total_effort += zone->GetFilledPolysList( layer )->FullPointCount(); + for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) + { + zoneLayers.push_back( { zone, layer } ); + total_effort += zone->GetFilledPolysList( layer )->FullPointCount(); + } } } diff --git a/pcbnew/zone.h b/pcbnew/zone.h index 4330561ba3..50794d491c 100644 --- a/pcbnew/zone.h +++ b/pcbnew/zone.h @@ -44,6 +44,24 @@ class ZONE; class MSG_PANEL_ITEM; +/** + * A struct recording the isolated and single-pad islands within a zone. Each array holds + * indexes into the outlines of a SHAPE_POLY_SET for a zone fill on a particular layer. + * + * Isolated outlines are those whose *connectivity cluster* contains no pads. These generate + * DRC violations. + * + * Single-connection outlines are those with a *direct* connection to only a single item. These + * participate in thermal spoke counting as a pad spoke to an *otherwise* unconnected island + * provides no connectivity to the pad. + */ +struct ISOLATED_ISLANDS +{ + std::vector m_IsolatedOutlines; + std::vector m_SingleConnectionOutlines; +}; + + /** * Handle a list of polygons defining a copper zone. * diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 9821bc4dc3..004db46045 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -90,9 +90,9 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare { std::lock_guard lock( m_board->GetConnectivity()->GetLock() ); - std::vector> toFill; - std::map, MD5_HASH> oldFillHashes; - std::vector islandsList; + std::vector> toFill; + std::map, MD5_HASH> oldFillHashes; + std::map> isolatedIslandsMap; std::shared_ptr connectivity = m_board->GetConnectivity(); @@ -328,9 +328,9 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare // Add the zone to the list of zones to test or refill toFill.emplace_back( std::make_pair( zone, layer ) ); - } - islandsList.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST( zone ) ); + isolatedIslandsMap[ zone ][ layer ] = ISOLATED_ISLANDS(); + } // Remove existing fill first to prevent drawing invalid polygons on some platforms zone->UnFill(); @@ -534,7 +534,7 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare } connectivity->SetProgressReporter( m_progressReporter ); - connectivity->FindIsolatedCopperIslands( islandsList ); + connectivity->FillIsolatedIslandsMap( isolatedIslandsMap ); connectivity->SetProgressReporter( nullptr ); if( m_progressReporter && m_progressReporter->IsCancelled() ) @@ -552,26 +552,15 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare // Now remove isolated copper islands according to the isolated islands strategy assigned // by the user (always, never, below-certain-size). // - for( CN_ZONE_ISOLATED_ISLAND_LIST& zone : islandsList ) + for( const auto& [ zone, zoneIslands ] : isolatedIslandsMap ) { // If *all* the polygons are islands, do not remove any of them bool allIslands = true; - for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() ) + for( const auto& [ layer, layerIslands ] : zoneIslands ) { - std::shared_ptr poly = zone.m_zone->GetFilledPolysList( layer ); - - if( !zone.m_islands.count( layer ) ) - { - if( poly->OutlineCount() > 0 ) - allIslands = false; - - continue; - } - - std::vector& islands = zone.m_islands.at( layer ); - - if( islands.size() != static_cast( poly->OutlineCount() ) ) + if( layerIslands.m_IsolatedOutlines.size() + != static_cast( zone->GetFilledPolysList( layer )->OutlineCount() ) ) { allIslands = false; break; @@ -581,23 +570,23 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare if( allIslands ) continue; - for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() ) + for( const auto& [ layer, layerIslands ] : zoneIslands ) { if( m_debugZoneFiller && LSET::InternalCuMask().Contains( layer ) ) continue; - if( !zone.m_islands.count( layer ) ) + if( layerIslands.m_IsolatedOutlines.empty() ) continue; - std::vector& islands = zone.m_islands.at( layer ); + std::vector islands = layerIslands.m_IsolatedOutlines; // The list of polygons to delete must be explored from last to first in list, // to allow deleting a polygon from list without breaking the remaining of the list std::sort( islands.begin(), islands.end(), std::greater() ); - std::shared_ptr poly = zone.m_zone->GetFilledPolysList( layer ); - long long int minArea = zone.m_zone->GetMinIslandArea(); - ISLAND_REMOVAL_MODE mode = zone.m_zone->GetIslandRemovalMode(); + std::shared_ptr poly = zone->GetFilledPolysList( layer ); + long long int minArea = zone->GetMinIslandArea(); + ISLAND_REMOVAL_MODE mode = zone->GetIslandRemovalMode(); for( int idx : islands ) { @@ -608,11 +597,11 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare else if ( mode == ISLAND_REMOVAL_MODE::AREA && outline.Area( true ) < minArea ) poly->DeletePolygonAndTriangulationData( idx, false ); else - zone.m_zone->SetIsIsland( layer, idx ); + zone->SetIsIsland( layer, idx ); } poly->UpdateTriangulationDataHash(); - zone.m_zone->CalculateFilledArea(); + zone->CalculateFilledArea(); if( m_progressReporter && m_progressReporter->IsCancelled() ) return false; @@ -646,39 +635,42 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare } } - auto island_lambda = [&]( int aStart, int aEnd ) -> island_check_return - { - island_check_return retval; - - for( int ii = aStart; ii < aEnd && !cancelled; ++ii ) + auto island_lambda = + [&]( int aStart, int aEnd ) -> island_check_return { - auto [poly, minArea] = polys_to_check[ii]; + island_check_return retval; - for( int jj = poly->OutlineCount() - 1; jj >= 0; jj-- ) + for( int ii = aStart; ii < aEnd && !cancelled; ++ii ) { - SHAPE_POLY_SET island; - SHAPE_POLY_SET intersection; - const SHAPE_LINE_CHAIN& test_poly = poly->Polygon( jj ).front(); - double island_area = test_poly.Area(); + auto [poly, minArea] = polys_to_check[ii]; - if( island_area < minArea ) - continue; + for( int jj = poly->OutlineCount() - 1; jj >= 0; jj-- ) + { + SHAPE_POLY_SET island; + SHAPE_POLY_SET intersection; + const SHAPE_LINE_CHAIN& test_poly = poly->Polygon( jj ).front(); + double island_area = test_poly.Area(); + + if( island_area < minArea ) + continue; - island.AddOutline( test_poly ); - intersection.BooleanIntersection( m_boardOutline, island, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST ); + island.AddOutline( test_poly ); + intersection.BooleanIntersection( m_boardOutline, island, + SHAPE_POLY_SET::POLYGON_MODE::PM_FAST ); - // 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 they are equal, you are inside). But in practice, - // we sometimes can have slight overlap at the edges. So testing against half-size area is - // a fail-safe - if( intersection.Area() < island_area / 2.0 ) - retval.emplace_back( poly, jj ); + // 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 + // they are equal, you are inside). But in practice, we sometimes have + // slight overlap at the edges, so testing against half-size area acts as + // a fail-safe. + if( intersection.Area() < island_area / 2.0 ) + retval.emplace_back( poly, jj ); + } } - } - return retval; - }; + return retval; + }; auto island_returns = tp.parallelize_loop( 0, polys_to_check.size(), island_lambda ); cancelled = false; @@ -1575,10 +1567,14 @@ bool ZONE_FILLER::fillCopperZone( const ZONE* aZone, PCB_LAYER_ID aLayer, PCB_LA DUMP_POLYS_TO_COPPER_LAYER( aFillPolys, In15_Cu, wxT( "after-reinflating" ) ); /* ------------------------------------------------------------------------------------- - * Ensure additive changes (thermal stubs and particularly inflating acute corners) do not - * add copper outside the zone boundary or inside the clearance holes + * Ensure additive changes (thermal stubs and inflating acute corners) do not add copper + * outside the zone boundary, inside the clearance holes, or between otherwise isolated + * islands */ + for( PAD* pad : thermalConnectionPads ) + addHoleKnockout( pad, 0, clearanceHoles ); + aFillPolys.BooleanIntersection( aMaxExtents, SHAPE_POLY_SET::PM_FAST ); DUMP_POLYS_TO_COPPER_LAYER( aFillPolys, In16_Cu, wxT( "after-trim-to-outline" ) ); aFillPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );