From 04fec5016b8ff1dad66ade023e27442d3b424752 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Fri, 7 Oct 2022 22:21:24 +0100 Subject: [PATCH] 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 --- pcbnew/pcb_painter.cpp | 14 ++++- pcbnew/tools/edit_tool_move_fct.cpp | 95 +++++++++++++++++++++-------- pcbnew/zone.cpp | 9 +++ pcbnew/zone.h | 6 ++ 4 files changed, 96 insertions(+), 28 deletions(-) diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index cf09660ab6..189e075b58 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -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. diff --git a/pcbnew/tools/edit_tool_move_fct.cpp b/pcbnew/tools/edit_tool_move_fct.cpp index bbfad05c68..981c7a8ac8 100644 --- a/pcbnew/tools/edit_tool_move_fct.cpp +++ b/pcbnew/tools/edit_tool_move_fct.cpp @@ -105,8 +105,8 @@ public: return wxT( "Tests footprints' courtyard clearance" ); } - // The list of footprints having issues - std::set m_FpInConflict; + // The list of items in collision + std::set m_ItemsInConflict; // The list of moved footprints std::vector 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 sel_items; // All the items operated on by the move below - std::vector orig_items; // All the original items in the selection - std::vector lastFpInConflict; // last footprints with courtyard overlapping + std::vector sel_items; // All the items operated on by the move below + std::vector orig_items; // All the original items in the selection + std::vector 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 ); diff --git a/pcbnew/zone.cpp b/pcbnew/zone.cpp index 0c16a5bfd1..94618ba6ca 100644 --- a/pcbnew/zone.cpp +++ b/pcbnew/zone.cpp @@ -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; } diff --git a/pcbnew/zone.h b/pcbnew/zone.h index 439bf36152..530b1747d3 100644 --- a/pcbnew/zone.h +++ b/pcbnew/zone.h @@ -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 */