PNS: First pass at updating meander placers for arcs
Fixes https://gitlab.com/kicad/code/kicad/-/issues/6464
This commit is contained in:
parent
8619086cf2
commit
7431d5c985
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
Loading…
Reference in New Issue