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(); double moduleArea = GetFootprintRect().GetArea();
wxRegion uncoveredRegion( GetFootprintRect() );
for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
padArea += pad->GetBoundingBox().GetArea(); uncoveredRegion.Subtract( pad->GetBoundingBox() );
if( moduleArea == 0.0 ) for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
return 1.0; 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 ); return std::min( ratio, 1.0 );
} }
// see convert_drawsegment_list_to_polygon.cpp: // see convert_drawsegment_list_to_polygon.cpp:
extern bool ConvertOutlineToPolygon( std::vector< DRAWSEGMENT* >& aSegList, extern bool ConvertOutlineToPolygon( std::vector< DRAWSEGMENT* >& aSegList,
SHAPE_POLY_SET& aPolygons, int aSegmentsByCircle, SHAPE_POLY_SET& aPolygons, int aSegmentsByCircle,

View File

@ -657,12 +657,12 @@ public:
} }
/** /**
* Function PadCoverageRatio * Function CoverageRatio
* Calculates the ratio of total area of the footprint pads to the area of the * Calculates the ratio of total area of the footprint pads and graphical items
* footprint. Used by selection tool heuristics. * to the area of the footprint. Used by selection tool heuristics.
* @return the ratio * @return the ratio
*/ */
double PadCoverageRatio() const; double CoverageRatio() const;
/// Return the initial comments block or NULL if none, without transfer of ownership. /// Return the initial comments block or NULL if none, without transfer of ownership.
const wxArrayString* GetInitialComments() const { return m_initial_comments; } 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 // footprints which are below this percentage of the largest footprint will be considered
// for selection; all others will not // for selection; all others will not
constexpr double footprintAreaRatio = 0.2; constexpr double footprintToFootprintMinRatio = 0.20;
// footprints containing pads with pad-to-footprint area ratio smaller than this will be dropped // pads which are below this percentage of their parent's area will exclude their parent
constexpr double modulePadMinCoverRatio = 0.45; constexpr double padToFootprintMinRatio = 0.45;
// footprints containing pads with pad-to-footprint area ratio higher than this will be // footprints containing items with items-to-footprint area ratio higher than this will be
// forced to stay on the list // forced to stay on the list
constexpr double modulePadMaxCoverRatio = 0.80; constexpr double footprintMaxCoverRatio = 0.80;
constexpr double padViaAreaRatio = 0.5; constexpr double viaToPadMinRatio = 0.50;
constexpr double trackViaLengthRatio = 2.0; constexpr double trackViaLengthRatio = 2.0;
constexpr double trackTrackLengthRatio = 0.3; constexpr double trackTrackLengthRatio = 0.3;
constexpr double textToFeatureMinRatio = 0.2; constexpr double textToFeatureMinRatio = 0.2;
@ -1831,9 +1831,13 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c
double itemCommonRatio = calcRatio( commonArea, itemArea ); double itemCommonRatio = calcRatio( commonArea, itemArea );
double txtCommonRatio = calcRatio( commonArea, textArea ); double txtCommonRatio = calcRatio( commonArea, textArea );
if( item->Type() == PCB_MODULE_T && areaRatio < textToFootprintMinRatio && if( item->Type() == PCB_MODULE_T )
itemCommonRatio < commonAreaRatio ) {
rejected.insert( item ); // 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() ) 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] ) ) 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, // when pad area is small compared to the parent footprint,
// then it is a clear sign the pad is the selection target // then it is a clear sign the pad is the selection target
if( ratio < modulePadMinCoverRatio ) if( ratio < padToFootprintMinRatio )
rejected.insert( pad->GetParent() ); 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] ) ) 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 // filter out components larger than the viewport
if( mod->ViewBBox().Contains( viewport ) ) if( mod->ViewBBox().Contains( viewport ) )
rejected.insert( mod ); rejected.insert( mod );
// if a module is much less than the area of the largest module // footprints completely covered with other features have no other
// then it should be considered for selection; reject all other // means of selection, so must be kept
// modules else if ( mod->CoverageRatio() > footprintMaxCoverRatio )
else if( calcRatio( calcArea( mod ), maxArea ) > footprintAreaRatio ) 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 ); rejected.insert( mod );
} }
} }
@ -1916,10 +1916,10 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector ) c
BOARD_ITEM* item = aCollector[j]; BOARD_ITEM* item = aCollector[j];
double areaRatio = calcRatio( viaArea, calcArea( item ) ); 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 ); rejected.insert( item );
if( item->Type() == PCB_PAD_T && areaRatio < padViaAreaRatio ) if( item->Type() == PCB_PAD_T && areaRatio < viaToPadMinRatio )
rejected.insert( item ); rejected.insert( item );
if( TRACK* track = dyn_cast<TRACK*>( 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() ); double ratio = calcRatio( maxArea, mod->GetFootprintRect().GetArea() );
if( ratio < modulePadMinCoverRatio && calcCommonArea( maxTrack, mod ) < commonAreaRatio ) if( ratio < padToFootprintMinRatio && calcCommonArea( maxTrack, mod ) < commonAreaRatio )
rejected.insert( mod ); rejected.insert( mod );
} }
} }