PNS: re-enable optimization of colinear segs in lines with arcs

This commit is contained in:
Jon Evans 2021-01-03 22:36:42 -05:00
parent 8901e71fc8
commit 8619086cf2
5 changed files with 55 additions and 28 deletions

View File

@ -628,9 +628,10 @@ public:
* Function Simplify()
*
* Simplifies the line chain by removing colinear adjacent segments and duplicate vertices.
* @param aRemoveColinear controsl the removal of colinear adjacent segments
* @return reference to self.
*/
SHAPE_LINE_CHAIN& Simplify();
SHAPE_LINE_CHAIN& Simplify( bool aRemoveColinear = true );
/**
* Converts an arc to only a point chain by removing the arc and references
@ -747,7 +748,14 @@ public:
bool isArc( size_t aSegment ) const
{
return aSegment < m_shapes.size() && m_shapes[aSegment] != SHAPE_IS_PT;
/**
* A segment is part of an arc except in the special case of two arcs next to each other
* but without a shared vertex. Here there is a segment between the end of the first arc
* and the start of the second arc.
*/
return ( aSegment < m_shapes.size() - 1
&& m_shapes[aSegment] != SHAPE_IS_PT
&& m_shapes[aSegment] == m_shapes[aSegment + 1] );
}
virtual const VECTOR2I GetPoint( int aIndex ) const override { return CPoint(aIndex); }

View File

@ -936,7 +936,7 @@ const OPT<SHAPE_LINE_CHAIN::INTERSECTION> SHAPE_LINE_CHAIN::SelfIntersecting() c
}
SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify( bool aRemoveColinear )
{
std::vector<VECTOR2I> pts_unique;
std::vector<ssize_t> shapes_unique;
@ -961,11 +961,25 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
{
int j = i + 1;
while( j < np && m_points[i] == m_points[j] && m_shapes[i] == m_shapes[j] )
// We can eliminate duplicate vertices as long as they are part of the same shape, OR if
// one of them is part of a shape and one is not.
while( j < np && m_points[i] == m_points[j] &&
( m_shapes[i] == m_shapes[j] ||
m_shapes[i] == SHAPE_IS_PT ||
m_shapes[j] == SHAPE_IS_PT ) )
{
j++;
}
int shapeToKeep = m_shapes[i];
if( shapeToKeep == SHAPE_IS_PT )
shapeToKeep = m_shapes[j - 1];
wxASSERT( shapeToKeep < static_cast<int>( m_arcs.size() ) );
pts_unique.push_back( CPoint( i ) );
shapes_unique.push_back( m_shapes[i] );
shapes_unique.push_back( shapeToKeep );
i = j;
}
@ -976,17 +990,20 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
i = 0;
// stage 1: eliminate collinear segments
// stage 2: eliminate colinear segments
while( i < np - 2 )
{
const VECTOR2I p0 = pts_unique[i];
const VECTOR2I p1 = pts_unique[i + 1];
int n = i;
while( n < np - 2
&& ( SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1
|| SEG( p0, p1 ).Collinear( SEG( p1, pts_unique[n + 2] ) ) ) )
n++;
if( aRemoveColinear )
{
while( n < np - 2
&& ( SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1
|| SEG( p0, p1 ).Collinear( SEG( p1, pts_unique[n + 2] ) ) ) )
n++;
}
m_points.push_back( p0 );
m_shapes.push_back( shapes_unique[i] );

View File

@ -1111,9 +1111,10 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis
else
lastV = std::max( 1, l.SegmentCount() - 1 );
SEGMENT seg;
SEGMENT* lastSeg = nullptr;
int lastArc = -1;
ARC arc;
SEGMENT seg;
LINKED_ITEM* lastItem = nullptr;
int lastArc = -1;
for( int i = 0; i < lastV; i++ )
{
@ -1126,27 +1127,28 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis
seg.SetLayer( m_currentLayer );
if( m_lastNode->Add( std::make_unique<SEGMENT>( seg ) ) )
lastSeg = &seg;
lastItem = &seg;
}
else
{
if( arcIndex == lastArc )
continue;
std::unique_ptr<ARC> arc = std::make_unique<ARC>( l.Arc( arcIndex ), m_currentNet );
arc->SetWidth( pl.Width() );
arc->SetLayer( m_currentLayer );
m_lastNode->Add( std::move( arc ) );
lastSeg = nullptr;
lastArc = arcIndex;
arc = ARC( l.Arc( arcIndex ), m_currentNet );
arc.SetWidth( pl.Width() );
arc.SetLayer( m_currentLayer );
m_lastNode->Add( std::make_unique<ARC>( arc ) );
lastItem = &arc;
lastArc = arcIndex;
}
}
if( pl.EndsWithVia() )
m_lastNode->Add( Clone( pl.Via() ) );
if( realEnd && lastSeg )
simplifyNewLine( m_lastNode, lastSeg );
if( realEnd && lastItem )
simplifyNewLine( m_lastNode, lastItem );
if( !realEnd )
{
@ -1297,8 +1299,9 @@ void LINE_PLACER::removeLoops( NODE* aNode, LINE& aLatest )
}
void LINE_PLACER::simplifyNewLine( NODE* aNode, SEGMENT* aLatest )
void LINE_PLACER::simplifyNewLine( NODE* aNode, LINKED_ITEM* aLatest )
{
wxASSERT( aLatest->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) );
LINE l = aNode->AssembleLine( aLatest );
bool optimized = OPTIMIZER::Optimize( &l, OPTIMIZER::MERGE_COLINEAR, aNode );

View File

@ -320,13 +320,11 @@ private:
void removeLoops( NODE* aNode, LINE& aLatest );
/**
* Function simplifyNewLine()
*
* Assembles a line starting from segment aLatest, removes collinear segments
* Assembles a line starting from segment or arc aLatest, removes collinear segments
* and redundant vertexes. If a simplification bhas been found, replaces the
* old line with the simplified one in aNode.
*/
void simplifyNewLine( NODE* aNode, SEGMENT* aLatest );
void simplifyNewLine( NODE* aNode, LINKED_ITEM* aLatest );
/**
* Function handleSelfIntersections()

View File

@ -958,7 +958,8 @@ const LINE NODE::AssembleLine( LINKED_ITEM* aSeg, int* aOriginSegmentIndex,
prev_seg = li;
}
pl.Line().Simplify();
// Remove duplicate verts, but do NOT remove colinear segments here!
pl.Line().Simplify( false );
assert( pl.SegmentCount() != 0 );