From 14378812be91f1d4267446aa281ee08b002c01f3 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sun, 13 Mar 2022 15:53:34 +0000 Subject: [PATCH] Improved performance for Cleanup Tracks & Vias. --- pcbnew/tracks_cleaner.cpp | 53 ++++++++++++++++++++++++++------------- pcbnew/tracks_cleaner.h | 3 ++- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/pcbnew/tracks_cleaner.cpp b/pcbnew/tracks_cleaner.cpp index c4b7f379af..178c67d04e 100644 --- a/pcbnew/tracks_cleaner.cpp +++ b/pcbnew/tracks_cleaner.cpp @@ -270,6 +270,7 @@ void TRACKS_CLEANER::deleteTracksInPads() void TRACKS_CLEANER::cleanup( bool aDeleteDuplicateVias, bool aDeleteNullSegments, bool aDeleteDuplicateSegments, bool aMergeSegments ) { + KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T, PCB_ZONE_T }; DRC_RTREE rtree; for( PCB_TRACK* track : m_brd->Tracks() ) @@ -410,12 +411,17 @@ void TRACKS_CLEANER::cleanup( bool aDeleteDuplicateVias, bool aDeleteNullSegment // merge collinear segments: for( PCB_TRACK* segment : temp_segments ) { - if( segment->Type() != PCB_TRACE_T ) // one can merge only track collinear segments, not vias. + // one can merge only collinear segments, not vias or arcs. + if( segment->Type() != PCB_TRACE_T ) continue; - if( segment->HasFlag( IS_DELETED ) ) // already taken in account + if( segment->HasFlag( IS_DELETED ) ) // already taken into account continue; + std::vector connectedItems = + m_brd->GetConnectivity()->GetConnectedItems( segment, types ); + + // for each end of the segment: for( CN_ITEM* citem : connectivity->ItemEntry( segment ).GetItems() ) { // Do not merge an end which has different width tracks attached -- it's a @@ -428,25 +434,34 @@ void TRACKS_CLEANER::cleanup( bool aDeleteDuplicateVias, bool aDeleteNullSegment if( !connected->Valid() ) continue; - BOARD_CONNECTED_ITEM* candidateItem = connected->Parent(); + BOARD_CONNECTED_ITEM* candidate = connected->Parent(); - if( candidateItem->Type() == PCB_TRACE_T && !candidateItem->HasFlag( IS_DELETED ) ) + if( candidate->Type() == PCB_TRACE_T && !candidate->HasFlag( IS_DELETED ) ) { - PCB_TRACK* candidateSegment = static_cast( candidateItem ); + PCB_TRACK* candidateSegment = static_cast( candidate ); if( candidateSegment->GetWidth() == segment->GetWidth() ) + { sameWidthCandidates.push_back( candidateSegment ); + } else + { differentWidthCandidates.push_back( candidateSegment ); + break; + } } } - if( differentWidthCandidates.size() == 0 ) + if( !differentWidthCandidates.empty() ) + continue; + + for( PCB_TRACK* candidate : sameWidthCandidates ) { - for( PCB_TRACK* candidate : sameWidthCandidates ) + if( segment->ApproxCollinear( *candidate ) + && mergeCollinearSegments( segment, candidate, connectedItems ) ) { - if( segment->ApproxCollinear( *candidate ) ) - merged |= mergeCollinearSegments( segment, candidate ); + merged = true; + break; } } } @@ -459,27 +474,29 @@ void TRACKS_CLEANER::cleanup( bool aDeleteDuplicateVias, bool aDeleteNullSegment } -bool TRACKS_CLEANER::mergeCollinearSegments( PCB_TRACK* aSeg1, PCB_TRACK* aSeg2 ) +bool TRACKS_CLEANER::mergeCollinearSegments( PCB_TRACK* aSeg1, PCB_TRACK* aSeg2, + const std::vector& aSeg1Items ) { - KICAD_T items[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T, PCB_ZONE_T }; + static KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T, PCB_ZONE_T }; if( aSeg1->IsLocked() || aSeg2->IsLocked() ) return false; std::shared_ptr connectivity = m_brd->GetConnectivity(); - std::vector tracks = connectivity->GetConnectedItems( aSeg1, items ); - std::vector tracks2 = connectivity->GetConnectedItems( aSeg2, items ); + std::vector tracks = aSeg1Items; + std::vector tracks2 = connectivity->GetConnectedItems( aSeg2, types ); std::move( tracks2.begin(), tracks2.end(), std::back_inserter( tracks ) ); std::sort( tracks.begin(), tracks.end() ); tracks.erase( std::unique( tracks.begin(), tracks.end() ), tracks.end() ); - tracks.erase( - std::remove_if( tracks.begin(), tracks.end(), [ aSeg1, aSeg2 ]( BOARD_CONNECTED_ITEM* aTest ) - { - return ( aTest == aSeg1 ) || ( aTest == aSeg2 ); - } ), tracks.end() ); + tracks.erase( std::remove_if( tracks.begin(), tracks.end(), + [ aSeg1, aSeg2 ]( BOARD_CONNECTED_ITEM* aTest ) + { + return ( aTest == aSeg1 ) || ( aTest == aSeg2 ); + } ), + tracks.end() ); std::set pts; diff --git a/pcbnew/tracks_cleaner.h b/pcbnew/tracks_cleaner.h index 31d007ad8c..59110e4dbc 100644 --- a/pcbnew/tracks_cleaner.h +++ b/pcbnew/tracks_cleaner.h @@ -81,7 +81,8 @@ private: * @param aSeg1 is the reference * @param aSeg2 is the candidate, and after merging, the removed segment */ - bool mergeCollinearSegments( PCB_TRACK* aSeg1, PCB_TRACK* aSeg2 ); + bool mergeCollinearSegments( PCB_TRACK* aSeg1, PCB_TRACK* aSeg2, + const std::vector& aSeg1Items ); /** * @return true if a track end position is a node, i.e. a end connected