eeschema: Ensure all wires are joined

When running the cleanup routine, we should check that we haven't
changed our lines during the process.  If we have, we run again to pick
up the new merges

Fixes https://gitlab.com/kicad/code/kicad/issues/5265
This commit is contained in:
Seth Hillbrand 2020-08-20 06:48:01 -07:00
parent 2deefdd9ce
commit ee5c991d2f
1 changed files with 54 additions and 46 deletions

View File

@ -147,12 +147,14 @@ bool SCH_EDIT_FRAME::SchematicCleanUp( SCH_SCREEN* aScreen )
std::vector<SCH_LINE*> lines; std::vector<SCH_LINE*> lines;
std::vector<SCH_JUNCTION*> junctions; std::vector<SCH_JUNCTION*> junctions;
std::vector<SCH_NO_CONNECT*> ncs; std::vector<SCH_NO_CONNECT*> ncs;
bool changed = true;
if( aScreen == nullptr ) if( aScreen == nullptr )
aScreen = GetScreen(); aScreen = GetScreen();
auto remove_item = [&itemList, &deletedItems, &aScreen]( SCH_ITEM* aItem ) -> void auto remove_item = [&]( SCH_ITEM* aItem ) -> void
{ {
changed = true;
aItem->SetFlags( STRUCT_DELETED ); aItem->SetFlags( STRUCT_DELETED );
itemList.PushItem( ITEM_PICKER( aScreen, aItem, UR_DELETED ) ); itemList.PushItem( ITEM_PICKER( aScreen, aItem, UR_DELETED ) );
deletedItems.push_back( aItem ); deletedItems.push_back( aItem );
@ -160,12 +162,6 @@ bool SCH_EDIT_FRAME::SchematicCleanUp( SCH_SCREEN* aScreen )
BreakSegmentsOnJunctions( aScreen ); BreakSegmentsOnJunctions( aScreen );
for( SCH_ITEM* item : aScreen->Items().OfType( SCH_LINE_T ) )
{
if( item->GetLayer() == LAYER_WIRE || item->GetLayer() == LAYER_BUS )
lines.push_back( static_cast<SCH_LINE*>( item ) );
}
for( SCH_ITEM* item : aScreen->Items().OfType( SCH_JUNCTION_T ) ) for( SCH_ITEM* item : aScreen->Items().OfType( SCH_JUNCTION_T ) )
{ {
if( !aScreen->IsJunctionNeeded( item->GetPosition() ) ) if( !aScreen->IsJunctionNeeded( item->GetPosition() ) )
@ -205,67 +201,79 @@ bool SCH_EDIT_FRAME::SchematicCleanUp( SCH_SCREEN* aScreen )
remove_item( aSecond ); remove_item( aSecond );
} ); } );
for( auto it1 = lines.begin(); it1 != lines.end(); ++it1 )
while( changed )
{ {
SCH_LINE* firstLine = *it1; changed = false;
lines.clear();
if( firstLine->GetEditFlags() & STRUCT_DELETED ) for( SCH_ITEM* item : aScreen->Items().OfType( SCH_LINE_T ) )
continue;
if( firstLine->IsNull() )
{ {
remove_item( firstLine ); if( item->GetLayer() == LAYER_WIRE || item->GetLayer() == LAYER_BUS )
continue; lines.push_back( static_cast<SCH_LINE*>( item ) );
} }
auto it2 = it1; for( auto it1 = lines.begin(); it1 != lines.end(); ++it1 )
for( ++it2; it2 != lines.end(); ++it2 )
{ {
SCH_LINE* secondLine = *it2; SCH_LINE* firstLine = *it1;
bool needed = false;
if( secondLine->GetFlags() & STRUCT_DELETED ) if( firstLine->GetEditFlags() & STRUCT_DELETED )
continue; continue;
if( !secondLine->IsParallel( firstLine ) if( firstLine->IsNull() )
|| secondLine->GetStroke() != firstLine->GetStroke()
|| secondLine->GetLayer() != firstLine->GetLayer() )
continue;
// Remove identical lines
if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
&& firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
{ {
remove_item( secondLine ); remove_item( firstLine );
continue; continue;
} }
// If the end points overlap, check if we still need the junction auto it2 = it1;
if( secondLine->IsEndPoint( firstLine->GetStartPoint() ) )
needed = aScreen->IsJunctionNeeded( firstLine->GetStartPoint() );
else if( secondLine->IsEndPoint( firstLine->GetEndPoint() ) )
needed = aScreen->IsJunctionNeeded( firstLine->GetEndPoint() );
SCH_LINE* mergedLine = nullptr; for( ++it2; it2 != lines.end(); ++it2 )
if( !needed && ( mergedLine = secondLine->MergeOverlap( firstLine ) ) )
{ {
remove_item( firstLine ); SCH_LINE* secondLine = *it2;
remove_item( secondLine ); bool needed = false;
itemList.PushItem( ITEM_PICKER( aScreen, mergedLine, UR_NEW ) );
AddToScreen( mergedLine, aScreen ); if( secondLine->GetFlags() & STRUCT_DELETED )
continue;
if( firstLine->IsSelected() ) if( !secondLine->IsParallel( firstLine )
selectionTool->AddItemToSel( mergedLine, true /*quiet mode*/ ); || secondLine->GetStroke() != firstLine->GetStroke()
|| secondLine->GetLayer() != firstLine->GetLayer() )
continue;
break; // Remove identical lines
if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
&& firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
{
remove_item( secondLine );
continue;
}
// If the end points overlap, check if we still need the junction
if( secondLine->IsEndPoint( firstLine->GetStartPoint() ) )
needed = aScreen->IsJunctionNeeded( firstLine->GetStartPoint() );
else if( secondLine->IsEndPoint( firstLine->GetEndPoint() ) )
needed = aScreen->IsJunctionNeeded( firstLine->GetEndPoint() );
SCH_LINE* mergedLine = nullptr;
if( !needed && ( mergedLine = secondLine->MergeOverlap( firstLine ) ) )
{
remove_item( firstLine );
remove_item( secondLine );
itemList.PushItem( ITEM_PICKER( aScreen, mergedLine, UR_NEW ) );
AddToScreen( mergedLine, aScreen );
if( firstLine->IsSelected() )
selectionTool->AddItemToSel( mergedLine, true /*quiet mode*/ );
break;
}
} }
} }
} }
for( auto item : deletedItems ) for( auto item : deletedItems )
{ {
if( item->IsSelected() ) if( item->IsSelected() )