PNS: Fix several issues with arc dragging

Do not merge vertices that belong to different arcs
Fix start segment identification after arcs
Fix free-angle drag after arc

Fixes https://gitlab.com/kicad/code/kicad/-/issues/8173
Fixes https://gitlab.com/kicad/code/kicad/-/issues/8150
This commit is contained in:
Jon Evans 2021-04-11 15:15:13 -04:00
parent 7d58c53e42
commit a26fc6d65d
5 changed files with 77 additions and 17 deletions

View File

@ -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<ssize_t> new_shapes = aLine.m_shapes;
size_t prev_arc_count = m_arcs.size();
std::vector<ssize_t> 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

View File

@ -89,15 +89,23 @@ bool DRAGGER::startDragSegment( const VECTOR2D& aP, SEGMENT* aSeg )
else if( distB <= w2 )
{
//todo (snh) Adjust segment for arcs
m_draggedSegmentIndex++;
m_mode = DM_CORNER;
}
else if ( m_freeAngleMode )
{
if( distB < distA )
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 )
{
if( distB < distA &&
( m_draggedSegmentIndex < m_draggedLine.PointCount() - 1 ) &&
( m_draggedLine.CLine().CShapes()[ m_draggedSegmentIndex + 1 ] < 0 ) )
{
m_draggedSegmentIndex++;
}
m_mode = DM_CORNER;
}
else

View File

@ -587,6 +587,22 @@ void LINE::dragCorner45( const VECTOR2I& aP, int aIndex )
void LINE::dragCornerFree( const VECTOR2I& aP, int aIndex )
{
const std::vector<ssize_t>& 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();
}

View File

@ -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<const ARC*>( li );
const SHAPE_ARC* sa = static_cast<const SHAPE_ARC*>( arc->Shape() );
int nSegs = pl.Line().SegmentCount();
int nSegs = line.PointCount();
VECTOR2I last = line.CPoint( -1 );
ssize_t lastShape = line.CShapes()[nSegs - 1];
pl.Line().Append( arcReversed[i] ? sa->Reversed() : *sa );
line.Append( arcReversed[i] ? sa->Reversed() : *sa );
segIdxIncrement = pl.Line().SegmentCount() - nSegs - 1;
segIdxIncrement = line.PointCount() - nSegs - 1;
// Are we adding an arc after an arc? add the hidden segment
if( lastShape >= 0 )
segIdxIncrement++;
}
pl.Link( li );

View File

@ -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<ssize_t> 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 );
}