Better algorithm for knocking out footprints.

(Though anything would have been as the previous
one didn't work at all.)
This commit is contained in:
Jeff Young 2025-02-24 23:00:46 +00:00
parent 78fc95fd6d
commit 7db3ccd98a
5 changed files with 130 additions and 35 deletions

View File

@ -149,23 +149,24 @@ void BOARD_COMMIT::propagateDamage( BOARD_ITEM* aItem, std::vector<ZONE*>* aStal
else
layers &= LSET::AllCuMask();
if( layers.empty() )
return;
for( ZONE* zone : board->Zones() )
if( layers.any() )
{
if( zone->GetIsRuleArea() )
continue;
if( ( zone->GetLayerSet() & layers ).any()
&& zone->GetBoundingBox().Intersects( bbox ) )
for( ZONE* zone : board->Zones() )
{
aStaleZones->push_back( zone );
if( zone->GetIsRuleArea() )
continue;
if( ( zone->GetLayerSet() & layers ).any()
&& zone->GetBoundingBox().Intersects( bbox ) )
{
aStaleZones->push_back( zone );
}
}
}
}
if( aStaleHatchedShapes && ( aItem->Type() == PCB_TEXT_T
if( aStaleHatchedShapes && ( aItem->Type() == PCB_FIELD_T
|| aItem->Type() == PCB_TEXT_T
|| aItem->Type() == PCB_TEXTBOX_T
|| aItem->Type() == PCB_SHAPE_T ) )
{

View File

@ -1513,7 +1513,6 @@ SHAPE_POLY_SET FOOTPRINT::GetBoundingHull() const
}
SHAPE_POLY_SET rawPolys;
SHAPE_POLY_SET hull;
for( BOARD_ITEM* item : m_drawings )
{
@ -1588,6 +1587,58 @@ SHAPE_POLY_SET FOOTPRINT::GetBoundingHull() const
}
SHAPE_POLY_SET FOOTPRINT::GetBoundingHull( PCB_LAYER_ID aLayer ) const
{
const BOARD* board = GetBoard();
bool isFPEdit = board && board->IsFootprintHolder();
SHAPE_POLY_SET rawPolys;
SHAPE_POLY_SET hull;
for( BOARD_ITEM* item : m_drawings )
{
if( !isFPEdit && m_privateLayers.test( item->GetLayer() ) )
continue;
if( item->IsOnLayer( aLayer ) )
{
if( item->Type() != PCB_FIELD_T && item->Type() != PCB_REFERENCE_IMAGE_T )
{
item->TransformShapeToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
ERROR_OUTSIDE );
}
// We intentionally exclude footprint fields from the bounding hull.
}
}
for( PAD* pad : m_pads )
{
if( pad->IsOnLayer( aLayer ) )
pad->TransformShapeToPolygon( rawPolys, aLayer, 0, ARC_LOW_DEF, ERROR_OUTSIDE );
}
for( ZONE* zone : m_zones )
{
if( const std::shared_ptr<SHAPE_POLY_SET>& layerPoly = zone->GetFilledPolysList( aLayer ) )
{
for( int ii = 0; ii < layerPoly->OutlineCount(); ii++ )
rawPolys.AddOutline( layerPoly->COutline( ii ) );
}
}
std::vector<VECTOR2I> convex_hull;
BuildConvexHull( convex_hull, rawPolys );
hull.NewOutline();
for( const VECTOR2I& pt : convex_hull )
hull.Append( pt );
return hull;
}
void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
{
wxString msg, msg2;

View File

@ -187,6 +187,7 @@ public:
* This operation is slower but more accurate than calculating a bounding box.
*/
SHAPE_POLY_SET GetBoundingHull() const;
SHAPE_POLY_SET GetBoundingHull( PCB_LAYER_ID aLayer ) const;
bool TextOnly() const;

View File

@ -304,44 +304,58 @@ void PCB_SHAPE::updateHatching() const
{
EDA_SHAPE::updateHatching();
static std::initializer_list<KICAD_T> knockoutTypes = { PCB_TEXT_T, PCB_TEXTBOX_T,
PCB_SHAPE_T };
if( !m_hatching.IsEmpty() )
{
PCB_LAYER_ID layer = GetLayer();
BOX2I bbox = GetBoundingBox();
SHAPE_POLY_SET holes;
int maxError = ARC_LOW_DEF;
auto knockoutItem =
[&]( BOARD_ITEM* item )
{
int margin = GetHatchLineSpacing() / 2;
if( item->Type() == PCB_TEXTBOX_T )
margin = 0;
item->TransformShapeToPolygon( holes, layer, margin, maxError, ERROR_OUTSIDE );
};
for( BOARD_ITEM* item : GetBoard()->Drawings() )
{
if( item == this )
continue;
if( item->IsType( knockoutTypes )
&& item->GetLayer() == layer
&& item->GetBoundingBox().Intersects( bbox ) )
if( item->Type() == PCB_FIELD_T
|| item->Type() == PCB_TEXT_T
|| item->Type() == PCB_TEXTBOX_T
|| item->Type() == PCB_SHAPE_T )
{
item->TransformShapeToPolygon( holes, layer, 0, ARC_LOW_DEF, ERROR_OUTSIDE, true );
if( item->GetLayer() == layer && item->GetBoundingBox().Intersects( bbox ) )
knockoutItem( item );
}
if( item->Type() == PCB_FOOTPRINT_T )
{
static_cast<FOOTPRINT*>( item )->RunOnDescendants(
[&]( BOARD_ITEM* descendant )
}
for( FOOTPRINT* footprint : GetBoard()->Footprints() )
{
int margin = GetHatchLineSpacing() / 2;
SHAPE_POLY_SET hull = footprint->GetBoundingHull( layer );
hull.Inflate( margin, CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS, maxError );
holes.Append( hull );
footprint->RunOnDescendants(
[&]( BOARD_ITEM* item )
{
if( item->Type() == PCB_FIELD_T
&& item->GetLayer() == layer
&& item->GetBoundingBox().Intersects( bbox ) )
{
if( descendant == this )
return;
if( descendant->IsType( knockoutTypes )
&& descendant->GetLayer() == layer
&& descendant->GetBoundingBox().Intersects( bbox ) )
{
descendant->TransformShapeToPolygon( holes, layer, 0, ARC_LOW_DEF,
ERROR_OUTSIDE, true );
}
} );
}
knockoutItem( item );
}
} );
}
m_hatching.BooleanSubtract( holes );

View File

@ -31,6 +31,7 @@ using namespace std::placeholders;
#include <pcb_edit_frame.h>
#include <pcb_track.h>
#include <pcb_group.h>
#include <pcb_shape.h>
#include <pcb_generator.h>
#include <pcb_target.h>
#include <footprint.h>
@ -612,6 +613,33 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList )
}
}
auto checkHatching =
[&]( BOARD_ITEM* item )
{
if( item->Type() == PCB_SHAPE_T )
{
PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
if( shape->IsHatchedFill() )
{
shape->SetHatchingDirty();
view->Update( shape );
}
}
};
for( BOARD_ITEM* item : GetBoard()->Drawings() )
checkHatching( item );
for( FOOTPRINT* footprint : GetBoard()->Footprints() )
{
footprint->RunOnDescendants(
[&]( BOARD_ITEM* item )
{
checkHatching( item );
} );
}
if( added_items.size() > 0 || deleted_items.size() > 0 || changed_items.size() > 0 )
GetBoard()->OnItemsCompositeUpdate( added_items, deleted_items, changed_items );
}