Eeschema: Automatically manage junctions
CHANGE: eeschema automatically adds and removes junctions when required by the schematic Fixes: lp:593888 * https://bugs.launchpad.net/kicad/+bug/593888 Fixes: lp:1482111 * https://bugs.launchpad.net/kicad/+bug/1482111 Fixes: lp:1563153 * https://bugs.launchpad.net/kicad/+bug/1563153 Fixes: lp:1730219 * https://bugs.launchpad.net/kicad/+bug/1730219 Fixes: lp:1491052 * https://bugs.launchpad.net/kicad/+bug/1491052
This commit is contained in:
parent
b5ec5f9a73
commit
069448f20e
|
@ -127,9 +127,8 @@ void SCH_EDIT_FRAME::HandleBlockPlace( wxDC* DC )
|
|||
if( m_canvas->IsMouseCaptured() )
|
||||
m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
|
||||
|
||||
SaveCopyInUndoList( block->GetItems(), UR_MOVED, false, block->GetMoveVector() );
|
||||
SaveCopyInUndoList( block->GetItems(), UR_CHANGED, false, block->GetMoveVector() );
|
||||
MoveItemsInList( block->GetItems(), block->GetMoveVector() );
|
||||
block->ClearItemsList();
|
||||
break;
|
||||
|
||||
case BLOCK_DUPLICATE: /* Duplicate */
|
||||
|
@ -141,8 +140,6 @@ void SCH_EDIT_FRAME::HandleBlockPlace( wxDC* DC )
|
|||
|
||||
SaveCopyInUndoList( block->GetItems(),
|
||||
( block->GetCommand() == BLOCK_PRESELECT_MOVE ) ? UR_CHANGED : UR_NEW );
|
||||
|
||||
block->ClearItemsList();
|
||||
break;
|
||||
|
||||
case BLOCK_PASTE:
|
||||
|
@ -150,13 +147,15 @@ void SCH_EDIT_FRAME::HandleBlockPlace( wxDC* DC )
|
|||
m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
|
||||
|
||||
PasteListOfItems( DC );
|
||||
block->ClearItemsList();
|
||||
break;
|
||||
|
||||
default: // others are handled by HandleBlockEnd()
|
||||
break;
|
||||
}
|
||||
|
||||
CheckJunctionsInList( block->GetItems(), true );
|
||||
block->ClearItemsList();
|
||||
SchematicCleanUp( true );
|
||||
OnModify();
|
||||
|
||||
// clear dome flags and pointers
|
||||
|
@ -218,6 +217,8 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC )
|
|||
SetCrossHairPosition( rotationPoint );
|
||||
SaveCopyInUndoList( block->GetItems(), UR_ROTATED, false, rotationPoint );
|
||||
RotateListOfItems( block->GetItems(), rotationPoint );
|
||||
CheckJunctionsInList( block->GetItems(), true );
|
||||
SchematicCleanUp( true );
|
||||
OnModify();
|
||||
}
|
||||
|
||||
|
@ -270,6 +271,7 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC )
|
|||
if( block->GetCount() )
|
||||
{
|
||||
DeleteItemsInList( block->GetItems() );
|
||||
SchematicCleanUp( true );
|
||||
OnModify();
|
||||
}
|
||||
block->ClearItemsList();
|
||||
|
@ -301,6 +303,7 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC )
|
|||
copyBlockItems( block->GetItems() );
|
||||
MoveItemsInList( m_blockItems.GetItems(), move_vector );
|
||||
DeleteItemsInList( block->GetItems() );
|
||||
SchematicCleanUp( true );
|
||||
OnModify();
|
||||
}
|
||||
|
||||
|
@ -329,6 +332,7 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC )
|
|||
SetCrossHairPosition( mirrorPoint );
|
||||
SaveCopyInUndoList( block->GetItems(), UR_MIRRORED_X, false, mirrorPoint );
|
||||
MirrorX( block->GetItems(), mirrorPoint );
|
||||
SchematicCleanUp( true );
|
||||
OnModify();
|
||||
}
|
||||
|
||||
|
@ -348,6 +352,7 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC )
|
|||
SetCrossHairPosition( mirrorPoint );
|
||||
SaveCopyInUndoList( block->GetItems(), UR_MIRRORED_Y, false, mirrorPoint );
|
||||
MirrorY( block->GetItems(), mirrorPoint );
|
||||
SchematicCleanUp( true );
|
||||
OnModify();
|
||||
}
|
||||
|
||||
|
|
|
@ -267,81 +267,77 @@ void SCH_EDIT_FRAME::BeginSegment( wxDC* DC, int type )
|
|||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::GetSchematicConnections( std::vector< wxPoint >& aConnections )
|
||||
{
|
||||
for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = item->Next() )
|
||||
item->GetConnectionPoints( aConnections );
|
||||
|
||||
// We always have some overlapping connection points. Drop duplicates here
|
||||
std::sort( aConnections.begin(), aConnections.end(),
|
||||
[]( wxPoint& a, wxPoint& b ) -> bool
|
||||
{ return a.x < b.x || (a.x == b.x && a.y < b.y); } );
|
||||
aConnections.erase( unique( aConnections.begin(), aConnections.end() ), aConnections.end() );
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::EndSegment()
|
||||
{
|
||||
SCH_SCREEN* screen = GetScreen();
|
||||
SCH_LINE* segment = (SCH_LINE*) screen->GetCurItem();
|
||||
PICKED_ITEMS_LIST itemList;
|
||||
|
||||
if( segment == NULL || segment->Type() != SCH_LINE_T || !segment->IsNew() )
|
||||
return;
|
||||
|
||||
// Delete zero length segments and clear item flags.
|
||||
SCH_ITEM* item = s_wires.begin();
|
||||
|
||||
while( item )
|
||||
{
|
||||
item->ClearFlags();
|
||||
|
||||
wxCHECK_RET( item->Type() == SCH_LINE_T, wxT( "Unexpected object type in wire list." ) );
|
||||
|
||||
segment = (SCH_LINE*) item;
|
||||
item = item->Next();
|
||||
|
||||
if( segment->IsNull() )
|
||||
delete s_wires.Remove( segment );
|
||||
}
|
||||
// Remove segments backtracking over others
|
||||
RemoveBacktracks( s_wires );
|
||||
|
||||
if( s_wires.GetCount() == 0 )
|
||||
return;
|
||||
|
||||
// Collect the possible connection points for the new lines
|
||||
std::vector< wxPoint > connections;
|
||||
std::vector< wxPoint > new_ends;
|
||||
GetSchematicConnections( connections );
|
||||
|
||||
// Check each new segment for possible junctions and add/split if needed
|
||||
for( SCH_ITEM* wire = s_wires.GetFirst(); wire; wire=wire->Next() )
|
||||
{
|
||||
SCH_LINE* test_line = (SCH_LINE*) wire;
|
||||
if( wire->GetFlags() & SKIP_STRUCT )
|
||||
continue;
|
||||
|
||||
wire->GetConnectionPoints( new_ends );
|
||||
|
||||
for( auto i : connections )
|
||||
{
|
||||
if( IsPointOnSegment( test_line->GetStartPoint(), test_line->GetEndPoint(), i ) )
|
||||
{
|
||||
new_ends.push_back( i );
|
||||
}
|
||||
}
|
||||
itemList.PushItem( ITEM_PICKER( wire, UR_NEW ) );
|
||||
}
|
||||
|
||||
// Get the last non-null wire (this is the last created segment).
|
||||
SetRepeatItem( segment = (SCH_LINE*) s_wires.GetLast() );
|
||||
|
||||
screen->SetCurItem( NULL );
|
||||
m_canvas->EndMouseCapture( -1, -1, wxEmptyString, false );
|
||||
|
||||
// store the terminal point of this last segment: a junction could be needed
|
||||
// (the last wire could be merged/deleted/modified, and lost)
|
||||
wxPoint endpoint = segment->GetEndPoint();
|
||||
|
||||
// store the starting point of this first segment: a junction could be needed
|
||||
SCH_LINE* firstsegment = (SCH_LINE*) s_wires.GetFirst();
|
||||
wxPoint startPoint = firstsegment->GetStartPoint();
|
||||
|
||||
// Save the old wires for the undo command
|
||||
DLIST< SCH_ITEM > oldWires; // stores here the old wires
|
||||
GetScreen()->ExtractWires( oldWires, true ); // Save them in oldWires list
|
||||
// Put the snap shot of the previous wire, buses, and junctions in the undo/redo list.
|
||||
PICKED_ITEMS_LIST oldItems;
|
||||
oldItems.m_Status = UR_WIRE_IMAGE;
|
||||
|
||||
while( oldWires.GetCount() != 0 )
|
||||
{
|
||||
ITEM_PICKER picker = ITEM_PICKER( oldWires.PopFront(), UR_WIRE_IMAGE );
|
||||
oldItems.PushItem( picker );
|
||||
}
|
||||
|
||||
SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE );
|
||||
|
||||
// Remove segments backtracking over others
|
||||
RemoveBacktracks( s_wires );
|
||||
|
||||
// Add the new wires
|
||||
screen->Append( s_wires );
|
||||
SaveCopyInUndoList(itemList, UR_NEW);
|
||||
|
||||
// Correct and remove segments that need to be merged.
|
||||
SchematicCleanUp();
|
||||
|
||||
// A junction could be needed to connect the end point of the last created segment.
|
||||
if( screen->IsJunctionNeeded( endpoint ) )
|
||||
screen->Append( AddJunction( endpoint ) );
|
||||
|
||||
// A junction could be needed to connect the start point of the set of new created wires
|
||||
if( screen->IsJunctionNeeded( startPoint ) )
|
||||
screen->Append( AddJunction( startPoint ) );
|
||||
|
||||
m_canvas->Refresh();
|
||||
SchematicCleanUp( true );
|
||||
for( auto i : new_ends )
|
||||
{
|
||||
if( screen->IsJunctionNeeded( i, true ) )
|
||||
AddJunction( i, true );
|
||||
}
|
||||
|
||||
screen->TestDanglingEnds();
|
||||
screen->ClearDrawingState();
|
||||
screen->SetCurItem( NULL );
|
||||
m_canvas->EndMouseCapture( -1, -1, wxEmptyString, false );
|
||||
OnModify();
|
||||
}
|
||||
|
||||
|
@ -441,54 +437,100 @@ void SCH_EDIT_FRAME::SaveWireImage()
|
|||
}
|
||||
|
||||
|
||||
bool SCH_EDIT_FRAME::SchematicCleanUp()
|
||||
bool SCH_EDIT_FRAME::SchematicCleanUp( bool aAppend )
|
||||
{
|
||||
bool modified = false;
|
||||
SCH_ITEM* item = NULL;
|
||||
SCH_ITEM* secondItem = NULL;
|
||||
PICKED_ITEMS_LIST itemList;
|
||||
SCH_SCREEN* screen = GetScreen();
|
||||
|
||||
for( SCH_ITEM* item = GetScreen()->GetDrawItems() ; item; item = item->Next() )
|
||||
auto remove_item = [ &itemList, screen ]( SCH_ITEM* aItem ) -> void
|
||||
{
|
||||
if( ( item->Type() != SCH_LINE_T ) && ( item->Type() != SCH_JUNCTION_T ) )
|
||||
aItem->SetFlags( STRUCT_DELETED );
|
||||
itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) );
|
||||
};
|
||||
|
||||
BreakSegmentsOnJunctions( true );
|
||||
|
||||
for( item = screen->GetDrawItems(); item; item = item->Next() )
|
||||
{
|
||||
if( ( item->Type() != SCH_LINE_T ) &&
|
||||
( item->Type() != SCH_JUNCTION_T ) &&
|
||||
( item->Type() != SCH_NO_CONNECT_T ))
|
||||
continue;
|
||||
|
||||
bool restart;
|
||||
if( item->GetFlags() & STRUCT_DELETED )
|
||||
continue;
|
||||
|
||||
for( SCH_ITEM* testItem = item->Next(); testItem; testItem = restart ? GetScreen()->GetDrawItems() : testItem->Next() )
|
||||
// Remove unneeded junctions
|
||||
if( ( item->Type() == SCH_JUNCTION_T )
|
||||
&& ( !screen->IsJunctionNeeded( item->GetPosition() ) ) )
|
||||
{
|
||||
restart = false;
|
||||
remove_item( item );
|
||||
continue;
|
||||
}
|
||||
// Remove zero-length lines
|
||||
if( item->Type() == SCH_LINE_T
|
||||
&& ( (SCH_LINE*) item )->IsNull() )
|
||||
{
|
||||
remove_item( item );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( item->Type() == SCH_LINE_T ) && ( testItem->Type() == SCH_LINE_T ) )
|
||||
for( secondItem = item->Next(); secondItem; secondItem = secondItem->Next() )
|
||||
{
|
||||
if( item->Type() != secondItem->Type() || ( secondItem->GetFlags() & STRUCT_DELETED ) )
|
||||
continue;
|
||||
|
||||
// Merge overlapping lines
|
||||
if( item->Type() == SCH_LINE_T )
|
||||
{
|
||||
SCH_LINE* line = (SCH_LINE*) item;
|
||||
SCH_LINE* firstLine = (SCH_LINE*) item;
|
||||
SCH_LINE* secondLine = (SCH_LINE*) secondItem;
|
||||
SCH_LINE* line = NULL;
|
||||
bool needed = false;
|
||||
|
||||
if( line->MergeOverlap( (SCH_LINE*) testItem ) )
|
||||
if( !secondLine->IsParallel( firstLine ) )
|
||||
continue;
|
||||
|
||||
// Check if a junction needs to be kept
|
||||
// This can only happen if:
|
||||
// 1) the endpoints overlap,
|
||||
// 2) the lines are not pointing in the same direction AND
|
||||
// 3) IsJunction Needed is false
|
||||
if( secondLine->IsEndPoint( firstLine->GetStartPoint() )
|
||||
&& !secondLine->IsSameQuadrant( firstLine, firstLine->GetStartPoint() ) )
|
||||
needed = screen->IsJunctionNeeded( firstLine->GetStartPoint() );
|
||||
else if( secondLine->IsEndPoint( firstLine->GetEndPoint() )
|
||||
&& !secondLine->IsSameQuadrant( firstLine, firstLine->GetEndPoint() ) )
|
||||
needed = screen->IsJunctionNeeded( firstLine->GetEndPoint() );
|
||||
|
||||
if( !needed && ( line = (SCH_LINE*) secondLine->MergeOverlap( firstLine ) ) )
|
||||
{
|
||||
// Keep the current flags, because the deleted segment can be flagged.
|
||||
item->SetFlags( testItem->GetFlags() );
|
||||
DeleteItem( testItem );
|
||||
restart = true;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
else if ( ( ( item->Type() == SCH_JUNCTION_T )
|
||||
&& ( testItem->Type() == SCH_JUNCTION_T ) ) && ( testItem != item ) )
|
||||
{
|
||||
if ( testItem->HitTest( item->GetPosition() ) )
|
||||
{
|
||||
// Keep the current flags, because the deleted segment can be flagged.
|
||||
item->SetFlags( testItem->GetFlags() );
|
||||
DeleteItem( testItem );
|
||||
restart = true;
|
||||
modified = true;
|
||||
remove_item( item );
|
||||
remove_item( secondItem );
|
||||
itemList.PushItem( ITEM_PICKER( line, UR_NEW ) );
|
||||
screen->Append( (SCH_ITEM*) line );
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Remove duplicate junctions and no-connects
|
||||
else if( secondItem->GetPosition() == item->GetPosition() )
|
||||
remove_item( secondItem );
|
||||
}
|
||||
}
|
||||
for( item = screen->GetDrawItems(); item; item = secondItem )
|
||||
{
|
||||
secondItem = item->Next();
|
||||
if( item->GetFlags() & STRUCT_DELETED )
|
||||
screen->Remove( item );
|
||||
}
|
||||
SaveCopyInUndoList( itemList, UR_CHANGED, aAppend );
|
||||
|
||||
GetScreen()->TestDanglingEnds();
|
||||
|
||||
return modified;
|
||||
return !!( itemList.GetCount() );
|
||||
}
|
||||
|
||||
|
||||
bool SCH_EDIT_FRAME::BreakSegment( SCH_LINE *aSegment, const wxPoint& aPoint, bool aAppend )
|
||||
{
|
||||
if( !IsPointOnSegment( aSegment->GetStartPoint(), aSegment->GetEndPoint(), aPoint )
|
||||
|
@ -552,20 +594,17 @@ bool SCH_EDIT_FRAME::BreakSegmentsOnJunctions( bool aAppend )
|
|||
}
|
||||
|
||||
|
||||
SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( const wxPoint& aPosition,
|
||||
bool aPutInUndoList )
|
||||
SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( const wxPoint& aPosition, bool aAppend )
|
||||
{
|
||||
SCH_JUNCTION* junction = new SCH_JUNCTION( aPosition );
|
||||
SCH_SCREEN* screen = GetScreen();
|
||||
bool broken_segments = false;
|
||||
|
||||
SetRepeatItem( junction );
|
||||
|
||||
if( aPutInUndoList )
|
||||
{
|
||||
GetScreen()->Append( junction );
|
||||
SaveCopyInUndoList( junction, UR_NEW );
|
||||
OnModify();
|
||||
}
|
||||
|
||||
screen->Append( junction );
|
||||
broken_segments = BreakSegments( aPosition, aAppend );
|
||||
screen->TestDanglingEnds();
|
||||
OnModify();
|
||||
SaveCopyInUndoList( junction, UR_NEW, broken_segments || aAppend );
|
||||
return junction;
|
||||
}
|
||||
|
||||
|
|
|
@ -336,19 +336,19 @@ public:
|
|||
/**
|
||||
* Test if a junction is required for the items at \a aPosition on the screen.
|
||||
* <p>
|
||||
* A junction is required at \a aPosition if the following criteria are satisfied:
|
||||
* A junction is required at \a aPosition if one of the following criteria is satisfied:
|
||||
* <ul>
|
||||
* <li>one wire midpoint, one or more wire endpoints and no junction.</li>
|
||||
* <li>three or more wire endpoints and no junction.</li>
|
||||
* <li>two wire midpoints and no junction</li>
|
||||
* <li>one wire midpoint, a component pin, and no junction.</li>
|
||||
* <li>three wire endpoints, a component pin, and no junction.</li>
|
||||
* <li>one wire midpoint and one or more wire endpoints;</li>
|
||||
* <li>three or more wire endpoints;</li>
|
||||
* <li>one wire midpoint and a component pin;</li>
|
||||
* <li>two or more wire endpoints and a component pin.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* @param aPosition The position to test.
|
||||
* @param aNew Checks if a _new_ junction is needed, i.e. there isn't one already
|
||||
* @return True if a junction is required at \a aPosition.
|
||||
*/
|
||||
bool IsJunctionNeeded( const wxPoint& aPosition );
|
||||
bool IsJunctionNeeded( const wxPoint& aPosition, bool aNew = false );
|
||||
|
||||
/**
|
||||
* Test if \a aPosition is a connection point on \a aLayer.
|
||||
|
|
|
@ -356,6 +356,11 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
|||
}
|
||||
|
||||
schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
|
||||
|
||||
// Ensure the schematic is fully segmented on first display
|
||||
BreakSegmentsOnJunctions();
|
||||
SchematicCleanUp( true );
|
||||
GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
|
||||
GetScreen()->TestDanglingEnds(); // Only perform the dangling end test on root sheet.
|
||||
}
|
||||
|
||||
|
@ -768,6 +773,11 @@ bool SCH_EDIT_FRAME::ImportFile( const wxString& aFileName, int aFileType )
|
|||
|
||||
UpdateFileHistory( fullFileName );
|
||||
schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
|
||||
|
||||
// Ensure the schematic is fully segmented on first display
|
||||
BreakSegmentsOnJunctions();
|
||||
SchematicCleanUp( true );
|
||||
GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
|
||||
GetScreen()->TestDanglingEnds(); // Only perform the dangling end test on root sheet.
|
||||
|
||||
GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId );
|
||||
|
|
|
@ -299,7 +299,13 @@ void SCH_EDIT_FRAME::DisplayCurrentSheet()
|
|||
screen->m_FirstRedraw = false;
|
||||
SetCrossHairPosition( GetScrollCenterPosition() );
|
||||
m_canvas->MoveCursorToCrossHair();
|
||||
SchematicCleanUp();
|
||||
|
||||
// Ensure the schematic is fully segmented on first display
|
||||
BreakSegmentsOnJunctions();
|
||||
SchematicCleanUp( true );
|
||||
screen->ClearUndoORRedoList( screen->m_UndoList, 1 );
|
||||
|
||||
screen->TestDanglingEnds();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -115,6 +115,42 @@ void MoveItemsInList( PICKED_ITEMS_LIST& aItemsList, const wxPoint& aMoveVector
|
|||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::CheckJunctionsInList( PICKED_ITEMS_LIST& aItemsList, bool aAppend )
|
||||
{
|
||||
std::vector< wxPoint > pts;
|
||||
std::vector< wxPoint > connections;
|
||||
|
||||
GetSchematicConnections( connections );
|
||||
for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
|
||||
{
|
||||
SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii );
|
||||
item->GetConnectionPoints( pts );
|
||||
if( item->Type() == SCH_LINE_T )
|
||||
{
|
||||
SCH_LINE* line = (SCH_LINE*) item;
|
||||
for( auto i : connections )
|
||||
if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), i ) )
|
||||
pts.push_back( i );
|
||||
}
|
||||
}
|
||||
|
||||
// We always have some overlapping connection points. Drop duplicates here
|
||||
std::sort( pts.begin(), pts.end(),
|
||||
[]( wxPoint& a, wxPoint& b ) -> bool
|
||||
{ return a.x < b.x || (a.x == b.x && a.y < b.y); } );
|
||||
pts.erase( unique( pts.begin(), pts.end() ), pts.end() );
|
||||
|
||||
for( auto point : pts )
|
||||
{
|
||||
if( GetScreen()->IsJunctionNeeded( point, true ) )
|
||||
{
|
||||
AddJunction( point, aAppend );
|
||||
aAppend = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::DeleteItemsInList( PICKED_ITEMS_LIST& aItemsList, bool aAppend )
|
||||
{
|
||||
PICKED_ITEMS_LIST itemsList;
|
||||
|
|
|
@ -557,6 +557,7 @@ bool SCH_EDIT_FRAME::rescueProject( RESCUER& aRescuer, bool aRunningOnDemand )
|
|||
|
||||
// Clean up wire ends
|
||||
SchematicCleanUp();
|
||||
GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
|
||||
m_canvas->Refresh( true );
|
||||
OnModify();
|
||||
|
||||
|
|
|
@ -388,7 +388,8 @@ bool SCH_LINE::IsParallel( SCH_LINE* aLine )
|
|||
return !( (long long) firstSeg.x * secondSeg.y - (long long) firstSeg.y * secondSeg.x );
|
||||
}
|
||||
|
||||
bool SCH_LINE::MergeOverlap( SCH_LINE* aLine )
|
||||
|
||||
EDA_ITEM* SCH_LINE::MergeOverlap( SCH_LINE* aLine )
|
||||
{
|
||||
auto less = []( const wxPoint& lhs, const wxPoint& rhs ) -> bool
|
||||
{
|
||||
|
@ -396,12 +397,11 @@ bool SCH_LINE::MergeOverlap( SCH_LINE* aLine )
|
|||
return lhs.y < rhs.y;
|
||||
return lhs.x < rhs.x;
|
||||
};
|
||||
|
||||
wxCHECK_MSG( aLine != NULL && aLine->Type() == SCH_LINE_T, false,
|
||||
wxCHECK_MSG( aLine != NULL && aLine->Type() == SCH_LINE_T, NULL,
|
||||
wxT( "Cannot test line segment for overlap." ) );
|
||||
|
||||
if( this == aLine || GetLayer() != aLine->GetLayer() )
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
SCH_LINE leftmost = SCH_LINE( *aLine );
|
||||
SCH_LINE rightmost = SCH_LINE( *this );
|
||||
|
@ -428,16 +428,14 @@ bool SCH_LINE::MergeOverlap( SCH_LINE* aLine )
|
|||
// If we end one before the beginning of the other, no overlap is possible
|
||||
if( less( leftmost.m_end, other.m_start ) )
|
||||
{
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Search for a common end:
|
||||
if( ( leftmost.m_start == other.m_start )
|
||||
&& ( leftmost.m_end == other.m_end ) ) // Trivial case
|
||||
{
|
||||
m_start = leftmost.m_start;
|
||||
m_end = leftmost.m_end;
|
||||
return true;
|
||||
return new SCH_LINE( leftmost );
|
||||
}
|
||||
|
||||
bool colinear = false;
|
||||
|
@ -471,12 +469,11 @@ bool SCH_LINE::MergeOverlap( SCH_LINE* aLine )
|
|||
// Make a new segment that merges the 2 segments
|
||||
if( colinear )
|
||||
{
|
||||
m_start = leftmost.m_start;
|
||||
m_end = rightmost.m_end;
|
||||
return true;
|
||||
leftmost.m_end = rightmost.m_end;
|
||||
return new SCH_LINE( leftmost );
|
||||
}
|
||||
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -696,6 +693,7 @@ bool SCH_LINE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy )
|
|||
return rect.Intersects( m_start, m_end );
|
||||
}
|
||||
|
||||
|
||||
void SCH_LINE::SwapData( SCH_ITEM* aItem )
|
||||
{
|
||||
SCH_LINE* item = (SCH_LINE*) aItem;
|
||||
|
@ -711,6 +709,7 @@ void SCH_LINE::SwapData( SCH_ITEM* aItem )
|
|||
std::swap( m_color, item->m_color );
|
||||
}
|
||||
|
||||
|
||||
bool SCH_LINE::doIsConnected( const wxPoint& aPosition ) const
|
||||
{
|
||||
if( m_Layer != LAYER_WIRE && m_Layer != LAYER_BUS )
|
||||
|
|
|
@ -133,14 +133,14 @@ public:
|
|||
/**
|
||||
* Check line against \a aLine to see if it overlaps and merge if it does.
|
||||
*
|
||||
* This method will change the line to be equivalent of the line and \a aLine if the
|
||||
* This method will return an equivalent of the union of line and \a aLine if the
|
||||
* two lines overlap. This method is used to merge multiple line segments into a single
|
||||
* line.
|
||||
*
|
||||
* @param aLine - Line to compare.
|
||||
* @return True if lines overlap and the line was merged with \a aLine.
|
||||
* @return New line that combines the two or NULL on non-overlapping segments.
|
||||
*/
|
||||
bool MergeOverlap( SCH_LINE* aLine );
|
||||
EDA_ITEM* MergeOverlap( SCH_LINE* aLine );
|
||||
|
||||
/**
|
||||
* Check if two lines are in the same quadrant as each other, using a reference point as
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include <lib_pin.h>
|
||||
#include <symbol_lib_table.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#define EESCHEMA_FILE_STAMP "EESchema"
|
||||
|
||||
|
@ -346,20 +347,60 @@ void SCH_SCREEN::MarkConnections( SCH_LINE* aSegment )
|
|||
}
|
||||
|
||||
|
||||
bool SCH_SCREEN::IsJunctionNeeded( const wxPoint& aPosition )
|
||||
bool SCH_SCREEN::IsJunctionNeeded( const wxPoint& aPosition, bool aNew )
|
||||
{
|
||||
if( GetItem( aPosition, 0, SCH_JUNCTION_T ) )
|
||||
return false;
|
||||
bool has_line = false;
|
||||
bool has_nonparallel = false;
|
||||
int end_count = 0;
|
||||
|
||||
if( GetWire( aPosition, 0, EXCLUDE_END_POINTS_T ) )
|
||||
std::vector< SCH_LINE* > lines;
|
||||
|
||||
for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() )
|
||||
{
|
||||
if( GetWire( aPosition, 0, END_POINTS_ONLY_T ) )
|
||||
return true;
|
||||
if( item->GetFlags() & STRUCT_DELETED )
|
||||
continue;
|
||||
if( aNew && ( item->Type() == SCH_JUNCTION_T ) && ( item->HitTest( aPosition ) ) )
|
||||
return false;
|
||||
|
||||
if( GetPin( aPosition, NULL, true ) )
|
||||
return true;
|
||||
if( item->Type() != SCH_LINE_T )
|
||||
continue;
|
||||
|
||||
if( item->GetLayer() != LAYER_WIRE )
|
||||
continue;
|
||||
|
||||
if( item->HitTest( aPosition, 0 ) )
|
||||
lines.push_back( (SCH_LINE*) item );
|
||||
}
|
||||
|
||||
BOOST_FOREACH( SCH_LINE* line, lines)
|
||||
{
|
||||
if( !line->IsEndPoint( aPosition ) )
|
||||
has_line = true;
|
||||
else
|
||||
end_count++;
|
||||
BOOST_REVERSE_FOREACH( SCH_LINE* second_line, lines )
|
||||
{
|
||||
if( line == second_line )
|
||||
break;
|
||||
if( line->IsEndPoint( second_line->GetStartPoint() )
|
||||
&& line->IsEndPoint( second_line->GetEndPoint() ) )
|
||||
end_count--;
|
||||
if( !line->IsParallel( second_line ) )
|
||||
has_nonparallel = true;
|
||||
}
|
||||
}
|
||||
|
||||
int has_pin = !!( GetPin( aPosition, NULL, true ) );
|
||||
|
||||
// If there is line intersecting a pin or non-parallel end
|
||||
if( has_pin && ( has_line || end_count > 1 ) )
|
||||
return true;
|
||||
|
||||
// If there is at least one segment that ends on a non-parallel line or
|
||||
// junction of two other lines
|
||||
if( has_nonparallel && (has_line || end_count > 2 ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1098,30 +1139,6 @@ int SCH_SCREEN::GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aLis
|
|||
}
|
||||
}
|
||||
|
||||
// Get redundant junctions (junctions which connect < 3 end wires
|
||||
// and no pin)
|
||||
for( item = m_drawList.begin(); item; item = item->Next() )
|
||||
{
|
||||
if( item->GetFlags() & STRUCT_DELETED )
|
||||
continue;
|
||||
|
||||
if( !(item->GetFlags() & CANDIDATE) )
|
||||
continue;
|
||||
|
||||
if( item->Type() != SCH_JUNCTION_T )
|
||||
continue;
|
||||
|
||||
SCH_JUNCTION* junction = (SCH_JUNCTION*) item;
|
||||
|
||||
if( CountConnectedItems( junction->GetPosition(), false ) <= 2 )
|
||||
{
|
||||
item->SetFlags( STRUCT_DELETED );
|
||||
|
||||
ITEM_PICKER picker( item, UR_DELETED );
|
||||
aList.PushItem( picker );
|
||||
}
|
||||
}
|
||||
|
||||
for( item = m_drawList.begin(); item; item = item->Next() )
|
||||
{
|
||||
if( item->GetFlags() & STRUCT_DELETED )
|
||||
|
@ -1132,7 +1149,7 @@ int SCH_SCREEN::GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aLis
|
|||
|
||||
tmp = GetWireOrBus( ( (SCH_TEXT*) item )->GetPosition() );
|
||||
|
||||
if( tmp && tmp->GetFlags() & STRUCT_DELETED )
|
||||
if( tmp && ( tmp->GetFlags() & STRUCT_DELETED ) )
|
||||
{
|
||||
item->SetFlags( STRUCT_DELETED );
|
||||
|
||||
|
|
|
@ -190,6 +190,7 @@ void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
|||
case ID_POPUP_SCH_DELETE_CONNECTION:
|
||||
m_canvas->MoveCursorToCrossHair();
|
||||
DeleteConnection( id == ID_POPUP_SCH_DELETE_CONNECTION );
|
||||
SchematicCleanUp( true );
|
||||
screen->SetCurItem( NULL );
|
||||
SetRepeatItem( NULL );
|
||||
|
||||
|
@ -214,6 +215,7 @@ void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
|||
break;
|
||||
|
||||
DeleteItem( item );
|
||||
SchematicCleanUp( true );
|
||||
screen->SetCurItem( NULL );
|
||||
SetRepeatItem( NULL );
|
||||
screen->TestDanglingEnds();
|
||||
|
@ -630,6 +632,7 @@ void SCH_EDIT_FRAME::DeleteConnection( bool aFullConnection )
|
|||
if( screen->GetConnection( pos, pickList, aFullConnection ) != 0 )
|
||||
{
|
||||
DeleteItemsInList( pickList );
|
||||
SchematicCleanUp( true );
|
||||
OnModify();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1443,7 +1443,16 @@ void SCH_EDIT_FRAME::addCurrentItemToList( bool aRedraw )
|
|||
m_canvas->EndMouseCapture();
|
||||
|
||||
if( item->IsConnectable() )
|
||||
{
|
||||
std::vector< wxPoint > pts;
|
||||
item->GetConnectionPoints( pts );
|
||||
for( auto i : pts )
|
||||
{
|
||||
if( screen->IsJunctionNeeded( i, true ) )
|
||||
AddJunction( i, true );
|
||||
}
|
||||
screen->TestDanglingEnds();
|
||||
}
|
||||
|
||||
if( aRedraw )
|
||||
GetCanvas()->Refresh();
|
||||
|
|
|
@ -937,19 +937,25 @@ private:
|
|||
SCH_JUNCTION* AddJunction( const wxPoint& aPosition, bool aPutInUndoList = false );
|
||||
|
||||
/**
|
||||
* Function SaveWireImage
|
||||
* saves a copy of the current wire image in the undo list
|
||||
* Save a copy of the current wire image in the undo list.
|
||||
*/
|
||||
void SaveWireImage();
|
||||
|
||||
/**
|
||||
* Function SchematicCleanUp
|
||||
* performs routine schematic cleaning including breaking wire and buses and
|
||||
* Collects a unique list of all possible connection points in the schematic.
|
||||
*
|
||||
* @param aConnections vector of connections
|
||||
*/
|
||||
void GetSchematicConnections( std::vector< wxPoint >& aConnections );
|
||||
|
||||
/**
|
||||
* Performs routine schematic cleaning including breaking wire and buses and
|
||||
* deleting identical objects superimposed on top of each other.
|
||||
*
|
||||
* @param aAppend The changes to the schematic should be appended to the previous undo
|
||||
* @return True if any schematic clean up was performed.
|
||||
*/
|
||||
bool SchematicCleanUp();
|
||||
bool SchematicCleanUp( bool aAppend = false );
|
||||
|
||||
/**
|
||||
* Start moving \a aItem using the mouse.
|
||||
|
@ -1128,6 +1134,15 @@ public:
|
|||
*/
|
||||
void DeleteItemsInList( PICKED_ITEMS_LIST& aItemsList, bool aAppend = false );
|
||||
|
||||
/**
|
||||
* Adds junctions if needed to each item in the list after they have been
|
||||
* moved.
|
||||
*
|
||||
* @param aItemsList The list of items to check
|
||||
* @param aAppend True if we are updating a previous commit
|
||||
*/
|
||||
void CheckJunctionsInList( PICKED_ITEMS_LIST& aItemsList, bool aAppend = false );
|
||||
|
||||
int GetLabelIncrement() const { return m_repeatLabelDelta; }
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in New Issue