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
This commit is contained in:
Seth Hillbrand 2022-02-17 15:22:18 -08:00
parent 8b1f1c0296
commit 8e9d44942f
1 changed files with 46 additions and 11 deletions

View File

@ -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_DATA> connectivity = m_brd->GetConnectivity();
std::vector<PCB_TRACK*> tracks = connectivity->GetConnectedTracks( aSeg1 );
std::vector<PCB_TRACK*> 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<VECTOR2I> 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( wxPoint( 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<CLEANUP_ITEM> item = std::make_shared<CLEANUP_ITEM>( CLEANUP_MERGE_TRACKS );