ADDED: report copper area for current selection.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20439
This commit is contained in:
Jeff Young 2025-03-27 10:13:31 +00:00
parent d16a5bf87d
commit 07eda5d57e
3 changed files with 100 additions and 32 deletions

View File

@ -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; wxString source;
int clearance = GetOwnClearance( GetLayer(), &source ); int clearance = GetOwnClearance( GetLayer(), &source );

View File

@ -24,6 +24,7 @@
*/ */
#include "pcb_control.h" #include "pcb_control.h"
#include "convert_basic_shapes_to_polygon.h"
#include <kiplatform/ui.h> #include <kiplatform/ui.h>
#include <tools/edit_tool.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(); PCB_LAYER_ID layer = overlap.CuStack().front();
constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer ); 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() ) ); m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
std::shared_ptr<SHAPE> a_shape( a_conn->GetEffectiveShape( layer ) ); 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() ) if( actual_clearance > -1 && actual_clearance < std::numeric_limits<int>::max() )
{ {
msgItems.emplace_back( _( "Actual clearance" ), msgItems.emplace_back( _( "Actual Clearance" ),
m_frame->MessageTextFromValue( 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() ) if( actual < std::numeric_limits<int>::max() )
{ {
constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer ); constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer );
msgItems.emplace_back( _( "Resolved hole clearance" ), msgItems.emplace_back( _( "Resolved Hole Clearance" ),
m_frame->MessageTextFromValue( constraint.m_Value.Min() ) ); m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
if( actual > -1 && actual < std::numeric_limits<int>::max() ) if( actual > -1 && actual < std::numeric_limits<int>::max() )
{ {
msgItems.emplace_back( _( "Actual hole clearance" ), msgItems.emplace_back( _( "Actual Hole Clearance" ),
m_frame->MessageTextFromValue( actual ) ); m_frame->MessageTextFromValue( actual ) );
} }
} }
} }
@ -1964,12 +1965,12 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
if( edgeLayer == Edge_Cuts ) if( edgeLayer == Edge_Cuts )
{ {
msgItems.emplace_back( _( "Resolved edge clearance" ), msgItems.emplace_back( _( "Resolved Edge Clearance" ),
m_frame->MessageTextFromValue( constraint.m_Value.Min() ) ); m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
} }
else else
{ {
msgItems.emplace_back( _( "Resolved margin clearance" ), msgItems.emplace_back( _( "Resolved Margin Clearance" ),
m_frame->MessageTextFromValue( constraint.m_Value.Min() ) ); 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 ) ) if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
{ {
netNames.insert( UnescapeString( bci->GetNetname() ) ); netNames.insert( UnescapeString( bci->GetNetname() ) );
netClasses.insert( UnescapeString( netClasses.insert( UnescapeString( bci->GetEffectiveNetClass()->GetHumanReadableName() ) );
bci->GetEffectiveNetClass()->GetHumanReadableName() ) );
if( netNames.size() > 1 && netClasses.size() > 1 ) if( netNames.size() > 1 && netClasses.size() > 1 )
break; break;
@ -2020,16 +2020,21 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
accumulateTrackLength = accumulateTrackLength =
[&]( EDA_ITEM* aItem ) [&]( 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 if( shape->GetShape() == SHAPE_T::SEGMENT
|| shapeType == SHAPE_T::BEZIER ) || shape->GetShape() == SHAPE_T::ARC
|| shape->GetShape() == SHAPE_T::BEZIER )
{ {
selectedLength += shape->GetLength(); selectedLength += shape->GetLength();
} }
@ -2038,6 +2043,7 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
lengthValid = false; lengthValid = false;
} }
} }
// Use dynamic_cast to include PCB_GENERATORs.
else if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) ) else if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
{ {
group->RunOnChildren( accumulateTrackLength ); group->RunOnChildren( accumulateTrackLength );
@ -2049,7 +2055,10 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
}; };
for( EDA_ITEM* item : selection ) for( EDA_ITEM* item : selection )
accumulateTrackLength( item ); {
if( lengthValid )
accumulateTrackLength( item );
}
if( lengthValid ) if( lengthValid )
{ {
@ -2057,6 +2066,72 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
m_frame->MessageTextFromValue( selectedLength ) ); 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 else
{ {

View File

@ -1504,20 +1504,8 @@ double ZONE::CalculateFilledArea()
{ {
m_area = 0.0; m_area = 0.0;
// Iterate over each outline polygon in the zone and then iterate over for( const auto& [layer, poly] : m_FilledPolysList )
// each hole it has to compute the total area. m_area += poly->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();
}
}
return m_area; return m_area;
} }