From 7431d5c9852b3c7bdd7d96f0b4e4baa65c5f93fa Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Mon, 4 Jan 2021 08:54:29 -0500 Subject: [PATCH] PNS: First pass at updating meander placers for arcs Fixes https://gitlab.com/kicad/code/kicad/-/issues/6464 --- libs/kimath/include/geometry/shape_arc.h | 4 ++ .../include/geometry/shape_line_chain.h | 9 ++- libs/kimath/src/geometry/shape_arc.cpp | 12 ++++ libs/kimath/src/geometry/shape_line_chain.cpp | 71 +++++++++++++++---- pcbnew/router/pns_dp_meander_placer.cpp | 13 ++-- pcbnew/router/pns_dp_meander_placer.h | 2 +- pcbnew/router/pns_meander_placer.cpp | 18 ++--- pcbnew/router/pns_meander_placer.h | 2 +- pcbnew/router/pns_meander_placer_base.cpp | 29 +++++++- pcbnew/router/pns_meander_placer_base.h | 2 + pcbnew/router/pns_meander_skew_placer.cpp | 13 ++-- 11 files changed, 124 insertions(+), 51 deletions(-) diff --git a/libs/kimath/include/geometry/shape_arc.h b/libs/kimath/include/geometry/shape_arc.h index 95055029db..0c3e6bee85 100644 --- a/libs/kimath/include/geometry/shape_arc.h +++ b/libs/kimath/include/geometry/shape_arc.h @@ -135,6 +135,10 @@ public: void Mirror( bool aX = true, bool aY = false, const VECTOR2I& aVector = { 0, 0 } ); + void Reverse(); + + SHAPE_ARC Reversed() const; + double GetRadius() const; SEG GetChord() const diff --git a/libs/kimath/include/geometry/shape_line_chain.h b/libs/kimath/include/geometry/shape_line_chain.h index 68cbb9b003..cb1019b07b 100644 --- a/libs/kimath/include/geometry/shape_line_chain.h +++ b/libs/kimath/include/geometry/shape_line_chain.h @@ -654,16 +654,15 @@ public: int NearestSegment( const VECTOR2I& aP ) const; /** - * Function NearestPoint() - * * Finds a point on the line chain that is closest to point aP. + * @param aP is the point to find + * @param aAllowInternalShapePoints if false will not return points internal to an arc (i.e. + * only the arc endpoints are possible candidates) * @return the nearest point. */ - const VECTOR2I NearestPoint( const VECTOR2I& aP ) const; + const VECTOR2I NearestPoint( const VECTOR2I& aP, bool aAllowInternalShapePoints = true ) const; /** - * Function NearestPoint() - * * Finds a point on the line chain that is closest to the line defined by the points of * segment aSeg, also returns the distance. * @param aSeg Segment defining the line. diff --git a/libs/kimath/src/geometry/shape_arc.cpp b/libs/kimath/src/geometry/shape_arc.cpp index 7d16963e68..3aa017f380 100644 --- a/libs/kimath/src/geometry/shape_arc.cpp +++ b/libs/kimath/src/geometry/shape_arc.cpp @@ -472,3 +472,15 @@ void SHAPE_ARC::Mirror( bool aX, bool aY, const VECTOR2I& aVector ) update_bbox(); } + + +void SHAPE_ARC::Reverse() +{ + std::swap( m_start, m_end ); +} + + +SHAPE_ARC SHAPE_ARC::Reversed() const +{ + return SHAPE_ARC( m_end, m_mid, m_start, m_width ); +} diff --git a/libs/kimath/src/geometry/shape_line_chain.cpp b/libs/kimath/src/geometry/shape_line_chain.cpp index fb45c43fc2..fd6ff8c7ec 100644 --- a/libs/kimath/src/geometry/shape_line_chain.cpp +++ b/libs/kimath/src/geometry/shape_line_chain.cpp @@ -220,6 +220,8 @@ const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Reverse() const sh = a.m_arcs.size() - sh - 1; } + for( SHAPE_ARC& arc : a.m_arcs ) + arc.Reverse(); a.m_closed = m_closed; @@ -390,6 +392,11 @@ int SHAPE_LINE_CHAIN::Split( const VECTOR2I& aP ) if( ii >= 0 ) { + // Are we splitting at the beginning of an arc? If so, let's split right before so that + // the shape is preserved + if( ii < PointCount() - 1 && m_shapes[ii] >= 0 && m_shapes[ii] == m_shapes[ii + 1] ) + ii--; + m_points.insert( m_points.begin() + ii + 1, aP ); m_shapes.insert( m_shapes.begin() + ii + 1, ssize_t( SHAPE_IS_PT ) ); @@ -528,34 +535,42 @@ const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex ) if( aStartIndex < 0 ) aStartIndex += PointCount(); - for( int i = aStartIndex; i <= aEndIndex && static_cast( i ) < m_points.size(); i++ ) -#if 0 + int numPoints = static_cast( m_points.size() ); + + for( int i = aStartIndex; i <= aEndIndex && i < numPoints; i++ ) { if( m_shapes[i] != SHAPE_IS_PT ) { - int arcIdx = m_shapes[i]; + int arcIdx = m_shapes[i]; + bool wholeArc = true; + int arcStart = i; - // wxASSERT_MSG( i == 0 || ( m_shapes[i - 1] != arcIdx ), - // "SHAPE_LINE_CHAIN::Slice in the middle of an arc!" ); + if( i > 0 && m_shapes[i - 1] >= 0 && m_shapes[i - 1] != arcIdx ) + wholeArc = false; - rv.Append( m_arcs[arcIdx] ); - - while( m_shapes[i] == arcIdx && static_cast( i ) < m_shapes.size() ) + while( i < numPoints && m_shapes[i] == arcIdx ) i++; i--; - // FIXME: PNS currently slices in the middle of arcs all the time (LINE::Walkaround) - // wxASSERT_MSG( i <= aEndIndex, "SHAPE_LINE_CHAIN::Slice in the middle of an arc!" ); + if( i > aEndIndex ) + wholeArc = false; + + if( wholeArc ) + { + rv.Append( m_arcs[arcIdx] ); + } + else + { + rv.Append( m_points[arcStart] ); + i = arcStart; + } } else { rv.Append( m_points[i] ); } } -#else - rv.Append( m_points[i] ); -#endif return rv; } @@ -1036,7 +1051,8 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify( bool aRemoveColinear ) } -const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP ) const +const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP, + bool aAllowInternalShapePoints ) const { int min_d = INT_MAX; int nearest = 0; @@ -1045,13 +1061,38 @@ const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP ) const { int d = CSegment( i ).Distance( aP ); - if( d < min_d ) + bool isInternalShapePoint = false; + + // An internal shape point here is everything after the start of an arc and before the + // second-to-last vertex of the arc, because we are looking at segments here! + if( i > 0 && i < SegmentCount() - 1 && m_shapes[i] >= 0 && + ( ( m_shapes[i - 1] >= 0 && m_shapes[i - 1] == m_shapes[i] ) && + ( m_shapes[i + 2] >= 0 && m_shapes[i + 2] == m_shapes[i] ) ) ) + { + isInternalShapePoint = true; + } + + if( ( d < min_d ) && ( aAllowInternalShapePoints || !isInternalShapePoint ) ) { min_d = d; nearest = i; } } + // Is this the start of an arc? If so, return it directly + if( !aAllowInternalShapePoints && + ( ( nearest == 0 && m_shapes[nearest] >= 0 ) || + ( m_shapes[nearest] >= 0 && m_shapes[nearest] != m_shapes[nearest - 1] ) ) ) + { + return m_points[nearest]; + } + else if( !aAllowInternalShapePoints && nearest < SegmentCount() && + m_shapes[nearest] >= 0 && m_shapes[nearest + 1] == m_shapes[nearest] ) + { + // If the nearest segment is the last of the arc, just return the arc endpoint + return m_points[nearest + 1]; + } + return CSegment( nearest ).NearestPoint( aP ); } diff --git a/pcbnew/router/pns_dp_meander_placer.cpp b/pcbnew/router/pns_dp_meander_placer.cpp index e0bf2bad5e..b2000f660f 100644 --- a/pcbnew/router/pns_dp_meander_placer.cpp +++ b/pcbnew/router/pns_dp_meander_placer.cpp @@ -71,20 +71,15 @@ NODE* DP_MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const bool DP_MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem ) { - VECTOR2I p; - - if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T ) ) + if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) ) { Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) ); return false; } - m_initialSegment = static_cast( aStartItem ); - - p = m_initialSegment->Seg().NearestPoint( aP ); - - m_currentNode=NULL; - m_currentStart = p; + m_initialSegment = static_cast( aStartItem ); + m_currentNode = nullptr; + m_currentStart = getSnappedStartPoint( m_initialSegment, aP ); m_world = Router()->GetWorld()->Branch(); diff --git a/pcbnew/router/pns_dp_meander_placer.h b/pcbnew/router/pns_dp_meander_placer.h index 2f876a26dc..21d4f07215 100644 --- a/pcbnew/router/pns_dp_meander_placer.h +++ b/pcbnew/router/pns_dp_meander_placer.h @@ -145,7 +145,7 @@ private: SHAPE_LINE_CHAIN m_finalShapeP, m_finalShapeN; MEANDERED_LINE m_result; - SEGMENT* m_initialSegment; + LINKED_ITEM* m_initialSegment; long long int m_lastLength; int m_padToDieP; diff --git a/pcbnew/router/pns_meander_placer.cpp b/pcbnew/router/pns_meander_placer.cpp index ad41acc125..f42cd1ee5c 100644 --- a/pcbnew/router/pns_meander_placer.cpp +++ b/pcbnew/router/pns_meander_placer.cpp @@ -59,20 +59,15 @@ NODE* MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const bool MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem ) { - VECTOR2I p; - - if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T ) ) + if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) ) { Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) ); return false; } - m_initialSegment = static_cast( aStartItem ); - - p = m_initialSegment->Seg().NearestPoint( aP ); - - m_currentNode = NULL; - m_currentStart = p; + m_initialSegment = static_cast( aStartItem ); + m_currentNode = nullptr; + m_currentStart = getSnappedStartPoint( m_initialSegment, aP ); m_world = Router()->GetWorld()->Branch(); m_originLine = m_world->AssembleLine( m_initialSegment ); @@ -127,8 +122,13 @@ bool MEANDER_PLACER::doMove( const VECTOR2I& aP, ITEM* aEndItem, long long int a m_result.SetWidth( m_originLine.Width() ); m_result.SetBaselineOffset( 0 ); + const std::vector& tunedShapes = tuned.CShapes(); + for( int i = 0; i < tuned.SegmentCount(); i++ ) { + if( tunedShapes[i] >= 0 ) + continue; + const SEG s = tuned.CSegment( i ); m_result.AddCorner( s.A ); m_result.MeanderSegment( s ); diff --git a/pcbnew/router/pns_meander_placer.h b/pcbnew/router/pns_meander_placer.h index 6378e32238..6a4d14b36a 100644 --- a/pcbnew/router/pns_meander_placer.h +++ b/pcbnew/router/pns_meander_placer.h @@ -116,7 +116,7 @@ protected: SHAPE_LINE_CHAIN m_finalShape; MEANDERED_LINE m_result; - SEGMENT* m_initialSegment; + LINKED_ITEM* m_initialSegment; long long int m_lastLength; TUNING_STATUS m_lastStatus; diff --git a/pcbnew/router/pns_meander_placer_base.cpp b/pcbnew/router/pns_meander_placer_base.cpp index acb0577980..f22dd12277 100644 --- a/pcbnew/router/pns_meander_placer_base.cpp +++ b/pcbnew/router/pns_meander_placer_base.cpp @@ -23,6 +23,7 @@ #include "pns_meander.h" #include "pns_router.h" #include "pns_solid.h" +#include "pns_arc.h" namespace PNS { @@ -85,8 +86,8 @@ void MEANDER_PLACER_BASE::cutTunedLine( const SHAPE_LINE_CHAIN& aOrigin, const V } } - VECTOR2I n = aOrigin.NearestPoint( cp ); - VECTOR2I m = aOrigin.NearestPoint( aTuneStart ); + VECTOR2I n = aOrigin.NearestPoint( cp, false ); + VECTOR2I m = aOrigin.NearestPoint( aTuneStart, false ); SHAPE_LINE_CHAIN l( aOrigin ); l.Split( n ); @@ -235,4 +236,28 @@ int MEANDER_PLACER_BASE::compareWithTolerance( return 0; } + +VECTOR2I MEANDER_PLACER_BASE::getSnappedStartPoint( LINKED_ITEM* aStartItem, VECTOR2I aStartPoint ) +{ + if( aStartItem->Kind() == ITEM::SEGMENT_T ) + { + return static_cast( aStartItem )->Seg().NearestPoint( aStartPoint ); + } + else + { + wxASSERT( aStartItem->Kind() == ITEM::ARC_T ); + ARC* arc = static_cast( aStartItem ); + + if( ( VECTOR2I( arc->Anchor( 0 ) - aStartPoint ) ).SquaredEuclideanNorm() <= + ( VECTOR2I( arc->Anchor( 1 ) - aStartPoint ) ).SquaredEuclideanNorm() ) + { + return arc->Anchor( 0 ); + } + else + { + return arc->Anchor( 1 ); + } + } +} + } diff --git a/pcbnew/router/pns_meander_placer_base.h b/pcbnew/router/pns_meander_placer_base.h index c1daf8b4da..c77b8dcb07 100644 --- a/pcbnew/router/pns_meander_placer_base.h +++ b/pcbnew/router/pns_meander_placer_base.h @@ -159,6 +159,8 @@ protected: int compareWithTolerance( long long int aValue, long long int aExpected, long long int aTolerance = 0 ) const; + VECTOR2I getSnappedStartPoint( LINKED_ITEM* aStartItem, VECTOR2I aStartPoint ); + ///> pointer to world to search colliding items NODE* m_world; diff --git a/pcbnew/router/pns_meander_skew_placer.cpp b/pcbnew/router/pns_meander_skew_placer.cpp index ca58f94f12..5b3a35d5d2 100644 --- a/pcbnew/router/pns_meander_skew_placer.cpp +++ b/pcbnew/router/pns_meander_skew_placer.cpp @@ -48,20 +48,15 @@ MEANDER_SKEW_PLACER::~MEANDER_SKEW_PLACER( ) bool MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem ) { - VECTOR2I p; - - if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T ) ) + if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T) ) { Router()->SetFailureReason( _( "Please select a differential pair trace you want to tune." ) ); return false; } - m_initialSegment = static_cast( aStartItem ); - - p = m_initialSegment->Seg().NearestPoint( aP ); - - m_currentNode = NULL; - m_currentStart = p; + m_initialSegment = static_cast( aStartItem ); + m_currentNode = nullptr; + m_currentStart = getSnappedStartPoint( m_initialSegment, aP ); m_world = Router()->GetWorld( )->Branch(); m_originLine = m_world->AssembleLine( m_initialSegment );