From 07eda5d57e052a29360cd5c21442e2e85950aebc Mon Sep 17 00:00:00 2001 From: Jeff Young <jeff@rokeby.ie> Date: Thu, 27 Mar 2025 10:13:31 +0000 Subject: [PATCH] ADDED: report copper area for current selection. Fixes https://gitlab.com/kicad/code/kicad/-/issues/20439 --- pcbnew/pcb_track.cpp | 5 ++ pcbnew/tools/pcb_control.cpp | 111 +++++++++++++++++++++++++++++------ pcbnew/zone.cpp | 16 +---- 3 files changed, 100 insertions(+), 32 deletions(-) diff --git a/pcbnew/pcb_track.cpp b/pcbnew/pcb_track.cpp index 6e90110092..e163abe7a5 100644 --- a/pcbnew/pcb_track.cpp +++ b/pcbnew/pcb_track.cpp @@ -1749,6 +1749,11 @@ void PCB_TRACK::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_I } } + SHAPE_POLY_SET copper; + TransformShapeToPolySet( copper, GetLayer(), 0, ARC_LOW_DEF, ERROR_INSIDE ); + aList.emplace_back( _( "Copper Area" ), + aFrame->MessageTextFromValue( copper.Area(), true, EDA_DATA_TYPE::AREA ) ); + wxString source; int clearance = GetOwnClearance( GetLayer(), &source ); diff --git a/pcbnew/tools/pcb_control.cpp b/pcbnew/tools/pcb_control.cpp index 856b03db7d..43bd5230f7 100644 --- a/pcbnew/tools/pcb_control.cpp +++ b/pcbnew/tools/pcb_control.cpp @@ -24,6 +24,7 @@ */ #include "pcb_control.h" +#include "convert_basic_shapes_to_polygon.h" #include <kiplatform/ui.h> #include <tools/edit_tool.h> @@ -1873,7 +1874,7 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) PCB_LAYER_ID layer = overlap.CuStack().front(); constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer ); - msgItems.emplace_back( _( "Resolved clearance" ), + msgItems.emplace_back( _( "Resolved Clearance" ), m_frame->MessageTextFromValue( constraint.m_Value.Min() ) ); std::shared_ptr<SHAPE> a_shape( a_conn->GetEffectiveShape( layer ) ); @@ -1883,8 +1884,8 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) if( actual_clearance > -1 && actual_clearance < std::numeric_limits<int>::max() ) { - msgItems.emplace_back( _( "Actual clearance" ), - m_frame->MessageTextFromValue( actual_clearance ) ); + msgItems.emplace_back( _( "Actual Clearance" ), + m_frame->MessageTextFromValue( actual_clearance ) ); } } } @@ -1926,13 +1927,13 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) if( actual < std::numeric_limits<int>::max() ) { constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer ); - msgItems.emplace_back( _( "Resolved hole clearance" ), - m_frame->MessageTextFromValue( constraint.m_Value.Min() ) ); + msgItems.emplace_back( _( "Resolved Hole Clearance" ), + m_frame->MessageTextFromValue( constraint.m_Value.Min() ) ); if( actual > -1 && actual < std::numeric_limits<int>::max() ) { - msgItems.emplace_back( _( "Actual hole clearance" ), - m_frame->MessageTextFromValue( actual ) ); + msgItems.emplace_back( _( "Actual Hole Clearance" ), + m_frame->MessageTextFromValue( actual ) ); } } } @@ -1964,12 +1965,12 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) if( edgeLayer == Edge_Cuts ) { - msgItems.emplace_back( _( "Resolved edge clearance" ), + msgItems.emplace_back( _( "Resolved Edge Clearance" ), m_frame->MessageTextFromValue( constraint.m_Value.Min() ) ); } else { - msgItems.emplace_back( _( "Resolved margin clearance" ), + msgItems.emplace_back( _( "Resolved Margin Clearance" ), m_frame->MessageTextFromValue( constraint.m_Value.Min() ) ); } } @@ -1993,8 +1994,7 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) ) { netNames.insert( UnescapeString( bci->GetNetname() ) ); - netClasses.insert( UnescapeString( - bci->GetEffectiveNetClass()->GetHumanReadableName() ) ); + netClasses.insert( UnescapeString( bci->GetEffectiveNetClass()->GetHumanReadableName() ) ); if( netNames.size() > 1 && netClasses.size() > 1 ) break; @@ -2020,16 +2020,21 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) accumulateTrackLength = [&]( EDA_ITEM* aItem ) { - if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( aItem ) ) + if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T ) { - selectedLength += track->GetLength(); + selectedLength += static_cast<PCB_TRACK*>( aItem )->GetLength(); } - else if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( aItem ) ) + else if( aItem->Type() == PCB_VIA_T ) { - const SHAPE_T shapeType = shape->GetShape(); + // zero 2D length + } + else if( aItem->Type() == PCB_SHAPE_T ) + { + PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem ); - if( shapeType == SHAPE_T::SEGMENT || shapeType == SHAPE_T::ARC - || shapeType == SHAPE_T::BEZIER ) + if( shape->GetShape() == SHAPE_T::SEGMENT + || shape->GetShape() == SHAPE_T::ARC + || shape->GetShape() == SHAPE_T::BEZIER ) { selectedLength += shape->GetLength(); } @@ -2038,6 +2043,7 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) lengthValid = false; } } + // Use dynamic_cast to include PCB_GENERATORs. else if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) ) { group->RunOnChildren( accumulateTrackLength ); @@ -2049,7 +2055,10 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) }; for( EDA_ITEM* item : selection ) - accumulateTrackLength( item ); + { + if( lengthValid ) + accumulateTrackLength( item ); + } if( lengthValid ) { @@ -2057,6 +2066,72 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) m_frame->MessageTextFromValue( selectedLength ) ); } } + + if( selection.GetSize() >= 2 && selection.GetSize() < 100 ) + { + LSET enabledCopper = LSET::AllCuMask( m_frame->GetBoard()->GetCopperLayerCount() ); + bool areaValid = true; + + std::map<PCB_LAYER_ID, SHAPE_POLY_SET> copperPolys; + SHAPE_POLY_SET holes; + + std::function<void( EDA_ITEM* )> accumulateArea; + + accumulateArea = + [&]( EDA_ITEM* aItem ) + { + if( aItem->Type() == PCB_FOOTPRINT_T ) + { + areaValid = false; + return; + } + + if( BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( aItem ) ) + { + boardItem->RunOnChildren( accumulateArea ); + + for( PCB_LAYER_ID layer : LSET( boardItem->GetLayerSet() & enabledCopper ) ) + { + boardItem->TransformShapeToPolySet( copperPolys[layer], layer, 0, + ARC_LOW_DEF, ERROR_INSIDE ); + } + + if( aItem->Type() == PCB_PAD_T && static_cast<PAD*>( aItem )->HasHole() ) + { + static_cast<PAD*>( aItem )->TransformHoleToPolygon( holes, 0, ARC_LOW_DEF, + ERROR_OUTSIDE ); + } + else if( aItem->Type() == PCB_VIA_T ) + { + PCB_VIA* via = static_cast<PCB_VIA*>( aItem ); + VECTOR2I center = via->GetPosition(); + int R = via->GetDrillValue() / 2; + + TransformCircleToPolygon( holes, center, R, ARC_LOW_DEF, ERROR_OUTSIDE ); + } + } + }; + + for( EDA_ITEM* item : selection ) + { + if( areaValid ) + accumulateArea( item ); + } + + if( areaValid ) + { + double area = 0.0; + + for( auto& [layer, copperPoly] : copperPolys ) + { + copperPoly.BooleanSubtract( holes ); + area += copperPoly.Area(); + } + + msgItems.emplace_back( _( "Selected 2D Copper Area" ), + m_frame->MessageTextFromValue( area, true, EDA_DATA_TYPE::AREA ) ); + } + } } else { diff --git a/pcbnew/zone.cpp b/pcbnew/zone.cpp index b1cf1cad6c..d65214666e 100644 --- a/pcbnew/zone.cpp +++ b/pcbnew/zone.cpp @@ -1504,20 +1504,8 @@ double ZONE::CalculateFilledArea() { m_area = 0.0; - // Iterate over each outline polygon in the zone and then iterate over - // each hole it has to compute the total area. - for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList ) - { - std::shared_ptr<SHAPE_POLY_SET>& poly = pair.second; - - for( int i = 0; i < poly->OutlineCount(); i++ ) - { - m_area += poly->Outline( i ).Area(); - - for( int j = 0; j < poly->HoleCount( i ); j++ ) - m_area -= poly->Hole( i, j ).Area(); - } - } + for( const auto& [layer, poly] : m_FilledPolysList ) + m_area += poly->Area(); return m_area; }