Scale zone hit area by zoom.
Fixes: lp:1803362 * https://bugs.launchpad.net/kicad/+bug/1803362
This commit is contained in:
parent
0de9cb345c
commit
208622699f
|
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 ) );
|
||||
|
|
|
@ -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 ) );
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue