PNS: First pass at updating meander placers for arcs

Fixes https://gitlab.com/kicad/code/kicad/-/issues/6464
This commit is contained in:
Jon Evans 2021-01-04 08:54:29 -05:00
parent 8619086cf2
commit 7431d5c985
11 changed files with 124 additions and 51 deletions

View File

@ -135,6 +135,10 @@ public:
void Mirror( bool aX = true, bool aY = false, const VECTOR2I& aVector = { 0, 0 } ); void Mirror( bool aX = true, bool aY = false, const VECTOR2I& aVector = { 0, 0 } );
void Reverse();
SHAPE_ARC Reversed() const;
double GetRadius() const; double GetRadius() const;
SEG GetChord() const SEG GetChord() const

View File

@ -654,16 +654,15 @@ public:
int NearestSegment( const VECTOR2I& aP ) const; int NearestSegment( const VECTOR2I& aP ) const;
/** /**
* Function NearestPoint()
*
* Finds a point on the line chain that is closest to point aP. * 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. * @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 * Finds a point on the line chain that is closest to the line defined by the points of
* segment aSeg, also returns the distance. * segment aSeg, also returns the distance.
* @param aSeg Segment defining the line. * @param aSeg Segment defining the line.

View File

@ -472,3 +472,15 @@ void SHAPE_ARC::Mirror( bool aX, bool aY, const VECTOR2I& aVector )
update_bbox(); 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 );
}

View File

@ -220,6 +220,8 @@ const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Reverse() const
sh = a.m_arcs.size() - sh - 1; sh = a.m_arcs.size() - sh - 1;
} }
for( SHAPE_ARC& arc : a.m_arcs )
arc.Reverse();
a.m_closed = m_closed; a.m_closed = m_closed;
@ -390,6 +392,11 @@ int SHAPE_LINE_CHAIN::Split( const VECTOR2I& aP )
if( ii >= 0 ) 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_points.insert( m_points.begin() + ii + 1, aP );
m_shapes.insert( m_shapes.begin() + ii + 1, ssize_t( SHAPE_IS_PT ) ); 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 ) if( aStartIndex < 0 )
aStartIndex += PointCount(); aStartIndex += PointCount();
for( int i = aStartIndex; i <= aEndIndex && static_cast<size_t>( i ) < m_points.size(); i++ ) int numPoints = static_cast<int>( m_points.size() );
#if 0
for( int i = aStartIndex; i <= aEndIndex && i < numPoints; i++ )
{ {
if( m_shapes[i] != SHAPE_IS_PT ) 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 ), if( i > 0 && m_shapes[i - 1] >= 0 && m_shapes[i - 1] != arcIdx )
// "SHAPE_LINE_CHAIN::Slice in the middle of an arc!" ); wholeArc = false;
rv.Append( m_arcs[arcIdx] ); while( i < numPoints && m_shapes[i] == arcIdx )
while( m_shapes[i] == arcIdx && static_cast<size_t>( i ) < m_shapes.size() )
i++; i++;
i--; i--;
// FIXME: PNS currently slices in the middle of arcs all the time (LINE::Walkaround) if( i > aEndIndex )
// wxASSERT_MSG( i <= aEndIndex, "SHAPE_LINE_CHAIN::Slice in the middle of an arc!" ); wholeArc = false;
if( wholeArc )
{
rv.Append( m_arcs[arcIdx] );
}
else
{
rv.Append( m_points[arcStart] );
i = arcStart;
}
} }
else else
{ {
rv.Append( m_points[i] ); rv.Append( m_points[i] );
} }
} }
#else
rv.Append( m_points[i] );
#endif
return rv; 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 min_d = INT_MAX;
int nearest = 0; int nearest = 0;
@ -1045,13 +1061,38 @@ const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP ) const
{ {
int d = CSegment( i ).Distance( aP ); 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; min_d = d;
nearest = i; 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 ); return CSegment( nearest ).NearestPoint( aP );
} }

View File

@ -71,20 +71,15 @@ NODE* DP_MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const
bool DP_MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem ) bool DP_MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
{ {
VECTOR2I p; if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T ) )
{ {
Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) ); Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) );
return false; return false;
} }
m_initialSegment = static_cast<SEGMENT*>( aStartItem ); m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
m_currentNode = nullptr;
p = m_initialSegment->Seg().NearestPoint( aP ); m_currentStart = getSnappedStartPoint( m_initialSegment, aP );
m_currentNode=NULL;
m_currentStart = p;
m_world = Router()->GetWorld()->Branch(); m_world = Router()->GetWorld()->Branch();

View File

@ -145,7 +145,7 @@ private:
SHAPE_LINE_CHAIN m_finalShapeP, m_finalShapeN; SHAPE_LINE_CHAIN m_finalShapeP, m_finalShapeN;
MEANDERED_LINE m_result; MEANDERED_LINE m_result;
SEGMENT* m_initialSegment; LINKED_ITEM* m_initialSegment;
long long int m_lastLength; long long int m_lastLength;
int m_padToDieP; int m_padToDieP;

View File

@ -59,20 +59,15 @@ NODE* MEANDER_PLACER::CurrentNode( bool aLoopsRemoved ) const
bool MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem ) bool MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
{ {
VECTOR2I p; if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T ) )
{ {
Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) ); Router()->SetFailureReason( _( "Please select a track whose length you want to tune." ) );
return false; return false;
} }
m_initialSegment = static_cast<SEGMENT*>( aStartItem ); m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
m_currentNode = nullptr;
p = m_initialSegment->Seg().NearestPoint( aP ); m_currentStart = getSnappedStartPoint( m_initialSegment, aP );
m_currentNode = NULL;
m_currentStart = p;
m_world = Router()->GetWorld()->Branch(); m_world = Router()->GetWorld()->Branch();
m_originLine = m_world->AssembleLine( m_initialSegment ); 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.SetWidth( m_originLine.Width() );
m_result.SetBaselineOffset( 0 ); m_result.SetBaselineOffset( 0 );
const std::vector<ssize_t>& tunedShapes = tuned.CShapes();
for( int i = 0; i < tuned.SegmentCount(); i++ ) for( int i = 0; i < tuned.SegmentCount(); i++ )
{ {
if( tunedShapes[i] >= 0 )
continue;
const SEG s = tuned.CSegment( i ); const SEG s = tuned.CSegment( i );
m_result.AddCorner( s.A ); m_result.AddCorner( s.A );
m_result.MeanderSegment( s ); m_result.MeanderSegment( s );

View File

@ -116,7 +116,7 @@ protected:
SHAPE_LINE_CHAIN m_finalShape; SHAPE_LINE_CHAIN m_finalShape;
MEANDERED_LINE m_result; MEANDERED_LINE m_result;
SEGMENT* m_initialSegment; LINKED_ITEM* m_initialSegment;
long long int m_lastLength; long long int m_lastLength;
TUNING_STATUS m_lastStatus; TUNING_STATUS m_lastStatus;

View File

@ -23,6 +23,7 @@
#include "pns_meander.h" #include "pns_meander.h"
#include "pns_router.h" #include "pns_router.h"
#include "pns_solid.h" #include "pns_solid.h"
#include "pns_arc.h"
namespace PNS { namespace PNS {
@ -85,8 +86,8 @@ void MEANDER_PLACER_BASE::cutTunedLine( const SHAPE_LINE_CHAIN& aOrigin, const V
} }
} }
VECTOR2I n = aOrigin.NearestPoint( cp ); VECTOR2I n = aOrigin.NearestPoint( cp, false );
VECTOR2I m = aOrigin.NearestPoint( aTuneStart ); VECTOR2I m = aOrigin.NearestPoint( aTuneStart, false );
SHAPE_LINE_CHAIN l( aOrigin ); SHAPE_LINE_CHAIN l( aOrigin );
l.Split( n ); l.Split( n );
@ -235,4 +236,28 @@ int MEANDER_PLACER_BASE::compareWithTolerance(
return 0; return 0;
} }
VECTOR2I MEANDER_PLACER_BASE::getSnappedStartPoint( LINKED_ITEM* aStartItem, VECTOR2I aStartPoint )
{
if( aStartItem->Kind() == ITEM::SEGMENT_T )
{
return static_cast<SEGMENT*>( aStartItem )->Seg().NearestPoint( aStartPoint );
}
else
{
wxASSERT( aStartItem->Kind() == ITEM::ARC_T );
ARC* arc = static_cast<ARC*>( aStartItem );
if( ( VECTOR2I( arc->Anchor( 0 ) - aStartPoint ) ).SquaredEuclideanNorm() <=
( VECTOR2I( arc->Anchor( 1 ) - aStartPoint ) ).SquaredEuclideanNorm() )
{
return arc->Anchor( 0 );
}
else
{
return arc->Anchor( 1 );
}
}
}
} }

View File

@ -159,6 +159,8 @@ protected:
int compareWithTolerance( int compareWithTolerance(
long long int aValue, long long int aExpected, long long int aTolerance = 0 ) const; 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 ///> pointer to world to search colliding items
NODE* m_world; NODE* m_world;

View File

@ -48,20 +48,15 @@ MEANDER_SKEW_PLACER::~MEANDER_SKEW_PLACER( )
bool MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem ) bool MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
{ {
VECTOR2I p; if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T) )
if( !aStartItem || !aStartItem->OfKind( ITEM::SEGMENT_T ) )
{ {
Router()->SetFailureReason( _( "Please select a differential pair trace you want to tune." ) ); Router()->SetFailureReason( _( "Please select a differential pair trace you want to tune." ) );
return false; return false;
} }
m_initialSegment = static_cast<SEGMENT*>( aStartItem ); m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
m_currentNode = nullptr;
p = m_initialSegment->Seg().NearestPoint( aP ); m_currentStart = getSnappedStartPoint( m_initialSegment, aP );
m_currentNode = NULL;
m_currentStart = p;
m_world = Router()->GetWorld( )->Branch(); m_world = Router()->GetWorld( )->Branch();
m_originLine = m_world->AssembleLine( m_initialSegment ); m_originLine = m_world->AssembleLine( m_initialSegment );