Tweak PCB selection behavior to reduce unintuitive behavior

We were discarding shapes too aggressively for having a
larger area than a shape underneath.

Let's also try showing fewer disambiguation menus, in particular
always preferring items on the active layer when the candidates
include overlapping items of similar area on other layers.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/7949
This commit is contained in:
Jon Evans 2021-03-20 12:46:19 -04:00
parent e4b99b9bb5
commit f1c599fa4d
3 changed files with 61 additions and 2 deletions

View File

@ -190,6 +190,9 @@ SHAPE_ARC& SHAPE_ARC::ConstructFromStartEndAngle( const VECTOR2I& aStart, const
bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance, int* aActual, VECTOR2I* aLocation ) const
{
if( aSeg.A == aSeg.B )
return Collide( aSeg.A, aClearance, aActual, aLocation );
int minDist = aClearance + m_width / 2;
VECTOR2I center = GetCenter();
ecoord dist_sq;

View File

@ -1766,7 +1766,6 @@ double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLEC
return combinedArea;
}
if( aItem->Type() == PCB_FOOTPRINT_T )
{
const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
@ -1780,6 +1779,41 @@ double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLEC
text->TransformTextShapeWithClearanceToPolygon( poly, UNDEFINED_LAYER, textMargin,
ARC_LOW_DEF, ERROR_OUTSIDE );
}
else if( aItem->Type() == PCB_SHAPE_T )
{
// Approximate "linear" shapes with just their width squared, as we don't want to consider
// a linear shape as being much bigger than another for purposes of selection filtering
// just because it happens to be really long.
const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
switch( shape->GetShape() )
{
case S_SEGMENT:
case S_ARC:
case S_CURVE:
return shape->GetWidth() * shape->GetWidth();
case S_RECT:
case S_CIRCLE:
case S_POLYGON:
{
if( !shape->IsFilled() )
return shape->GetWidth() * shape->GetWidth();
KI_FALLTHROUGH;
}
default:
aItem->TransformShapeWithClearanceToPolygon( poly, UNDEFINED_LAYER, 0,
ARC_LOW_DEF, ERROR_OUTSIDE );
}
}
else if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
{
double width = static_cast<const TRACK*>( aItem )->GetWidth();
return width * width;
}
else
{
aItem->TransformShapeWithClearanceToPolygon( poly, UNDEFINED_LAYER, 0,

View File

@ -2411,7 +2411,7 @@ void PCB_SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector
// If the user clicked on a small item within a much larger one then it's pretty clear
// they're trying to select the smaller one.
constexpr double sizeRatio = 1.3;
constexpr double sizeRatio = 1.5;
std::vector<std::pair<BOARD_ITEM*, double>> itemsByArea;
@ -2486,6 +2486,28 @@ void PCB_SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector
for( BOARD_ITEM* item : rejected )
aCollector.Transfer( item );
}
// Finally, what we are left with is a set of items of similar coverage area. We now reject
// any that are not on the active layer, to reduce the number of disambiguation menus shown.
// If the user wants to force-disambiguate, they can either switch layers or use the modifier
// key to force the menu.
if( aCollector.GetCount() > 1 )
{
bool haveItemOnActive = false;
rejected.clear();
for( int i = 0; i < aCollector.GetCount(); ++i )
{
if( !aCollector[i]->IsOnLayer( activeLayer ) )
rejected.insert( aCollector[i] );
else
haveItemOnActive = true;
}
if( haveItemOnActive )
for( BOARD_ITEM* item : rejected )
aCollector.Transfer( item );
}
}