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() * Function Simplify()
* *
* Simplifies the line chain by removing colinear adjacent segments and duplicate vertices. * 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. * @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 * 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 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); } 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<VECTOR2I> pts_unique;
std::vector<ssize_t> shapes_unique; std::vector<ssize_t> shapes_unique;
@ -961,11 +961,25 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
{ {
int j = i + 1; 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++; 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 ) ); pts_unique.push_back( CPoint( i ) );
shapes_unique.push_back( m_shapes[i] ); shapes_unique.push_back( shapeToKeep );
i = j; i = j;
} }
@ -976,17 +990,20 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
i = 0; i = 0;
// stage 1: eliminate collinear segments // stage 2: eliminate colinear segments
while( i < np - 2 ) while( i < np - 2 )
{ {
const VECTOR2I p0 = pts_unique[i]; const VECTOR2I p0 = pts_unique[i];
const VECTOR2I p1 = pts_unique[i + 1]; const VECTOR2I p1 = pts_unique[i + 1];
int n = i; int n = i;
while( n < np - 2 if( aRemoveColinear )
&& ( SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1 {
|| SEG( p0, p1 ).Collinear( SEG( p1, pts_unique[n + 2] ) ) ) ) while( n < np - 2
n++; && ( 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_points.push_back( p0 );
m_shapes.push_back( shapes_unique[i] ); 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 else
lastV = std::max( 1, l.SegmentCount() - 1 ); lastV = std::max( 1, l.SegmentCount() - 1 );
SEGMENT seg; ARC arc;
SEGMENT* lastSeg = nullptr; SEGMENT seg;
int lastArc = -1; LINKED_ITEM* lastItem = nullptr;
int lastArc = -1;
for( int i = 0; i < lastV; i++ ) 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 ); seg.SetLayer( m_currentLayer );
if( m_lastNode->Add( std::make_unique<SEGMENT>( seg ) ) ) if( m_lastNode->Add( std::make_unique<SEGMENT>( seg ) ) )
lastSeg = &seg; lastItem = &seg;
} }
else else
{ {
if( arcIndex == lastArc ) if( arcIndex == lastArc )
continue; continue;
std::unique_ptr<ARC> arc = std::make_unique<ARC>( l.Arc( arcIndex ), m_currentNet ); arc = ARC( l.Arc( arcIndex ), m_currentNet );
arc->SetWidth( pl.Width() ); arc.SetWidth( pl.Width() );
arc->SetLayer( m_currentLayer ); arc.SetLayer( m_currentLayer );
m_lastNode->Add( std::move( arc ) );
lastSeg = nullptr; m_lastNode->Add( std::make_unique<ARC>( arc ) );
lastArc = arcIndex; lastItem = &arc;
lastArc = arcIndex;
} }
} }
if( pl.EndsWithVia() ) if( pl.EndsWithVia() )
m_lastNode->Add( Clone( pl.Via() ) ); m_lastNode->Add( Clone( pl.Via() ) );
if( realEnd && lastSeg ) if( realEnd && lastItem )
simplifyNewLine( m_lastNode, lastSeg ); simplifyNewLine( m_lastNode, lastItem );
if( !realEnd ) 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 ); LINE l = aNode->AssembleLine( aLatest );
bool optimized = OPTIMIZER::Optimize( &l, OPTIMIZER::MERGE_COLINEAR, aNode ); bool optimized = OPTIMIZER::Optimize( &l, OPTIMIZER::MERGE_COLINEAR, aNode );

View File

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

View File

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