Scale zone hit area by zoom.

Fixes: lp:1803362
* https://bugs.launchpad.net/kicad/+bug/1803362
This commit is contained in:
Jeff Young 2018-11-17 00:34:12 +00:00
parent 0de9cb345c
commit 208622699f
8 changed files with 101 additions and 53 deletions

View File

@ -651,16 +651,21 @@ void ZONE_CONTAINER::SetCornerRadius( unsigned int aRadius )
bool ZONE_CONTAINER::HitTest( const wxPoint& aPosition ) const
{
return HitTestForCorner( aPosition ) || HitTestForEdge( aPosition );
// Normally accuracy is zoom-relative, but for the generic HitTest we just use
// a fixed (small) value.
int accuracy = Millimeter2iu( 0.05 );
return HitTestForCorner( aPosition, accuracy * 2 ) || HitTestForEdge( aPosition, accuracy );
}
void ZONE_CONTAINER::SetSelectedCorner( const wxPoint& aPosition )
void ZONE_CONTAINER::SetSelectedCorner( const wxPoint& aPosition, int aAccuracy )
{
SHAPE_POLY_SET::VERTEX_INDEX corner;
// If there is some corner to be selected, assign it to m_CornerSelection
if( HitTestForCorner( aPosition, corner ) || HitTestForEdge( aPosition, corner ) )
if( HitTestForCorner( aPosition, aAccuracy * 2, corner )
|| HitTestForEdge( aPosition, aAccuracy, corner ) )
{
if( m_CornerSelection == nullptr )
m_CornerSelection = new SHAPE_POLY_SET::VERTEX_INDEX;
@ -669,40 +674,31 @@ void ZONE_CONTAINER::SetSelectedCorner( const wxPoint& aPosition )
}
}
// Zones outlines have no thickness, so it Hit Test functions
// we must have a default distance between the test point
// and a corner or a zone edge:
#define MAX_DIST_IN_MM 0.25
bool ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos,
bool ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos, int aAccuracy,
SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const
{
int distmax = Millimeter2iu( MAX_DIST_IN_MM );
return m_Poly->CollideVertex( VECTOR2I( refPos ), aCornerHit, distmax );
return m_Poly->CollideVertex( VECTOR2I( refPos ), aCornerHit, aAccuracy );
}
bool ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos ) const
bool ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos, int aAccuracy ) const
{
SHAPE_POLY_SET::VERTEX_INDEX dummy;
return HitTestForCorner( refPos, dummy );
return HitTestForCorner( refPos, aAccuracy, dummy );
}
bool ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos,
bool ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos, int aAccuracy,
SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const
{
int distmax = Millimeter2iu( MAX_DIST_IN_MM );
return m_Poly->CollideEdge( VECTOR2I( refPos ), aCornerHit, distmax );
return m_Poly->CollideEdge( VECTOR2I( refPos ), aCornerHit, aAccuracy );
}
bool ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos ) const
bool ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos, int aAccuracy ) const
{
SHAPE_POLY_SET::VERTEX_INDEX dummy;
return HitTestForEdge( refPos, dummy );
return HitTestForEdge( refPos, aAccuracy, dummy );
}

View File

@ -231,7 +231,7 @@ public:
///
// Like HitTest but selects the current corner to be operated on
void SetSelectedCorner( const wxPoint& aPosition );
void SetSelectedCorner( const wxPoint& aPosition, int aAccuracy );
int GetLocalFlags() const { return m_localFlgs; }
void SetLocalFlags( int aFlags ) { m_localFlgs = aFlags; }
@ -329,39 +329,45 @@ public:
* Function HitTestForCorner
* tests if the given wxPoint is near a corner.
* @param refPos is the wxPoint to test.
* @param aAccuracy increase the item bounding box by this amount.
* @param aCornerHit [out] is the index of the closest vertex found, useless when return
* value is false.
* @return bool - true if some corner was found to be closer to refPos than aClearance; false
* otherwise.
*/
bool HitTestForCorner( const wxPoint& refPos, SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const;
bool HitTestForCorner( const wxPoint& refPos, int aAccuracy,
SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const;
/**
* Function HitTestForCorner
* tests if the given wxPoint is near a corner.
* @param refPos is the wxPoint to test.
* @param aAccuracy increase the item bounding box by this amount.
* @return bool - true if some corner was found to be closer to refPos than aClearance; false
* otherwise.
*/
bool HitTestForCorner( const wxPoint& refPos ) const;
bool HitTestForCorner( const wxPoint& refPos, int aAccuracy ) const;
/**
* Function HitTestForEdge
* tests if the given wxPoint is near a segment defined by 2 corners.
* @param refPos is the wxPoint to test.
* @param aAccuracy increase the item bounding box by this amount.
* @param aCornerHit [out] is the index of the closest vertex found, useless when return
* value is false.
* @return bool - true if some edge was found to be closer to refPos than aClearance.
*/
bool HitTestForEdge( const wxPoint& refPos, SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const;
bool HitTestForEdge( const wxPoint& refPos, int aAccuracy,
SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const;
/**
* Function HitTestForEdge
* tests if the given wxPoint is near a segment defined by 2 corners.
* @param refPos is the wxPoint to test.
* @param aAccuracy increase the item bounding box by this amount.
* @return bool - true if some edge was found to be closer to refPos than aClearance.
*/
bool HitTestForEdge( const wxPoint& refPos ) const;
bool HitTestForEdge( const wxPoint& refPos, int aAccuracy ) const;
/** @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect,
* bool aContained = true, int aAccuracy ) const

View File

@ -393,12 +393,10 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
{
PCB_LAYER_ID layer = item->GetLayer();
/* Modules and their subcomponents: reference, value and pads
* are not sensitive to the layer visibility controls. They all
* have their own separate visibility controls for vias,
* GetLayer() has no meaning, but IsOnLayer() works fine. User
* text in module *is* sensitive to layer visibility but that
* was already handled */
// Modules and their subcomponents: reference, value and pads are not sensitive
// to the layer visibility controls. They all have their own separate visibility
// controls for vias, GetLayer() has no meaning, but IsOnLayer() works fine. User
// text in module *is* sensitive to layer visibility but that was already handled.
if( via || module || pad || m_Guide->IsLayerVisible( layer )
|| !m_Guide->IgnoreNonVisibleLayers() )
@ -407,13 +405,28 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
{
if( !item->IsLocked() || !m_Guide->IgnoreLockedItems() )
{
if( item->HitTest( m_RefPos ) )
if( zone )
{
if( !module || module->HitTestAccurate( m_RefPos ) )
bool testFill = !m_Guide->IgnoreZoneFills();
int accuracy = KiROUND( 5 * m_Guide->OnePixelInIU() );
if( zone->HitTestForCorner( m_RefPos, accuracy * 2 )
|| zone->HitTestForEdge( m_RefPos, accuracy )
|| ( testFill && zone->HitTestFilledArea( m_RefPos ) ) )
{
Append( item );
goto exit;
goto exit;
}
}
else if( zone && !m_Guide->IgnoreZoneFills() && zone->HitTestFilledArea( m_RefPos ) )
else if( module )
{
if( module->HitTest( m_RefPos ) && module->HitTestAccurate( m_RefPos ) )
{
Append( item );
goto exit;
}
}
else if( item->HitTest( m_RefPos ) )
{
Append( item );
goto exit;
@ -432,11 +445,10 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
PCB_LAYER_ID layer = item->GetLayer();
/* Modules and their subcomponents: reference, value and pads
* are not sensitive to the layer visibility controls. They all
* have their own separate visibility controls. User texts
* follows layer visibility controls (but that was already
* checked) */
// Modules and their subcomponents: reference, value and pads are not sensitive
// to the layer visibility controls. They all have their own separate visibility
// controls for vias, GetLayer() has no meaning, but IsOnLayer() works fine. User
// text in module *is* sensitive to layer visibility but that was already handled.
if( via || module || pad || m_Guide->IsLayerVisible( layer )
|| !m_Guide->IgnoreNonVisibleLayers() )
@ -445,16 +457,32 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
{
if( !item->IsLocked() || !m_Guide->IgnoreLockedItems() )
{
if( item->HitTest( m_RefPos ) )
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 )
|| ( testFill && zone->HitTestFilledArea( m_RefPos ) ) )
{
Append2nd( item );
goto exit;
}
}
else if( module )
{
if( module->HitTest( m_RefPos ) && module->HitTestAccurate( m_RefPos ) )
{
Append2nd( item );
goto exit;
}
}
else if( item->HitTest( m_RefPos ) )
{
Append2nd( item );
goto exit;
}
else if( zone && !m_Guide->IgnoreZoneFills() && zone->HitTestFilledArea( m_RefPos ) )
{
Append( item );
goto exit;
}
}
}
}

View File

@ -37,6 +37,7 @@
#include <collector.h>
#include <layers_id_colors_and_visibility.h> // LAYER_COUNT, layer defs
#include <view/view.h>
class BOARD_ITEM;
@ -193,6 +194,8 @@ public:
*/
virtual bool IgnoreZoneFills() const = 0;
virtual double OnePixelInIU() const = 0;
/**
* @return bool - true if Inspect() should use BOARD_ITEM::HitTest()
* or false if Inspect() should use BOARD_ITEM::BoundsTest().
@ -346,6 +349,8 @@ public:
*/
void SetGuide( const COLLECTORS_GUIDE* aGuide ) { m_Guide = aGuide; }
const COLLECTORS_GUIDE* GetGuide() { return m_Guide; }
/**
* @return int - The number if items which met the primary search criteria
*/
@ -417,6 +422,8 @@ private:
bool m_IgnoreTracks;
bool m_IgnoreZoneFills;
double m_OnePixelInIU;
public:
/**
@ -427,8 +434,11 @@ public:
* @param aVisibleLayerMask = current visible layers (bit mask)
* @param aPreferredLayer = the layer to search first
*/
GENERAL_COLLECTORS_GUIDE( LSET aVisibleLayerMask, PCB_LAYER_ID aPreferredLayer )
GENERAL_COLLECTORS_GUIDE( LSET aVisibleLayerMask, PCB_LAYER_ID aPreferredLayer,
KIGFX::VIEW* aView )
{
VECTOR2I one( 1, 1 );
m_PreferredLayer = aPreferredLayer;
m_IgnorePreferredLayer = false;
m_LayerVisible = aVisibleLayerMask;
@ -460,6 +470,8 @@ public:
m_IgnoreMicroVias = false;
m_IgnoreTracks = false;
m_IgnoreZoneFills = true;
m_OnePixelInIU = aView->ToWorld( one, false ).x;
}
/**
@ -602,6 +614,8 @@ public:
bool IgnoreZoneFills() const override { return m_IgnoreZoneFills; }
void SetIgnoreZoneFills( bool ignore ) { m_IgnoreZoneFills = ignore; }
double OnePixelInIU() const override { return m_OnePixelInIU; }
};

View File

@ -188,7 +188,8 @@ BOARD_ITEM* PCB_BASE_FRAME::PcbGeneralLocateAndDisplay( int aHotKeyCode )
/* We need to do the selection now because the menu text
* depends on it */
ZONE_CONTAINER *zone = static_cast<ZONE_CONTAINER*>( item );
zone->SetSelectedCorner( RefPos( true ) );
int accuracy = KiROUND( 5 * guide.OnePixelInIU() );
zone->SetSelectedCorner( RefPos( true ), accuracy );
}
break;

View File

@ -628,6 +628,7 @@ void PCB_EDIT_FRAME::createPopupMenuForTracks( TRACK* Track, wxMenu* PopMenu )
void PCB_EDIT_FRAME::createPopUpMenuForZones( ZONE_CONTAINER* edge_zone, wxMenu* aPopMenu )
{
wxString msg;
GENERAL_COLLECTORS_GUIDE guide = GetCollectorsGuide();
if( edge_zone->GetFlags() == IS_DRAGGED )
{
@ -646,19 +647,20 @@ void PCB_EDIT_FRAME::createPopUpMenuForZones( ZONE_CONTAINER* edge_zone, wxMenu*
else
{
wxMenu* zones_menu = new wxMenu();
int accuracy = KiROUND( 5 * guide.OnePixelInIU() );
AddMenuItem( aPopMenu, zones_menu, -1,
edge_zone->GetIsKeepout() ? _("Keepout Area") : _( "Zones" ),
KiBitmap( add_zone_xpm ) );
if( edge_zone->HitTestForCorner( RefPos( true ) ) )
if( edge_zone->HitTestForCorner( RefPos( true ), accuracy * 2 ) )
{
AddMenuItem( zones_menu, ID_POPUP_PCB_MOVE_ZONE_CORNER,
_( "Move" ), KiBitmap( move_xpm ) );
AddMenuItem( zones_menu, ID_POPUP_PCB_DELETE_ZONE_CORNER,
_( "Delete" ), KiBitmap( delete_xpm ) );
}
else if( edge_zone->HitTestForEdge( RefPos( true ) ) )
else if( edge_zone->HitTestForEdge( RefPos( true ), accuracy ) )
{
AddMenuItem( zones_menu, ID_POPUP_PCB_ADD_ZONE_CORNER,
_( "Create Corner" ), KiBitmap( add_corner_xpm ) );

View File

@ -760,7 +760,8 @@ BOARD_ITEM* PCB_BASE_FRAME::GetCurItem()
GENERAL_COLLECTORS_GUIDE PCB_BASE_FRAME::GetCollectorsGuide()
{
GENERAL_COLLECTORS_GUIDE guide( m_Pcb->GetVisibleLayers(), GetActiveLayer() );
GENERAL_COLLECTORS_GUIDE guide( m_Pcb->GetVisibleLayers(), GetActiveLayer(),
GetGalCanvas()->GetView() );
// account for the globals
guide.SetIgnoreMTextsMarkedNoShow( ! m_Pcb->IsElementVisible( LAYER_MOD_TEXT_INVISIBLE ) );

View File

@ -459,7 +459,7 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem )
const GENERAL_COLLECTORS_GUIDE SELECTION_TOOL::getCollectorsGuide() const
{
GENERAL_COLLECTORS_GUIDE guide( board()->GetVisibleLayers(),
(PCB_LAYER_ID) view()->GetTopLayer() );
(PCB_LAYER_ID) view()->GetTopLayer(), view() );
// account for the globals
guide.SetIgnoreMTextsMarkedNoShow( ! board()->IsElementVisible( LAYER_MOD_TEXT_INVISIBLE ) );
@ -2036,7 +2036,7 @@ void SELECTION_TOOL::guessSelectionCandidates( GENERAL_COLLECTOR& aCollector,
{
auto zone = static_cast<ZONE_CONTAINER*>( aCollector[i] );
if( zone->HitTestForEdge( where ) )
if( zone->HitTestForEdge( where, 5 * aCollector.GetGuide()->OnePixelInIU() ) )
preferred.insert( zone );
else
rejected.insert( zone );