From 689da3794d97599a9643e7f611a07ddda1958d34 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Tue, 29 Dec 2020 21:14:14 -0500 Subject: [PATCH] PNS: Merge co-linear segments during placement --- pcbnew/router/pns_line_placer.cpp | 32 +++++++++++++++++++++---------- pcbnew/router/pns_optimizer.cpp | 22 +++++++++++++++++++++ pcbnew/router/pns_optimizer.h | 17 ++++++++-------- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/pcbnew/router/pns_line_placer.cpp b/pcbnew/router/pns_line_placer.cpp index 99fdb97313..bbe0e88c91 100644 --- a/pcbnew/router/pns_line_placer.cpp +++ b/pcbnew/router/pns_line_placer.cpp @@ -1147,6 +1147,13 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis if( !l.SegmentCount() ) { + // Do a final optimization to the stored state + NODE::ITEM_VECTOR removed, added; + m_lastNode->GetUpdatedItems( removed, added ); + + if( !added.empty() && added.back()->Kind() == ITEM::SEGMENT_T ) + simplifyNewLine( m_lastNode, static_cast( added.back() ) ); + // Nothing to commit if we have an empty line if( !pl.EndsWithVia() ) return false; @@ -1181,6 +1188,7 @@ 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; @@ -1190,13 +1198,12 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis if( arcIndex < 0 ) { - const SEG& s = pl.CSegment( i ); - auto seg = std::make_unique( s, m_currentNet ); - seg->SetWidth( pl.Width() ); - seg->SetLayer( m_currentLayer ); + seg = SEGMENT( pl.CSegment( i ), m_currentNet ); + seg.SetWidth( pl.Width() ); + seg.SetLayer( m_currentLayer ); - if( !m_lastNode->Add( std::move( seg ) ) ) - lastSeg = nullptr; + if( m_lastNode->Add( std::make_unique( seg ) ) ) + lastSeg = &seg; } else { @@ -1242,10 +1249,12 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis if ( m_shove ) m_shove->AddLockedSpringbackNode( m_currentNode ); + DIRECTION_45 lastSegDir = pl.EndsWithVia() ? DIRECTION_45::UNDEFINED : d_last; + m_postureSolver.Clear(); m_postureSolver.SetTolerance( m_head.Width() ); m_postureSolver.AddTrailPoint( m_currentStart ); - m_postureSolver.SetDefaultDirections( m_initial_direction, d_last ); + m_postureSolver.SetDefaultDirections( m_initial_direction, lastSegDir ); m_placementCorrect = true; } @@ -1364,11 +1373,14 @@ void LINE_PLACER::removeLoops( NODE* aNode, LINE& aLatest ) void LINE_PLACER::simplifyNewLine( NODE* aNode, SEGMENT* aLatest ) { LINE l = aNode->AssembleLine( aLatest ); + + bool optimized = OPTIMIZER::Optimize( &l, OPTIMIZER::MERGE_COLINEAR, aNode ); + SHAPE_LINE_CHAIN simplified( l.CLine() ); simplified.Simplify(); - if( simplified.PointCount() != l.PointCount() ) + if( optimized || simplified.PointCount() != l.PointCount() ) { aNode->Remove( l ); l.SetShape( simplified ); @@ -1602,10 +1614,10 @@ void POSTURE_SOLVER::AddTrailPoint( const VECTOR2I& aP ) DIRECTION_45 POSTURE_SOLVER::GetPosture( const VECTOR2I& aP ) { // Tuning factor for how good the "fit" of the trail must be to the posture - const double areaRatioThreshold = 1.5; + const double areaRatioThreshold = 1.3; // Tuning factor to minimize flutter - const double areaRatioEpsilon = 0.3; + const double areaRatioEpsilon = 0.25; // Minimum distance factor of the trail before the min area test is used to lock the solver const double minAreaCutoffDistanceFactor = 6; diff --git a/pcbnew/router/pns_optimizer.cpp b/pcbnew/router/pns_optimizer.cpp index e882950270..0fb8f9be74 100644 --- a/pcbnew/router/pns_optimizer.cpp +++ b/pcbnew/router/pns_optimizer.cpp @@ -598,6 +598,25 @@ bool OPTIMIZER::mergeFull( LINE* aLine ) } +bool OPTIMIZER::mergeColinear( LINE* aLine ) +{ + SHAPE_LINE_CHAIN& line = aLine->Line(); + + int nSegs = line.SegmentCount(); + + for( int segIdx = 0; segIdx < line.SegmentCount() - 1; ++segIdx ) + { + SEG s1 = line.CSegment( segIdx ); + SEG s2 = line.CSegment( segIdx + 1 ); + + if( s1.Collinear( s2 ) ) + line.Replace( segIdx, segIdx + 1, s1.A ); + } + + return line.SegmentCount() < nSegs; +} + + bool OPTIMIZER::Optimize( LINE* aLine, LINE* aResult ) { if( !aResult ) @@ -636,6 +655,9 @@ bool OPTIMIZER::Optimize( LINE* aLine, LINE* aResult ) if( m_effortLevel & MERGE_OBTUSE ) rv |= mergeObtuse( aResult ); + if( m_effortLevel & MERGE_COLINEAR ) + rv |= mergeColinear( aResult ); + if( m_effortLevel & SMART_PADS ) rv |= runSmartPads( aResult ); diff --git a/pcbnew/router/pns_optimizer.h b/pcbnew/router/pns_optimizer.h index 91a0b2ab34..df61e95c3e 100644 --- a/pcbnew/router/pns_optimizer.h +++ b/pcbnew/router/pns_optimizer.h @@ -97,14 +97,14 @@ class OPTIMIZER public: enum OptimizationEffort { - MERGE_SEGMENTS = 0x01, - SMART_PADS = 0x02, - MERGE_OBTUSE = 0x04, - FANOUT_CLEANUP = 0x08, - KEEP_TOPOLOGY = 0x10, - PRESERVE_VERTEX = 0x20, - RESTRICT_VERTEX_RANGE = 0x40 - + MERGE_SEGMENTS = 0x01, ///< Reduce corner cost iteratively + SMART_PADS = 0x02, ///< Reroute pad exits + MERGE_OBTUSE = 0x04, ///< Reduce corner cost by merging obtuse segments + FANOUT_CLEANUP = 0x08, ///< Simplify pad-pad and pad-via connections if possible + KEEP_TOPOLOGY = 0x10, + PRESERVE_VERTEX = 0x20, + RESTRICT_VERTEX_RANGE = 0x40, + MERGE_COLINEAR = 0x80 ///< Merge co-linear segments }; OPTIMIZER( NODE* aWorld ); @@ -172,6 +172,7 @@ private: bool mergeObtuse( LINE* aLine ); bool mergeFull( LINE* aLine ); + bool mergeColinear( LINE* aLine ); bool removeUglyCorners( LINE* aLine ); bool runSmartPads( LINE* aLine ); bool mergeStep( LINE* aLine, SHAPE_LINE_CHAIN& aCurrentLine, int step );