From f0988c3c5dd1ec4b2ee840381ffb75419a51f5f1 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Sat, 25 Nov 2023 14:49:12 -0500 Subject: [PATCH] Fix commit/view handling when dragging arcs Fixes https://gitlab.com/kicad/code/kicad/-/issues/16145 --- pcbnew/tools/edit_tool.cpp | 166 +++++++++++++++++++++---------------- 1 file changed, 96 insertions(+), 70 deletions(-) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index b7d57f4fc6..602ad081a6 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -528,8 +528,9 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent ) if( theArc->GetAngle() + maxTangentDeviation >= ANGLE_180 ) { - wxString msg = wxString::Format( _( "Unable to resize arc tracks of %s or greater." ), - EDA_UNIT_UTILS::UI::MessageTextFromValue( ANGLE_180 - maxTangentDeviation ) ); + wxString msg = wxString::Format( + _( "Unable to resize arc tracks of %s or greater." ), + EDA_UNIT_UTILS::UI::MessageTextFromValue( ANGLE_180 - maxTangentDeviation ) ); frame()->ShowInfoBarError( msg ); return 0; // don't bother with > 180 degree arcs @@ -542,8 +543,8 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent ) controls->ShowCursor( true ); controls->SetAutoPan( true ); - BOARD_COMMIT commit( this ); - bool restore_state = false; + BOARD_COMMIT commit( this ); + bool restore_state = false; commit.Modify( theArc ); @@ -562,60 +563,61 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent ) tanEnd.A = *tanIntersect; tanEnd.B = theArc->GetEnd(); - auto getUniqueTrackAtAnchorCollinear = - [&]( const VECTOR2I& aAnchor, const SEG& aCollinearSeg ) -> PCB_TRACK* - { - std::shared_ptr conn = board()->GetConnectivity(); + std::set addedTracks; - // Allow items at a distance within the width of the arc track - int allowedDeviation = theArc->GetWidth(); + auto getUniqueTrackAtAnchorCollinear = [&]( const VECTOR2I& aAnchor, + const SEG& aCollinearSeg ) -> PCB_TRACK* + { + std::shared_ptr conn = board()->GetConnectivity(); - std::vector itemsOnAnchor; + // Allow items at a distance within the width of the arc track + int allowedDeviation = theArc->GetWidth(); - for( int i = 0; i < 3; i++ ) - { - itemsOnAnchor = conn->GetConnectedItemsAtAnchor( theArc, aAnchor, - { PCB_PAD_T, PCB_VIA_T, - PCB_TRACE_T, PCB_ARC_T }, - allowedDeviation ); - allowedDeviation /= 2; + std::vector itemsOnAnchor; - if( itemsOnAnchor.size() == 1 ) - break; - } + for( int i = 0; i < 3; i++ ) + { + itemsOnAnchor = conn->GetConnectedItemsAtAnchor( + theArc, aAnchor, { PCB_PAD_T, PCB_VIA_T, PCB_TRACE_T, PCB_ARC_T }, + allowedDeviation ); + allowedDeviation /= 2; - PCB_TRACK* track = nullptr; + if( itemsOnAnchor.size() == 1 ) + break; + } - if( itemsOnAnchor.size() == 1 && itemsOnAnchor.front()->Type() == PCB_TRACE_T ) - { - track = static_cast( itemsOnAnchor.front() ); - commit.Modify( track ); + PCB_TRACK* track = nullptr; - SEG trackSeg( track->GetStart(), track->GetEnd() ); + if( itemsOnAnchor.size() == 1 && itemsOnAnchor.front()->Type() == PCB_TRACE_T ) + { + track = static_cast( itemsOnAnchor.front() ); + commit.Modify( track ); - // Allow deviations in colinearity as defined in ADVANCED_CFG - if( trackSeg.Angle( aCollinearSeg ) > maxTangentDeviation ) - track = nullptr; - } + SEG trackSeg( track->GetStart(), track->GetEnd() ); - if( !track ) - { - track = new PCB_TRACK( theArc->GetParent() ); - track->SetStart( aAnchor ); - track->SetEnd( aAnchor ); - track->SetNet( theArc->GetNet() ); - track->SetLayer( theArc->GetLayer() ); - track->SetWidth( theArc->GetWidth() ); - track->SetLocked( theArc->IsLocked() ); - track->SetFlags( IS_NEW ); - getView()->Add( track ); - commit.Added( track ); - } + // Allow deviations in colinearity as defined in ADVANCED_CFG + if( trackSeg.Angle( aCollinearSeg ) > maxTangentDeviation ) + track = nullptr; + } - return track; - }; + if( !track ) + { + track = new PCB_TRACK( theArc->GetParent() ); + track->SetStart( aAnchor ); + track->SetEnd( aAnchor ); + track->SetNet( theArc->GetNet() ); + track->SetLayer( theArc->GetLayer() ); + track->SetWidth( theArc->GetWidth() ); + track->SetLocked( theArc->IsLocked() ); + track->SetFlags( IS_NEW ); + getView()->Add( track ); + addedTracks.insert( track ); + } - PCB_TRACK* trackOnStart = getUniqueTrackAtAnchorCollinear( theArc->GetStart(), tanStart); + return track; + }; + + PCB_TRACK* trackOnStart = getUniqueTrackAtAnchorCollinear( theArc->GetStart(), tanStart ); PCB_TRACK* trackOnEnd = getUniqueTrackAtAnchorCollinear( theArc->GetEnd(), tanEnd ); if( trackOnStart->GetLength() != 0 ) @@ -634,14 +636,13 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent ) if( tanIntersect = tanStart.IntersectLines( tanEnd ); !tanIntersect ) return 0; - auto isTrackStartClosestToArcStart = - [&]( PCB_TRACK* aTrack ) -> bool - { - double trackStartToArcStart = GetLineLength( aTrack->GetStart(), theArc->GetStart() ); - double trackEndToArcStart = GetLineLength( aTrack->GetEnd(), theArc->GetStart() ); + auto isTrackStartClosestToArcStart = [&]( PCB_TRACK* aTrack ) -> bool + { + double trackStartToArcStart = GetLineLength( aTrack->GetStart(), theArc->GetStart() ); + double trackEndToArcStart = GetLineLength( aTrack->GetEnd(), theArc->GetStart() ); - return trackStartToArcStart < trackEndToArcStart; - }; + return trackStartToArcStart < trackEndToArcStart; + }; bool isStartTrackOnStartPt = isTrackStartClosestToArcStart( trackOnStart ); bool isEndTrackOnStartPt = isTrackStartClosestToArcStart( trackOnEnd ); @@ -673,19 +674,18 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent ) // * * // - auto getFurthestPointToTanInterstect = - [&]( VECTOR2I& aPointA, VECTOR2I& aPointB ) -> VECTOR2I - { - if( ( aPointA - *tanIntersect ).EuclideanNorm() - > ( aPointB - *tanIntersect ).EuclideanNorm() ) - { - return aPointA; - } - else - { - return aPointB; - } - }; + auto getFurthestPointToTanInterstect = [&]( VECTOR2I& aPointA, VECTOR2I& aPointB ) -> VECTOR2I + { + if( ( aPointA - *tanIntersect ).EuclideanNorm() + > ( aPointB - *tanIntersect ).EuclideanNorm() ) + { + return aPointA; + } + else + { + return aPointB; + } + }; CIRCLE maxTanCircle; VECTOR2I tanStartPoint = getFurthestPointToTanInterstect( tanStart.A, tanStart.B ); @@ -789,7 +789,7 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent ) break; // Finish } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) - || evt->IsDblClick( BUT_LEFT ) ) + || evt->IsDblClick( BUT_LEFT ) ) { // Eat mouse-up/-click events that leaked through from the lock dialog if( eatFirstMouseUp && !evt->IsAction( &ACTIONS::cursorClick ) ) @@ -817,19 +817,45 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent ) if( trackOnStart->GetLength() <= maxLengthIU ) { - commit.Remove( trackOnStart ); + if( addedTracks.count( trackOnStart ) ) + { + getView()->Remove( trackOnStart ); + addedTracks.erase( trackOnStart ); + delete trackOnStart; + } + else + { + commit.Remove( trackOnStart ); + } + theArc->SetStart( newStart ); } if( trackOnEnd->GetLength() <= maxLengthIU ) { - commit.Remove( trackOnEnd ); + if( addedTracks.count( trackOnEnd ) ) + { + getView()->Remove( trackOnEnd ); + addedTracks.erase( trackOnEnd ); + delete trackOnEnd; + } + else + { + commit.Remove( trackOnEnd ); + } + theArc->SetEnd( newEnd ); } if( theArc->GetLength() <= 0 ) commit.Remove( theArc ); + for( PCB_TRACK* added : addedTracks ) + { + getView()->Remove( added ); + commit.Add( added ); + } + // Should we commit? if( restore_state ) commit.Revert();