521 lines
13 KiB
C++
521 lines
13 KiB
C++
/*
|
|
* KiRouter - a push-and-(sometimes-)shove PCB router
|
|
*
|
|
* Copyright (C) 2013-2015 CERN
|
|
* Copyright (C) 2016-2023 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_DIFF_PAIR_H
|
|
#define __PNS_DIFF_PAIR_H
|
|
|
|
#include <vector>
|
|
|
|
#include "pns_line.h"
|
|
#include "pns_via.h"
|
|
#include "pns_link_holder.h"
|
|
|
|
#include "ranged_num.h"
|
|
|
|
namespace PNS {
|
|
|
|
class DIFF_PAIR;
|
|
|
|
/**
|
|
* Define a "gateway" for routing a differential pair - e.g. a pair of points (anchors) with
|
|
* certain orientation, spacing and (optionally) predefined entry paths. The routing algorithm
|
|
* connects such gateways with parallel lines, thus creating a differential pair.
|
|
*/
|
|
class DP_GATEWAY
|
|
{
|
|
public:
|
|
DP_GATEWAY( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN, bool aIsDiagonal,
|
|
int aAllowedEntryAngles = DIRECTION_45::ANG_OBTUSE, int aPriority = 0 ) :
|
|
m_anchorP( aAnchorP ),
|
|
m_anchorN( aAnchorN ), m_isDiagonal( aIsDiagonal ),
|
|
m_allowedEntryAngles( aAllowedEntryAngles ), m_priority( aPriority )
|
|
{
|
|
m_hasEntryLines = false;
|
|
}
|
|
|
|
~DP_GATEWAY()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* @return true if the gateway anchors lie on a diagonal line.
|
|
*/
|
|
bool IsDiagonal() const
|
|
{
|
|
return m_isDiagonal;
|
|
}
|
|
|
|
const VECTOR2I& AnchorP() const { return m_anchorP; }
|
|
|
|
const VECTOR2I& AnchorN() const { return m_anchorN; }
|
|
|
|
/**
|
|
* @return a mask of 45-degree entry directions allowed for the gateway.
|
|
*/
|
|
int AllowedAngles () const { return m_allowedEntryAngles; }
|
|
|
|
/**
|
|
* @return priority/score value for gateway matching.
|
|
*/
|
|
int Priority() const
|
|
{
|
|
return m_priority;
|
|
}
|
|
|
|
void SetPriority(int aPriority)
|
|
{
|
|
m_priority = aPriority;
|
|
}
|
|
|
|
void SetEntryLines( const SHAPE_LINE_CHAIN& aEntryP, const SHAPE_LINE_CHAIN& aEntryN )
|
|
{
|
|
m_entryP = aEntryP;
|
|
m_entryN = aEntryN;
|
|
m_hasEntryLines = true;
|
|
}
|
|
|
|
const SHAPE_LINE_CHAIN& EntryP() const { return m_entryP; }
|
|
const SHAPE_LINE_CHAIN& EntryN() const { return m_entryN; }
|
|
const DIFF_PAIR Entry() const ;
|
|
|
|
void Reverse();
|
|
|
|
bool HasEntryLines () const
|
|
{
|
|
return m_hasEntryLines;
|
|
}
|
|
|
|
private:
|
|
SHAPE_LINE_CHAIN m_entryP, m_entryN;
|
|
bool m_hasEntryLines;
|
|
VECTOR2I m_anchorP, m_anchorN;
|
|
bool m_isDiagonal;
|
|
int m_allowedEntryAngles;
|
|
int m_priority;
|
|
};
|
|
|
|
/**
|
|
* Store starting/ending primitives (pads, vias or segments) for a differential pair.
|
|
*/
|
|
class DP_PRIMITIVE_PAIR
|
|
{
|
|
public:
|
|
DP_PRIMITIVE_PAIR():
|
|
m_primP( nullptr ), m_primN( nullptr ) {};
|
|
|
|
DP_PRIMITIVE_PAIR( const DP_PRIMITIVE_PAIR& aOther );
|
|
DP_PRIMITIVE_PAIR( ITEM* aPrimP, ITEM* aPrimN );
|
|
DP_PRIMITIVE_PAIR( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN );
|
|
|
|
~DP_PRIMITIVE_PAIR();
|
|
|
|
void SetAnchors( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN );
|
|
|
|
const VECTOR2I& AnchorP() const { return m_anchorP; }
|
|
const VECTOR2I& AnchorN() const { return m_anchorN; }
|
|
|
|
DP_PRIMITIVE_PAIR& operator=( const DP_PRIMITIVE_PAIR& aOther );
|
|
|
|
ITEM* PrimP() const { return m_primP; }
|
|
ITEM* PrimN() const { return m_primN; }
|
|
|
|
bool Directional() const;
|
|
|
|
DIRECTION_45 DirP() const;
|
|
DIRECTION_45 DirN() const;
|
|
|
|
|
|
void CursorOrientation( const VECTOR2I& aCursorPos, VECTOR2I& aMidpoint,
|
|
VECTOR2I& aDirection ) const;
|
|
|
|
void dump()
|
|
{
|
|
printf( "-- Prim-P %p anchor [%d, %d]\n", m_primP, m_anchorP.x, m_anchorP.y );
|
|
printf( "-- Prim-N %p anchor [%d, %d]\n", m_primN, m_anchorN.x, m_anchorN.y );
|
|
}
|
|
|
|
private:
|
|
DIRECTION_45 anchorDirection( const ITEM* aItem, const VECTOR2I& aP ) const;
|
|
|
|
ITEM* m_primP;
|
|
ITEM* m_primN;
|
|
VECTOR2I m_anchorP, m_anchorN;
|
|
};
|
|
|
|
/**
|
|
* A set of gateways calculated for the cursor or starting/ending primitive pair.
|
|
*/
|
|
class DP_GATEWAYS
|
|
{
|
|
public:
|
|
DP_GATEWAYS( int aGap ):
|
|
m_gap( aGap ),
|
|
m_viaGap( aGap )
|
|
{
|
|
// Do not leave uninitialized members, and keep static analyzer quiet:
|
|
m_viaDiameter = 0;
|
|
m_fitVias = true;
|
|
}
|
|
|
|
void Clear() { m_gateways.clear(); }
|
|
|
|
void SetFitVias( bool aEnable, int aDiameter = 0, int aViaGap = -1 )
|
|
{
|
|
m_fitVias = aEnable;
|
|
m_viaDiameter = aDiameter;
|
|
|
|
if( aViaGap < 0 )
|
|
m_viaGap = m_gap;
|
|
else
|
|
m_viaGap = aViaGap;
|
|
}
|
|
|
|
|
|
void BuildForCursor( const VECTOR2I& aCursorPos );
|
|
void BuildOrthoProjections( DP_GATEWAYS& aEntries, const VECTOR2I& aCursorPos,
|
|
int aOrthoScore );
|
|
void BuildGeneric( const VECTOR2I& p0_p, const VECTOR2I& p0_n, bool aBuildEntries = false,
|
|
bool aViaMode = false );
|
|
void BuildFromPrimitivePair( const DP_PRIMITIVE_PAIR& aPair, bool aPreferDiagonal );
|
|
|
|
bool FitGateways( DP_GATEWAYS& aEntry, DP_GATEWAYS& aTarget, bool aPrefDiagonal,
|
|
DIFF_PAIR& aDp );
|
|
|
|
std::vector<DP_GATEWAY>& Gateways() { return m_gateways; }
|
|
|
|
const std::vector<DP_GATEWAY>& CGateways() const { return m_gateways; }
|
|
|
|
void FilterByOrientation( int aAngleMask, DIRECTION_45 aRefOrientation );
|
|
|
|
private:
|
|
struct DP_CANDIDATE
|
|
{
|
|
SHAPE_LINE_CHAIN p, n;
|
|
VECTOR2I gw_p, gw_n;
|
|
int score;
|
|
};
|
|
|
|
bool checkDiagonalAlignment( const VECTOR2I& a, const VECTOR2I& b ) const;
|
|
void buildDpContinuation( const DP_PRIMITIVE_PAIR& aPair, bool aIsDiagonal );
|
|
void buildEntries( const VECTOR2I& p0_p, const VECTOR2I& p0_n );
|
|
|
|
int m_gap;
|
|
int m_viaGap;
|
|
int m_viaDiameter;
|
|
bool m_fitVias;
|
|
|
|
std::vector<DP_GATEWAY> m_gateways;
|
|
};
|
|
|
|
|
|
/**
|
|
* Basic class for a differential pair. Stores two PNS_LINEs (for positive and negative nets,
|
|
* respectively), the gap and coupling constraints.
|
|
*/
|
|
class DIFF_PAIR : public LINK_HOLDER
|
|
{
|
|
public:
|
|
struct COUPLED_SEGMENTS
|
|
{
|
|
COUPLED_SEGMENTS ( const SEG& aCoupledP, const SEG& aParentP, int aIndexP,
|
|
const SEG& aCoupledN, const SEG& aParentN, int aIndexN ) :
|
|
coupledP( aCoupledP ),
|
|
coupledN( aCoupledN ),
|
|
parentP( aParentP ),
|
|
parentN( aParentN ),
|
|
indexP( aIndexP ),
|
|
indexN( aIndexN )
|
|
{}
|
|
|
|
SEG coupledP;
|
|
SEG coupledN;
|
|
SEG parentP;
|
|
SEG parentN;
|
|
int indexP;
|
|
int indexN;
|
|
};
|
|
|
|
typedef std::vector<COUPLED_SEGMENTS> COUPLED_SEGMENTS_VEC;
|
|
|
|
DIFF_PAIR() :
|
|
LINK_HOLDER( ITEM::DIFF_PAIR_T ),
|
|
m_hasVias( false )
|
|
{
|
|
// Initialize some members, to avoid uninitialized variables.
|
|
m_net_p = 0;
|
|
m_net_n = 0;;
|
|
m_width = 0;
|
|
m_gap = 0;
|
|
m_viaGap = 0;
|
|
m_maxUncoupledLength = 0;
|
|
m_chamferLimit = 0;
|
|
}
|
|
|
|
DIFF_PAIR( int aGap ) :
|
|
LINK_HOLDER( ITEM::DIFF_PAIR_T ),
|
|
m_hasVias( false )
|
|
{
|
|
m_gapConstraint = aGap;
|
|
|
|
// Initialize other members, to avoid uninitialized variables.
|
|
m_net_p = 0;
|
|
m_net_n = 0;;
|
|
m_width = 0;
|
|
m_gap = 0;
|
|
m_viaGap = 0;
|
|
m_maxUncoupledLength = 0;
|
|
m_chamferLimit = 0;
|
|
}
|
|
|
|
DIFF_PAIR( const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN& aN, int aGap = 0 ) :
|
|
LINK_HOLDER( ITEM::DIFF_PAIR_T ),
|
|
m_n( aN ),
|
|
m_p( aP ),
|
|
m_hasVias( false )
|
|
{
|
|
m_gapConstraint = aGap;
|
|
|
|
// Initialize other members, to avoid uninitialized variables.
|
|
m_net_p = 0;
|
|
m_net_n = 0;;
|
|
m_width = 0;
|
|
m_gap = 0;
|
|
m_viaGap = 0;
|
|
m_maxUncoupledLength = 0;
|
|
m_chamferLimit = 0;
|
|
}
|
|
|
|
DIFF_PAIR( const LINE &aLineP, const LINE &aLineN, int aGap = 0 ) :
|
|
LINK_HOLDER( ITEM::DIFF_PAIR_T ),
|
|
m_line_p( aLineP ),
|
|
m_line_n( aLineN ),
|
|
m_hasVias( false )
|
|
{
|
|
m_gapConstraint = aGap;
|
|
m_net_p = aLineP.Net();
|
|
m_net_n = aLineN.Net();
|
|
m_p = aLineP.CLine();
|
|
m_n = aLineN.CLine();
|
|
|
|
// Do not leave uninitialized members, and keep static analyzer quiet:
|
|
m_width = 0;
|
|
m_gap = 0;
|
|
m_viaGap = 0;
|
|
m_maxUncoupledLength = 0;
|
|
m_chamferLimit = 0;
|
|
}
|
|
|
|
static inline bool ClassOf( const ITEM* aItem )
|
|
{
|
|
return aItem && ITEM::DIFF_PAIR_T == aItem->Kind();
|
|
}
|
|
|
|
DIFF_PAIR* Clone() const override
|
|
{
|
|
assert( false );
|
|
return nullptr;
|
|
}
|
|
|
|
virtual void ClearLinks() override
|
|
{
|
|
m_links.clear();
|
|
m_line_p.ClearLinks();
|
|
m_line_n.ClearLinks();
|
|
}
|
|
|
|
static DIFF_PAIR* AssembleDp( LINE *aLine );
|
|
|
|
void SetShape( const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN& aN, bool aSwapLanes = false )
|
|
{
|
|
if( aSwapLanes )
|
|
{
|
|
m_p = aN;
|
|
m_n = aP;
|
|
}
|
|
else
|
|
{
|
|
m_p = aP;
|
|
m_n = aN;
|
|
}
|
|
}
|
|
|
|
void SetShape( const DIFF_PAIR& aPair )
|
|
{
|
|
m_p = aPair.m_p;
|
|
m_n = aPair.m_n;
|
|
}
|
|
|
|
void SetNets( NET_HANDLE aP, NET_HANDLE aN )
|
|
{
|
|
m_net_p = aP;
|
|
m_net_n = aN;
|
|
}
|
|
|
|
void SetWidth( int aWidth )
|
|
{
|
|
m_width = aWidth;
|
|
m_n.SetWidth( aWidth );
|
|
m_p.SetWidth( aWidth );
|
|
}
|
|
|
|
int Width() const { return m_width; }
|
|
|
|
void SetGap( int aGap )
|
|
{
|
|
m_gap = aGap;
|
|
m_gapConstraint = RANGED_NUM<int>( m_gap, 10000, 10000 );
|
|
}
|
|
|
|
int Gap() const
|
|
{
|
|
return m_gap;
|
|
}
|
|
|
|
void AppendVias( const VIA &aViaP, const VIA& aViaN )
|
|
{
|
|
m_hasVias = true;
|
|
m_via_p = aViaP;
|
|
m_via_p.SetHole( aViaP.Hole()->Clone() );
|
|
m_via_n = aViaN;
|
|
m_via_n.SetHole( aViaN.Hole()->Clone() );
|
|
}
|
|
|
|
void RemoveVias()
|
|
{
|
|
m_hasVias = false;
|
|
m_line_n.RemoveVia();
|
|
m_line_p.RemoveVia();
|
|
}
|
|
|
|
bool EndsWithVias() const
|
|
{
|
|
return m_hasVias;
|
|
}
|
|
|
|
void SetViaDiameter( int aDiameter )
|
|
{
|
|
m_via_p.SetDiameter( VIA::ALL_LAYERS, aDiameter );
|
|
m_via_n.SetDiameter( VIA::ALL_LAYERS, aDiameter );
|
|
}
|
|
|
|
void SetViaDrill( int aDrill )
|
|
{
|
|
m_via_p.SetDrill( aDrill );
|
|
m_via_n.SetDrill( aDrill );
|
|
}
|
|
|
|
NET_HANDLE NetP() const
|
|
{
|
|
return m_net_p;
|
|
}
|
|
|
|
NET_HANDLE NetN() const
|
|
{
|
|
return m_net_n;
|
|
}
|
|
|
|
LINE& PLine()
|
|
{
|
|
if( !m_line_p.IsLinked() )
|
|
updateLine( m_line_p, m_p, m_net_p, m_via_p );
|
|
|
|
return m_line_p;
|
|
}
|
|
|
|
LINE& NLine()
|
|
{
|
|
if( !m_line_n.IsLinked() )
|
|
updateLine( m_line_n, m_n, m_net_n, m_via_n );
|
|
|
|
return m_line_n;
|
|
}
|
|
|
|
DP_PRIMITIVE_PAIR EndingPrimitives();
|
|
|
|
double CoupledLength() const;
|
|
double TotalLength() const;
|
|
double CoupledLengthFactor() const;
|
|
double Skew() const;
|
|
|
|
void CoupledSegmentPairs( COUPLED_SEGMENTS_VEC& aPairs ) const;
|
|
|
|
void Clear()
|
|
{
|
|
m_n.Clear();
|
|
m_p.Clear();
|
|
}
|
|
|
|
void Append( const DIFF_PAIR& aOther )
|
|
{
|
|
m_n.Append( aOther.m_n );
|
|
m_p.Append( aOther.m_p );
|
|
}
|
|
|
|
bool Empty() const
|
|
{
|
|
return ( m_n.SegmentCount() == 0 ) || ( m_p.SegmentCount() == 0 );
|
|
}
|
|
|
|
const SHAPE_LINE_CHAIN& CP() const { return m_p; }
|
|
const SHAPE_LINE_CHAIN& CN() const { return m_n; }
|
|
|
|
bool BuildInitial( const DP_GATEWAY& aEntry, const DP_GATEWAY& aTarget, bool aPrefDiagonal );
|
|
bool CheckConnectionAngle( const DIFF_PAIR &aOther, int allowedAngles ) const;
|
|
int CoupledLength( const SEG& aP, const SEG& aN ) const;
|
|
|
|
int64_t CoupledLength( const SHAPE_LINE_CHAIN& aP, const SHAPE_LINE_CHAIN& aN ) const;
|
|
|
|
const RANGED_NUM<int> GapConstraint() const
|
|
{
|
|
return m_gapConstraint;
|
|
}
|
|
|
|
private:
|
|
void updateLine( LINE &aLine, const SHAPE_LINE_CHAIN& aShape, NET_HANDLE aNet, const VIA& aVia )
|
|
{
|
|
aLine.SetShape( aShape );
|
|
aLine.SetWidth( m_width );
|
|
aLine.SetNet( aNet );
|
|
aLine.SetLayer( Layers().Start() );
|
|
|
|
if( m_hasVias )
|
|
aLine.AppendVia( aVia );
|
|
}
|
|
|
|
SHAPE_LINE_CHAIN m_n, m_p;
|
|
LINE m_line_p, m_line_n;
|
|
VIA m_via_p, m_via_n;
|
|
|
|
bool m_hasVias;
|
|
NET_HANDLE m_net_p, m_net_n;
|
|
int m_width;
|
|
int m_gap;
|
|
int m_viaGap;
|
|
int m_maxUncoupledLength;
|
|
int m_chamferLimit;
|
|
RANGED_NUM<int> m_gapConstraint;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|