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 Reverse();
SHAPE_ARC Reversed() const;
double GetRadius() const;
SEG GetChord() const

View File

@ -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.

View File

@ -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 );
}

View File

@ -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<size_t>( i ) < m_points.size(); i++ )
#if 0
int numPoints = static_cast<int>( m_points.size() );
for( int i = aStartIndex; i <= aEndIndex && i < numPoints; i++ )
{
if( m_shapes[i] != SHAPE_IS_PT )
{
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<size_t>( 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 );
}

View File

@ -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<SEGMENT*>( aStartItem );
p = m_initialSegment->Seg().NearestPoint( aP );
m_currentNode=NULL;
m_currentStart = p;
m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
m_currentNode = nullptr;
m_currentStart = getSnappedStartPoint( m_initialSegment, aP );
m_world = Router()->GetWorld()->Branch();

View File

@ -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;

View File

@ -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<SEGMENT*>( aStartItem );
p = m_initialSegment->Seg().NearestPoint( aP );
m_currentNode = NULL;
m_currentStart = p;
m_initialSegment = static_cast<LINKED_ITEM*>( 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<ssize_t>& 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 );

View File

@ -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;

View File

@ -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<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(
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;

View File

@ -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<SEGMENT*>( aStartItem );
p = m_initialSegment->Seg().NearestPoint( aP );
m_currentNode = NULL;
m_currentStart = p;
m_initialSegment = static_cast<LINKED_ITEM*>( aStartItem );
m_currentNode = nullptr;
m_currentStart = getSnappedStartPoint( m_initialSegment, aP );
m_world = Router()->GetWorld( )->Branch();
m_originLine = m_world->AssembleLine( m_initialSegment );