Pcbnew: fix footprint selection bug.

Do not remove footprint objects from list of selected objects when there
are no drawable objects other than the reference and value text.

Increase the minimum size rectangle for footprints from 0.025mm to 1mm
when the footprint has no drawing objects so that it is easier to select
the footprint in this case.

Add debugging code to show the footprint bounding box and polygon outline
so that it's possible to tell the difference between selection areas.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/8379
This commit is contained in:
Wayne Stambaugh 2021-06-24 14:13:30 -04:00
parent c9cc824761
commit 5c1c24cdab
3 changed files with 56 additions and 12 deletions

View File

@ -4,7 +4,7 @@
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2015 Wayne Stambaugh <stambaughw@gmail.com> * Copyright (C) 2015 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -460,7 +460,9 @@ EDA_RECT MODULE::GetFootprintRect() const
area.SetOrigin( m_Pos ); area.SetOrigin( m_Pos );
area.SetEnd( m_Pos ); area.SetEnd( m_Pos );
area.Inflate( Millimeter2iu( 0.25 ) ); // Give a min size to the area
// Give a minimum size to the area in case footprint has no drawing or pad objects.
area.Inflate( Millimeter2iu( 0.5 ) );
for( const BOARD_ITEM* item = m_Drawings.GetFirst(); item; item = item->Next() ) for( const BOARD_ITEM* item = m_Drawings.GetFirst(); item; item = item->Next() )
{ {
@ -479,13 +481,6 @@ const EDA_RECT MODULE::GetBoundingBox() const
{ {
EDA_RECT area = GetFootprintRect(); EDA_RECT area = GetFootprintRect();
// Add in items not collected by GetFootprintRect():
for( const BOARD_ITEM* item = m_Drawings.GetFirst(); item; item = item->Next() )
{
if( item->Type() != PCB_MODULE_EDGE_T )
area.Merge( item->GetBoundingBox() );
}
area.Merge( m_Value->GetBoundingBox() ); area.Merge( m_Value->GetBoundingBox() );
area.Merge( m_Reference->GetBoundingBox() ); area.Merge( m_Reference->GetBoundingBox() );
@ -529,6 +524,7 @@ SHAPE_POLY_SET MODULE::GetBoundingPoly() const
poly.Append( p ); poly.Append( p );
BOARD* board = GetBoard(); BOARD* board = GetBoard();
if( board ) if( board )
{ {
int biggest_clearance = board->GetDesignSettings().GetBiggestClearanceValue(); int biggest_clearance = board->GetDesignSettings().GetBiggestClearanceValue();
@ -650,13 +646,20 @@ bool MODULE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) co
arect.Inflate( aAccuracy ); arect.Inflate( aAccuracy );
if( aContained ) if( aContained )
{
return arect.Contains( m_BoundaryBox ); return arect.Contains( m_BoundaryBox );
}
else else
{ {
// If the rect does not intersect the bounding box, skip any tests // If the rect does not intersect the bounding box, skip any tests
if( !aRect.Intersects( GetBoundingBox() ) ) if( !aRect.Intersects( GetBoundingBox() ) )
return false; return false;
// If there are no drawing objects, there was still an intersection with the reference
// and/or value text.
if( m_Pads.GetCount() == 0 && m_Drawings.GetCount() == 0 )
return true;
// Determine if any elements in the MODULE intersect the rect // Determine if any elements in the MODULE intersect the rect
for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
{ {

View File

@ -2,6 +2,8 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2013-2019 CERN * Copyright (C) 2013-2019 CERN
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch> * @author Maciej Suminski <maciej.suminski@cern.ch>
* *
@ -383,7 +385,40 @@ bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
return false; return false;
} }
return true; // Draw bounding boxes after drawing objects so they can be seen.
#if 0
// Show bounding boxes of painted objects for debugging.
EDA_RECT box = item->GetBoundingBox();
m_gal->SetIsFill( false );
m_gal->SetIsStroke( true );
if( item->Type() == PCB_MODULE_T )
m_gal->SetStrokeColor( item->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 ) :
COLOR4D( MAGENTA ) );
else
m_gal->SetStrokeColor( item->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 ) :
COLOR4D( 0.2, 0.2, 0.2, 1 ) );
m_gal->SetLineWidth( 1.5 / m_gal->GetWorldScale() );
m_gal->DrawRectangle( box.GetOrigin(), box.GetEnd() );
if( item->Type() == PCB_MODULE_T )
{
m_gal->SetStrokeColor( item->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 ) :
COLOR4D( CYAN ) );
const MODULE* fp = static_cast<const MODULE*>( item );
if( fp )
{
SHAPE_POLY_SET convex = fp->GetBoundingPoly();
m_gal->DrawPolyline( convex.COutline( 0 ) );
}
}
#endif
return true;
} }

View File

@ -2,9 +2,10 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2013-2017 CERN * Copyright (C) 2013-2017 CERN
* Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch> * @author Maciej Suminski <maciej.suminski@cern.ch>
* Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -1701,9 +1702,14 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem, bool checkVisibilityOn
return false; return false;
// Allow selection of footprints if some part of the footprint is visible. // Allow selection of footprints if some part of the footprint is visible.
MODULE* module = const_cast<MODULE*>( static_cast<const MODULE*>( aItem ) ); MODULE* module = const_cast<MODULE*>( static_cast<const MODULE*>( aItem ) );
// If the footprint has no drawable items other than the reference and value test,
// then it can be selected.
if( ( module->GraphicalItemsList().GetCount() == 0 ) &&
( module->PadsList().GetCount() == 0 ) )
return true;
for( auto item : module->GraphicalItems() ) for( auto item : module->GraphicalItems() )
{ {
if( selectable( item, true ) ) if( selectable( item, true ) )