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