Disambiguation menu fix for footprints with a single pad.

Fix selection disambiguation to allow for selecting of footprints which are
mostly covered by their pads, text, etc.

Fixes: lp:1739425
* https://bugs.launchpad.net/kicad/+bug/1739425

Fixes: lp:1723469
* https://bugs.launchpad.net/kicad/+bug/1723469
This commit is contained in:
Jeff Young 2017-12-22 00:49:35 +00:00 committed by Wayne Stambaugh
parent bd7f5081d1
commit 0f943f1e4b
3 changed files with 54 additions and 37 deletions

View File

@ -1240,22 +1240,39 @@ wxString MODULE::GetReferencePrefix() const
}
double MODULE::PadCoverageRatio() const
double CalcArea( wxRegion aRegion )
{
double area = 0.0;
for( wxRegionIterator iterator( aRegion ); iterator.HaveRects(); iterator++ )
{
wxRect aRect = iterator.GetRect();
area += static_cast<double>( aRect.GetWidth() ) * aRect.GetHeight();
}
return area;
}
double MODULE::CoverageRatio() const
{
double padArea = 0.0;
double moduleArea = GetFootprintRect().GetArea();
wxRegion uncoveredRegion( GetFootprintRect() );
for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
padArea += pad->GetBoundingBox().GetArea();
uncoveredRegion.Subtract( pad->GetBoundingBox() );
if( moduleArea == 0.0 )
return 1.0;
for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
uncoveredRegion.Subtract( item->GetBoundingBox() );
double ratio = padArea / moduleArea;
uncoveredRegion.Subtract( m_Reference->GetBoundingBox() );
uncoveredRegion.Subtract( m_Value->GetBoundingBox() );
double coveredArea = moduleArea - CalcArea( uncoveredRegion );
double ratio = ( coveredArea / moduleArea );
return std::min( ratio, 1.0 );
}
// see convert_drawsegment_list_to_polygon.cpp:
extern bool ConvertOutlineToPolygon( std::vector< DRAWSEGMENT* >& aSegList,
SHAPE_POLY_SET& aPolygons, int aSegmentsByCircle,

View File

@ -657,12 +657,12 @@ public:
}
/**
* Function PadCoverageRatio
* Calculates the ratio of total area of the footprint pads to the area of the
* footprint. Used by selection tool heuristics.
* Function CoverageRatio
* Calculates the ratio of total area of the footprint pads and graphical items
* to the area of the footprint. Used by selection tool heuristics.
* @return the ratio
*/
double PadCoverageRatio() const;
double CoverageRatio() const;
/// Return the initial comments block or NULL if none, without transfer of ownership.
const wxArrayString* GetInitialComments() const { return m_initial_comments; }

View File

@ -1765,13 +1765,13 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c
// footprints which are below this percentage of the largest footprint will be considered
// for selection; all others will not
constexpr double footprintAreaRatio = 0.2;
// footprints containing pads with pad-to-footprint area ratio smaller than this will be dropped
constexpr double modulePadMinCoverRatio = 0.45;
// footprints containing pads with pad-to-footprint area ratio higher than this will be
constexpr double footprintToFootprintMinRatio = 0.20;
// pads which are below this percentage of their parent's area will exclude their parent
constexpr double padToFootprintMinRatio = 0.45;
// footprints containing items with items-to-footprint area ratio higher than this will be
// forced to stay on the list
constexpr double modulePadMaxCoverRatio = 0.80;
constexpr double padViaAreaRatio = 0.5;
constexpr double footprintMaxCoverRatio = 0.80;
constexpr double viaToPadMinRatio = 0.50;
constexpr double trackViaLengthRatio = 2.0;
constexpr double trackTrackLengthRatio = 0.3;
constexpr double textToFeatureMinRatio = 0.2;
@ -1831,9 +1831,13 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c
double itemCommonRatio = calcRatio( commonArea, itemArea );
double txtCommonRatio = calcRatio( commonArea, textArea );
if( item->Type() == PCB_MODULE_T && areaRatio < textToFootprintMinRatio &&
itemCommonRatio < commonAreaRatio )
rejected.insert( item );
if( item->Type() == PCB_MODULE_T )
{
// when text area is small compared to an overlapping footprint,
// then it's a clear sign the text is the selection target
if( areaRatio < textToFootprintMinRatio && itemCommonRatio < commonAreaRatio )
rejected.insert( item );
}
switch( item->Type() )
{
@ -1859,17 +1863,13 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c
{
if( D_PAD* pad = dyn_cast<D_PAD*>( aCollector[i] ) )
{
double ratio = pad->GetParent()->PadCoverageRatio();
MODULE* parent = pad->GetParent();
double ratio = calcRatio( calcArea( pad ), calcArea( parent ) );
// when pad area is small compared to the parent footprint,
// then it is a clear sign the pad is the selection target
if( ratio < modulePadMinCoverRatio )
if( ratio < padToFootprintMinRatio )
rejected.insert( pad->GetParent() );
// for pads covering most of the footprint area the parent footprint
// should be kept in the disambiguation menu, otherwise it is very hard
// to select the footprint
else if( ratio > modulePadMaxCoverRatio )
forced.insert( pad->GetParent() );
}
}
}
@ -1884,17 +1884,17 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c
{
if( MODULE* mod = dyn_cast<MODULE*>( aCollector[i] ) )
{
// do not check the module if it is forced on the list
if( forced.count( mod ) )
continue;
// filter out components larger than the viewport
if( mod->ViewBBox().Contains( viewport ) )
rejected.insert( mod );
// if a module is much less than the area of the largest module
// then it should be considered for selection; reject all other
// modules
else if( calcRatio( calcArea( mod ), maxArea ) > footprintAreaRatio )
// footprints completely covered with other features have no other
// means of selection, so must be kept
else if ( mod->CoverageRatio() > footprintMaxCoverRatio )
rejected.erase( mod );
// if a footprint is much smaller than the largest overlapping
// footprint then it should be considered for selection; reject
// all other footprints
else if( calcRatio( calcArea( mod ), maxArea ) > footprintToFootprintMinRatio )
rejected.insert( mod );
}
}
@ -1916,10 +1916,10 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c
BOARD_ITEM* item = aCollector[j];
double areaRatio = calcRatio( viaArea, calcArea( item ) );
if( item->Type() == PCB_MODULE_T && areaRatio < modulePadMinCoverRatio )
if( item->Type() == PCB_MODULE_T && areaRatio < padToFootprintMinRatio )
rejected.insert( item );
if( item->Type() == PCB_PAD_T && areaRatio < padViaAreaRatio )
if( item->Type() == PCB_PAD_T && areaRatio < viaToPadMinRatio )
rejected.insert( item );
if( TRACK* track = dyn_cast<TRACK*>( item ) )
@ -1986,7 +1986,7 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c
{
double ratio = calcRatio( maxArea, mod->GetFootprintRect().GetArea() );
if( ratio < modulePadMinCoverRatio && calcCommonArea( maxTrack, mod ) < commonAreaRatio )
if( ratio < padToFootprintMinRatio && calcCommonArea( maxTrack, mod ) < commonAreaRatio )
rejected.insert( mod );
}
}