624 lines
16 KiB
C++
624 lines
16 KiB
C++
/*
|
|
* KiRouter - a push-and-(sometimes-)shove PCB router
|
|
*
|
|
* Copyright (C) 2013-2015 CERN
|
|
* Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation, either version 3 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef __PNS_MEANDER_H
|
|
#define __PNS_MEANDER_H
|
|
|
|
#include <math/vector2d.h>
|
|
#include <core/minoptmax.h>
|
|
|
|
#include <geometry/shape.h>
|
|
#include <geometry/shape_line_chain.h>
|
|
|
|
namespace PNS {
|
|
|
|
class MEANDER_PLACER_BASE;
|
|
class MEANDERED_LINE;
|
|
|
|
///< Shapes of available meanders.
|
|
enum MEANDER_TYPE {
|
|
MT_SINGLE, // _|^|_, single-sided
|
|
MT_START, // _|^|
|
|
MT_FINISH, // |^|_
|
|
MT_TURN, // |^| or |_|
|
|
MT_CHECK_START, // try fitting a start type, but don't produce a line
|
|
MT_CHECK_FINISH, // try fitting a finish type, but don't produce a line
|
|
MT_CORNER, // line corner
|
|
MT_ARC, // arc corner
|
|
MT_EMPTY // no meander (straight line)
|
|
};
|
|
|
|
///< Meander corner shape.
|
|
enum MEANDER_STYLE {
|
|
MEANDER_STYLE_ROUND = 1, // rounded (90 degree arc)
|
|
MEANDER_STYLE_CHAMFER // chamfered (45 degree segment)
|
|
};
|
|
|
|
///< Initial side the meander is placed on.
|
|
enum MEANDER_SIDE
|
|
{
|
|
MEANDER_SIDE_LEFT = -1,
|
|
MEANDER_SIDE_DEFAULT = 0,
|
|
MEANDER_SIDE_RIGHT = 1
|
|
};
|
|
|
|
/**
|
|
* Dimensions for the meandering algorithm.
|
|
*/
|
|
class MEANDER_SETTINGS
|
|
{
|
|
public:
|
|
static const long long int DEFAULT_TOLERANCE = 100000;
|
|
static const long long int LENGTH_UNCONSTRAINED = std::numeric_limits<int>::max();
|
|
|
|
MEANDER_SETTINGS()
|
|
{
|
|
m_minAmplitude = 100000;
|
|
m_maxAmplitude = 1000000;
|
|
m_step = 50000;
|
|
m_lenPadToDie = 0;
|
|
m_spacing = 600000;
|
|
SetTargetLength( LENGTH_UNCONSTRAINED );
|
|
SetTargetSkew( 0 );
|
|
m_overrideCustomRules = false;
|
|
m_cornerStyle = MEANDER_STYLE_ROUND;
|
|
m_cornerRadiusPercentage = 100;
|
|
m_singleSided = false;
|
|
m_initialSide = MEANDER_SIDE_LEFT;
|
|
m_lengthTolerance = 0;
|
|
m_keepEndpoints = false;
|
|
}
|
|
|
|
void SetTargetLength( long long int aOpt )
|
|
{
|
|
m_targetLength.SetOpt( aOpt );
|
|
|
|
if( aOpt == std::numeric_limits<long long int>::max() )
|
|
{
|
|
m_targetLength.SetMin( 0 );
|
|
m_targetLength.SetMax( aOpt );
|
|
}
|
|
else
|
|
{
|
|
m_targetLength.SetMin( aOpt - DEFAULT_TOLERANCE );
|
|
m_targetLength.SetMax( aOpt + DEFAULT_TOLERANCE );
|
|
}
|
|
}
|
|
|
|
void SetTargetLength( const MINOPTMAX<int>& aConstraint )
|
|
{
|
|
SetTargetLength( aConstraint.Opt() );
|
|
|
|
if( aConstraint.HasMin() )
|
|
m_targetLength.SetMin( aConstraint.Min() );
|
|
|
|
if( aConstraint.HasMax() )
|
|
m_targetLength.SetMax( aConstraint.Max() );
|
|
}
|
|
|
|
void SetTargetSkew( int aOpt )
|
|
{
|
|
m_targetSkew.SetOpt( aOpt );
|
|
|
|
if( aOpt == std::numeric_limits<int>::max() )
|
|
{
|
|
m_targetSkew.SetMin( 0 );
|
|
m_targetSkew.SetMax( aOpt );
|
|
}
|
|
else
|
|
{
|
|
m_targetSkew.SetMin( aOpt - DEFAULT_TOLERANCE );
|
|
m_targetSkew.SetMax( aOpt + DEFAULT_TOLERANCE );
|
|
}
|
|
}
|
|
|
|
void SetTargetSkew( const MINOPTMAX<int>& aConstraint )
|
|
{
|
|
SetTargetSkew( aConstraint.Opt() );
|
|
|
|
if( aConstraint.HasMin() )
|
|
m_targetSkew.SetMin( aConstraint.Min() );
|
|
|
|
if( aConstraint.HasMax() )
|
|
m_targetSkew.SetMax( aConstraint.Max() );
|
|
}
|
|
|
|
///< Minimum meandering amplitude.
|
|
int m_minAmplitude;
|
|
|
|
///< Maximum meandering amplitude.
|
|
int m_maxAmplitude;
|
|
|
|
///< Meandering period/spacing (see dialog picture for explanation).
|
|
int m_spacing;
|
|
|
|
///< Amplitude/spacing adjustment step.
|
|
int m_step;
|
|
|
|
///< Length PadToDie.
|
|
int m_lenPadToDie;
|
|
|
|
///< Desired length of the tuned line/diff pair (this is in nm, so allow more than board width).
|
|
MINOPTMAX<long long int> m_targetLength;
|
|
|
|
///< Target skew value for diff pair de-skewing.
|
|
MINOPTMAX<int> m_targetSkew;
|
|
|
|
bool m_overrideCustomRules;
|
|
|
|
///< Type of corners for the meandered line.
|
|
MEANDER_STYLE m_cornerStyle;
|
|
|
|
///< Rounding percentage (0 - 100).
|
|
int m_cornerRadiusPercentage;
|
|
|
|
///< Place meanders on one side.
|
|
bool m_singleSided;
|
|
|
|
///< Initial side when placing meanders at segment
|
|
MEANDER_SIDE m_initialSide;
|
|
|
|
///< Allowable tuning error.
|
|
int m_lengthTolerance;
|
|
|
|
///< Keep vertices between pre, tuned and post parts of the line.
|
|
bool m_keepEndpoints;
|
|
};
|
|
|
|
/**
|
|
* The geometry of a single meander.
|
|
*/
|
|
class MEANDER_SHAPE
|
|
{
|
|
public:
|
|
/**
|
|
* @param aPlacer the meander placer instance.
|
|
* @param aWidth width of the meandered line.
|
|
* @param aIsDual when true, the shape contains two meandered
|
|
* lines at a given offset (diff pairs).
|
|
*/
|
|
MEANDER_SHAPE( MEANDER_PLACER_BASE* aPlacer, int aWidth, bool aIsDual = false ) :
|
|
m_placer( aPlacer ),
|
|
m_dual( aIsDual ),
|
|
m_width( aWidth ),
|
|
m_baselineOffset( 0 )
|
|
{
|
|
// Do not leave uninitialized members, and keep static analyzer quiet:
|
|
m_type = MT_SINGLE;
|
|
m_amplitude = 0;
|
|
m_targetBaseLen = 0;
|
|
m_side = false;
|
|
m_baseIndex = 0;
|
|
m_currentTarget = nullptr;
|
|
m_meanCornerRadius = 0;
|
|
}
|
|
|
|
/**
|
|
* Set the type of the meander.
|
|
*/
|
|
void SetType( MEANDER_TYPE aType )
|
|
{
|
|
m_type = aType;
|
|
}
|
|
|
|
/**
|
|
* @return the type of the meander.
|
|
*/
|
|
MEANDER_TYPE Type() const
|
|
{
|
|
return m_type;
|
|
}
|
|
|
|
/**
|
|
* Set an auxiliary index of the segment being meandered in its original LINE.
|
|
*/
|
|
void SetBaseIndex( int aIndex )
|
|
{
|
|
m_baseIndex = aIndex;
|
|
}
|
|
|
|
/**
|
|
* @return auxiliary index of the segment being meandered in its original LINE.
|
|
*/
|
|
int BaseIndex() const
|
|
{
|
|
return m_baseIndex;
|
|
}
|
|
|
|
/**
|
|
* @return the amplitude of the meander shape.
|
|
*/
|
|
int Amplitude() const
|
|
{
|
|
return m_amplitude;
|
|
}
|
|
|
|
/**
|
|
* Create a dummy meander shape representing a line corner. Used to define
|
|
* the starts/ends of meandered segments.
|
|
*
|
|
* @param aP1 corner point of the 1st line.
|
|
* @param aP2 corner point of the 2nd line (if m_dual == true).
|
|
*/
|
|
void MakeCorner( const VECTOR2I& aP1, const VECTOR2I& aP2 = VECTOR2I( 0, 0 ) );
|
|
|
|
/**
|
|
* Create a dummy meander shape representing an arc corner. Allows representing existing
|
|
* arc tracks so they can be reconstructed after length tuning.
|
|
*
|
|
* @param aArc1 Arc shape on the 1st line.
|
|
* @param aArc2 Arc shape on the 2nd line (if m_dual == true).
|
|
*/
|
|
void MakeArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 = SHAPE_ARC() );
|
|
|
|
/**
|
|
* Change the amplitude of the meander shape to aAmpl and recalculates the resulting
|
|
* line chain.
|
|
*
|
|
* @param aAmpl new amplitude.
|
|
*/
|
|
void Resize( int aAmpl );
|
|
|
|
/**
|
|
* Recalculate the line chain representing the meander's shape.
|
|
*/
|
|
void Recalculate();
|
|
|
|
/**
|
|
* @return true if the shape represents 2 parallel lines (diff pair).
|
|
*/
|
|
bool IsDual() const
|
|
{
|
|
return m_dual;
|
|
}
|
|
|
|
/**
|
|
* @return true if the meander is to the right of its base segment.
|
|
*/
|
|
bool Side() const
|
|
{
|
|
return m_side;
|
|
}
|
|
|
|
/**
|
|
* @return end vertex of the base segment of the meander shape.
|
|
*/
|
|
VECTOR2I End() const
|
|
{
|
|
return m_clippedBaseSeg.B;
|
|
}
|
|
|
|
/**
|
|
* @return the line chain representing the shape of the meander.
|
|
*/
|
|
const SHAPE_LINE_CHAIN& CLine( int aShape ) const
|
|
{
|
|
return m_shapes[aShape];
|
|
}
|
|
|
|
/**
|
|
* Replace the meander with straight bypass line(s), effectively clearing it.
|
|
*/
|
|
void MakeEmpty();
|
|
|
|
/**
|
|
* Attempt to fit a meander of a given type onto a segment, avoiding collisions with other
|
|
* board features.
|
|
*
|
|
* @param aType type of meander shape.
|
|
* @param aSeg base segment for meandering.
|
|
* @param aP start point of the meander.
|
|
* @param aSide side of aSeg to put the meander on (true = right).
|
|
* @return true on success.
|
|
*/
|
|
bool Fit( MEANDER_TYPE aType, const SEG& aSeg, const VECTOR2I& aP, bool aSide );
|
|
|
|
/**
|
|
* Return the base segment the meander was fitted to.
|
|
*
|
|
* @return the base segment.
|
|
*/
|
|
const SEG& BaseSegment() const
|
|
{
|
|
return m_clippedBaseSeg;
|
|
}
|
|
|
|
/**
|
|
* @return length of the base segment for the meander (i.e.the minimum tuned length).
|
|
*/
|
|
int BaselineLength() const;
|
|
|
|
/**
|
|
* @return the length of the fitted line chain.
|
|
*/
|
|
long long int CurrentLength() const;
|
|
|
|
/**
|
|
* @return the minumum tunable length according to settings.
|
|
*/
|
|
long long int MinTunableLength() const;
|
|
|
|
/**
|
|
* @return the minumum possible amplitude according to settings.
|
|
*/
|
|
int MinAmplitude() const;
|
|
|
|
/**
|
|
* @return the current meandering settings.
|
|
*/
|
|
const MEANDER_SETTINGS& Settings() const;
|
|
|
|
/**
|
|
* @return width of the meandered line.
|
|
*/
|
|
int Width() const
|
|
{
|
|
return m_width;
|
|
}
|
|
|
|
/**
|
|
* Set the parallel offset between the base segment and the meandered line. Used for
|
|
* dual meanders (diff pair) only.
|
|
*
|
|
* @param aOffset the offset.
|
|
*/
|
|
void SetBaselineOffset( int aOffset )
|
|
{
|
|
m_baselineOffset = aOffset;
|
|
}
|
|
|
|
/**
|
|
* Sets the target length of the baseline. When resizing, the meander will try to
|
|
* fit the baseline length into the specified value.
|
|
*
|
|
* @param aLength the minimum baseline length.
|
|
*/
|
|
void SetTargetBaselineLength( int aLength ) { m_targetBaseLen = aLength; }
|
|
|
|
private:
|
|
friend class MEANDERED_LINE;
|
|
|
|
///< Start turtle drawing
|
|
void start( SHAPE_LINE_CHAIN* aTarget, const VECTOR2D& aWhere, const VECTOR2D& aDir );
|
|
|
|
///< Move turtle forward by \a aLength.
|
|
void forward( int aLength );
|
|
|
|
///< Turn the turtle by \a aAngle
|
|
void turn( const EDA_ANGLE& aAngle );
|
|
|
|
///< Tell the turtle to draw a mitered corner of given radius and turn direction.
|
|
void miter( int aRadius, bool aSide );
|
|
|
|
///< Tell the turtle to draw an U-like shape.
|
|
void uShape( int aSides, int aCorner, int aTop );
|
|
|
|
///< Generate a 90-degree circular arc.
|
|
SHAPE_LINE_CHAIN makeMiterShape( const VECTOR2D& aP, const VECTOR2D& aDir, bool aSide );
|
|
|
|
///< Produce a meander shape of given type.
|
|
SHAPE_LINE_CHAIN genMeanderShape( const VECTOR2D& aP, const VECTOR2D& aDir, bool aSide,
|
|
MEANDER_TYPE aType, int aBaselineOffset = 0 );
|
|
|
|
///< Recalculate the clipped baseline after the parameters of the meander have been changed.
|
|
void updateBaseSegment();
|
|
|
|
///< Return sanitized corner radius value.
|
|
int cornerRadius() const;
|
|
|
|
///< Return sanitized spacing value.
|
|
int spacing() const;
|
|
|
|
///< The type of meander.
|
|
MEANDER_TYPE m_type;
|
|
|
|
///< The placer that placed this meander.
|
|
MEANDER_PLACER_BASE* m_placer;
|
|
|
|
///< Dual or single line.
|
|
bool m_dual;
|
|
|
|
///< Width of the line.
|
|
int m_width;
|
|
|
|
///< Amplitude of the meander.
|
|
int m_amplitude;
|
|
|
|
///< Offset wrs the base segment (dual only).
|
|
int m_baselineOffset;
|
|
|
|
///< Average radius of meander corners (for correction of DP meanders).
|
|
int m_meanCornerRadius;
|
|
|
|
///< Minimum length of the base segment to target when resizing.
|
|
int m_targetBaseLen;
|
|
|
|
///< First point of the meandered line.
|
|
VECTOR2I m_p0;
|
|
|
|
///< Base segment (unclipped).
|
|
SEG m_baseSeg;
|
|
|
|
///< Base segment (clipped).
|
|
SEG m_clippedBaseSeg;
|
|
|
|
///< Side (true = right).
|
|
bool m_side;
|
|
|
|
///< The actual shapes (0 used for single, both for dual).
|
|
SHAPE_LINE_CHAIN m_shapes[2];
|
|
|
|
///< Index of the meandered segment in the base line.
|
|
int m_baseIndex;
|
|
|
|
///< The current turtle direction.
|
|
VECTOR2D m_currentDir;
|
|
|
|
///< The current turtle position.
|
|
VECTOR2D m_currentPos;
|
|
|
|
///< The line the turtle is drawing on.
|
|
SHAPE_LINE_CHAIN* m_currentTarget;
|
|
};
|
|
|
|
|
|
/**
|
|
* Represent a set of meanders fitted over a single or two lines.
|
|
*/
|
|
class MEANDERED_LINE
|
|
{
|
|
public:
|
|
MEANDERED_LINE()
|
|
{
|
|
// Do not leave uninitialized members, and keep static analyzer quiet:
|
|
m_placer = nullptr;
|
|
m_dual = false;
|
|
m_width = 0;
|
|
m_baselineOffset = 0;
|
|
}
|
|
|
|
/**
|
|
* @param aPlacer the meander placer instance
|
|
* @param aIsDual when true, the meanders are generated for two coupled lines
|
|
*/
|
|
MEANDERED_LINE( MEANDER_PLACER_BASE* aPlacer, bool aIsDual = false ) :
|
|
m_placer( aPlacer ),
|
|
m_dual( aIsDual )
|
|
{
|
|
// Do not leave uninitialized members, and keep static analyzer quiet:
|
|
m_width = 0;
|
|
m_baselineOffset = 0;
|
|
}
|
|
|
|
~MEANDERED_LINE()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
/**
|
|
* Create a dummy meander shape representing a line corner. Used to define the starts/ends
|
|
* of meandered segments.
|
|
*
|
|
* @param aA corner point of the 1st line.
|
|
* @param aB corner point of the 2nd line (if m_dual == true).
|
|
*/
|
|
void AddCorner( const VECTOR2I& aA, const VECTOR2I& aB = VECTOR2I( 0, 0 ) );
|
|
|
|
/**
|
|
* Create a dummy meander shape representing an arc corner. Allows representing existing
|
|
* arc tracks so they can be reconstructed after length tuning.
|
|
*
|
|
* @param aArc1 Arc shape on the 1st line.
|
|
* @param aArc2 Arc shape on the 2nd line (if m_dual == true).
|
|
*/
|
|
void AddArc( const SHAPE_ARC& aArc1, const SHAPE_ARC& aArc2 = SHAPE_ARC() );
|
|
|
|
/**
|
|
* Create a dummy meander shape representing an arc corner. Allows representing existing
|
|
* arc tracks so they can be reconstructed after length tuning.
|
|
*
|
|
* @param aArc1 Arc shape on the 1st line.
|
|
* @param aPt2 corner point of the 2nd line (if m_dual == true).
|
|
*/
|
|
void AddArcAndPt( const SHAPE_ARC& aArc1, const VECTOR2I& aPt2 );
|
|
|
|
/**
|
|
* Create a dummy meander shape representing an arc corner. Allows representing existing
|
|
* arc tracks so they can be reconstructed after length tuning.
|
|
*
|
|
* @param aPt1 corner point of the 1st line.
|
|
* @param aArc2 Arc shape on the 2nd line (if m_dual == true).
|
|
*/
|
|
void AddPtAndArc( const VECTOR2I& aPt1, const SHAPE_ARC& aArc2 );
|
|
|
|
/**
|
|
* Add a new meander shape to the meandered line.
|
|
*
|
|
* @param aShape the meander shape to add
|
|
*/
|
|
void AddMeander( MEANDER_SHAPE* aShape );
|
|
|
|
/**
|
|
* Clear the line geometry, removing all corners and meanders.
|
|
*/
|
|
void Clear();
|
|
|
|
/**
|
|
* Set the line width.
|
|
*/
|
|
void SetWidth( int aWidth )
|
|
{
|
|
m_width = aWidth;
|
|
}
|
|
|
|
/**
|
|
* Fit maximum amplitude meanders on a given segment and adds to the current line.
|
|
*
|
|
* @param aSeg the base segment to meander.
|
|
* @param aSide Side to start meandering the segment. True=left, False=Right
|
|
* @param aBaseIndex index of the base segment in the original line.
|
|
*/
|
|
void MeanderSegment( const SEG& aSeg, bool aSide, int aBaseIndex = 0 );
|
|
|
|
/// @copydoc MEANDER_SHAPE::SetBaselineOffset()
|
|
void SetBaselineOffset( int aOffset )
|
|
{
|
|
m_baselineOffset = aOffset;
|
|
}
|
|
|
|
/**
|
|
* @return set of meander shapes for this line.
|
|
*/
|
|
std::vector<MEANDER_SHAPE*>& Meanders()
|
|
{
|
|
return m_meanders;
|
|
}
|
|
|
|
/**
|
|
* Check if the given shape is intersecting with any other meander in the current line.
|
|
*
|
|
* @param aShape the shape to check.
|
|
* @param aClearance clearance value.
|
|
* @return true, if the meander shape is not colliding.
|
|
*/
|
|
bool CheckSelfIntersections( MEANDER_SHAPE* aShape, int aClearance );
|
|
|
|
/**
|
|
* @return the current meandering settings.
|
|
*/
|
|
const MEANDER_SETTINGS& Settings() const;
|
|
|
|
private:
|
|
VECTOR2I m_last;
|
|
|
|
MEANDER_PLACER_BASE* m_placer;
|
|
std::vector<MEANDER_SHAPE*> m_meanders;
|
|
|
|
bool m_dual;
|
|
int m_width;
|
|
int m_baselineOffset;
|
|
};
|
|
|
|
}
|
|
|
|
#endif // __PNS_MEANDER_H
|