From 9e019a1ad177c995e5148c19b83ec040b660d4ec Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Thu, 3 Aug 2023 15:03:04 +0100 Subject: [PATCH] Don't conclude we're unconnected if only connected to isolated island. Also adds the layer name to the "thermal connection incomplete" DRC error message. Also improves zone layer description to not say "X and 1 more" (which takes as much room as saying "X and Y"). Fixes https://gitlab.com/kicad/code/kicad/-/issues/15279 --- .../drc_test_provider_zone_connections.cpp | 23 +++--- pcbnew/zone.cpp | 74 +++++++++++++------ 2 files changed, 65 insertions(+), 32 deletions(-) diff --git a/pcbnew/drc/drc_test_provider_zone_connections.cpp b/pcbnew/drc/drc_test_provider_zone_connections.cpp index 737e02e159..d4ed756a05 100644 --- a/pcbnew/drc/drc_test_provider_zone_connections.cpp +++ b/pcbnew/drc/drc_test_provider_zone_connections.cpp @@ -79,6 +79,7 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings(); std::shared_ptr connectivity = board->GetConnectivity(); DRC_CONSTRAINT constraint; + wxString msg; const std::shared_ptr& zoneFill = aZone->GetFilledPolysList( aLayer ); ISOLATED_ISLANDS isolatedIslands; @@ -140,25 +141,28 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I SHAPE_LINE_CHAIN& padOutline = padPoly.Outline( 0 ); BOX2I padBBox( item_bbox ); - std::vector intersections; + int spokes = 0; + int ignoredSpokes = 0; for( int jj = 0; jj < zoneFill->OutlineCount(); ++jj ) { + std::vector intersections; + + zoneFill->Outline( jj ).Intersect( padOutline, intersections, true, &padBBox ); + // 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 ); + ignoredSpokes += (int) intersections.size() / 2; + else + spokes += (int) intersections.size() / 2; } - int spokes = intersections.size() / 2; - - if( spokes <= 0 ) // Not connected at all + if( spokes == 0 && ignoredSpokes == 0 ) // Not connected at all continue; - if( spokes >= minCount ) // We already have enough + if( spokes >= minCount ) // We already have enough continue; // @@ -186,7 +190,8 @@ void DRC_TEST_PROVIDER_ZONE_CONNECTIONS::testZoneLayer( ZONE* aZone, PCB_LAYER_I if( spokes < minCount ) { std::shared_ptr drce = DRC_ITEM::Create( DRCE_STARVED_THERMAL ); - wxString msg = wxString::Format( _( "(%s min spoke count %d; actual %d)" ), + wxString msg = wxString::Format( _( "(layer %s; %s min spoke count %d; actual %d)" ), + board->GetLayerName( aLayer ), constraint.GetName(), minCount, spokes ); diff --git a/pcbnew/zone.cpp b/pcbnew/zone.cpp index 7a572c8247..1e97f07b0d 100644 --- a/pcbnew/zone.cpp +++ b/pcbnew/zone.cpp @@ -600,19 +600,33 @@ void ZONE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& aList.emplace_back( _( "Status" ), _( "Locked" ) ); } + LSEQ layers = m_layerSet.Seq(); wxString layerDesc; - int count = 0; - for( PCB_LAYER_ID layer : m_layerSet.Seq() ) + if( layers.size() == 1 ) { - if( count == 0 ) - layerDesc = GetBoard()->GetLayerName( layer ); - - count++; + layerDesc.Printf( _( "%s" ), GetBoard()->GetLayerName( layers[0] ) ); + } + else if (layers.size() == 2 ) + { + layerDesc.Printf( _( "%s and %s" ), + GetBoard()->GetLayerName( layers[0] ), + GetBoard()->GetLayerName( layers[1] ) ); + } + else if (layers.size() == 3 ) + { + layerDesc.Printf( _( "%s, %s and %s" ), + GetBoard()->GetLayerName( layers[0] ), + GetBoard()->GetLayerName( layers[1] ), + GetBoard()->GetLayerName( layers[2] ) ); + } + else if( layers.size() > 3 ) + { + layerDesc.Printf( _( "%s, %s and %d more" ), + GetBoard()->GetLayerName( layers[0] ), + GetBoard()->GetLayerName( layers[1] ), + layers.size() - 2 ); } - - if( count > 1 ) - layerDesc.Printf( _( "%s and %d more" ), layerDesc, count - 1 ); aList.emplace_back( _( "Layer" ), layerDesc ); @@ -644,7 +658,7 @@ void ZONE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& if( !m_FilledPolysList.empty() ) { - count = 0; + int count = 0; for( std::pair>& ii: m_FilledPolysList ) count += ii.second->TotalVertices(); @@ -807,34 +821,48 @@ bool ZONE::AppendCorner( VECTOR2I aPosition, int aHoleIdx, bool aAllowDuplicatio wxString ZONE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const { + LSEQ layers = m_layerSet.Seq(); wxString layerDesc; - int count = 0; - for( PCB_LAYER_ID layer : m_layerSet.Seq() ) + if( layers.size() == 1 ) { - if( count == 0 ) - layerDesc = GetBoard()->GetLayerName( layer ); - - count++; + layerDesc.Printf( _( "on %s" ), GetBoard()->GetLayerName( layers[0] ) ); + } + else if (layers.size() == 2 ) + { + layerDesc.Printf( _( "on %s and %s" ), + GetBoard()->GetLayerName( layers[0] ), + GetBoard()->GetLayerName( layers[1] ) ); + } + else if (layers.size() == 3 ) + { + layerDesc.Printf( _( "on %s, %s and %s" ), + GetBoard()->GetLayerName( layers[0] ), + GetBoard()->GetLayerName( layers[1] ), + GetBoard()->GetLayerName( layers[2] ) ); + } + else if( layers.size() > 3 ) + { + layerDesc.Printf( _( "on %s, %s and %d more" ), + GetBoard()->GetLayerName( layers[0] ), + GetBoard()->GetLayerName( layers[1] ), + layers.size() - 2 ); } - - if( count > 1 ) - layerDesc.Printf( _( "%s and %d more" ), layerDesc, count - 1 ); // Check whether the selected contour is a hole (contour index > 0) if( m_CornerSelection != nullptr && m_CornerSelection->m_contour > 0 ) { if( GetIsRuleArea() ) - return wxString::Format( _( "Rule Area Cutout on %s" ), layerDesc ); + return wxString::Format( _( "Rule Area Cutout %s" ), layerDesc ); else - return wxString::Format( _( "Zone Cutout on %s" ), layerDesc ); + return wxString::Format( _( "Zone Cutout %s" ), layerDesc ); } else { if( GetIsRuleArea() ) - return wxString::Format( _( "Rule Area on %s" ), layerDesc ); + return wxString::Format( _( "Rule Area %s" ), layerDesc ); else - return wxString::Format( _( "Zone %s on %s" ), GetNetnameMsg(), layerDesc ); + return wxString::Format( _( "Zone %s %s" ), GetNetnameMsg(), layerDesc ); } }