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 8e9d44942f
)
This commit is contained in:
parent
944fe9637d
commit
cf88b9aaec
|
@ -464,7 +464,40 @@ bool TRACKS_CLEANER::mergeCollinearSegments( PCB_TRACK* aSeg1, PCB_TRACK* aSeg2
|
||||||
if( aSeg1->IsLocked() || aSeg2->IsLocked() )
|
if( aSeg1->IsLocked() || aSeg2->IsLocked() )
|
||||||
return false;
|
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.
|
// 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
|
// 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 ) );
|
dummy_seg.SetEnd( VECTOR2I( max_x, min_y ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now find the removed end(s) and stop merging if it is a node:
|
// If the existing connected points are not the same as the points generated by our
|
||||||
if( aSeg1->GetStart() != dummy_seg.GetStart() && aSeg1->GetStart() != dummy_seg.GetEnd() )
|
// 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 ) )
|
if( !dummy_seg.IsPointOnEnds( wxPoint( pt.x, pt.y ) ) )
|
||||||
return false;
|
{
|
||||||
|
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 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aSeg1->GetEnd() != dummy_seg.GetStart() && aSeg1->GetEnd() != dummy_seg.GetEnd() )
|
|
||||||
{
|
|
||||||
if( testTrackEndpointIsNode( aSeg1, false ) )
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<CLEANUP_ITEM> item = std::make_shared<CLEANUP_ITEM>( CLEANUP_MERGE_TRACKS );
|
std::shared_ptr<CLEANUP_ITEM> item = std::make_shared<CLEANUP_ITEM>( CLEANUP_MERGE_TRACKS );
|
||||||
|
|
Loading…
Reference in New Issue