diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 77ac35cdb5..7823e1d985 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -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 ); } diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 030ca68fac..69bbc5a28b 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -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 diff --git a/pcbnew/collectors.cpp b/pcbnew/collectors.cpp index fbd0879747..040191cb54 100644 --- a/pcbnew/collectors.cpp +++ b/pcbnew/collectors.cpp @@ -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; - } } } } diff --git a/pcbnew/collectors.h b/pcbnew/collectors.h index a5a2ec6008..c2b8ae18e6 100644 --- a/pcbnew/collectors.h +++ b/pcbnew/collectors.h @@ -37,6 +37,7 @@ #include #include // LAYER_COUNT, layer defs +#include 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; } }; diff --git a/pcbnew/controle.cpp b/pcbnew/controle.cpp index c8220d4704..fdda966c0e 100644 --- a/pcbnew/controle.cpp +++ b/pcbnew/controle.cpp @@ -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( item ); - zone->SetSelectedCorner( RefPos( true ) ); + int accuracy = KiROUND( 5 * guide.OnePixelInIU() ); + zone->SetSelectedCorner( RefPos( true ), accuracy ); } break; diff --git a/pcbnew/onrightclick.cpp b/pcbnew/onrightclick.cpp index ac73282081..0284cbe55a 100644 --- a/pcbnew/onrightclick.cpp +++ b/pcbnew/onrightclick.cpp @@ -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 ) ); diff --git a/pcbnew/pcb_base_frame.cpp b/pcbnew/pcb_base_frame.cpp index cb077a2e51..f6342d1e01 100644 --- a/pcbnew/pcb_base_frame.cpp +++ b/pcbnew/pcb_base_frame.cpp @@ -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 ) ); diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index a679870447..728fb03905 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -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( aCollector[i] ); - if( zone->HitTestForEdge( where ) ) + if( zone->HitTestForEdge( where, 5 * aCollector.GetGuide()->OnePixelInIU() ) ) preferred.insert( zone ); else rejected.insert( zone );