/* * KiRouter - a push-and-(sometimes-)shove PCB router * * Copyright (C) 2013-2015 CERN * Author: Tomasz Wlostowski * * 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 . */ #ifndef __PNS_DIFF_PAIR_H #define __PNS_DIFF_PAIR_H #include #include #include #include "pns_line.h" #include "pns_via.h" #include "ranged_num.h" class PNS_DIFF_PAIR; /** * Class PNS_DP_GATEWAY * * Defines 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 difrerential pair. **/ class PNS_DP_GATEWAY { public: PNS_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; } ~PNS_DP_GATEWAY() { } /** * Function IsDiagonal() * * @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; } /** * Function AllowedAngles() * * @return a mask of 45-degree entry directoins allowed for the * gateway. */ int AllowedAngles () const { return m_allowedEntryAngles; } /** * Function Priority() * * @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 PNS_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; }; /** * Class PNS_DP_PRIMITIVE_PAIR * * Stores staring/ending primitives (pads, vias or segments) for a differential pair. **/ class PNS_DP_PRIMITIVE_PAIR { public: PNS_DP_PRIMITIVE_PAIR(): m_primP( NULL ), m_primN( NULL ) {}; PNS_DP_PRIMITIVE_PAIR( const PNS_DP_PRIMITIVE_PAIR& aOther ); PNS_DP_PRIMITIVE_PAIR( PNS_ITEM* aPrimP, PNS_ITEM* aPrimN ); PNS_DP_PRIMITIVE_PAIR( const VECTOR2I& aAnchorP, const VECTOR2I& aAnchorN ); ~PNS_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; } PNS_DP_PRIMITIVE_PAIR& operator=( const PNS_DP_PRIMITIVE_PAIR& aOther ); PNS_ITEM* PrimP() const { return m_primP; } PNS_ITEM* PrimN() const { return m_primN; } bool Directional() const; DIRECTION_45 DirP() const; DIRECTION_45 DirN() const; private: DIRECTION_45 anchorDirection( PNS_ITEM* aItem, const VECTOR2I& aP ) const; PNS_ITEM* m_primP; PNS_ITEM* m_primN; VECTOR2I m_anchorP, m_anchorN; }; /** * Class PNS_GATEWAYS * * A set of gateways calculated for the cursor or starting/ending primitive pair. **/ class PNS_DP_GATEWAYS { public: PNS_DP_GATEWAYS ( int aGap ): m_gap(aGap), m_viaGap( aGap ) { // Do not leave unitialized members, and keep static analyser quiet: m_viaDiameter = 0; m_fitVias = true; } void SetGap ( int aGap ) { m_gap = aGap; m_viaGap = aGap; } 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 ( PNS_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( PNS_DP_PRIMITIVE_PAIR aPair, bool aPreferDiagonal ); bool FitGateways ( PNS_DP_GATEWAYS& aEntry, PNS_DP_GATEWAYS& aTarget, bool aPrefDiagonal, PNS_DIFF_PAIR& aDp ); std::vector& Gateways() { return m_gateways; } 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 ( PNS_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 m_gateways; }; /** * Class PNS_DIFF_PAIR * * Basic class for a differential pair. Stores two PNS_LINEs (for positive and negative nets, respectively), * the gap and coupling constraints. **/ class PNS_DIFF_PAIR : public PNS_ITEM { 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_VEC; PNS_DIFF_PAIR ( ) : PNS_ITEM ( DIFF_PAIR ), 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; } PNS_DIFF_PAIR ( int aGap ) : PNS_ITEM ( DIFF_PAIR ), 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; } PNS_DIFF_PAIR ( const SHAPE_LINE_CHAIN &aP, const SHAPE_LINE_CHAIN& aN, int aGap = 0 ): PNS_ITEM ( DIFF_PAIR ), 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; } PNS_DIFF_PAIR ( const PNS_LINE &aLineP, const PNS_LINE &aLineN, int aGap = 0 ): PNS_ITEM ( DIFF_PAIR ), 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 unitialized members, and keep static analyser quiet: m_width = 0; m_gap = 0; m_viaGap = 0; m_maxUncoupledLength = 0; m_chamferLimit = 0; } static inline bool ClassOf( const PNS_ITEM* aItem ) { return aItem && DIFF_PAIR == aItem->Kind(); } PNS_DIFF_PAIR * Clone() const { assert(false); return NULL; } static PNS_DIFF_PAIR* AssembleDp ( PNS_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 PNS_DIFF_PAIR& aPair ) { m_p = aPair.m_p; m_n = aPair.m_n; } void SetNets ( int aP, int aN ) { m_net_p = aP; m_net_n = aN; } void SetWidth ( int aWidth ) { m_width = aWidth; } int Width() const { return m_width; } void SetGap ( int aGap) { m_gap = aGap; m_gapConstraint = RANGED_NUM ( m_gap, 10000, 10000 ); } int Gap() const { return m_gap; } void AppendVias ( const PNS_VIA &aViaP, const PNS_VIA& aViaN ) { m_hasVias = true; m_via_p = aViaP; m_via_n = aViaN; } void RemoveVias () { m_hasVias = false; } bool EndsWithVias() const { return m_hasVias; } int NetP() const { return m_net_p; } int NetN() const { return m_net_n; } PNS_LINE& PLine() { if ( !m_line_p.IsLinked ( ) ) updateLine(m_line_p, m_p, m_net_p, m_via_p ); return m_line_p; } PNS_LINE& NLine() { if ( !m_line_n.IsLinked ( ) ) updateLine(m_line_n, m_n, m_net_n, m_via_n ); return m_line_n; } PNS_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 PNS_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 ( PNS_DP_GATEWAY& aEntry, PNS_DP_GATEWAY& aTarget, bool aPrefDiagonal ); bool CheckConnectionAngle ( const PNS_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 GapConstraint() const { return m_gapConstraint; } private: void updateLine( PNS_LINE &aLine, const SHAPE_LINE_CHAIN& aShape, int aNet, PNS_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; PNS_LINE m_line_p, m_line_n; PNS_VIA m_via_p, m_via_n; bool m_hasVias; int m_net_p, m_net_n; int m_width; int m_gap; int m_viaGap; int m_maxUncoupledLength; int m_chamferLimit; RANGED_NUM m_gapConstraint; }; #endif