diff --git a/pcbnew/connectivity/connectivity_data.cpp b/pcbnew/connectivity/connectivity_data.cpp index e0469c626f..f24ea11ccb 100644 --- a/pcbnew/connectivity/connectivity_data.cpp +++ b/pcbnew/connectivity/connectivity_data.cpp @@ -413,21 +413,35 @@ bool CONNECTIVITY_DATA::IsConnectedOnLayer( const BOARD_CONNECTED_ITEM *aItem, i && connected->Layers().Overlaps( aLayer ) && matchType( connected->Parent()->Type() ) ) { - if( connected->Net() == aItem->GetNetCode() ) - { - return true; - } - // For optionally-flashed layers we normally want to avoid different-net items - // by dropping the flashing. However, if the different-net item collides with - // our hole then that's not going to help. Showing the flashing in that case - // is clearer (and highlights the probable DRC error better). - else if( aCheckOptionalFlashing && aItem->Type() == PCB_PAD_T ) + if( aCheckOptionalFlashing && aItem->Type() == PCB_PAD_T ) { const PAD* pad = static_cast( aItem ); SHAPE_SEGMENT hole( *pad->GetEffectiveHoleShape() ); PCB_LAYER_ID layer = ToLAYER_ID( aLayer ); - return connected->Parent()->GetEffectiveShape( layer )->Collide( &hole ); + if( connected->Net() != aItem->GetNetCode() ) + { + // Even if the nets aren't the same, we need to check for a physical + // connection with the unflashed pad's hole (as its walls are plated). + return connected->Parent()->GetEffectiveShape( layer )->Collide( &hole ); + } + else if( CN_ZONE_LAYER* zoneLayer = dynamic_cast( connected ) ) + { + ZONE* zone = static_cast( zoneLayer->Parent() ); + int idx = zoneLayer->SubpolyIndex(); + const SHAPE_LINE_CHAIN& island = zone->GetFill( layer )->COutline( idx ); + std::shared_ptr flashing = pad->GetEffectiveShape(); + + for( const VECTOR2I& pt : island.CPoints() ) + { + if( !flashing->Collide( pt ) ) + return true; + } + + // If the entire island is inside the pad's flashing then the pad won't + // *actually* connect to anything *else* so don't consider it connected. + return false; + } } else if( aCheckOptionalFlashing && aItem->Type() == PCB_VIA_T ) { @@ -435,8 +449,32 @@ bool CONNECTIVITY_DATA::IsConnectedOnLayer( const BOARD_CONNECTED_ITEM *aItem, i SHAPE_CIRCLE hole( via->GetCenter(), via->GetDrillValue() / 2 ); PCB_LAYER_ID layer = ToLAYER_ID( aLayer ); - return connected->Parent()->GetEffectiveShape( layer )->Collide( &hole ); + if( connected->Net() != aItem->GetNetCode() ) + { + // Even if the nets aren't the same, we need to check for a physical + // connection with the unflashed via's hole (as its walls are plated). + return connected->Parent()->GetEffectiveShape( layer )->Collide( &hole ); + } + else if( CN_ZONE_LAYER* zoneLayer = dynamic_cast( connected ) ) + { + ZONE* zone = static_cast( zoneLayer->Parent() ); + int idx = zoneLayer->SubpolyIndex(); + const SHAPE_LINE_CHAIN& island = zone->GetFill( layer )->COutline( idx ); + SHAPE_CIRCLE flashing( via->GetCenter(), via->GetWidth() / 2 ); + + for( const VECTOR2I& pt : island.CPoints() ) + { + if( !flashing.SHAPE::Collide( pt ) ) + return true; + } + + // If the entire island is inside the via's flashing then the via won't + // *actually* connect to anything *else* so don't consider it connected. + return false; + } } + + return connected->Net() == aItem->GetNetCode(); } } } diff --git a/pcbnew/connectivity/connectivity_items.h b/pcbnew/connectivity/connectivity_items.h index 7fb2c298ef..dba8ee0e12 100644 --- a/pcbnew/connectivity/connectivity_items.h +++ b/pcbnew/connectivity/connectivity_items.h @@ -314,10 +314,9 @@ public: } } - int SubpolyIndex() const - { - return m_subpolyIndex; - } + int SubpolyIndex() const { return m_subpolyIndex; } + + PCB_LAYER_ID GetLayer() const { return m_layer; } bool ContainsPoint( const VECTOR2I& p ) const { diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 5d3aa91e93..ad7e359de4 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -373,11 +373,17 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare } } - // Now remove islands outside the board edge + // Now remove islands which are either outside the board edge or fail to meet the minimum + // area requirements // for( ZONE* zone : aZones ) { - LSET zoneCopperLayers = zone->GetLayerSet() & LSET::AllCuMask( MAX_CU_LAYERS ); + LSET zoneCopperLayers = zone->GetLayerSet() & LSET::AllCuMask( MAX_CU_LAYERS ); + + // Min-thickness is the web thickness. On the other hand, a blob min-thickness by + // min-thickness is not useful. Since there's no obvious definition of web vs. blob, we + // arbitrarily choose "at least 2X the area". + double minArea = (double) zone->GetMinThickness() * zone->GetMinThickness() * 2; for( PCB_LAYER_ID layer : zoneCopperLayers.Seq() ) { @@ -390,8 +396,12 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare { std::vector& island = poly->Polygon( ii ); - if( island.empty() || !m_boardOutline.Contains( island.front().CPoint( 0 ) ) ) + if( island.empty() + || !m_boardOutline.Contains( island.front().CPoint( 0 ) ) + || island.front().Area() < minArea ) + { poly->DeletePolygonAndTriangulationData( ii, false ); + } } poly->UpdateTriangulationDataHash(); @@ -665,10 +675,8 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa if( aPad->GetNetCode() > 0 && aPad->GetNetCode() == aZone->GetNetCode() ) { - // For pads having the same netcode as the zone, the net and hole - // clearances have no meanings. - // So just knock out the greater of the zone's local clearance and - // thermal relief. + // For unconnected but same-net pads, electrical clearances don't apply. + // Use the greater of the zone's local clearance and thermal relief. gap = std::max( aZone->GetLocalClearance(), aZone->GetThermalReliefGap() ); knockoutHoleClearance = false; } @@ -715,18 +723,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE* aZone, PCB_LAYER_ID aLa int gap = 0; bool checkHoleClearance = true; - if( via->GetNetCode() > 0 && via->GetNetCode() == aZone->GetNetCode() ) - { - // For pads having the same netcode as the zone, the net and hole - // clearances have no meanings. - // So just knock out the zone's local clearance. - gap = aZone->GetLocalClearance(); - checkHoleClearance = false; - } - else - { - gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer ); - } + gap = evalRulesForItems( CLEARANCE_CONSTRAINT, aZone, aTrack, aLayer ); if( via->FlashLayer( aLayer ) ) {