Add keepout zones set to keepout footprints to footprint courtyard checker.

(This is for the move tool, not DRC.  DRC uses more sophisticated keepout
processing which is too slow for the move tool, and doesn't let us know which
keepout area collided for collision highlighting.)

Fixes https://gitlab.com/kicad/code/kicad/issues/12594
This commit is contained in:
Jeff Young 2022-10-07 22:21:24 +01:00
parent e9bcab07bc
commit 04fec5016b
4 changed files with 96 additions and 28 deletions

View File

@ -2162,7 +2162,7 @@ void PCB_PAINTER::draw( const FOOTPRINT* aFootprint, int aLayer )
#endif
}
if( aLayer == LAYER_CONFLICTS_SHADOW ) // happens only if locked
if( aLayer == LAYER_CONFLICTS_SHADOW )
{
const SHAPE_POLY_SET& frontpoly = aFootprint->GetCourtyard( F_CrtYd );
const SHAPE_POLY_SET& backpoly = aFootprint->GetCourtyard( B_CrtYd );
@ -2251,6 +2251,18 @@ void PCB_PAINTER::draw( const PCB_GROUP* aGroup, int aLayer )
void PCB_PAINTER::draw( const ZONE* aZone, int aLayer )
{
if( aLayer == LAYER_CONFLICTS_SHADOW )
{
COLOR4D color = m_pcbSettings.GetColor( aZone, aLayer );
m_gal->SetIsFill( true );
m_gal->SetIsStroke( false );
m_gal->SetFillColor( color );
m_gal->DrawPolygon( aZone->Outline()->Outline( 0 ) );
return;
}
/*
* aLayer will be the virtual zone layer (LAYER_ZONE_START, ... in GAL_LAYER_ID)
* This is used for draw ordering in the GAL.

View File

@ -105,8 +105,8 @@ public:
return wxT( "Tests footprints' courtyard clearance" );
}
// The list of footprints having issues
std::set<FOOTPRINT*> m_FpInConflict;
// The list of items in collision
std::set<BOARD_ITEM*> m_ItemsInConflict;
// The list of moved footprints
std::vector<FOOTPRINT*> m_FpInMove;
@ -163,8 +163,8 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE_ON_MOVE::testCourtyardClearances()
if( frontA.Collide( &frontB, clearance, &actual, &pos ) )
{
m_FpInConflict.insert( fpA );
m_FpInConflict.insert( fpB );
m_ItemsInConflict.insert( fpA );
m_ItemsInConflict.insert( fpB );
}
}
@ -176,11 +176,10 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE_ON_MOVE::testCourtyardClearances()
// constraint.GetValue().Min();
clearance = 0;
if( backA.Collide( &backB, clearance, &actual, &pos ) )
{
m_FpInConflict.insert( fpA );
m_FpInConflict.insert( fpB );
m_ItemsInConflict.insert( fpA );
m_ItemsInConflict.insert( fpB );
}
}
@ -213,8 +212,8 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE_ON_MOVE::testCourtyardClearances()
{
if( testPadAgainstCourtyards( padB, fpA ) )
{
m_FpInConflict.insert( fpA );
m_FpInConflict.insert( fpB );
m_ItemsInConflict.insert( fpA );
m_ItemsInConflict.insert( fpB );
skipNextCmp = true;
break;
}
@ -231,8 +230,50 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE_ON_MOVE::testCourtyardClearances()
{
if( testPadAgainstCourtyards( padA, fpB ) )
{
m_FpInConflict.insert( fpA );
m_FpInConflict.insert( fpB );
m_ItemsInConflict.insert( fpA );
m_ItemsInConflict.insert( fpB );
break;
}
}
}
}
}
for( ZONE* zone : m_board->Zones() )
{
if( !zone->GetIsRuleArea() || !zone->GetDoNotAllowFootprints() )
continue;
bool disallowFront = ( zone->GetLayerSet() | LSET::FrontMask() ).any();
bool disallowBack = ( zone->GetLayerSet() | LSET::BackMask() ).any();
for( FOOTPRINT* fp : m_FpInMove )
{
if( disallowFront )
{
const SHAPE_POLY_SET& frontCourtyard = fp->GetCourtyard( F_CrtYd );
if( !frontCourtyard.IsEmpty() )
{
if( zone->Outline()->Collide( &frontCourtyard.Outline( 0 ) ) )
{
m_ItemsInConflict.insert( fp );
m_ItemsInConflict.insert( zone );
break;
}
}
}
if( disallowBack )
{
const SHAPE_POLY_SET& backCourtyard = fp->GetCourtyard( B_CrtYd );
if( !backCourtyard.IsEmpty() )
{
if( zone->Outline()->Collide( &backCourtyard.Outline( 0 ) ) )
{
m_ItemsInConflict.insert( fp );
m_ItemsInConflict.insert( zone );
break;
}
}
@ -257,7 +298,7 @@ void DRC_TEST_PROVIDER_COURTYARD_CLEARANCE_ON_MOVE::Init( BOARD* aBoard )
bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE_ON_MOVE::Run()
{
m_FpInConflict.clear();
m_ItemsInConflict.clear();
m_largestCourtyardClearance = 0;
DRC_CONSTRAINT constraint;
@ -593,9 +634,9 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, bool aPickReference )
: wxT( "" ) );
};
std::vector<BOARD_ITEM*> sel_items; // All the items operated on by the move below
std::vector<BOARD_ITEM*> orig_items; // All the original items in the selection
std::vector<FOOTPRINT*> lastFpInConflict; // last footprints with courtyard overlapping
std::vector<BOARD_ITEM*> sel_items; // All the items operated on by the move below
std::vector<BOARD_ITEM*> orig_items; // All the original items in the selection
std::vector<BOARD_ITEM*> lastItemsInConflict; // last footprints with courtyard overlapping
for( EDA_ITEM* item : selection )
{
@ -758,25 +799,25 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, bool aPickReference )
// has changed
// Ensure the "old" conflicts are cleared
for( FOOTPRINT* fp: lastFpInConflict )
for( BOARD_ITEM* item: lastItemsInConflict )
{
fp->ClearFlags( COURTYARD_CONFLICT );
m_toolMgr->GetView()->Update( fp );
item->ClearFlags( COURTYARD_CONFLICT );
m_toolMgr->GetView()->Update( item );
need_redraw = true;
}
lastFpInConflict.clear();
lastItemsInConflict.clear();
for( FOOTPRINT* fp: drc_on_move.m_FpInConflict )
for( BOARD_ITEM* item: drc_on_move.m_ItemsInConflict )
{
if( !fp->HasFlag( COURTYARD_CONFLICT ) )
if( !item->HasFlag( COURTYARD_CONFLICT ) )
{
fp->SetFlags( COURTYARD_CONFLICT );
m_toolMgr->GetView()->Update( fp );
item->SetFlags( COURTYARD_CONFLICT );
m_toolMgr->GetView()->Update( item );
need_redraw = true;
}
lastFpInConflict.push_back( fp );
lastItemsInConflict.push_back( item );
}
if( need_redraw )
@ -976,10 +1017,10 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, bool aPickReference )
} while( ( evt = Wait() ) ); // Assignment (instead of equality test) is intentional
// Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
for( FOOTPRINT* fp: lastFpInConflict )
for( BOARD_ITEM* item: lastItemsInConflict )
{
m_toolMgr->GetView()->Update( fp );
fp->ClearFlags( COURTYARD_CONFLICT );
m_toolMgr->GetView()->Update( item );
item->ClearFlags( COURTYARD_CONFLICT );
}
controls->ForceCursorPosition( false );

View File

@ -221,6 +221,12 @@ bool ZONE::UnFill()
}
bool ZONE::IsConflicting() const
{
return HasFlag( COURTYARD_CONFLICT );
}
VECTOR2I ZONE::GetPosition() const
{
return GetCornerPosition( 0 );
@ -289,6 +295,9 @@ void ZONE::ViewGetLayers( int aLayers[], int& aCount ) const
aLayers[idx] = LAYER_ZONE_START + layers[idx];
aCount = layers.size();
if( IsConflicting() )
aLayers[ aCount++ ] = LAYER_CONFLICTS_SHADOW;
}

View File

@ -89,6 +89,12 @@ public:
*/
void InitDataFromSrcInCopyCtor( const ZONE& aZone );
/**
* For rule areas which exclude footprints (and therefore participate in courtyard conflicts
* during move).
*/
bool IsConflicting() const;
/**
* @return a VECTOR2I, position of the first point of the outline
*/