Keep track of single-pad-islands so we can discount spokes to them.
This commit is contained in:
parent
4e27e91b2f
commit
d6dd58fff9
|
@ -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<DRC_RTREE>();
|
||||
}
|
||||
|
|
|
@ -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<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> m_ZoneIsolatedIslandsMap;
|
||||
|
||||
private:
|
||||
// The default copy constructor & operator= are inadequate,
|
||||
|
|
|
@ -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<int>& aIslands )
|
||||
{
|
||||
if( aZone->GetFilledPolysList( aLayer )->IsEmpty() )
|
||||
return;
|
||||
|
||||
aIslands.clear();
|
||||
|
||||
Remove( aZone );
|
||||
Add( aZone );
|
||||
|
||||
m_connClusters = SearchClusters( CSM_CONNECTIVITY_CHECK );
|
||||
|
||||
for( const std::shared_ptr<CN_CLUSTER>& 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<CN_ZONE_LAYER*>(z)->SubpolyIndex() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxLogTrace( wxT( "CN" ), wxT( "Found %u isolated islands\n" ), (unsigned) aIslands.size() );
|
||||
}
|
||||
|
||||
void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones,
|
||||
bool aConnectivityAlreadyRebuilt )
|
||||
void CN_CONNECTIVITY_ALGO::FillIsolatedIslandsMap(
|
||||
std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>>& 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::vector<CN_ZONE_ISOLAT
|
|||
|
||||
m_connClusters = SearchClusters( CSM_CONNECTIVITY_CHECK );
|
||||
|
||||
for( CN_ZONE_ISOLATED_ISLAND_LIST& zone : aZones )
|
||||
for( auto& [ zone, zoneIslands ] : aMap )
|
||||
{
|
||||
for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
|
||||
for( auto& [ layer, layerIslands ] : zoneIslands )
|
||||
{
|
||||
if( zone.m_zone->GetFilledPolysList( layer )->IsEmpty() )
|
||||
if( zone->GetFilledPolysList( layer )->IsEmpty() )
|
||||
continue;
|
||||
|
||||
for( const std::shared_ptr<CN_CLUSTER>& 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<CN_ZONE_LAYER*>( z )->SubpolyIndex() );
|
||||
}
|
||||
CN_ZONE_LAYER* z = static_cast<CN_ZONE_LAYER*>( item );
|
||||
|
||||
if( cluster->IsOrphaned() )
|
||||
layerIslands.m_IsolatedOutlines.push_back( z->SubpolyIndex() );
|
||||
else if( z->HasSingleConnection() )
|
||||
layerIslands.m_SingleConnectionOutlines.push_back( z->SubpolyIndex() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -221,18 +221,11 @@ public:
|
|||
*/
|
||||
void PropagateNets( BOARD_COMMIT* aCommit = nullptr );
|
||||
|
||||
void FindIsolatedCopperIslands( ZONE* aZone, PCB_LAYER_ID aLayer, std::vector<int>& 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<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones,
|
||||
bool aConnectivityAlreadyRebuilt );
|
||||
void FillIsolatedIslandsMap( std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>>& aMap,
|
||||
bool aConnectivityAlreadyRebuilt );
|
||||
|
||||
const CLUSTERS& GetClusters();
|
||||
|
||||
|
|
|
@ -309,18 +309,10 @@ int CONNECTIVITY_DATA::GetNetCount() const
|
|||
}
|
||||
|
||||
|
||||
void CONNECTIVITY_DATA::FindIsolatedCopperIslands( ZONE* aZone, std::vector<int>& aIslands )
|
||||
void CONNECTIVITY_DATA::FillIsolatedIslandsMap( std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>>& aMap,
|
||||
bool aConnectivityAlreadyRebuilt )
|
||||
{
|
||||
// TODO(JE) ZONES
|
||||
#if 0
|
||||
m_connAlgo->FindIsolatedCopperIslands( aZone, aIslands );
|
||||
#endif
|
||||
}
|
||||
|
||||
void CONNECTIVITY_DATA::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones,
|
||||
bool aConnectivityAlreadyRebuilt )
|
||||
{
|
||||
m_connAlgo->FindIsolatedCopperIslands( aZones, aConnectivityAlreadyRebuilt );
|
||||
m_connAlgo->FillIsolatedIslandsMap( aMap, aConnectivityAlreadyRebuilt );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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<PCB_LAYER_ID, std::vector<int>> 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<int>& aIslands );
|
||||
void FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones,
|
||||
bool aConnectivityAlreadyRebuilt = false );
|
||||
void FillIsolatedIslandsMap( std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>>& aMap,
|
||||
bool aConnectivityAlreadyRebuilt = false );
|
||||
|
||||
/**
|
||||
* Function RecalculateRatsnest()
|
||||
|
|
|
@ -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 */ )
|
||||
|
|
|
@ -387,6 +387,8 @@ public:
|
|||
return collision;
|
||||
}
|
||||
|
||||
bool HasSingleConnection();
|
||||
|
||||
private:
|
||||
int m_subpolyIndex;
|
||||
PCB_LAYER_ID m_layer;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <footprint.h>
|
||||
#include <thread_pool.h>
|
||||
#include <zone.h>
|
||||
|
||||
#include <connectivity/connectivity_data.h>
|
||||
#include <drc/drc_engine.h>
|
||||
#include <drc/drc_rtree.h>
|
||||
#include <drc/drc_cache_generator.h>
|
||||
|
@ -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_DATA> connectivity = m_board->GetConnectivity();
|
||||
|
||||
connectivity->ClearRatsnest();
|
||||
connectivity->Build( m_board, m_drcEngine->GetProgressReporter() );
|
||||
connectivity->FillIsolatedIslandsMap( m_board->m_ZoneIsolatedIslandsMap, true );
|
||||
|
||||
return !m_drcEngine->IsCancelled();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include <connectivity/connectivity_data.h>
|
||||
#include <connectivity/connectivity_algo.h>
|
||||
|
||||
#include <zone.h>
|
||||
#include <drc/drc_engine.h>
|
||||
#include <drc/drc_item.h>
|
||||
#include <drc/drc_rule.h>
|
||||
|
@ -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_DATA> connectivity = board->GetConnectivity();
|
||||
std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> 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_DATA> 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<SHAPE_POLY_SET> 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<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
|
||||
|
||||
std::shared_ptr<DRC_ITEM> 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,17 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I
|
|||
DRC_CONSTRAINT constraint;
|
||||
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& 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<SHAPE_LINE_CHAIN::INTERSECTION> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<int> m_IsolatedOutlines;
|
||||
std::vector<int> m_SingleConnectionOutlines;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle a list of polygons defining a copper zone.
|
||||
*
|
||||
|
|
|
@ -90,9 +90,9 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
|
|||
{
|
||||
std::lock_guard<KISPINLOCK> lock( m_board->GetConnectivity()->GetLock() );
|
||||
|
||||
std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
|
||||
std::map<std::pair<ZONE*, PCB_LAYER_ID>, MD5_HASH> oldFillHashes;
|
||||
std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> islandsList;
|
||||
std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
|
||||
std::map<std::pair<ZONE*, PCB_LAYER_ID>, MD5_HASH> oldFillHashes;
|
||||
std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
|
||||
|
||||
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
|
||||
|
||||
|
@ -328,9 +328,9 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& 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<ZONE*>& 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<ZONE*>& 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<SHAPE_POLY_SET> poly = zone.m_zone->GetFilledPolysList( layer );
|
||||
|
||||
if( !zone.m_islands.count( layer ) )
|
||||
{
|
||||
if( poly->OutlineCount() > 0 )
|
||||
allIslands = false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<int>& islands = zone.m_islands.at( layer );
|
||||
|
||||
if( islands.size() != static_cast<size_t>( poly->OutlineCount() ) )
|
||||
if( layerIslands.m_IsolatedOutlines.size()
|
||||
!= static_cast<size_t>( zone->GetFilledPolysList( layer )->OutlineCount() ) )
|
||||
{
|
||||
allIslands = false;
|
||||
break;
|
||||
|
@ -581,23 +570,23 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& 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<int>& islands = zone.m_islands.at( layer );
|
||||
std::vector<int> 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<int>() );
|
||||
|
||||
std::shared_ptr<SHAPE_POLY_SET> 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<SHAPE_POLY_SET> 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<ZONE*>& 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<ZONE*>& 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 );
|
||||
|
|
Loading…
Reference in New Issue