Employ an accuracy when hittesting (particularly for lines).

Also fixes a bug where the parent module was being hit-tested
for its children.

Fixes https://gitlab.com/kicad/code/kicad/issues/3750
This commit is contained in:
Jeff Young 2020-02-03 02:23:27 +00:00
parent 2286652abe
commit 89dfee9ebe
2 changed files with 99 additions and 13 deletions

View File

@ -26,10 +26,12 @@
#include <class_board_item.h> // class BOARD_ITEM
#include <class_module.h>
#include <class_edge_mod.h>
#include <class_pad.h>
#include <class_track.h>
#include <class_marker_pcb.h>
#include <class_zone.h>
#include <class_drawsegment.h>
#include <math/util.h> // for KiROUND
@ -152,13 +154,14 @@ const KICAD_T GENERAL_COLLECTOR::Zones[] = {
SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
{
BOARD_ITEM* item = (BOARD_ITEM*) testItem;
MODULE* module = NULL;
D_PAD* pad = NULL;
BOARD_ITEM* item = (BOARD_ITEM*) testItem;
MODULE* module = nullptr;
D_PAD* pad = nullptr;
bool pad_through = false;
VIA* via = NULL;
MARKER_PCB* marker = NULL;
ZONE_CONTAINER* zone = NULL;
VIA* via = nullptr;
MARKER_PCB* marker = nullptr;
ZONE_CONTAINER* zone = nullptr;
DRAWSEGMENT* drawSegment = nullptr;
#if 0 // debugging
static int breakhere = 0;
@ -275,6 +278,7 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
break;
case PCB_LINE_T:
drawSegment = static_cast<DRAWSEGMENT*>( item );
break;
case PCB_DIMENSION_T:
@ -325,6 +329,10 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
}
break;
case PCB_MODULE_EDGE_T:
drawSegment = static_cast<EDGE_MODULE*>( item );
break;
case PCB_MODULE_T:
module = static_cast<MODULE*>( item );
break;
@ -403,10 +411,11 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
{
if( !item->IsLocked() || !m_Guide->IgnoreLockedItems() )
{
int accuracy = KiROUND( 5 * m_Guide->OnePixelInIU() );
if( zone )
{
bool testFill = !m_Guide->IgnoreZoneFills();
int accuracy = KiROUND( 5 * m_Guide->OnePixelInIU() );
if( zone->HitTestForCorner( m_RefPos, accuracy * 2 )
|| zone->HitTestForEdge( m_RefPos, accuracy )
@ -416,9 +425,26 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
goto exit;
}
}
else if( item->HitTest( m_RefPos ) )
else if( item->Type() == PCB_MODULE_T )
{
if( !module || module->HitTestAccurate( m_RefPos ) )
if( module->HitTest( m_RefPos, accuracy )
&& module->HitTestAccurate( m_RefPos, accuracy ) )
{
Append( item );
goto exit;
}
}
else if( drawSegment )
{
if( drawSegment->HitTest( m_RefPos, accuracy ) )
{
Append( item );
goto exit;
}
}
else
{
if( item->HitTest( m_RefPos, 0 ) )
{
Append( item );
goto exit;
@ -449,10 +475,11 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
{
if( !item->IsLocked() || !m_Guide->IgnoreLockedItems() )
{
int accuracy = KiROUND( 5 * m_Guide->OnePixelInIU() );
if( zone )
{
bool testFill = !m_Guide->IgnoreZoneFills();
int accuracy = KiROUND( 5 * m_Guide->OnePixelInIU() );
if( zone->HitTestForCorner( m_RefPos, accuracy * 2 )
|| zone->HitTestForEdge( m_RefPos, accuracy )
@ -462,10 +489,30 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
goto exit;
}
}
else if( item->HitTest( m_RefPos ) )
else if( item->Type() == PCB_MODULE_T )
{
Append2nd( item );
goto exit;
if( module->HitTest( m_RefPos, accuracy )
&& module->HitTestAccurate( m_RefPos, accuracy ) )
{
Append( item );
goto exit;
}
}
else if( drawSegment )
{
if( drawSegment->HitTest( m_RefPos, accuracy ) )
{
Append( item );
goto exit;
}
}
else
{
if( item->HitTest( m_RefPos, 0 ) )
{
Append( item );
goto exit;
}
}
}
}

View File

@ -31,6 +31,7 @@ using namespace std::placeholders;
#include <class_board_item.h>
#include <class_track.h>
#include <class_module.h>
#include <class_edge_mod.h>
#include <class_drawsegment.h>
#include <class_zone.h>
#include <collectors.h>
@ -2046,6 +2047,44 @@ void SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector,
}
}
if( aCollector.CountType( PCB_MODULE_EDGE_T ) + aCollector.CountType( PCB_LINE_T ) > 1 )
{
// Prefer exact hits to sloppy ones
int accuracy = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
bool found = false;
for( int dist = 0; dist < accuracy; ++dist )
{
for( int i = 0; i < aCollector.GetCount(); ++i )
{
if( DRAWSEGMENT* drawSegment = dynamic_cast<DRAWSEGMENT*>( aCollector[i] ) )
{
if( drawSegment->HitTest( where, dist ) )
{
found = true;
break;
}
}
}
if( found )
{
// throw out everything that is more sloppy than what we found
for( int i = 0; i < aCollector.GetCount(); ++i )
{
if( DRAWSEGMENT* drawSegment = dynamic_cast<DRAWSEGMENT*>( aCollector[i] ) )
{
if( !drawSegment->HitTest( where, dist ) )
rejected.insert( drawSegment );
}
}
// we're done now
break;
}
}
}
if( aCollector.CountType( PCB_PAD_T ) > 0 )
{
for( int i = 0; i < aCollector.GetCount(); ++i )