diff --git a/libs/kimath/src/geometry/shape_line_chain.cpp b/libs/kimath/src/geometry/shape_line_chain.cpp index 242c2adbdc..af7059c022 100644 --- a/libs/kimath/src/geometry/shape_line_chain.cpp +++ b/libs/kimath/src/geometry/shape_line_chain.cpp @@ -305,11 +305,36 @@ void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE if( aStartIndex < 0 ) aStartIndex += PointCount(); + // We only process lines in order in this house + wxASSERT( aStartIndex <= aEndIndex ); + + SHAPE_LINE_CHAIN newLine = aLine; + + // It's possible that the start or end lands on the end of an arc. If so, we'd better have a + // replacement line that matches up to the same coordinates, as we can't break the arc(s). + ssize_t startShape = m_shapes[aStartIndex]; + ssize_t endShape = m_shapes[aEndIndex]; + + if( startShape >= 0 ) + { + wxASSERT( newLine.m_points.front() == m_points[aStartIndex] && + aStartIndex < m_points.size() - 1 ); + aStartIndex++; + newLine.Remove( 0 ); + } + + if( endShape >= 0 ) + { + wxASSERT( newLine.m_points.back() == m_points[aEndIndex] && aEndIndex > 0 ); + aEndIndex--; + newLine.Remove( -1 ); + } + Remove( aStartIndex, aEndIndex ); // The total new arcs index is added to the new arc indices - size_t prev_arc_count = m_arcs.size(); - std::vector new_shapes = aLine.m_shapes; + size_t prev_arc_count = m_arcs.size(); + std::vector new_shapes = newLine.m_shapes; for( ssize_t& shape : new_shapes ) { @@ -318,8 +343,9 @@ void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE } m_shapes.insert( m_shapes.begin() + aStartIndex, new_shapes.begin(), new_shapes.end() ); - m_points.insert( m_points.begin() + aStartIndex, aLine.m_points.begin(), aLine.m_points.end() ); - m_arcs.insert( m_arcs.end(), aLine.m_arcs.begin(), aLine.m_arcs.end() ); + m_points.insert( m_points.begin() + aStartIndex, newLine.m_points.begin(), + newLine.m_points.end() ); + m_arcs.insert( m_arcs.end(), newLine.m_arcs.begin(), newLine.m_arcs.end() ); assert( m_shapes.size() == m_points.size() ); } @@ -328,6 +354,7 @@ void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex ) { assert( m_shapes.size() == m_points.size() ); + if( aEndIndex < 0 ) aEndIndex += PointCount(); @@ -1025,7 +1052,7 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify( bool aRemoveColinear ) const VECTOR2I p1 = pts_unique[i + 1]; int n = i; - if( aRemoveColinear ) + if( aRemoveColinear && shapes_unique[i] < 0 && shapes_unique[i + 1] < 0 ) { while( n < np - 2 && ( SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1 diff --git a/pcbnew/router/pns_dragger.cpp b/pcbnew/router/pns_dragger.cpp index d9b05375a6..59f3824d61 100644 --- a/pcbnew/router/pns_dragger.cpp +++ b/pcbnew/router/pns_dragger.cpp @@ -89,15 +89,23 @@ bool DRAGGER::startDragSegment( const VECTOR2D& aP, SEGMENT* aSeg ) else if( distB <= w2 ) { //todo (snh) Adjust segment for arcs - m_draggedSegmentIndex++; + if( ( m_draggedSegmentIndex < m_draggedLine.PointCount() - 1 ) && + ( m_draggedLine.CLine().CShapes()[ m_draggedSegmentIndex + 1 ] < 0 ) ) + { + m_draggedSegmentIndex++; + } + m_mode = DM_CORNER; } - else if ( m_freeAngleMode ) + else if( m_freeAngleMode ) { - if( distB < distA ) + if( distB < distA && + ( m_draggedSegmentIndex < m_draggedLine.PointCount() - 1 ) && + ( m_draggedLine.CLine().CShapes()[ m_draggedSegmentIndex + 1 ] < 0 ) ) { m_draggedSegmentIndex++; } + m_mode = DM_CORNER; } else diff --git a/pcbnew/router/pns_line.cpp b/pcbnew/router/pns_line.cpp index 1df6351ef7..9ac2a138a9 100644 --- a/pcbnew/router/pns_line.cpp +++ b/pcbnew/router/pns_line.cpp @@ -587,6 +587,22 @@ void LINE::dragCorner45( const VECTOR2I& aP, int aIndex ) void LINE::dragCornerFree( const VECTOR2I& aP, int aIndex ) { + const std::vector& shapes = m_line.CShapes(); + + // If we're asked to drag the end of an arc, insert a new vertex to drag instead + if( shapes[aIndex] >= 0 ) + { + if( aIndex > 0 && shapes[aIndex - 1] == -1 ) + m_line.Insert( aIndex, m_line.GetPoint( aIndex ) ); + else if( aIndex < shapes.size() - 1 && shapes[aIndex + 1] == -1 ) + { + aIndex++; + m_line.Insert( aIndex, m_line.GetPoint( aIndex ) ); + } + else + wxASSERT_MSG( false, "Attempt to dragCornerFree in the middle of an arc!" ); + } + m_line.SetPoint( aIndex, aP ); m_line.Simplify(); } diff --git a/pcbnew/router/pns_node.cpp b/pcbnew/router/pns_node.cpp index 995cb3b8a1..478e1df0e9 100644 --- a/pcbnew/router/pns_node.cpp +++ b/pcbnew/router/pns_node.cpp @@ -943,13 +943,15 @@ const LINE NODE::AssembleLine( LINKED_ITEM* aSeg, int* aOriginSegmentIndex, LINKED_ITEM* prev_seg = NULL; bool originSet = false; + SHAPE_LINE_CHAIN& line = pl.Line(); + for( int i = i_start + 1; i < i_end; i++ ) { const VECTOR2I& p = corners[i]; LINKED_ITEM* li = segs[i]; if( !li || li->Kind() != ITEM::ARC_T ) - pl.Line().Append( p ); + line.Append( p ); if( li && prev_seg != li ) { @@ -960,11 +962,17 @@ const LINE NODE::AssembleLine( LINKED_ITEM* aSeg, int* aOriginSegmentIndex, const ARC* arc = static_cast( li ); const SHAPE_ARC* sa = static_cast( arc->Shape() ); - int nSegs = pl.Line().SegmentCount(); + int nSegs = line.PointCount(); + VECTOR2I last = line.CPoint( -1 ); + ssize_t lastShape = line.CShapes()[nSegs - 1]; + + line.Append( arcReversed[i] ? sa->Reversed() : *sa ); - pl.Line().Append( arcReversed[i] ? sa->Reversed() : *sa ); + segIdxIncrement = line.PointCount() - nSegs - 1; - segIdxIncrement = pl.Line().SegmentCount() - nSegs - 1; + // Are we adding an arc after an arc? add the hidden segment + if( lastShape >= 0 ) + segIdxIncrement++; } pl.Link( li ); diff --git a/pcbnew/router/pns_optimizer.cpp b/pcbnew/router/pns_optimizer.cpp index 17fa10fad8..238f46d260 100644 --- a/pcbnew/router/pns_optimizer.cpp +++ b/pcbnew/router/pns_optimizer.cpp @@ -561,7 +561,8 @@ bool OPTIMIZER::mergeFull( LINE* aLine ) bool OPTIMIZER::mergeColinear( LINE* aLine ) { - SHAPE_LINE_CHAIN& line = aLine->Line(); + SHAPE_LINE_CHAIN& line = aLine->Line(); + const std::vector shapes = line.CShapes(); int nSegs = line.SegmentCount(); @@ -570,7 +571,7 @@ bool OPTIMIZER::mergeColinear( LINE* aLine ) SEG s1 = line.CSegment( segIdx ); SEG s2 = line.CSegment( segIdx + 1 ); - if( s1.Collinear( s2 ) ) + if( shapes[segIdx] < 0 && shapes[segIdx + 1] < 0 && s1.Collinear( s2 ) ) line.Replace( segIdx, segIdx + 1, s1.A ); }