Updated patchset for this proposal, rebased to master. I've also updated the commit messages to match the CHANGE:/NEW: format and added one new bug from launchpad that this addresses.
-Seth On Wed, Nov 8, 2017 at 3:59 AM, Nick Østergaard <oe.n...@gmail.com> wrote: > For that specific issue with the junction drawing, there is a patch in the > thread "[Kicad-developers] [PATCH] Draw junctions last" > > 2017-11-03 13:12 GMT+01:00 Jon Evans <j...@craftyjon.com>: > >> I looked at fixing this and some other related things, and decided to >> just wait for the GAL port. There will need to be huge refactoring of the >> eeschema draw code as part of that effort, so putting much effort into >> making the wxDC drawing better seems not worth it. >> >> -Jon >> >> On Nov 3, 2017 00:08, "Kevin Cozens" <ke...@ve3syb.ca> wrote: >> >> On 2017-11-02 06:31 PM, Seth Hillbrand wrote: >> >>> Please let me know if there are any additional issues or suggestions for >>> improvement. >>> >> >> How difficult would it be to have junctions draw last on schematics? >> There is a minor negative visual effect when you have a component with one >> end joined to a wire by a junction and you replace the component. >> >> When you replace the component the pin of the component is now seen >> extending through the round disc of the junction to the center of the >> junction. I prefer to always see just the full round disc of a junction >> mark even if I have replaced a component since placing the junction. >> >> -- >> Cheers! >> >> Kevin. >> >> http://www.ve3syb.ca/ |"Nerds make the shiny things that >> distract >> Owner of Elecraft K2 #2172 | the mouth-breathers, and that's why >> we're >> | powerful!" >> #include <disclaimer/favourite> | --Chris Hardwick >> >> >> _______________________________________________ >> Mailing list: https://launchpad.net/~kicad-developers >> Post to : kicad-developers@lists.launchpad.net >> Unsubscribe : https://launchpad.net/~kicad-developers >> More help : https://help.launchpad.net/ListHelp >> >> >> >> _______________________________________________ >> Mailing list: https://launchpad.net/~kicad-developers >> Post to : kicad-developers@lists.launchpad.net >> Unsubscribe : https://launchpad.net/~kicad-developers >> More help : https://help.launchpad.net/ListHelp >> >> > > _______________________________________________ > Mailing list: https://launchpad.net/~kicad-developers > Post to : kicad-developers@lists.launchpad.net > Unsubscribe : https://launchpad.net/~kicad-developers > More help : https://help.launchpad.net/ListHelp > >
From b70ac1d34998ea04c62f4c74e8f7713fab24f601 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Thu, 12 Oct 2017 14:08:14 -0700 Subject: [PATCH 01/11] Optimize speed of TestSegmentHit Improves speed of function by exiting on non-hits more quickly for the majority of tests. Hits are also calculated slightly faster. --- common/trigo.cpp | 172 +++++++++++++------------------------------------------ 1 file changed, 39 insertions(+), 133 deletions(-) diff --git a/common/trigo.cpp b/common/trigo.cpp index 96dafa00e..5cf46d121 100644 --- a/common/trigo.cpp +++ b/common/trigo.cpp @@ -125,146 +125,52 @@ bool SegmentIntersectsSegment( const wxPoint &a_p1_l1, const wxPoint &a_p2_l1, * aRefPoint = reference point to test * aStart, aEnd are coordinates of end points segment * aDist = maximum distance for hit - * Note: for calculation time reasons, the distance between the ref point - * and the segment is not always exactly calculated - * (we only know if the actual dist is < aDist, not exactly know this dist. - * Because many times we have horizontal or vertical segments, - * a special calcultaion is made for them - * Note: sometimes we need to calculate the distande between 2 points - * A square root should be calculated. - * However, because we just compare 2 distnaces, to avoid calculating square root, - * the square of distances are compared. + * */ -static inline double square( int x ) // helper function to calculate x*x -{ - return (double) x * x; -} bool TestSegmentHit( const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist ) { - // test for vertical or horizontal segment - if( aEnd.x == aStart.x ) - { - // vertical segment - int ll = abs( aRefPoint.x - aStart.x ); - - if( ll > aDist ) - return false; - - // To have only one case to examine, ensure aEnd.y > aStart.y - if( aEnd.y < aStart.y ) - std::swap( aStart.y, aEnd.y ); - - if( aRefPoint.y <= aEnd.y && aRefPoint.y >= aStart.y ) - return true; - - // there is a special case: x,y near an end point (distance < dist ) - // the distance should be carefully calculated - if( (aStart.y - aRefPoint.y) < aDist ) - { - double dd = square( aRefPoint.x - aStart.x) + - square( aRefPoint.y - aStart.y ); - if( dd <= square( aDist ) ) - return true; - } - - if( (aRefPoint.y - aEnd.y) < aDist ) - { - double dd = square( aRefPoint.x - aEnd.x ) + - square( aRefPoint.y - aEnd.y ); - if( dd <= square( aDist ) ) - return true; - } - } - else if( aEnd.y == aStart.y ) - { - // horizontal segment - int ll = abs( aRefPoint.y - aStart.y ); - - if( ll > aDist ) - return false; - - // To have only one case to examine, ensure xf > xi - if( aEnd.x < aStart.x ) - std::swap( aStart.x, aEnd.x ); - - if( aRefPoint.x <= aEnd.x && aRefPoint.x >= aStart.x ) - return true; - - // there is a special case: x,y near an end point (distance < dist ) - // the distance should be carefully calculated - if( (aStart.x - aRefPoint.x) <= aDist ) - { - double dd = square( aRefPoint.x - aStart.x ) + - square( aRefPoint.y - aStart.y ); - if( dd <= square( aDist ) ) - return true; - } - - if( (aRefPoint.x - aEnd.x) <= aDist ) - { - double dd = square( aRefPoint.x - aEnd.x ) + - square( aRefPoint.y - aEnd.y ); - if( dd <= square( aDist ) ) - return true; - } - } - else + int xmin = aStart.x; + int xmax = aEnd.x; + int ymin = aStart.y; + int ymax = aEnd.y; + double dist_square = (double)aDist * aDist; + double length_square; + double delta_x, delta_y; + + if( xmax < xmin ) + std::swap( xmax, xmin ); + if( ymax < ymin ) + std::swap( ymax, ymin ); + + // First, check if we are outside of the bounding box + if ( ( ymin - aRefPoint.y > aDist ) || ( aRefPoint.y - ymax > aDist ) ) + return false; + if ( ( xmin - aRefPoint.x > aDist ) || ( aRefPoint.x - xmax > aDist ) ) + return false; + + // Next, deal with a potential zero-length case + if ( aStart == aEnd ) { - // oblique segment: - // First, we need to calculate the distance between the point - // and the line defined by aStart and aEnd - // this dist should be < dist - // - // find a,slope such that aStart and aEnd lie on y = a + slope*x - double slope = (double) (aEnd.y - aStart.y) / (aEnd.x - aStart.x); - double a = (double) aStart.y - slope * aStart.x; - // find c,orthoslope such that (x,y) lies on y = c + orthoslope*x, - // where orthoslope=(-1/slope) - // to calculate xp, yp = near point from aRefPoint - // which is on the line defined by aStart, aEnd - double orthoslope = -1.0 / slope; - double c = (double) aRefPoint.y - orthoslope * aRefPoint.x; - // find nearest point to (x,y) on line defined by aStart, aEnd - double xp = (a - c) / (orthoslope - slope); - double yp = a + slope * xp; - // find distance to line, in fact the square of dist, - // because we just know if it is > or < aDist - double dd = square( aRefPoint.x - xp ) + square( aRefPoint.y - yp ); - double dist = square( aDist ); - - if( dd > dist ) // this reference point is not a good candiadte. - return false; - - // dd is < dist, therefore we should make a fine test - if( fabs( slope ) > 0.7 ) - { - // line segment more vertical than horizontal - if( (aEnd.y > aStart.y && yp <= aEnd.y && yp >= aStart.y) || - (aEnd.y < aStart.y && yp >= aEnd.y && yp <= aStart.y) ) - return true; - } - else - { - // line segment more horizontal than vertical - if( (aEnd.x > aStart.x && xp <= aEnd.x && xp >= aStart.x) || - (aEnd.x < aStart.x && xp >= aEnd.x && xp <= aStart.x) ) - return true; - } - - // Here, the test point is still a good candidate, - // however it is not "between" the end points of the segment. - // It is "outside" the segment, but it could be near a segment end point - // Therefore, we test the dist from the test point to each segment end point - dd = square( aRefPoint.x - aEnd.x ) + square( aRefPoint.y - aEnd.y ); - if( dd <= dist ) - return true; - dd = square( aRefPoint.x - aStart.x ) + square( aRefPoint.y - aStart.y ); - if( dd <= dist ) - return true; + delta_x = aStart.x - aRefPoint.x; + delta_y = aStart.y - aRefPoint.y; + return ( delta_x * delta_x + delta_y * delta_y <= dist_square); } - return false; // no hit + delta_x = aEnd.x - aStart.x; + delta_y = aEnd.y - aStart.y; + length_square = delta_x * delta_x + delta_y * delta_y; + // This is now the projection of the vector from start to reference onto the segment + double u = (aRefPoint.x - aStart.x) * delta_x + (aRefPoint.y - aStart.y) * delta_y; + // Sanity check that the projection is never negative or longer than the element itself + u = std::min( std::max( 0., u ), length_square ); + + // Calculate the x,y offsets by shifting from the start along the projection + // to the nearest point on the segment + double x = ( aStart.x - aRefPoint.x) + ( u * delta_x ) / length_square; + double y = ( aStart.y - aRefPoint.y) + ( u * delta_y ) / length_square; + + return dist_square >= x * x + y * y; } -- 2.11.0
From 6922daeea3cd1f5f904e3ab5d6e17ac64346ee87 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Thu, 26 Oct 2017 09:53:17 -0700 Subject: [PATCH 02/11] Eeschema: Simplify GetItem Avoids calling HitTest on each item when it is not needed --- eeschema/sch_screen.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/eeschema/sch_screen.cpp b/eeschema/sch_screen.cpp index edc90bc4b..cfdd458fc 100644 --- a/eeschema/sch_screen.cpp +++ b/eeschema/sch_screen.cpp @@ -216,9 +216,6 @@ SCH_ITEM* SCH_SCREEN::GetItem( const wxPoint& aPosition, int aAccuracy, KICAD_T { for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) { - if( item->HitTest( aPosition, aAccuracy ) && (aType == NOT_USED) ) - return item; - if( (aType == SCH_FIELD_T) && (item->Type() == SCH_COMPONENT_T) ) { SCH_COMPONENT* component = (SCH_COMPONENT*) item; @@ -240,7 +237,8 @@ SCH_ITEM* SCH_SCREEN::GetItem( const wxPoint& aPosition, int aAccuracy, KICAD_T if( label ) return (SCH_ITEM*) label; } - else if( (item->Type() == aType) && item->HitTest( aPosition, aAccuracy ) ) + else if( ( ( item->Type() == aType ) || ( aType == NOT_USED ) ) + && item->HitTest( aPosition, aAccuracy ) ) { return item; } -- 2.11.0
From 94eeddce2490fb9a5886cef909a390edaf46e05b Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Thu, 16 Nov 2017 12:36:09 -0800 Subject: [PATCH 03/11] Eeschema: Add 'append' option to undo/redo NEW: Eeschema can add elements to previous undo commits --- eeschema/block.cpp | 8 +++---- eeschema/edit_bitmap.cpp | 2 +- eeschema/schematic_undo_redo.cpp | 47 +++++++++++++++++++++++++++++++++++----- eeschema/schframe.h | 4 ++++ 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/eeschema/block.cpp b/eeschema/block.cpp index b6d0d7824..2d2af403f 100644 --- a/eeschema/block.cpp +++ b/eeschema/block.cpp @@ -127,7 +127,7 @@ void SCH_EDIT_FRAME::HandleBlockPlace( wxDC* DC ) if( m_canvas->IsMouseCaptured() ) m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); - SaveCopyInUndoList( block->GetItems(), UR_MOVED, block->GetMoveVector() ); + SaveCopyInUndoList( block->GetItems(), UR_MOVED, false, block->GetMoveVector() ); MoveItemsInList( block->GetItems(), block->GetMoveVector() ); block->ClearItemsList(); break; @@ -216,7 +216,7 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC ) wxPoint rotationPoint = block->Centre(); rotationPoint = GetNearestGridPosition( rotationPoint ); SetCrossHairPosition( rotationPoint ); - SaveCopyInUndoList( block->GetItems(), UR_ROTATED, rotationPoint ); + SaveCopyInUndoList( block->GetItems(), UR_ROTATED, false, rotationPoint ); RotateListOfItems( block->GetItems(), rotationPoint ); OnModify(); } @@ -330,7 +330,7 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC ) wxPoint mirrorPoint = block->Centre(); mirrorPoint = GetNearestGridPosition( mirrorPoint ); SetCrossHairPosition( mirrorPoint ); - SaveCopyInUndoList( block->GetItems(), UR_MIRRORED_X, mirrorPoint ); + SaveCopyInUndoList( block->GetItems(), UR_MIRRORED_X, false, mirrorPoint ); MirrorX( block->GetItems(), mirrorPoint ); OnModify(); } @@ -349,7 +349,7 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC ) wxPoint mirrorPoint = block->Centre(); mirrorPoint = GetNearestGridPosition( mirrorPoint ); SetCrossHairPosition( mirrorPoint ); - SaveCopyInUndoList( block->GetItems(), UR_MIRRORED_Y, mirrorPoint ); + SaveCopyInUndoList( block->GetItems(), UR_MIRRORED_Y, false, mirrorPoint ); MirrorY( block->GetItems(), mirrorPoint ); OnModify(); } diff --git a/eeschema/edit_bitmap.cpp b/eeschema/edit_bitmap.cpp index ad2a2b93a..d49efcda8 100644 --- a/eeschema/edit_bitmap.cpp +++ b/eeschema/edit_bitmap.cpp @@ -161,7 +161,7 @@ void SCH_EDIT_FRAME::MoveImage( SCH_BITMAP* aImageItem, wxDC* aDC ) void SCH_EDIT_FRAME::RotateImage( SCH_BITMAP* aItem ) { if( aItem->GetFlags( ) == 0 ) - SaveCopyInUndoList( aItem, UR_ROTATED, aItem->GetPosition() ); + SaveCopyInUndoList( aItem, UR_ROTATED, false, aItem->GetPosition() ); aItem->Rotate( aItem->GetPosition() ); OnModify(); diff --git a/eeschema/schematic_undo_redo.cpp b/eeschema/schematic_undo_redo.cpp index 09a83a6bc..75c1731eb 100644 --- a/eeschema/schematic_undo_redo.cpp +++ b/eeschema/schematic_undo_redo.cpp @@ -108,8 +108,11 @@ void SCH_EDIT_FRAME::SaveCopyInUndoList( SCH_ITEM* aItem, UNDO_REDO_T aCommandType, + bool aAppend, const wxPoint& aTransformPoint ) { + PICKED_ITEMS_LIST* commandToUndo = NULL; + /* Does not save a null item or a UR_WIRE_IMAGE command type. UR_WIRE_IMAGE commands * are handled by the overloaded version of SaveCopyInUndoList that takes a reference * to a PICKED_ITEMS_LIST. @@ -117,8 +120,14 @@ void SCH_EDIT_FRAME::SaveCopyInUndoList( SCH_ITEM* aItem, if( aItem == NULL || aCommandType == UR_WIRE_IMAGE ) return; - PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST(); - commandToUndo->m_TransformPoint = aTransformPoint; + if( aAppend ) + commandToUndo = GetScreen()->PopCommandFromUndoList(); + + if( !commandToUndo ) + { + commandToUndo = new PICKED_ITEMS_LIST(); + commandToUndo->m_TransformPoint = aTransformPoint; + } ITEM_PICKER itemWrapper( aItem, aCommandType ); itemWrapper.SetFlags( aItem->GetFlags() ); @@ -160,15 +169,41 @@ void SCH_EDIT_FRAME::SaveCopyInUndoList( SCH_ITEM* aItem, void SCH_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, + bool aAppend, const wxPoint& aTransformPoint ) { - PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST(); + PICKED_ITEMS_LIST* commandToUndo = NULL; + + if( !aItemsList.GetCount() ) + return; + + // Can't append a WIRE IMAGE, so fail to a new undo point + if( aAppend && ( aTypeCommand != UR_WIRE_IMAGE ) ) + { + commandToUndo = GetScreen()->PopCommandFromUndoList(); + if( commandToUndo && commandToUndo->m_Status == UR_WIRE_IMAGE ) + { + GetScreen()->PushCommandToUndoList( commandToUndo ); + commandToUndo = NULL; + } + } - commandToUndo->m_TransformPoint = aTransformPoint; - commandToUndo->m_Status = aTypeCommand; + if( !commandToUndo ) + { + commandToUndo = new PICKED_ITEMS_LIST(); + commandToUndo->m_TransformPoint = aTransformPoint; + commandToUndo->m_Status = aTypeCommand; + } // Copy picker list: - commandToUndo->CopyList( aItemsList ); + if( !commandToUndo->GetCount() ) + commandToUndo->CopyList( aItemsList ); + else + { + // Unless we are appending, in which case, get the picker items + for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) + commandToUndo->PushItem( aItemsList.GetItemWrapper( ii) ); + } // Verify list, and creates data if needed for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ ) diff --git a/eeschema/schframe.h b/eeschema/schframe.h index e80e9bbeb..bd0f08a06 100644 --- a/eeschema/schframe.h +++ b/eeschema/schframe.h @@ -1161,11 +1161,13 @@ public: * * @param aItemToCopy = the schematic item modified by the command to undo * @param aTypeCommand = command type (see enum UNDO_REDO_T) + * @param aAppend = add the item to the previous undo list * @param aTransformPoint = the reference point of the transformation, * for commands like move */ void SaveCopyInUndoList( SCH_ITEM* aItemToCopy, UNDO_REDO_T aTypeCommand, + bool aAppend = false, const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); /** @@ -1173,11 +1175,13 @@ public: * * @param aItemsList = the list of items modified by the command to undo * @param aTypeCommand = command type (see enum UNDO_REDO_T) + * @param aAppend = add the item to the previous undo list * @param aTransformPoint = the reference point of the transformation, * for commands like move */ void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, + bool aAppend = false, const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); private: -- 2.11.0
From f667cf229bf0b1ecc83c9add6abf471d5b683f4d Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Thu, 12 Oct 2017 16:41:25 -0700 Subject: [PATCH 04/11] Eeschema: Unify delete operations CHANGE: DeleteItemsInList shares the code for DeleteItem. CHANGE: DeleteItem removes junctions that are no longer needed. --- eeschema/block.cpp | 4 +-- eeschema/operations_on_items_lists.cpp | 56 ++++++++++++++++++++++------------ eeschema/schedit.cpp | 2 +- eeschema/schframe.h | 11 ++++++- 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/eeschema/block.cpp b/eeschema/block.cpp index 2d2af403f..f0a52f795 100644 --- a/eeschema/block.cpp +++ b/eeschema/block.cpp @@ -272,7 +272,7 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC ) if( block->GetCount() ) { - DeleteItemsInList( m_canvas, block->GetItems() ); + DeleteItemsInList( block->GetItems() ); OnModify(); } block->ClearItemsList(); @@ -303,7 +303,7 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC ) wxPoint move_vector = -GetScreen()->m_BlockLocate.GetLastCursorPosition(); copyBlockItems( block->GetItems() ); MoveItemsInList( m_blockItems.GetItems(), move_vector ); - DeleteItemsInList( m_canvas, block->GetItems() ); + DeleteItemsInList( block->GetItems() ); OnModify(); } diff --git a/eeschema/operations_on_items_lists.cpp b/eeschema/operations_on_items_lists.cpp index a470c5d6f..ad8313d38 100644 --- a/eeschema/operations_on_items_lists.cpp +++ b/eeschema/operations_on_items_lists.cpp @@ -115,10 +115,8 @@ void MoveItemsInList( PICKED_ITEMS_LIST& aItemsList, const wxPoint& aMoveVector } -void DeleteItemsInList( EDA_DRAW_PANEL* panel, PICKED_ITEMS_LIST& aItemsList ) +void SCH_EDIT_FRAME::DeleteItemsInList( PICKED_ITEMS_LIST& aItemsList, bool aAppend ) { - SCH_SCREEN* screen = (SCH_SCREEN*) panel->GetScreen(); - SCH_EDIT_FRAME* frame = (SCH_EDIT_FRAME*) panel->GetParent(); PICKED_ITEMS_LIST itemsList; for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) @@ -126,46 +124,64 @@ void DeleteItemsInList( EDA_DRAW_PANEL* panel, PICKED_ITEMS_LIST& aItemsList ) SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii ); ITEM_PICKER itemWrapper( item, UR_DELETED ); - if( item->Type() == SCH_SHEET_PIN_T ) - { - /* this item is depending on a sheet, and is not in global list */ - wxMessageBox( wxT( "DeleteItemsInList() err: unexpected SCH_SHEET_PIN_T" ) ); - } - else - { - screen->Remove( item ); + if( item->GetFlags() & STRUCT_DELETED ) + continue; - /* Unlink the structure */ - itemsList.PushItem( itemWrapper ); - } + DeleteItem( item, aAppend ); + aAppend = true; } - frame->SaveCopyInUndoList( itemsList, UR_DELETED ); + GetScreen()->ClearDrawingState(); } -void SCH_EDIT_FRAME::DeleteItem( SCH_ITEM* aItem ) +void SCH_EDIT_FRAME::DeleteItem( SCH_ITEM* aItem, bool aAppend ) { wxCHECK_RET( aItem != NULL, wxT( "Cannot delete invalid item." ) ); + wxCHECK_RET( !( aItem->GetFlags() & STRUCT_DELETED ), + wxT( "Cannot delete item that is already deleted." ) ); // Here, aItem is not null. - SCH_SCREEN* screen = GetScreen(); if( aItem->Type() == SCH_SHEET_PIN_T ) { - // This iten is attached to a node, and is not accessible by the global list directly. + // This item is attached to a node, and is not accessible by the global list directly. SCH_SHEET* sheet = (SCH_SHEET*) aItem->GetParent(); wxCHECK_RET( (sheet != NULL) && (sheet->Type() == SCH_SHEET_T), wxT( "Sheet label has invalid parent item." ) ); - SaveCopyInUndoList( (SCH_ITEM*) sheet, UR_CHANGED ); + SaveCopyInUndoList( (SCH_ITEM*) sheet, UR_CHANGED, aAppend ); sheet->RemovePin( (SCH_SHEET_PIN*) aItem ); m_canvas->RefreshDrawingRect( sheet->GetBoundingBox() ); } else { + PICKED_ITEMS_LIST itemsList; + ITEM_PICKER picker( aItem, UR_DELETED ); + + aItem->SetFlags( STRUCT_DELETED ); + itemsList.PushItem( picker ); screen->Remove( aItem ); - SaveCopyInUndoList( aItem, UR_DELETED ); + + if( aItem->IsConnectable() && aItem->Type() != SCH_JUNCTION_T ) + { + std::vector< wxPoint > pts; + aItem->GetConnectionPoints( pts ); + for( auto point : pts ) + { + SCH_ITEM* junction; + if( !screen->IsJunctionNeeded( point ) + && ( junction = screen->GetItem( point, 0, SCH_JUNCTION_T ) ) ) + { + ITEM_PICKER picker_juction( junction, UR_DELETED ); + junction->SetFlags( STRUCT_DELETED ); + itemsList.PushItem( picker_juction ); + screen->Remove( junction ); + } + } + } + + SaveCopyInUndoList( itemsList, UR_DELETED, aAppend ); m_canvas->RefreshDrawingRect( aItem->GetBoundingBox() ); } } diff --git a/eeschema/schedit.cpp b/eeschema/schedit.cpp index 102f1fcbe..80b17570c 100644 --- a/eeschema/schedit.cpp +++ b/eeschema/schedit.cpp @@ -648,7 +648,7 @@ void SCH_EDIT_FRAME::DeleteConnection( bool aFullConnection ) if( screen->GetConnection( pos, pickList, aFullConnection ) != 0 ) { - DeleteItemsInList( m_canvas, pickList ); + DeleteItemsInList( pickList ); OnModify(); } } diff --git a/eeschema/schframe.h b/eeschema/schframe.h index bd0f08a06..1e3e46dd8 100644 --- a/eeschema/schframe.h +++ b/eeschema/schframe.h @@ -1073,7 +1073,16 @@ public: * * @param aItem The item to remove from the current screen. */ - void DeleteItem( SCH_ITEM* aItem ); + void DeleteItem( SCH_ITEM* aItem, bool aAppend = false ); + + /** + * Removes all items (and unused junctions that connect to them) and saves + * each in the undo list + * + * @param aItemsList The list of items to delete + * @param aAppend True if we are updating a previous commit + */ + void DeleteItemsInList( PICKED_ITEMS_LIST& aItemsList, bool aAppend = false ); int GetLabelIncrement() const { return m_repeatLabelDelta; } -- 2.11.0
From 60b34dcf264bc52ac9802686c5e08e5c92b63ec5 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Mon, 16 Oct 2017 14:38:57 -0700 Subject: [PATCH 05/11] Eeschema: Add two utility functions to sch_line NEW: Add IsSameQuandrant and IsParallel functions --- eeschema/sch_line.cpp | 36 ++++++++++++++++++++++++++++++++++++ eeschema/sch_line.h | 12 ++++++++++++ 2 files changed, 48 insertions(+) diff --git a/eeschema/sch_line.cpp b/eeschema/sch_line.cpp index 4e3246c2a..7a05fee98 100644 --- a/eeschema/sch_line.cpp +++ b/eeschema/sch_line.cpp @@ -352,6 +352,42 @@ void SCH_LINE::Rotate( wxPoint aPosition ) } +bool SCH_LINE::IsSameQuadrant( SCH_LINE* aLine, const wxPoint& aPosition ) +{ + wxPoint first; + wxPoint second; + + if( m_start == aPosition ) + first = m_end - aPosition; + else if( m_end == aPosition ) + first = m_start - aPosition; + else + return false; + + if( aLine->m_start == aPosition ) + second = aLine->m_end - aPosition; + else if( aLine->m_end == aPosition ) + second = aLine->m_start - aPosition; + else + return false; + + return (std::signbit( first.x ) == std::signbit( second.x ) && + std::signbit( first.y ) == std::signbit( second.y ) ); +} + + +bool SCH_LINE::IsParallel( SCH_LINE* aLine ) +{ + wxCHECK_MSG( aLine != NULL && aLine->Type() == SCH_LINE_T, false, + wxT( "Cannot test line segment for overlap." ) ); + + wxPoint firstSeg = m_end - m_start; + wxPoint secondSeg = aLine->m_end - aLine->m_start; + + // Use long long here to avoid overflow in calculations + return !( (long long) firstSeg.x * secondSeg.y - (long long) firstSeg.y * secondSeg.x ); +} + bool SCH_LINE::MergeOverlap( SCH_LINE* aLine ) { auto less = []( const wxPoint& lhs, const wxPoint& rhs ) -> bool diff --git a/eeschema/sch_line.h b/eeschema/sch_line.h index ac84a2a6c..6b7594c31 100644 --- a/eeschema/sch_line.h +++ b/eeschema/sch_line.h @@ -142,6 +142,18 @@ public: */ bool MergeOverlap( SCH_LINE* aLine ); + /** + * Check if two lines are in the same quadrant as each other, using a reference point as + * the origin + * + * @param aLine - Line to compare + * @param aPosition - Point to reference against lines + * @return true if lines are mostly in different quadrants of aPosition, false otherwise + */ + bool IsSameQuadrant( SCH_LINE* aLine, const wxPoint& aPosition ); + + bool IsParallel( SCH_LINE* aLine ); + void GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList ) override; bool IsDanglingStateChanged( std::vector< DANGLING_END_ITEM >& aItemList ) override; -- 2.11.0
From 0a25c3cc245ae565c6a6acbd8c96775cd135d854 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Fri, 20 Oct 2017 09:31:02 -0700 Subject: [PATCH 06/11] Eeschema: don't cleanup unseen schematics Changes to the schematic shouldn't be made where the user isn't looking. Removing the cleanup in ERC and netlisting prevents unintended consequences CHANGE: ERC and Netlist calls do not modify schematic --- eeschema/dialogs/dialog_erc.cpp | 9 --------- eeschema/netlist.cpp | 4 ---- 2 files changed, 13 deletions(-) diff --git a/eeschema/dialogs/dialog_erc.cpp b/eeschema/dialogs/dialog_erc.cpp index 8e811a40d..47c9d686b 100644 --- a/eeschema/dialogs/dialog_erc.cpp +++ b/eeschema/dialogs/dialog_erc.cpp @@ -478,15 +478,6 @@ void DIALOG_ERC::TestErc( wxArrayString* aMessagesList ) // Erase all previous DRC markers. screens.DeleteAllMarkers( MARKER_BASE::MARKER_ERC ); - for( SCH_SCREEN* screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() ) - { - /* Ff wire list has changed, delete Undo Redo list to avoid pointers on deleted - * data problems. - */ - if( screen->SchematicCleanUp() ) - screen->ClearUndoRedoList(); - } - /* Test duplicate sheet names inside a given sheet, one cannot have sheets with * duplicate names (file names can be duplicated). */ diff --git a/eeschema/netlist.cpp b/eeschema/netlist.cpp index 6252f27c4..ef5d0a5f5 100644 --- a/eeschema/netlist.cpp +++ b/eeschema/netlist.cpp @@ -83,9 +83,6 @@ bool SCH_EDIT_FRAME::prepareForNetlist() return false; } - // Cleanup the entire hierarchy - schematic.SchematicCleanUp(); - return true; } @@ -123,7 +120,6 @@ bool SCH_EDIT_FRAME::CreateNetlist( int aFormat, const wxString& aFullFileName, schematic.UpdateSymbolLinks(); SCH_SHEET_LIST sheets( g_RootSheet ); sheets.AnnotatePowerSymbols(); - schematic.SchematicCleanUp(); } std::unique_ptr<NETLIST_OBJECT_LIST> connectedItemsList( BuildNetListBase() ); -- 2.11.0
From d33defbb89c8e98c05224755c59c30aec5b73672 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Tue, 31 Oct 2017 12:33:00 -0700 Subject: [PATCH 07/11] Eeschema: Remove zero-length wires in RemoveBacktracks CHANGE: RemoveBacktracks call removes zero-length wires as well --- eeschema/bus-wire-junction.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/eeschema/bus-wire-junction.cpp b/eeschema/bus-wire-junction.cpp index 528d09d68..fa0175463 100644 --- a/eeschema/bus-wire-junction.cpp +++ b/eeschema/bus-wire-junction.cpp @@ -74,6 +74,12 @@ static void RemoveBacktracks( DLIST<SCH_ITEM>& aWires ) SCH_LINE *line = static_cast<SCH_LINE*>( p ); p = line->Next(); + if( line->IsNull() ) + { + delete s_wires.Remove( line ); + continue; + } + if( !last_lines.empty() ) { SCH_LINE* last_line = last_lines[last_lines.size() - 1]; -- 2.11.0
From 1e54a60adb7a9143f895786a5bf3df979f5a522b Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Wed, 25 Oct 2017 15:21:42 -0700 Subject: [PATCH 08/11] Eeschema: Moving SchematicCleanup to SCH_EDIT_FRAME CHANGE: SchematicCleanup function moved from SCH_SCREEN to SCH_EDIT_FRAME --- eeschema/bus-wire-junction.cpp | 53 ++++++++++++++++++++++++++++++++++-- eeschema/class_sch_screen.h | 14 ---------- eeschema/hierarch.cpp | 2 +- eeschema/project_rescue.cpp | 2 +- eeschema/sch_screen.cpp | 62 ------------------------------------------ eeschema/schframe.cpp | 2 +- eeschema/schframe.h | 10 +++++++ 7 files changed, 64 insertions(+), 81 deletions(-) diff --git a/eeschema/bus-wire-junction.cpp b/eeschema/bus-wire-junction.cpp index fa0175463..410f830f6 100644 --- a/eeschema/bus-wire-junction.cpp +++ b/eeschema/bus-wire-junction.cpp @@ -330,7 +330,7 @@ void SCH_EDIT_FRAME::EndSegment( wxDC* DC ) screen->Append( s_wires ); // Correct and remove segments that need to be merged. - screen->SchematicCleanUp(); + SchematicCleanUp(); // A junction could be needed to connect the end point of the last created segment. if( screen->IsJunctionNeeded( endpoint ) ) @@ -417,6 +417,55 @@ void SCH_EDIT_FRAME::DeleteCurrentSegment( wxDC* DC ) } +bool SCH_EDIT_FRAME::SchematicCleanUp() +{ + bool modified = false; + + for( SCH_ITEM* item = GetScreen()->GetDrawItems() ; item; item = item->Next() ) + { + if( ( item->Type() != SCH_LINE_T ) && ( item->Type() != SCH_JUNCTION_T ) ) + continue; + + bool restart; + + for( SCH_ITEM* testItem = item->Next(); testItem; testItem = restart ? GetScreen()->GetDrawItems() : testItem->Next() ) + { + restart = false; + + if( ( item->Type() == SCH_LINE_T ) && ( testItem->Type() == SCH_LINE_T ) ) + { + SCH_LINE* line = (SCH_LINE*) item; + + if( line->MergeOverlap( (SCH_LINE*) testItem ) ) + { + // 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; + } + } + } + } + + GetScreen()->TestDanglingEnds(); + + return modified; +} + + SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( wxDC* aDC, const wxPoint& aPosition, bool aPutInUndoList ) { @@ -445,7 +494,7 @@ SCH_NO_CONNECT* SCH_EDIT_FRAME::AddNoConnect( wxDC* aDC, const wxPoint& aPositio SetRepeatItem( no_connect ); GetScreen()->Append( no_connect ); - GetScreen()->SchematicCleanUp(); + SchematicCleanUp(); OnModify(); m_canvas->Refresh(); SaveCopyInUndoList( no_connect, UR_NEW ); diff --git a/eeschema/class_sch_screen.h b/eeschema/class_sch_screen.h index 92c564d83..7bd647ff5 100644 --- a/eeschema/class_sch_screen.h +++ b/eeschema/class_sch_screen.h @@ -262,16 +262,7 @@ public: bool CheckIfOnDrawList( SCH_ITEM* st ); /** - * Perform routine schematic cleaning including breaking wire and buses and - * deleting identical objects superimposed on top of each other. - * - * @return True if any schematic clean up was performed. - */ - bool SchematicCleanUp(); - - /** * Test all of the connectable objects in the schematic for unused connection points. - * * @return True if any connection state changes were made. */ bool TestDanglingEnds(); @@ -542,11 +533,6 @@ public: void ClearAnnotation(); /** - * Merge and break wire segments in the entire schematic hierarchy. - */ - void SchematicCleanUp(); - - /** * Test all sheet and component objects in the schematic for duplicate time stamps * and replaces them as necessary. * Time stamps must be unique in order for complex hierarchies know which components go diff --git a/eeschema/hierarch.cpp b/eeschema/hierarch.cpp index d66aa4ea9..c41c82164 100644 --- a/eeschema/hierarch.cpp +++ b/eeschema/hierarch.cpp @@ -299,7 +299,7 @@ void SCH_EDIT_FRAME::DisplayCurrentSheet() screen->m_FirstRedraw = false; SetCrossHairPosition( GetScrollCenterPosition() ); m_canvas->MoveCursorToCrossHair(); - screen->SchematicCleanUp(); + SchematicCleanUp(); } else { diff --git a/eeschema/project_rescue.cpp b/eeschema/project_rescue.cpp index 0a482d1c7..5cd22e76a 100644 --- a/eeschema/project_rescue.cpp +++ b/eeschema/project_rescue.cpp @@ -554,7 +554,7 @@ bool SCH_EDIT_FRAME::rescueProject( RESCUER& aRescuer, bool aRunningOnDemand ) viewer->ReCreateListLib(); // Clean up wire ends - GetScreen()->SchematicCleanUp(); + SchematicCleanUp(); m_canvas->Refresh( true ); OnModify(); diff --git a/eeschema/sch_screen.cpp b/eeschema/sch_screen.cpp index cfdd458fc..56e9c2413 100644 --- a/eeschema/sch_screen.cpp +++ b/eeschema/sch_screen.cpp @@ -433,55 +433,6 @@ bool SCH_SCREEN::IsTerminalPoint( const wxPoint& aPosition, int aLayer ) } -bool SCH_SCREEN::SchematicCleanUp() -{ - bool modified = false; - - for( SCH_ITEM* item = m_drawList.begin() ; item; item = item->Next() ) - { - if( ( item->Type() != SCH_LINE_T ) && ( item->Type() != SCH_JUNCTION_T ) ) - continue; - - bool restart; - - for( SCH_ITEM* testItem = item->Next(); testItem; testItem = restart ? m_drawList.begin() : testItem->Next() ) - { - restart = false; - - if( ( item->Type() == SCH_LINE_T ) && ( testItem->Type() == SCH_LINE_T ) ) - { - SCH_LINE* line = (SCH_LINE*) item; - - if( line->MergeOverlap( (SCH_LINE*) testItem ) ) - { - // 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; - } - } - } - } - - TestDanglingEnds(); - - return modified; -} - - void SCH_SCREEN::UpdateSymbolLinks( bool aForce ) { // Initialize or reinitialize the pointer to the LIB_PART for each component @@ -1373,19 +1324,6 @@ void SCH_SCREENS::ClearAnnotation() m_screens[i]->ClearAnnotation( NULL ); } - -void SCH_SCREENS::SchematicCleanUp() -{ - for( size_t i = 0; i < m_screens.size(); i++ ) - { - // if wire list has changed, delete the undo/redo list to avoid - // pointer problems with deleted data. - if( m_screens[i]->SchematicCleanUp() ) - m_screens[i]->ClearUndoRedoList(); - } -} - - int SCH_SCREENS::ReplaceDuplicateTimeStamps() { EDA_ITEMS items; diff --git a/eeschema/schframe.cpp b/eeschema/schframe.cpp index 0cc8f0d86..97f23a5be 100644 --- a/eeschema/schframe.cpp +++ b/eeschema/schframe.cpp @@ -1243,7 +1243,7 @@ void SCH_EDIT_FRAME::OnOpenLibraryEditor( wxCommandEvent& event ) libeditFrame->LoadComponentAndSelectLib( id ); } - GetScreen()->SchematicCleanUp(); + SchematicCleanUp(); m_canvas->Refresh(); } diff --git a/eeschema/schframe.h b/eeschema/schframe.h index 1e3e46dd8..a583ab46f 100644 --- a/eeschema/schframe.h +++ b/eeschema/schframe.h @@ -909,6 +909,15 @@ private: SCH_JUNCTION* AddJunction( wxDC* aDC, const wxPoint& aPosition, bool aPutInUndoList = false ); /** + * Function SchematicCleanUp + * performs routine schematic cleaning including breaking wire and buses and + * deleting identical objects superimposed on top of each other. + * + * @return True if any schematic clean up was performed. + */ + bool SchematicCleanUp(); + + /** * Start moving \a aItem using the mouse. * * @param aItem A pointer to an SCH_ITEM to move. @@ -1072,6 +1081,7 @@ public: * Remove \a aItem from the current screen and saves it in the undo list. * * @param aItem The item to remove from the current screen. + * @param aAppend True if we are updating a previous Undo state */ void DeleteItem( SCH_ITEM* aItem, bool aAppend = false ); -- 2.11.0
From 699bf73a0c2efce95f75627aa27bfa55db4cfce5 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Thu, 16 Nov 2017 12:39:59 -0800 Subject: [PATCH 09/11] Eeschema: Removing DC dependencies --- eeschema/bus-wire-junction.cpp | 16 ++++++---------- eeschema/onleftclick.cpp | 6 +++--- eeschema/schedit.cpp | 4 ++-- eeschema/schframe.h | 7 +++---- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/eeschema/bus-wire-junction.cpp b/eeschema/bus-wire-junction.cpp index 410f830f6..ea215c302 100644 --- a/eeschema/bus-wire-junction.cpp +++ b/eeschema/bus-wire-junction.cpp @@ -248,7 +248,7 @@ void SCH_EDIT_FRAME::BeginSegment( wxDC* DC, int type ) // Terminate the command if the end point is on a pin, junction, or another wire or bus. if( GetScreen()->IsTerminalPoint( cursorpos, segment->GetLayer() ) ) { - EndSegment( DC ); + EndSegment(); return; } @@ -267,7 +267,7 @@ void SCH_EDIT_FRAME::BeginSegment( wxDC* DC, int type ) } -void SCH_EDIT_FRAME::EndSegment( wxDC* DC ) +void SCH_EDIT_FRAME::EndSegment() { SCH_SCREEN* screen = GetScreen(); SCH_LINE* segment = (SCH_LINE*) screen->GetCurItem(); @@ -334,11 +334,11 @@ void SCH_EDIT_FRAME::EndSegment( wxDC* DC ) // A junction could be needed to connect the end point of the last created segment. if( screen->IsJunctionNeeded( endpoint ) ) - screen->Append( AddJunction( DC, 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( DC, startPoint ) ); + screen->Append( AddJunction( startPoint ) ); m_canvas->Refresh(); @@ -466,17 +466,13 @@ bool SCH_EDIT_FRAME::SchematicCleanUp() } -SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( wxDC* aDC, const wxPoint& aPosition, +SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( const wxPoint& aPosition, bool aPutInUndoList ) { SCH_JUNCTION* junction = new SCH_JUNCTION( aPosition ); SetRepeatItem( junction ); - m_canvas->CrossHairOff( aDC ); // Erase schematic cursor - junction->Draw( m_canvas, aDC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE ); - m_canvas->CrossHairOn( aDC ); // Display schematic cursor - if( aPutInUndoList ) { GetScreen()->Append( junction ); @@ -488,7 +484,7 @@ SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( wxDC* aDC, const wxPoint& aPosition, } -SCH_NO_CONNECT* SCH_EDIT_FRAME::AddNoConnect( wxDC* aDC, const wxPoint& aPosition ) +SCH_NO_CONNECT* SCH_EDIT_FRAME::AddNoConnect( const wxPoint& aPosition ) { SCH_NO_CONNECT* no_connect = new SCH_NO_CONNECT( aPosition ); diff --git a/eeschema/onleftclick.cpp b/eeschema/onleftclick.cpp index ed349001b..2cfc9e045 100644 --- a/eeschema/onleftclick.cpp +++ b/eeschema/onleftclick.cpp @@ -120,7 +120,7 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) { if( GetScreen()->GetItem( gridPosition, 0, SCH_NO_CONNECT_T ) == NULL ) { - SCH_NO_CONNECT* no_connect = AddNoConnect( aDC, gridPosition ); + SCH_NO_CONNECT* no_connect = AddNoConnect( gridPosition ); SetRepeatItem( no_connect ); GetScreen()->SetCurItem( no_connect ); m_canvas->SetAutoPanRequest( true ); @@ -137,7 +137,7 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) { if( GetScreen()->GetItem( gridPosition, 0, SCH_JUNCTION_T ) == NULL ) { - SCH_JUNCTION* junction = AddJunction( aDC, gridPosition, true ); + SCH_JUNCTION* junction = AddJunction( gridPosition ); SetRepeatItem( junction ); GetScreen()->SetCurItem( junction ); m_canvas->SetAutoPanRequest( true ); @@ -442,7 +442,7 @@ void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition ) case ID_WIRE_BUTT: case ID_LINE_COMMENT_BUTT: if( item && item->IsNew() ) - EndSegment( aDC ); + EndSegment(); break; } diff --git a/eeschema/schedit.cpp b/eeschema/schedit.cpp index 80b17570c..61d9bf6e8 100644 --- a/eeschema/schedit.cpp +++ b/eeschema/schedit.cpp @@ -169,7 +169,7 @@ void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_POPUP_END_LINE: m_canvas->MoveCursorToCrossHair(); - EndSegment( &dc ); + EndSegment(); break; case ID_POPUP_SCH_BEGIN_WIRE: @@ -372,7 +372,7 @@ void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_POPUP_SCH_ADD_JUNCTION: m_canvas->MoveCursorToCrossHair(); - screen->SetCurItem( AddJunction( &dc, GetCrossHairPosition(), true ) ); + screen->SetCurItem( AddJunction( GetCrossHairPosition() ) ); if( screen->TestDanglingEnds() ) m_canvas->Refresh(); diff --git a/eeschema/schframe.h b/eeschema/schframe.h index a583ab46f..76013d54d 100644 --- a/eeschema/schframe.h +++ b/eeschema/schframe.h @@ -897,16 +897,15 @@ private: /** * Add no connect item to the current schematic sheet at \a aPosition. * - * @param aDC The device context to draw the no connect to. * @param aPosition The position in logical (drawing) units to add the no connect. * @return The no connect item added. */ - SCH_NO_CONNECT* AddNoConnect( wxDC* aDC, const wxPoint& aPosition ); + SCH_NO_CONNECT* AddNoConnect( const wxPoint& aPosition ); /** * Add a new junction at \a aPosition. */ - SCH_JUNCTION* AddJunction( wxDC* aDC, const wxPoint& aPosition, bool aPutInUndoList = false ); + SCH_JUNCTION* AddJunction( const wxPoint& aPosition, bool aPutInUndoList = false ); /** * Function SchematicCleanUp @@ -950,7 +949,7 @@ private: /** * Terminate a bus, wire, or line creation. */ - void EndSegment( wxDC* DC ); + void EndSegment(); /** * Erase the last segment at the current mouse position. -- 2.11.0
From c5275eb85b615d1cf49f899a7af1c2e595dee613 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Thu, 26 Oct 2017 08:25:47 -0700 Subject: [PATCH 10/11] Eeschema: Moving BreakSegment into SCH_EDIT_FRAME BreakSegment now breaks a known segment and BreakSegments breaks all segments. This allows functions to break a segment without needing to iterate through the whole list. CHANGE: BreakSegment breaks a single segment NEW: BreakSegments function replaces previous BreakSegment --- eeschema/block.cpp | 3 -- eeschema/bus-wire-junction.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++ eeschema/class_sch_screen.h | 17 --------- eeschema/sch_screen.cpp | 59 ----------------------------- eeschema/schedit.cpp | 23 +---------- eeschema/schframe.h | 34 +++++++++++++++++ 6 files changed, 122 insertions(+), 100 deletions(-) diff --git a/eeschema/block.cpp b/eeschema/block.cpp index f0a52f795..f4aa8517c 100644 --- a/eeschema/block.cpp +++ b/eeschema/block.cpp @@ -228,9 +228,6 @@ bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC ) case BLOCK_DRAG: case BLOCK_DRAG_ITEM: // Drag from a drag command - GetScreen()->BreakSegmentsOnJunctions(); - // fall through - case BLOCK_MOVE: case BLOCK_DUPLICATE: if( block->GetCommand() == BLOCK_DRAG_ITEM && diff --git a/eeschema/bus-wire-junction.cpp b/eeschema/bus-wire-junction.cpp index ea215c302..96c054c81 100644 --- a/eeschema/bus-wire-junction.cpp +++ b/eeschema/bus-wire-junction.cpp @@ -417,6 +417,30 @@ void SCH_EDIT_FRAME::DeleteCurrentSegment( wxDC* DC ) } +void SCH_EDIT_FRAME::SaveWireImage() +{ + DLIST< SCH_ITEM > oldWires; + + oldWires.SetOwnership( false ); // Prevent DLIST for deleting items in destructor. + GetScreen()->ExtractWires( oldWires, true ); + + if( oldWires.GetCount() != 0 ) + { + 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 ); + } +} + + bool SCH_EDIT_FRAME::SchematicCleanUp() { bool modified = false; @@ -465,6 +489,68 @@ bool SCH_EDIT_FRAME::SchematicCleanUp() return modified; } +bool SCH_EDIT_FRAME::BreakSegment( SCH_LINE *aSegment, const wxPoint& aPoint, bool aAppend ) +{ + if( !IsPointOnSegment( aSegment->GetStartPoint(), aSegment->GetEndPoint(), aPoint ) + || aSegment->IsEndPoint( aPoint ) ) + return false; + + SaveCopyInUndoList( aSegment, UR_CHANGED, aAppend ); + SCH_LINE* newSegment = new SCH_LINE( *aSegment ); + SaveCopyInUndoList( newSegment, UR_NEW, true ); + + newSegment->SetStartPoint( aPoint ); + aSegment->SetEndPoint( aPoint ); + GetScreen()->Append( newSegment ); + + return true; +} + + +bool SCH_EDIT_FRAME::BreakSegments( const wxPoint& aPoint, bool aAppend ) +{ + bool brokenSegments = false; + + for( SCH_ITEM* segment = GetScreen()->GetDrawItems(); segment; segment = segment->Next() ) + { + if( ( segment->Type() != SCH_LINE_T ) || ( segment->GetLayer() == LAYER_NOTES ) ) + continue; + + brokenSegments |= BreakSegment( (SCH_LINE*) segment, aPoint, aAppend || brokenSegments ); + } + + return brokenSegments; +} + + +bool SCH_EDIT_FRAME::BreakSegmentsOnJunctions() +{ + bool brokenSegments = false; + + for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = item->Next() ) + { + if( item->Type() == SCH_JUNCTION_T ) + { + SCH_JUNCTION* junction = ( SCH_JUNCTION* ) item; + + if( BreakSegments( junction->GetPosition(), brokenSegments ) ) + brokenSegments = true; + } + else + { + SCH_BUS_ENTRY_BASE* busEntry = dynamic_cast<SCH_BUS_ENTRY_BASE*>( item ); + if( busEntry ) + { + if( BreakSegments( busEntry->GetPosition(), brokenSegments ) + || BreakSegments( busEntry->m_End(), brokenSegments ) ) + brokenSegments = true; + } + } + } + + return brokenSegments; +} + SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( const wxPoint& aPosition, bool aPutInUndoList ) diff --git a/eeschema/class_sch_screen.h b/eeschema/class_sch_screen.h index 7bd647ff5..dd11205e0 100644 --- a/eeschema/class_sch_screen.h +++ b/eeschema/class_sch_screen.h @@ -308,23 +308,6 @@ public: */ int GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aList, bool aFullConnection ); - /** - * Checks every wire and bus for a intersection at \a aPoint and break into two segments - * at \a aPoint if an intersection is found. - * - * @param aPoint Test this point for an intersection. - * @return True if any wires or buses were broken. - */ - bool BreakSegment( const wxPoint& aPoint ); - - /** - * Tests all junctions and bus entries in the schematic for intersections with wires and - * buses and breaks any intersections into multiple segments. - * - * @return True if any wires or buses were broken. - */ - bool BreakSegmentsOnJunctions(); - /* full undo redo management : */ // use BASE_SCREEN::PushCommandToUndoList( PICKED_ITEMS_LIST* aItem ) // use BASE_SCREEN::PushCommandToRedoList( PICKED_ITEMS_LIST* aItem ) diff --git a/eeschema/sch_screen.cpp b/eeschema/sch_screen.cpp index 56e9c2413..d1004af73 100644 --- a/eeschema/sch_screen.cpp +++ b/eeschema/sch_screen.cpp @@ -843,64 +843,6 @@ bool SCH_SCREEN::TestDanglingEnds() } -bool SCH_SCREEN::BreakSegment( const wxPoint& aPoint ) -{ - SCH_LINE* segment; - SCH_LINE* newSegment; - bool brokenSegments = false; - - for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) - { - if( (item->Type() != SCH_LINE_T) || (item->GetLayer() == LAYER_NOTES) ) - continue; - - segment = (SCH_LINE*) item; - - if( !segment->HitTest( aPoint, 0 ) || segment->IsEndPoint( aPoint ) ) - continue; - - // Break the segment at aPoint and create a new segment. - newSegment = new SCH_LINE( *segment ); - newSegment->SetStartPoint( aPoint ); - segment->SetEndPoint( aPoint ); - m_drawList.Insert( newSegment, segment->Next() ); - item = newSegment; - brokenSegments = true; - } - - return brokenSegments; -} - - -bool SCH_SCREEN::BreakSegmentsOnJunctions() -{ - bool brokenSegments = false; - - for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) - { - if( item->Type() == SCH_JUNCTION_T ) - { - SCH_JUNCTION* junction = ( SCH_JUNCTION* ) item; - - if( BreakSegment( junction->GetPosition() ) ) - brokenSegments = true; - } - else - { - SCH_BUS_ENTRY_BASE* busEntry = dynamic_cast<SCH_BUS_ENTRY_BASE*>( item ); - if( busEntry ) - { - if( BreakSegment( busEntry->GetPosition() ) - || BreakSegment( busEntry->m_End() ) ) - brokenSegments = true; - } - } - } - - return brokenSegments; -} - - int SCH_SCREEN::GetNode( const wxPoint& aPosition, EDA_ITEMS& aList ) { for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() ) @@ -1045,7 +987,6 @@ int SCH_SCREEN::GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aLis // Clear flags member for all items. ClearDrawingState(); - BreakSegmentsOnJunctions(); if( GetNode( aPosition, list ) == 0 ) return 0; diff --git a/eeschema/schedit.cpp b/eeschema/schedit.cpp index 61d9bf6e8..37a9fd652 100644 --- a/eeschema/schedit.cpp +++ b/eeschema/schedit.cpp @@ -200,28 +200,9 @@ void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_POPUP_SCH_BREAK_WIRE: { - DLIST< SCH_ITEM > oldWires; - - oldWires.SetOwnership( false ); // Prevent DLIST for deleting items in destructor. + SaveWireImage(); m_canvas->MoveCursorToCrossHair(); - screen->ExtractWires( oldWires, true ); - screen->BreakSegment( GetCrossHairPosition() ); - - if( oldWires.GetCount() != 0 ) - { - 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 ); - } - + BreakSegments( GetCrossHairPosition() ); if( screen->TestDanglingEnds() ) m_canvas->Refresh(); } diff --git a/eeschema/schframe.h b/eeschema/schframe.h index 76013d54d..2749944b9 100644 --- a/eeschema/schframe.h +++ b/eeschema/schframe.h @@ -466,6 +466,34 @@ public: bool aWarpMouse ); /** + * Breaks a single segment into two at the specified point + * + * @param aSegment Line segment to break + * @param aPoint Point at which to break the segment + * @param aAppend Add the changes to the previous undo state + * @return True if any wires or buses were broken. + */ + bool BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint, bool aAppend = false ); + + /** + * Checks every wire and bus for a intersection at \a aPoint and break into two segments + * at \a aPoint if an intersection is found. + * + * @param aPoint Test this point for an intersection. + * @param aAppend Add the changes to the previous undo state + * @return True if any wires or buses were broken. + */ + bool BreakSegments( const wxPoint& aPoint, bool aAppend = false ); + + /** + * Tests all junctions and bus entries in the schematic for intersections with wires and + * buses and breaks any intersections into multiple segments. + * + * @return True if any wires or buses were broken. + */ + bool BreakSegmentsOnJunctions(); + + /** * Send a message to Pcbnew via a socket connection. * * Commands are: @@ -908,6 +936,12 @@ private: SCH_JUNCTION* AddJunction( const wxPoint& aPosition, bool aPutInUndoList = false ); /** + * Function SaveWireImage + * saves 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 * deleting identical objects superimposed on top of each other. -- 2.11.0
From b053fee2e6e6af2338c01e99dddfc38262210ba0 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <hillbr...@ucdavis.edu> Date: Thu, 16 Nov 2017 12:58:30 -0800 Subject: [PATCH 11/11] 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 --- eeschema/block.cpp | 13 +- eeschema/bus-wire-junction.cpp | 220 +++++++++++++++++++-------------- eeschema/class_sch_screen.h | 14 +-- eeschema/files-io.cpp | 10 ++ eeschema/hierarch.cpp | 8 +- eeschema/operations_on_items_lists.cpp | 40 ++++++ eeschema/project_rescue.cpp | 1 + eeschema/sch_line.cpp | 21 ++-- eeschema/sch_line.h | 6 +- eeschema/sch_screen.cpp | 82 +++++++----- eeschema/schedit.cpp | 3 + eeschema/schframe.cpp | 9 ++ eeschema/schframe.h | 25 +++- 13 files changed, 294 insertions(+), 158 deletions(-) diff --git a/eeschema/block.cpp b/eeschema/block.cpp index f4aa8517c..4d4ce9adc 100644 --- a/eeschema/block.cpp +++ b/eeschema/block.cpp @@ -129,7 +129,6 @@ void SCH_EDIT_FRAME::HandleBlockPlace( wxDC* DC ) SaveCopyInUndoList( block->GetItems(), UR_MOVED, 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(); } diff --git a/eeschema/bus-wire-junction.cpp b/eeschema/bus-wire-junction.cpp index 96c054c81..39e07956b 100644 --- a/eeschema/bus-wire-junction.cpp +++ b/eeschema/bus-wire-junction.cpp @@ -266,82 +266,76 @@ 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; - // Get the last non-null wire (this is the last created segment). - SetRepeatItem( segment = (SCH_LINE*) s_wires.GetLast() ); + // Collect the possible connection points for the new lines + std::vector< wxPoint > connections; + std::vector< wxPoint > new_ends; - 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(); + 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; - // 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; + wire->GetConnectionPoints( new_ends ); - while( oldWires.GetCount() != 0 ) - { - ITEM_PICKER picker = ITEM_PICKER( oldWires.PopFront(), UR_WIRE_IMAGE ); - oldItems.PushItem( picker ); + 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 ) ); } - SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE ); - - // Remove segments backtracking over others - RemoveBacktracks( s_wires ); + // Get the last non-null wire (this is the last created segment). + SetRepeatItem( segment = (SCH_LINE*) s_wires.GetLast() ); // 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,52 +435,95 @@ 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(); + + auto remove_item = [ &itemList, screen ]( SCH_ITEM* aItem ) -> void + { + aItem->SetFlags( STRUCT_DELETED ); + itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) ); + }; - for( SCH_ITEM* item = GetScreen()->GetDrawItems() ; item; item = item->Next() ) + for( item = screen->GetDrawItems(); item; item = item->Next() ) { - if( ( item->Type() != SCH_LINE_T ) && ( item->Type() != SCH_JUNCTION_T ) ) + 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 ) ) - { - SCH_LINE* line = (SCH_LINE*) item; + for( secondItem = item->Next(); secondItem; secondItem = secondItem->Next() ) + { + if( item->Type() != secondItem->Type() || ( secondItem->GetFlags() & STRUCT_DELETED ) ) + continue; - if( line->MergeOverlap( (SCH_LINE*) testItem ) ) - { - // 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 ) ) + // Merge overlapping lines + if( item->Type() == SCH_LINE_T ) { - if ( testItem->HitTest( item->GetPosition() ) ) + SCH_LINE* firstLine = (SCH_LINE*) item; + SCH_LINE* secondLine = (SCH_LINE*) secondItem; + SCH_LINE* line = NULL; + bool needed = false; + + 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; + 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 ) @@ -552,20 +589,17 @@ bool SCH_EDIT_FRAME::BreakSegmentsOnJunctions() } -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; } diff --git a/eeschema/class_sch_screen.h b/eeschema/class_sch_screen.h index dd11205e0..a90763f35 100644 --- a/eeschema/class_sch_screen.h +++ b/eeschema/class_sch_screen.h @@ -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. diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index c6a38495d..e99b6c54d 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -360,6 +360,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. } @@ -772,6 +777,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 ); diff --git a/eeschema/hierarch.cpp b/eeschema/hierarch.cpp index c41c82164..c65f388c4 100644 --- a/eeschema/hierarch.cpp +++ b/eeschema/hierarch.cpp @@ -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 { diff --git a/eeschema/operations_on_items_lists.cpp b/eeschema/operations_on_items_lists.cpp index ad8313d38..d3ff28636 100644 --- a/eeschema/operations_on_items_lists.cpp +++ b/eeschema/operations_on_items_lists.cpp @@ -115,6 +115,46 @@ 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; + } + } +} + +/** + * Function DeleteItemsInList + * delete schematic items in aItemsList + * deleted items are put in undo list + */ void SCH_EDIT_FRAME::DeleteItemsInList( PICKED_ITEMS_LIST& aItemsList, bool aAppend ) { PICKED_ITEMS_LIST itemsList; diff --git a/eeschema/project_rescue.cpp b/eeschema/project_rescue.cpp index 5cd22e76a..feb37e645 100644 --- a/eeschema/project_rescue.cpp +++ b/eeschema/project_rescue.cpp @@ -555,6 +555,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(); diff --git a/eeschema/sch_line.cpp b/eeschema/sch_line.cpp index 7a05fee98..385858dad 100644 --- a/eeschema/sch_line.cpp +++ b/eeschema/sch_line.cpp @@ -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; } diff --git a/eeschema/sch_line.h b/eeschema/sch_line.h index 6b7594c31..e82d48268 100644 --- a/eeschema/sch_line.h +++ b/eeschema/sch_line.h @@ -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 diff --git a/eeschema/sch_screen.cpp b/eeschema/sch_screen.cpp index d1004af73..f6d7ce434 100644 --- a/eeschema/sch_screen.cpp +++ b/eeschema/sch_screen.cpp @@ -55,6 +55,7 @@ #include <lib_pin.h> #include <symbol_lib_table.h> +#include <boost/foreach.hpp> #define EESCHEMA_FILE_STAMP "EESchema" @@ -344,20 +345,59 @@ 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; + + std::vector< SCH_LINE* > lines; - if( GetWire( aPosition, 0, EXCLUDE_END_POINTS_T ) ) + 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; } @@ -1096,30 +1136,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 ) @@ -1130,7 +1146,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 ); diff --git a/eeschema/schedit.cpp b/eeschema/schedit.cpp index 37a9fd652..b9dad1587 100644 --- a/eeschema/schedit.cpp +++ b/eeschema/schedit.cpp @@ -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(); } } diff --git a/eeschema/schframe.cpp b/eeschema/schframe.cpp index 97f23a5be..f2a193ebd 100644 --- a/eeschema/schframe.cpp +++ b/eeschema/schframe.cpp @@ -1437,7 +1437,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(); diff --git a/eeschema/schframe.h b/eeschema/schframe.h index 2749944b9..ee5e2983d 100644 --- a/eeschema/schframe.h +++ b/eeschema/schframe.h @@ -936,19 +936,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. @@ -1127,6 +1133,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: -- 2.11.0
_______________________________________________ Mailing list: https://launchpad.net/~kicad-developers Post to : kicad-developers@lists.launchpad.net Unsubscribe : https://launchpad.net/~kicad-developers More help : https://help.launchpad.net/ListHelp