From cf88b9aaecc84fdfc1398963c9e7ab8442a51933 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Thu, 17 Feb 2022 15:22:18 -0800 Subject: [PATCH] Maintain connectivity while cleaning tracks/vias When merging segments that loop back on each other, we need to merge them in such a way to to keep the resulting endpoints connected to the original adjoining endpoints Fixes https://gitlab.com/kicad/code/kicad/issues/10780 (cherry picked from commit 8e9d44942f54e2771c364f823b8bbb104ecb328e) --- pcbnew/tracks_cleaner.cpp | 57 +++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/pcbnew/tracks_cleaner.cpp b/pcbnew/tracks_cleaner.cpp index 7ced9cc5ff..a17e8377cb 100644 --- a/pcbnew/tracks_cleaner.cpp +++ b/pcbnew/tracks_cleaner.cpp @@ -464,7 +464,40 @@ bool TRACKS_CLEANER::mergeCollinearSegments( PCB_TRACK* aSeg1, PCB_TRACK* aSeg2 if( aSeg1->IsLocked() || aSeg2->IsLocked() ) return false; - auto connectivity = m_brd->GetConnectivity(); + std::shared_ptr connectivity = m_brd->GetConnectivity(); + + std::vector tracks = connectivity->GetConnectedTracks( aSeg1 ); + std::vector tracks2 = connectivity->GetConnectedTracks( aSeg2 ); + + std::move( tracks2.begin(), tracks2.end(), std::back_inserter( tracks ) ); + + tracks.erase( + std::remove_if( tracks.begin(), tracks.end(), [ aSeg1, aSeg2 ]( PCB_TRACK* aTest ) + { + return ( aTest == aSeg1 ) || ( aTest == aSeg2 ); + } ), tracks.end() ); + + std::set pts; + + // Collect the unique points where the two tracks are connected to others + for( PCB_TRACK* track : tracks ) + { + if( track->IsPointOnEnds( aSeg1->GetStart() ) ) + pts.emplace( aSeg1->GetStart() ); + + if( track->IsPointOnEnds( aSeg1->GetEnd() ) ) + pts.emplace( aSeg1->GetEnd() ); + + if( track->IsPointOnEnds( aSeg2->GetStart() ) ) + pts.emplace( aSeg2->GetStart() ); + + if( track->IsPointOnEnds( aSeg2->GetEnd() ) ) + pts.emplace( aSeg2->GetEnd() ); + } + + // This means there is a node in the center + if( pts.size() > 2 ) + return false; // Verify the removed point after merging is not a node. // If it is a node (i.e. if more than one other item is connected, the segments cannot be merged @@ -492,17 +525,19 @@ bool TRACKS_CLEANER::mergeCollinearSegments( PCB_TRACK* aSeg1, PCB_TRACK* aSeg2 dummy_seg.SetEnd( VECTOR2I( max_x, min_y ) ); } - // Now find the removed end(s) and stop merging if it is a node: - if( aSeg1->GetStart() != dummy_seg.GetStart() && aSeg1->GetStart() != dummy_seg.GetEnd() ) + // If the existing connected points are not the same as the points generated by our + // min/max alg, then assign the missing points to the end closest. This ensures that + // our replacment track is still connected + for( auto pt : pts ) { - if( testTrackEndpointIsNode( aSeg1, true ) ) - return false; - } - - if( aSeg1->GetEnd() != dummy_seg.GetStart() && aSeg1->GetEnd() != dummy_seg.GetEnd() ) - { - if( testTrackEndpointIsNode( aSeg1, false ) ) - return false; + if( !dummy_seg.IsPointOnEnds( wxPoint( pt.x, pt.y ) ) ) + { + if( ( VECTOR2I( dummy_seg.GetStart() ) - pt ).SquaredEuclideanNorm() < + ( VECTOR2I( dummy_seg.GetEnd() ) - pt ).SquaredEuclideanNorm() ) + dummy_seg.SetStart( wxPoint( pt.x, pt.y ) ); + else + dummy_seg.SetEnd( wxPoint( pt.x, pt.y ) ); + } } std::shared_ptr item = std::make_shared( CLEANUP_MERGE_TRACKS );