From 8a0be64ad437647e21d46d2328caf579fb462677 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Wed, 5 Aug 2020 13:15:27 -0700 Subject: [PATCH] Ensure dangling test takes track width into account When running a hit test to check if the anchors are connected, we should loosen the check for tracks to account for the width. Otherwise connected anchors can be connected in the system but test positive for IsDangling() Fixes https://gitlab.com/kicad/code/kicad/issues/5027 --- pcbnew/class_zone.cpp | 10 ++++++---- pcbnew/class_zone.h | 5 +++-- pcbnew/connectivity/connectivity_data.cpp | 4 +++- pcbnew/connectivity/connectivity_data.h | 2 +- pcbnew/connectivity/connectivity_items.cpp | 9 +++++++-- pcbnew/tracks_cleaner.cpp | 3 +-- 6 files changed, 21 insertions(+), 12 deletions(-) diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index d9fca60ad7..ea3a13e01f 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck - * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -528,17 +528,19 @@ int ZONE_CONTAINER::GetLocalClearance( wxString* aSource ) const } -bool ZONE_CONTAINER::HitTestFilledArea( PCB_LAYER_ID aLayer, const wxPoint& aRefPos ) const +bool ZONE_CONTAINER::HitTestFilledArea( PCB_LAYER_ID aLayer, const wxPoint &aRefPos, + int aAccuracy ) const { // Keepouts have no filled area, but it's generally nice to treat their interior as if it were // filled so that people don't have to select keepouts by their outline (which is min-width) if( GetIsKeepout() ) - return m_Poly->Contains( VECTOR2I( aRefPos.x, aRefPos.y ) ); + return m_Poly->Contains( VECTOR2I( aRefPos.x, aRefPos.y ), -1, aAccuracy ); if( !m_FilledPolysList.count( aLayer ) ) return false; - return m_FilledPolysList.at( aLayer ).Contains( VECTOR2I( aRefPos.x, aRefPos.y ) ); + return m_FilledPolysList.at( aLayer ).Contains( VECTOR2I( aRefPos.x, aRefPos.y ), -1, + aAccuracy ); } diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index c95eef94c5..d2a5c1e614 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -291,9 +291,10 @@ public: * tests if the given wxPoint is within the bounds of a filled area of this zone. * @param aLayer is the layer to test on * @param aRefPos A wxPoint to test + * @param aAccuracy Expand the distance by which the areas are expanded for the hittest * @return bool - true if a hit, else false */ - bool HitTestFilledArea( PCB_LAYER_ID aLayer, const wxPoint& aRefPos ) const; + bool HitTestFilledArea( PCB_LAYER_ID aLayer, const wxPoint &aRefPos, int aAccuracy = 0 ) const; /** * Tests if the given point is contained within a cutout of the zone. diff --git a/pcbnew/connectivity/connectivity_data.cpp b/pcbnew/connectivity/connectivity_data.cpp index 0279085698..f613c4cc0a 100644 --- a/pcbnew/connectivity/connectivity_data.cpp +++ b/pcbnew/connectivity/connectivity_data.cpp @@ -560,7 +560,9 @@ bool CONNECTIVITY_DATA::TestTrackEndpointDangling( TRACK* aTrack, wxPoint* aPos { if( anchor->IsDangling() ) { - *aPos = (wxPoint) anchor->Pos(); + if( aPos ) + *aPos = static_cast( anchor->Pos() ); + return true; } } diff --git a/pcbnew/connectivity/connectivity_data.h b/pcbnew/connectivity/connectivity_data.h index eec8404ecf..3e3f3f4a79 100644 --- a/pcbnew/connectivity/connectivity_data.h +++ b/pcbnew/connectivity/connectivity_data.h @@ -187,7 +187,7 @@ public: void GetUnconnectedEdges( std::vector& aEdges ) const; - bool TestTrackEndpointDangling( TRACK* aTrack, wxPoint* aPos ); + bool TestTrackEndpointDangling( TRACK* aTrack, wxPoint* aPos = nullptr ); /** * Function ClearDynamicRatsnest() diff --git a/pcbnew/connectivity/connectivity_items.cpp b/pcbnew/connectivity/connectivity_items.cpp index d7337bf19b..bc96d1ad50 100644 --- a/pcbnew/connectivity/connectivity_items.cpp +++ b/pcbnew/connectivity/connectivity_items.cpp @@ -340,6 +340,8 @@ bool CN_ANCHOR::Valid() const bool CN_ANCHOR::IsDangling() const { + int accuracy = 0; + if( !m_cluster ) return true; @@ -355,6 +357,9 @@ bool CN_ANCHOR::IsDangling() const if( m_item->AnchorCount() == 1 ) return connected_count < minimal_count; + if( Parent()->Type() == PCB_TRACE_T || Parent()->Type() == PCB_ARC_T ) + accuracy = ( static_cast( Parent() )->GetWidth() + 1 )/ 2; + // Items with multiple anchors have usually items connected to each anchor. // We want only the item count of this anchor point connected_count = 0; @@ -365,10 +370,10 @@ bool CN_ANCHOR::IsDangling() const ZONE_CONTAINER* zone = static_cast( item->Parent() ); if( zone->HitTestFilledArea( static_cast( item->Layer() ), - static_cast( Pos() ) ) ) + wxPoint( Pos() ), accuracy ) ) connected_count++; } - else if( item->Parent()->HitTest( (wxPoint) Pos() ) ) + else if( item->Parent()->HitTest( wxPoint( Pos() ), accuracy ) ) connected_count++; } diff --git a/pcbnew/tracks_cleaner.cpp b/pcbnew/tracks_cleaner.cpp index 92d72e5ab8..711b29433a 100644 --- a/pcbnew/tracks_cleaner.cpp +++ b/pcbnew/tracks_cleaner.cpp @@ -252,7 +252,6 @@ bool TRACKS_CLEANER::deleteDanglingTracks( bool aVia ) for( TRACK* track : temp_tracks ) { bool flag_erase = false; // Start without a good reason to erase it - wxPoint pos; if( aVia && track->Type() != PCB_VIA_T ) continue; @@ -260,7 +259,7 @@ bool TRACKS_CLEANER::deleteDanglingTracks( bool aVia ) continue; // Tst if a track (or a via) endpoint is not connected to another track or to a zone. - if( m_brd->GetConnectivity()->TestTrackEndpointDangling( track, &pos ) ) + if( m_brd->GetConnectivity()->TestTrackEndpointDangling( track ) ) flag_erase = true; if( flag_erase )