From 5598acb61768946167aa3c5590a00afc545c4c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Sumi=C5=84ski?= Date: Thu, 26 Sep 2013 23:53:54 +0200 Subject: [PATCH] Uncrustifying push&shove router --- pcbnew/router/CMakeLists.txt | 93 +- pcbnew/router/direction.h | 513 ++++---- pcbnew/router/pns_index.h | 312 ++--- pcbnew/router/pns_item.cpp | 85 +- pcbnew/router/pns_item.h | 189 +-- pcbnew/router/pns_itemset.cpp | 75 +- pcbnew/router/pns_itemset.h | 39 +- pcbnew/router/pns_joint.h | 261 +++-- pcbnew/router/pns_layerset.h | 146 +-- pcbnew/router/pns_line.cpp | 1189 ++++++++++--------- pcbnew/router/pns_line.h | 371 +++--- pcbnew/router/pns_line_placer.cpp | 1113 +++++++++--------- pcbnew/router/pns_line_placer.h | 303 +++-- pcbnew/router/pns_node.cpp | 1542 +++++++++++++------------ pcbnew/router/pns_node.h | 329 +++--- pcbnew/router/pns_optimizer.cpp | 1172 ++++++++++--------- pcbnew/router/pns_optimizer.h | 183 +-- pcbnew/router/pns_router.cpp | 1117 +++++++++--------- pcbnew/router/pns_router.h | 209 ++-- pcbnew/router/pns_routing_settings.h | 49 +- pcbnew/router/pns_segment.h | 152 +-- pcbnew/router/pns_shove.cpp | 675 +++++------ pcbnew/router/pns_shove.h | 82 +- pcbnew/router/pns_solid.cpp | 61 +- pcbnew/router/pns_solid.h | 63 +- pcbnew/router/pns_utils.cpp | 37 +- pcbnew/router/pns_utils.h | 12 +- pcbnew/router/pns_via.cpp | 191 +-- pcbnew/router/pns_via.h | 149 +-- pcbnew/router/pns_walkaround.cpp | 302 ++--- pcbnew/router/pns_walkaround.h | 121 +- pcbnew/router/readme.txt | 4 - pcbnew/router/router_preview_item.cpp | 287 +++-- pcbnew/router/router_preview_item.h | 94 +- pcbnew/router/router_tool.cpp | 355 +++--- pcbnew/router/router_tool.h | 45 +- pcbnew/router/trace.h | 27 +- 37 files changed, 6255 insertions(+), 5692 deletions(-) delete mode 100644 pcbnew/router/readme.txt diff --git a/pcbnew/router/CMakeLists.txt b/pcbnew/router/CMakeLists.txt index 7995cb4af9..2d1c4de6b2 100644 --- a/pcbnew/router/CMakeLists.txt +++ b/pcbnew/router/CMakeLists.txt @@ -1,50 +1,51 @@ -include_directories(BEFORE ${INC_BEFORE}) +include_directories( BEFORE ${INC_BEFORE} ) include_directories( - ./ - ../ - ../../include - ../../pcbnew - ../../polygon - ${INC_AFTER} - ) + ./ + ../ + ../../ include + ../../ pcbnew + ../../ polygon + $ { INC_AFTER } +) -set(PCBNEW_PNS_SRCS - direction.h - pns_via.h - pns_routing_settings.h - pns_shove.cpp - pns_line.cpp - pns_utils.h - pns_layerset.h - trace.h - pns_line.h - pns_walkaround.cpp - pns_node.h - pns_line_placer.cpp - pns_utils.cpp - pns_solid.h - pns_item.cpp - pns_via.cpp - pns_node.cpp - pns_solid.cpp - pns_line_placer.h - pns_optimizer.h - pns_walkaround.h - pns_shove.h - pns_router.h - pns_router.cpp - pns_index.h - pns_item.h - pns_optimizer.cpp - pns_joint.h - pns_segment.h - pns_itemset.h - pns_itemset.cpp - router_tool.cpp - router_tool.h - router_preview_item.cpp - router_preview_item.h - ) +set( PCBNEW_PNS_SRCS + direction.h + pns_via.h + pns_routing_settings.h + pns_shove.cpp + pns_line.cpp + pns_utils.h + pns_layerset.h + trace.h + pns_line.h + pns_walkaround.cpp + pns_node.h + pns_line_placer.cpp + pns_utils.cpp + pns_solid.h + pns_item.cpp + pns_via.cpp + pns_node.cpp + pns_solid.cpp + pns_line_placer.h + pns_optimizer.h + pns_walkaround.h + pns_shove.h + pns_router.h + pns_router.cpp + pns_index.h + pns_item.h + pns_optimizer.cpp + pns_joint.h + pns_segment.h + pns_itemset.h + pns_itemset.cpp + router_tool.cpp + router_tool.h + router_preview_item.cpp + router_preview_item.h +) + +add_library( pnsrouter STATIC ${PCBNEW_PNS_SRCS} ) -add_library(pnsrouter STATIC ${PCBNEW_PNS_SRCS}) diff --git a/pcbnew/router/direction.h b/pcbnew/router/direction.h index 9df3523987..d8584f6ff7 100644 --- a/pcbnew/router/direction.h +++ b/pcbnew/router/direction.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -31,265 +31,302 @@ class DIRECTION_45 { - public: - - /** - * Enum Directions - * Represents available directions - there are 8 of them, as on a rectilinear map (north = up) + - * an extra undefined direction, reserved for traces that don't respect 45-degree routing regime. - */ - enum Directions { - N = 0, - NE = 1, - E = 2, - SE = 3, - S = 4, - SW = 5, - W = 6, - NW = 7, - UNDEFINED = -1 - }; - /** - * Enum AngleType - * Represents kind of angle formed by vectors heading in two DIRECTION_45s. - */ - enum AngleType { - ANG_OBTUSE = 0x1, - ANG_RIGHT = 0x2, - ANG_ACUTE = 0x4, - ANG_STRAIGHT = 0x8, - ANG_HALF_FULL = 0x10, - ANG_UNDEFINED = 0x20 - }; + /** + * Enum Directions + * Represents available directions - there are 8 of them, as on a rectilinear map (north = up) + + * an extra undefined direction, reserved for traces that don't respect 45-degree routing regime. + */ + enum Directions + { + N = 0, + NE = 1, + E = 2, + SE = 3, + S = 4, + SW = 5, + W = 6, + NW = 7, + UNDEFINED = -1 + }; - DIRECTION_45(Directions aDir = UNDEFINED): m_dir(aDir) {}; - - /** - * Constructor - * @param aVec vector, whose direction will be translated into a DIRECTION_45. - */ - DIRECTION_45(const VECTOR2I& aVec) - { - construct(aVec); - } + /** + * Enum AngleType + * Represents kind of angle formed by vectors heading in two DIRECTION_45s. + */ + enum AngleType + { + ANG_OBTUSE = 0x01, + ANG_RIGHT = 0x02, + ANG_ACUTE = 0x04, + ANG_STRAIGHT = 0x08, + ANG_HALF_FULL = 0x10, + ANG_UNDEFINED = 0x20 + }; - /** - * Constructor - * @param aSeg segment, whose direction will be translated into a DIRECTION_45. - */ - DIRECTION_45(const SEG& aSeg) - { - construct( aSeg.b - aSeg.a ); - } + DIRECTION_45( Directions aDir = UNDEFINED ) : m_dir( aDir ) {}; - /** - * Function Format() - * Formats the direction in a human readable word. - * @return name of the direction - */ - const std::string Format() const - { - switch(m_dir) - { - case N : return "north"; - case NE : return "north-east"; - case E : return "east"; - case SE : return "south-east"; - case S : return "south"; - case SW : return "south-west"; - case W : return "west"; - case NW : return "north-west"; - case UNDEFINED : return "undefined"; - default: return ""; - } - } - - /** - * Function Opposite() - * Returns a direction opposite (180 degree) to (this) - * @return opposite direction - */ - DIRECTION_45 Opposite() const - { - if(m_dir == UNDEFINED) - return UNDEFINED; - const Directions OppositeMap[] = { S, SW, W, NW, N, NE, E, SE } ; - return OppositeMap[m_dir]; - } + /** + * Constructor + * @param aVec vector, whose direction will be translated into a DIRECTION_45. + */ + DIRECTION_45( const VECTOR2I& aVec ) + { + construct( aVec ); + } - /** - * Function Angle() - * Returns the type of angle between directions (this) and aOther. - * @param aOther direction to compare angle with - */ - AngleType Angle(const DIRECTION_45& aOther) const - { - if(m_dir == UNDEFINED || aOther.m_dir == UNDEFINED) - return ANG_UNDEFINED; + /** + * Constructor + * @param aSeg segment, whose direction will be translated into a DIRECTION_45. + */ + DIRECTION_45( const SEG& aSeg ) + { + construct( aSeg.b - aSeg.a ); + } - int d = std::abs(m_dir - aOther.m_dir); + /** + * Function Format() + * Formats the direction in a human readable word. + * @return name of the direction + */ + const std::string Format() const + { + switch( m_dir ) + { + case N: + return "north"; - if(d == 1 || d == 7) - return ANG_OBTUSE; - else if(d == 2 || d == 6) - return ANG_RIGHT; - else if(d == 3 || d == 5) - return ANG_ACUTE; - else if(d == 4) - return ANG_HALF_FULL; - else - return ANG_STRAIGHT; - } + case NE: + return "north-east"; - /** - * Function IsObtuse() - * @return true, when (this) forms an obtuse angle with aOther - */ - bool IsObtuse(const DIRECTION_45& aOther) const - { - return Angle(aOther) == ANG_OBTUSE; - } + case E: + return "east"; - /** - * Function IsDiagonal() - * Returns true if the direction is diagonal (e.g. North-West, South-East, etc) - * @return true, when diagonal. - */ - bool IsDiagonal() const - { - return (m_dir % 2) == 1; - } - - /** - * Function BuildInitialTrace() - * - * Builds a 2-segment line chain between points aP0 and aP1 and following 45-degree routing - * regime. If aStartDiagonal is true, the trace starts with a diagonal segment. - * @param aP0 starting point - * @param aP1 ending point - * @param aStartDiagonal whether the first segment has to be diagonal - * @return the trace - */ - const SHAPE_LINE_CHAIN BuildInitialTrace(const VECTOR2I& aP0, const VECTOR2I &aP1, bool aStartDiagonal = false) const - { - int w = abs(aP1.x - aP0.x); - int h = abs(aP1.y - aP0.y); - int sw = sign(aP1.x - aP0.x); - int sh = sign(aP1.y - aP0.y); + case SE: + return "south-east"; - VECTOR2I mp0, mp1; - - // we are more horizontal than vertical? - if(w > h) - { - mp0 = VECTOR2I((w - h) * sw, 0); // direction: E - mp1 = VECTOR2I(h * sw, h * sh); // direction: NE - } else { - mp0 = VECTOR2I(0, sh * (h - w)); // direction: N - mp1 = VECTOR2I(sw * w, sh * w); // direction: NE - } + case S: + return "south"; - bool start_diagonal; + case SW: + return "south-west"; - if(m_dir == UNDEFINED) - start_diagonal = aStartDiagonal; - else - start_diagonal = IsDiagonal(); + case W: + return "west"; - SHAPE_LINE_CHAIN pl; + case NW: + return "north-west"; - pl.Append(aP0); - if (start_diagonal) - pl.Append(aP0 + mp1); - else - pl.Append(aP0 + mp0); - - pl.Append(aP1); - pl.Simplify(); - return pl; - }; + case UNDEFINED: + return "undefined"; - bool operator==(const DIRECTION_45& aOther) const - { - return aOther.m_dir == m_dir; - } + default: + return ""; + } + } - bool operator!=(const DIRECTION_45& aOther) const - { - return aOther.m_dir != m_dir; - } + /** + * Function Opposite() + * Returns a direction opposite (180 degree) to (this) + * @return opposite direction + */ + DIRECTION_45 Opposite() const + { + if( m_dir == UNDEFINED ) + return UNDEFINED; - const DIRECTION_45 Right() const - { - DIRECTION_45 r; - r.m_dir = (Directions) (m_dir + 1); - if(r.m_dir == NW) - r.m_dir = N; - return r; - } + const Directions OppositeMap[] = { S, SW, W, NW, N, NE, E, SE }; + return OppositeMap[m_dir]; + } + + /** + * Function Angle() + * Returns the type of angle between directions (this) and aOther. + * @param aOther direction to compare angle with + */ + AngleType Angle( const DIRECTION_45& aOther ) const + { + if( m_dir == UNDEFINED || aOther.m_dir == UNDEFINED ) + return ANG_UNDEFINED; + + int d = std::abs( m_dir - aOther.m_dir ); + + if( d == 1 || d == 7 ) + return ANG_OBTUSE; + else if( d == 2 || d == 6 ) + return ANG_RIGHT; + else if( d == 3 || d == 5 ) + return ANG_ACUTE; + else if( d == 4 ) + return ANG_HALF_FULL; + else + return ANG_STRAIGHT; + } + + /** + * Function IsObtuse() + * @return true, when (this) forms an obtuse angle with aOther + */ + bool IsObtuse( const DIRECTION_45& aOther ) const + { + return Angle( aOther ) == ANG_OBTUSE; + } + + /** + * Function IsDiagonal() + * Returns true if the direction is diagonal (e.g. North-West, South-East, etc) + * @return true, when diagonal. + */ + bool IsDiagonal() const + { + return ( m_dir % 2 ) == 1; + } + + /** + * Function BuildInitialTrace() + * + * Builds a 2-segment line chain between points aP0 and aP1 and following 45-degree routing + * regime. If aStartDiagonal is true, the trace starts with a diagonal segment. + * @param aP0 starting point + * @param aP1 ending point + * @param aStartDiagonal whether the first segment has to be diagonal + * @return the trace + */ + const SHAPE_LINE_CHAIN BuildInitialTrace( const VECTOR2I& aP0, + const VECTOR2I& aP1, + bool aStartDiagonal = false ) const + { + int w = abs( aP1.x - aP0.x ); + int h = abs( aP1.y - aP0.y ); + int sw = sign( aP1.x - aP0.x ); + int sh = sign( aP1.y - aP0.y ); + + VECTOR2I mp0, mp1; + + // we are more horizontal than vertical? + if( w > h ) + { + mp0 = VECTOR2I( (w - h) * sw, 0 ); // direction: E + mp1 = VECTOR2I( h * sw, h * sh ); // direction: NE + } + else + { + mp0 = VECTOR2I( 0, sh * (h - w) ); // direction: N + mp1 = VECTOR2I( sw * w, sh * w ); // direction: NE + } + + bool start_diagonal; + + if( m_dir == UNDEFINED ) + start_diagonal = aStartDiagonal; + else + start_diagonal = IsDiagonal(); + + SHAPE_LINE_CHAIN pl; + + pl.Append( aP0 ); + + if( start_diagonal ) + pl.Append( aP0 + mp1 ); + else + pl.Append( aP0 + mp0 ); + + pl.Append( aP1 ); + pl.Simplify(); + return pl; + }; + + bool operator==( const DIRECTION_45& aOther ) const + { + return aOther.m_dir == m_dir; + } + + bool operator!=( const DIRECTION_45& aOther ) const + { + return aOther.m_dir != m_dir; + } + + const DIRECTION_45 Right() const + { + DIRECTION_45 r; + + r.m_dir = (Directions) (m_dir + 1); + + if( r.m_dir == NW ) + r.m_dir = N; + + return r; + } private: - template int sign(T val) const { - return (T(0) < val) - (val < T(0)); - } + template + int sign( T val ) const + { + return (T( 0 ) < val) - ( val < T( 0 ) ); + } - /** - * Function construct() - * Calculates the direction from a vector. If the vector's angle is not a multiple of 45 - * degrees, the direction is rounded to the nearest octant. - * @param aVec our vector - */ - void construct(const VECTOR2I& aVec) - { - m_dir = UNDEFINED; - if(aVec.x == 0 && aVec.y == 0) - return; + /** + * Function construct() + * Calculates the direction from a vector. If the vector's angle is not a multiple of 45 + * degrees, the direction is rounded to the nearest octant. + * @param aVec our vector + */ + void construct( const VECTOR2I& aVec ) + { + m_dir = UNDEFINED; - double mag = 360.0 - (180.0 / M_PI * atan2 ((double) aVec.y, (double) aVec.x )) + 90.0; - if (mag >= 360.0) - mag -= 360.0; - if(mag < 0.0) - mag += 360.0; - - m_dir = (Directions) ((mag + 22.5) / 45.0); + if( aVec.x == 0 && aVec.y == 0 ) + return; - if(m_dir >= 8) - m_dir = (Directions) (m_dir - 8); - if(m_dir < 0) - m_dir = (Directions) (m_dir + 8); + double mag = 360.0 - ( 180.0 / M_PI * atan2( (double) aVec.y, (double) aVec.x ) ) + 90.0; - return ; - if(aVec.y < 0) - { - if(aVec.x > 0) - m_dir = NE; - else if(aVec.x < 0) - m_dir = NW; - else - m_dir = N; - } - else if(aVec.y == 0) - { - if(aVec.x > 0) - m_dir = E; - else - m_dir = W; - } - else // aVec.y>0 - { - if(aVec.x > 0) - m_dir = SE; - else if(aVec.x < 0) - m_dir = SW; - else - m_dir = S; - } - } + if( mag >= 360.0 ) + mag -= 360.0; - Directions m_dir; ///> our actual direction -}; + if( mag < 0.0 ) + mag += 360.0; + + m_dir = (Directions)( ( mag + 22.5 ) / 45.0 ); + + if( m_dir >= 8 ) + m_dir = (Directions)( m_dir - 8 ); + + if( m_dir < 0 ) + m_dir = (Directions)( m_dir + 8 ); + + return; + + if( aVec.y < 0 ) + { + if( aVec.x > 0 ) + m_dir = NE; + else if( aVec.x < 0 ) + m_dir = NW; + else + m_dir = N; + } + else if( aVec.y == 0 ) + { + if( aVec.x > 0 ) + m_dir = E; + else + m_dir = W; + } + else // aVec.y>0 + { + if( aVec.x > 0 ) + m_dir = SE; + else if( aVec.x < 0 ) + m_dir = SW; + else + m_dir = S; + } + } + + Directions m_dir; ///> our actual direction +}; + +#endif // __DIRECTION_H -#endif // __DIRECTION_H diff --git a/pcbnew/router/pns_index.h b/pcbnew/router/pns_index.h index c7f8704202..6bd556b460 100644 --- a/pcbnew/router/pns_index.h +++ b/pcbnew/router/pns_index.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -37,205 +37,227 @@ * overlap and improving search time. **/ -class PNS_INDEX { - +class PNS_INDEX +{ public: - - typedef std::list NetItemsList; - typedef SHAPE_INDEX ItemShapeIndex; - typedef boost::unordered_set ItemSet; + typedef std::list NetItemsList; + typedef SHAPE_INDEX ItemShapeIndex; + typedef boost::unordered_set ItemSet; - PNS_INDEX(); - ~PNS_INDEX(); + PNS_INDEX(); + ~PNS_INDEX(); - void Add( PNS_ITEM *aItem ); - void Remove ( PNS_ITEM *aItem ); - void Replace ( PNS_ITEM *aOldItem, PNS_ITEM *aNewItem ); + void Add( PNS_ITEM* aItem ); + void Remove( PNS_ITEM* aItem ); + void Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ); - template - int Query( const PNS_ITEM *aItem, int aMinDistance, Visitor &v); - template - int Query( const SHAPE *aShape, int aMinDistance, Visitor &v); + template + int Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& v ); - void Clear(); + template + int Query( const SHAPE* aShape, int aMinDistance, Visitor& v ); - NetItemsList* GetItemsForNet ( int aNet ) ; + void Clear(); - ItemSet::iterator begin() { return m_allItems.begin(); } - ItemSet::iterator end() { return m_allItems.end(); } + NetItemsList* GetItemsForNet( int aNet ); - bool Contains ( PNS_ITEM *aItem ) const { - return m_allItems.find(aItem) != m_allItems.end(); - } + ItemSet::iterator begin() { return m_allItems.begin(); } + ItemSet::iterator end() { return m_allItems.end(); } - int Size() const { return m_allItems.size(); } + bool Contains( PNS_ITEM* aItem ) const + { + return m_allItems.find( aItem ) != m_allItems.end(); + } + + int Size() const { return m_allItems.size(); } private: - + static const int MaxSubIndices = 64; + static const int SI_Multilayer = 2; + static const int SI_SegDiagonal = 0; + static const int SI_SegStraight = 1; + static const int SI_Traces = 3; + static const int SI_PadsTop = 0; + static const int SI_PadsBottom = 1; - static const int MaxSubIndices = 64; - static const int SI_Multilayer = 2; - static const int SI_SegDiagonal = 0; - static const int SI_SegStraight = 1; - static const int SI_Traces = 3; - static const int SI_PadsTop = 0; - static const int SI_PadsBottom = 1; + template + int querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& v ); - template - int querySingle( int index, const SHAPE *aShape, int aMinDistance, Visitor &v); + ItemShapeIndex* getSubindex( const PNS_ITEM* aItem ); - ItemShapeIndex *getSubindex( const PNS_ITEM *aItem ); - - ItemShapeIndex *m_subIndices[ MaxSubIndices ]; - std::map m_netMap; - ItemSet m_allItems; + ItemShapeIndex* m_subIndices[MaxSubIndices]; + std::map m_netMap; + ItemSet m_allItems; }; + PNS_INDEX::PNS_INDEX() { - memset(m_subIndices, 0, sizeof(m_subIndices)); + memset( m_subIndices, 0, sizeof( m_subIndices ) ); } -PNS_INDEX::ItemShapeIndex *PNS_INDEX::getSubindex(const PNS_ITEM *aItem ) + +PNS_INDEX::ItemShapeIndex* PNS_INDEX::getSubindex( const PNS_ITEM* aItem ) { - int idx_n = -1; + int idx_n = -1; - const PNS_LAYERSET l = aItem->GetLayers(); - - switch(aItem->GetKind()) - { - case PNS_ITEM::VIA: - idx_n = SI_Multilayer; - break; - case PNS_ITEM::SOLID: - { - if( l.IsMultilayer() ) - idx_n = SI_Multilayer; - else if (l.Start() == 0) // fixme: use kicad layer codes - idx_n = SI_PadsTop; - else if (l.Start() == 15) - idx_n = SI_PadsBottom; - break; - } - case PNS_ITEM::SEGMENT: - case PNS_ITEM::LINE: - idx_n = SI_Traces + 2 * l.Start() + SI_SegStraight; - break; - default: - break; - } - assert(idx_n >= 0 && idx_n < MaxSubIndices); + const PNS_LAYERSET l = aItem->GetLayers(); - if(!m_subIndices[idx_n]) - m_subIndices[idx_n] = new ItemShapeIndex; + switch( aItem->GetKind() ) + { + case PNS_ITEM::VIA: + idx_n = SI_Multilayer; + break; - return m_subIndices[idx_n]; + case PNS_ITEM::SOLID: + { + if( l.IsMultilayer() ) + idx_n = SI_Multilayer; + else if( l.Start() == 0 ) // fixme: use kicad layer codes + idx_n = SI_PadsTop; + else if( l.Start() == 15 ) + idx_n = SI_PadsBottom; + + break; + } + + case PNS_ITEM::SEGMENT: + case PNS_ITEM::LINE: + idx_n = SI_Traces + 2 * l.Start() + SI_SegStraight; + break; + + default: + break; + } + + assert( idx_n >= 0 && idx_n < MaxSubIndices ); + + if( !m_subIndices[idx_n] ) + m_subIndices[idx_n] = new ItemShapeIndex; + + return m_subIndices[idx_n]; } -void PNS_INDEX::Add( PNS_ITEM *aItem ) + +void PNS_INDEX::Add( PNS_ITEM* aItem ) { - ItemShapeIndex *idx = getSubindex(aItem); - + ItemShapeIndex* idx = getSubindex( aItem ); - idx->Add(aItem); - m_allItems.insert(aItem); - int net = aItem->GetNet(); - if(net >= 0) - { - m_netMap[net].push_back(aItem); - } + idx->Add( aItem ); + m_allItems.insert( aItem ); + int net = aItem->GetNet(); + + if( net >= 0 ) + { + m_netMap[net].push_back( aItem ); + } } -void PNS_INDEX::Remove( PNS_ITEM *aItem ) + +void PNS_INDEX::Remove( PNS_ITEM* aItem ) { - ItemShapeIndex *idx = getSubindex(aItem); - idx->Remove(aItem); - m_allItems.erase (aItem); + ItemShapeIndex* idx = getSubindex( aItem ); - int net = aItem->GetNet(); - - if(net >= 0 && m_netMap.find(net) != m_netMap.end()) - m_netMap[net].remove(aItem); + idx->Remove( aItem ); + m_allItems.erase( aItem ); + + int net = aItem->GetNet(); + + if( net >= 0 && m_netMap.find( net ) != m_netMap.end() ) + m_netMap[net].remove( aItem ); } -void PNS_INDEX::Replace( PNS_ITEM *aOldItem, PNS_ITEM *aNewItem ) + +void PNS_INDEX::Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ) { - Remove(aOldItem); - Add(aNewItem); + Remove( aOldItem ); + Add( aNewItem ); } + template - int PNS_INDEX::querySingle( int index, const SHAPE *aShape, int aMinDistance, Visitor &v) - { - if(!m_subIndices[index]) - return 0; - return m_subIndices[index] -> Query(aShape, aMinDistance, v, false); - } +int PNS_INDEX::querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& v ) +{ + if( !m_subIndices[index] ) + return 0; + + return m_subIndices[index]->Query( aShape, aMinDistance, v, false ); +} + template - int PNS_INDEX::Query( const PNS_ITEM *aItem, int aMinDistance, Visitor &v) - { - const SHAPE *shape = aItem->GetShape(); - int total = 0; - - - total += querySingle(SI_Multilayer, shape, aMinDistance, v); +int PNS_INDEX::Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& v ) +{ + const SHAPE* shape = aItem->GetShape(); + int total = 0; - const PNS_LAYERSET layers = aItem->GetLayers(); - - if(layers.IsMultilayer()) - { - total += querySingle(SI_PadsTop, shape, aMinDistance, v); - total += querySingle(SI_PadsBottom, shape, aMinDistance, v); + total += querySingle( SI_Multilayer, shape, aMinDistance, v ); - - for(int i = layers.Start(); i <= layers.End(); ++i ) - total += querySingle( SI_Traces + 2 * i + SI_SegStraight, shape, aMinDistance, v); + const PNS_LAYERSET layers = aItem->GetLayers(); - } else { - int l = layers.Start(); + if( layers.IsMultilayer() ) + { + total += querySingle( SI_PadsTop, shape, aMinDistance, v ); + total += querySingle( SI_PadsBottom, shape, aMinDistance, v ); - if(l == 0) - total += querySingle(SI_PadsTop, shape, aMinDistance, v); - else if(l == 15) - total += querySingle(SI_PadsBottom, shape, aMinDistance, v); - total += querySingle ( SI_Traces + 2 * l + SI_SegStraight, shape, aMinDistance, v); - } + for( int i = layers.Start(); i <= layers.End(); ++i ) + total += querySingle( SI_Traces + 2 * i + SI_SegStraight, shape, aMinDistance, v ); + } + else + { + int l = layers.Start(); + + if( l == 0 ) + total += querySingle( SI_PadsTop, shape, aMinDistance, v ); + else if( l == 15 ) + total += querySingle( SI_PadsBottom, shape, aMinDistance, v ); + + total += querySingle( SI_Traces + 2 * l + SI_SegStraight, shape, aMinDistance, v ); + } + + return total; +} - return total; - } template - int PNS_INDEX::Query( const SHAPE *aShape, int aMinDistance, Visitor &v) - { - int total = 0; - for(int i = 0; i < MaxSubIndices; i++) - total += querySingle(i, aShape, aMinDistance, v); - return total; - } +int PNS_INDEX::Query( const SHAPE* aShape, int aMinDistance, Visitor& v ) +{ + int total = 0; + + for( int i = 0; i < MaxSubIndices; i++ ) + total += querySingle( i, aShape, aMinDistance, v ); + + return total; +} + - void PNS_INDEX::Clear() { - for(int i = 0; i < MaxSubIndices; ++i) - { - ItemShapeIndex *idx = m_subIndices[i]; - if(idx) - delete idx; - m_subIndices[i] = NULL; - } + for( int i = 0; i < MaxSubIndices; ++i ) + { + ItemShapeIndex* idx = m_subIndices[i]; + + if( idx ) + delete idx; + + m_subIndices[i] = NULL; + } } + PNS_INDEX::~PNS_INDEX() { - Clear(); + Clear(); } -PNS_INDEX::NetItemsList* PNS_INDEX::GetItemsForNet ( int aNet ) + +PNS_INDEX::NetItemsList* PNS_INDEX::GetItemsForNet( int aNet ) { - if(m_netMap.find(aNet) == m_netMap.end()) - return NULL; - return &m_netMap[aNet]; + if( m_netMap.find( aNet ) == m_netMap.end() ) + return NULL; + + return &m_netMap[aNet]; } #endif + diff --git a/pcbnew/router/pns_item.cpp b/pcbnew/router/pns_item.cpp index 43a6b97976..d2b79dddb9 100644 --- a/pcbnew/router/pns_item.cpp +++ b/pcbnew/router/pns_item.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -21,52 +21,69 @@ #include "pns_item.h" #include "pns_line.h" -bool PNS_ITEM::collideSimple ( const PNS_ITEM *aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) const +bool PNS_ITEM::collideSimple( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, + VECTOR2I& aMTV ) const { - // same nets? no collision! - if( m_net == aOther->m_net ) - return false; + // same nets? no collision! + if( m_net == aOther->m_net ) + return false; - // check if we are not on completely different layers first - if (!m_layers.Overlaps (aOther->m_layers)) - return false; + // check if we are not on completely different layers first + if( !m_layers.Overlaps( aOther->m_layers ) ) + return false; - return GetShape()->Collide ( aOther->GetShape(), aClearance ); + return GetShape()->Collide( aOther->GetShape(), aClearance ); - // fixme: MTV + // fixme: MTV } -bool PNS_ITEM::Collide( const PNS_ITEM *aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) const + +bool PNS_ITEM::Collide( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, + VECTOR2I& aMTV ) const { - if( collideSimple( aOther, aClearance, aNeedMTV, aMTV ) ) - return true; + if( collideSimple( aOther, aClearance, aNeedMTV, aMTV ) ) + return true; - // special case for "head" line with a via attached at the end. - if( aOther->m_kind == LINE ) - { - const PNS_LINE *line = static_cast (aOther); - if(line -> EndsWithVia()) - return collideSimple( &line->GetVia(), aClearance - line->GetWidth() / 2, aNeedMTV, aMTV ); - } + // special case for "head" line with a via attached at the end. + if( aOther->m_kind == LINE ) + { + const PNS_LINE* line = static_cast( aOther ); - return false; + if( line->EndsWithVia() ) + return collideSimple( &line->GetVia(), aClearance - line->GetWidth() / 2, aNeedMTV, + aMTV ); + } + + return false; } + const std::string PNS_ITEM::GetKindStr() const { - switch(m_kind) - { - case LINE: return "line"; - case SEGMENT: return "segment"; - case VIA: return "via"; - case JOINT: return "joint"; - case SOLID: return "solid"; - default: return "unknown"; - } + switch( m_kind ) + { + case LINE: + return "line"; + + case SEGMENT: + return "segment"; + + case VIA: + return "via"; + + case JOINT: + return "joint"; + + case SOLID: + return "solid"; + + default: + return "unknown"; + } } + PNS_ITEM::~PNS_ITEM() { - } - \ No newline at end of file + diff --git a/pcbnew/router/pns_item.h b/pcbnew/router/pns_item.h index 22114ed6af..a9b2da49e4 100644 --- a/pcbnew/router/pns_item.h +++ b/pcbnew/router/pns_item.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -37,119 +37,122 @@ class PNS_NODE; * Base class for PNS router board items. Implements the shared properties of all PCB items - * net, spanned layers, geometric shape & refererence to owning model. */ - -class PNS_ITEM + +class PNS_ITEM { public: + static const int UnusedNet = INT_MAX; - static const int UnusedNet = INT_MAX; + ///> Supported item types + enum PnsKind + { + SOLID = 1, + LINE = 2, + JOINT = 4, + SEGMENT = 8, + VIA = 16, + ANY = 0xff + }; - ///> Supported item types - enum PnsKind { - SOLID = 1, - LINE = 2, - JOINT = 4, - SEGMENT = 8, - VIA = 16, - ANY = 0xff - }; + PNS_ITEM( PnsKind aKind ) + { + m_net = UnusedNet; + m_movable = true; + m_kind = aKind; + m_parent = NULL; + m_world = NULL; + m_owner = NULL; + } - PNS_ITEM(PnsKind aKind) - { - m_net = UnusedNet; - m_movable = true; - m_kind = aKind; - m_parent = NULL; - m_world = NULL; - m_owner = NULL; - } + PNS_ITEM( const PNS_ITEM& aOther ) + { + m_layers = aOther.m_layers; + m_net = aOther.m_net; + m_movable = aOther.m_movable; + m_kind = aOther.m_kind; + m_world = aOther.m_world; + m_parent = aOther.m_parent; + m_owner = NULL; + } - PNS_ITEM( const PNS_ITEM& aOther ) - { - m_layers = aOther.m_layers; - m_net = aOther.m_net; - m_movable = aOther.m_movable; - m_kind = aOther.m_kind; - m_world = aOther.m_world; - m_parent = aOther.m_parent; - m_owner = NULL; - } + virtual ~PNS_ITEM(); - virtual ~PNS_ITEM(); - - virtual PNS_ITEM *Clone() const = 0; + virtual PNS_ITEM* Clone() const = 0; - ///> Returns a convex polygon "hull" of a the item, that is used as the walkaround - /// path. - /// aClearance defines how far from the body of the item the hull should be, - /// aWalkaroundThickness is the width of the line that walks around this hull. - virtual const SHAPE_LINE_CHAIN Hull(int aClearance = 0, int aWalkaroundThickness = 0) const - { - return SHAPE_LINE_CHAIN(); - }; + ///> Returns a convex polygon "hull" of a the item, that is used as the walkaround + /// path. + /// aClearance defines how far from the body of the item the hull should be, + /// aWalkaroundThickness is the width of the line that walks around this hull. + virtual const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0 ) const + { + return SHAPE_LINE_CHAIN(); + }; + PnsKind GetKind() const { return m_kind; } + bool OfKind( int aKind ) const { return (aKind & m_kind) != 0; } - - PnsKind GetKind() const { return m_kind; } - bool OfKind( int aKind ) const { return (aKind & m_kind) != 0; } - - const std::string GetKindStr() const; - - ///> Gets/Sets the corresponding parent object in the host application's model (pcbnew) - void SetParent(BOARD_ITEM *aParent) { m_parent = aParent; } - BOARD_ITEM *GetParent() const { return m_parent; } + const std::string GetKindStr() const; - ///> Net accessors - int GetNet() const { return m_net; } - void SetNet(int aNet) { m_net = aNet; } + ///> Gets/Sets the corresponding parent object in the host application's model (pcbnew) + void SetParent( BOARD_ITEM* aParent ) { m_parent = aParent; } + BOARD_ITEM* GetParent() const { return m_parent; } - ///> Layers accessors - const PNS_LAYERSET& GetLayers() const { return m_layers; } - void SetLayers ( const PNS_LAYERSET& aLayers ) { m_layers = aLayers; } - void SetLayer ( int aLayer ) { m_layers = PNS_LAYERSET (aLayer, aLayer); } + ///> Net accessors + int GetNet() const { return m_net; } + void SetNet( int aNet ) { m_net = aNet; } - ///> Ownership management. An item can belong to a single PNS_NODE or stay unowned. - void SetOwner (PNS_NODE *aOwner) { m_owner = aOwner; } - bool BelongsTo (PNS_NODE *aNode) const { return m_owner == aNode; } - PNS_NODE *GetOwner() const { return m_owner; } + ///> Layers accessors + const PNS_LAYERSET& GetLayers() const { return m_layers; } + void SetLayers( const PNS_LAYERSET& aLayers ) { m_layers = aLayers; } + void SetLayer( int aLayer ) + { + m_layers = PNS_LAYERSET( aLayer, aLayer ); + } - ///> Sets the world that is used for collision resolution. - void SetWorld (PNS_NODE *aWorld) { m_world = aWorld; } - PNS_NODE *GetWorld() const { return m_world; } + ///> Ownership management. An item can belong to a single PNS_NODE or stay unowned. + void SetOwner( PNS_NODE* aOwner ) { m_owner = aOwner; } + bool BelongsTo( PNS_NODE* aNode ) const { return m_owner == aNode; } + PNS_NODE* GetOwner() const { return m_owner; } + ///> Sets the world that is used for collision resolution. + void SetWorld( PNS_NODE* aWorld ) { m_world = aWorld; } + PNS_NODE* GetWorld() const { return m_world; } - ///> Collision function. Checks if the item aOther is closer to us than - /// aClearance and returns true if so. It can also calculate a minimum translation vector that resolves the - /// collision if needed. - virtual bool Collide( const PNS_ITEM *aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) const; + ///> Collision function. Checks if the item aOther is closer to us than + /// aClearance and returns true if so. It can also calculate a minimum translation vector that + /// resolves the collision if needed. + virtual bool Collide( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, + VECTOR2I& aMTV ) const; - ///> A shortcut without MTV calculation - bool Collide( const PNS_ITEM *aOther, int aClearance ) const - { - VECTOR2I dummy; - return Collide(aOther, aClearance, false, dummy); - } - - ///> Returns the geometric shape of the item - virtual const SHAPE* GetShape() const { - return NULL; - } + ///> A shortcut without MTV calculation + bool Collide( const PNS_ITEM* aOther, int aClearance ) const + { + VECTOR2I dummy; + + return Collide( aOther, aClearance, false, dummy ); + } + + ///> Returns the geometric shape of the item + virtual const SHAPE* GetShape() const + { + return NULL; + } private: - bool collideSimple ( const PNS_ITEM *aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) const; + bool collideSimple( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV, + VECTOR2I& aMTV ) const; protected: + PnsKind m_kind; - PnsKind m_kind; - - BOARD_ITEM *m_parent; - PNS_NODE *m_world; - PNS_NODE *m_owner; - PNS_LAYERSET m_layers; + BOARD_ITEM* m_parent; + PNS_NODE* m_world; + PNS_NODE* m_owner; + PNS_LAYERSET m_layers; - bool m_movable; - int m_net; + bool m_movable; + int m_net; }; -#endif // __PNS_ITEM_H +#endif // __PNS_ITEM_Ha diff --git a/pcbnew/router/pns_itemset.cpp b/pcbnew/router/pns_itemset.cpp index 494c1a07a9..1e6a603ae6 100644 --- a/pcbnew/router/pns_itemset.cpp +++ b/pcbnew/router/pns_itemset.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -25,49 +25,58 @@ PNS_ITEMSET::PNS_ITEMSET() { - } + PNS_ITEMSET::~PNS_ITEMSET() { - } -PNS_ITEMSET& PNS_ITEMSET::FilterLayers ( int aStart, int aEnd ) + +PNS_ITEMSET& PNS_ITEMSET::FilterLayers( int aStart, int aEnd ) { - ItemVector newItems; - PNS_LAYERSET l; - if(aEnd < 0) - l = PNS_LAYERSET(aStart); - else - l = PNS_LAYERSET(aStart, aEnd); + ItemVector newItems; + PNS_LAYERSET l; - BOOST_FOREACH( PNS_ITEM *item, m_items ) - if(item->GetLayers(). Overlaps ( l )) - newItems.push_back(item); - m_items = newItems; - return *this; + if( aEnd < 0 ) + l = PNS_LAYERSET( aStart ); + else + l = PNS_LAYERSET( aStart, aEnd ); + + BOOST_FOREACH( PNS_ITEM * item, m_items ) + + if( item->GetLayers().Overlaps( l ) ) + newItems.push_back( item ); + + m_items = newItems; + return *this; } -PNS_ITEMSET& PNS_ITEMSET::FilterKinds ( int aKindMask ) + +PNS_ITEMSET& PNS_ITEMSET::FilterKinds( int aKindMask ) { - ItemVector newItems; - - BOOST_FOREACH( PNS_ITEM *item, m_items ) - if(item->GetKind() & aKindMask ) - newItems.push_back(item); - m_items = newItems; - return *this; + ItemVector newItems; + + BOOST_FOREACH( PNS_ITEM * item, m_items ) + + if( item->GetKind() & aKindMask ) + newItems.push_back( item ); + + m_items = newItems; + return *this; } -PNS_ITEMSET& PNS_ITEMSET::FilterNet ( int aNet ) + +PNS_ITEMSET& PNS_ITEMSET::FilterNet( int aNet ) { - ItemVector newItems; - - BOOST_FOREACH( PNS_ITEM *item, m_items ) - if(item->GetNet() == aNet) - newItems.push_back(item); - m_items = newItems; - return *this; + ItemVector newItems; + + BOOST_FOREACH( PNS_ITEM * item, m_items ) + + if( item->GetNet() == aNet ) + newItems.push_back( item ); + + m_items = newItems; + return *this; } diff --git a/pcbnew/router/pns_itemset.h b/pcbnew/router/pns_itemset.h index 91ebea1a20..ae13ae78e9 100644 --- a/pcbnew/router/pns_itemset.h +++ b/pcbnew/router/pns_itemset.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -28,35 +28,36 @@ /** * Class PNS_ITEMSET * - * Holds a list of board items, that can be filtered against net, kinds, layers, etc. + * Holds a list of board items, that can be filtered against net, kinds, + * layers, etc. **/ class PNS_ITEMSET { public: + typedef std::vector ItemVector; - typedef std::vector ItemVector; + PNS_ITEMSET(); + ~PNS_ITEMSET(); - PNS_ITEMSET(); - ~PNS_ITEMSET(); + ItemVector& Items() { return m_items; } - ItemVector& Items() { return m_items; } + PNS_ITEMSET& FilterLayers( int aStart, int aEnd = -1 ); + PNS_ITEMSET& FilterKinds( int aKindMask ); + PNS_ITEMSET& FilterNet( int aNet ); - PNS_ITEMSET& FilterLayers ( int aStart, int aEnd = -1 ); - PNS_ITEMSET& FilterKinds ( int aKindMask ); - PNS_ITEMSET& FilterNet ( int aNet ); - - int Size() { return m_items.size(); } + int Size() { return m_items.size(); } - void Add(PNS_ITEM *item) - { - m_items.push_back(item); - } + void Add( PNS_ITEM* item ) + { + m_items.push_back( item ); + } - PNS_ITEM *Get( int index ) const { return m_items[index]; } + PNS_ITEM* Get( int index ) const { return m_items[index]; } private: - ItemVector m_items; + ItemVector m_items; }; #endif + diff --git a/pcbnew/router/pns_joint.h b/pcbnew/router/pns_joint.h index 88f7477a75..a4ad7340a0 100644 --- a/pcbnew/router/pns_joint.h +++ b/pcbnew/router/pns_joint.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -31,158 +31,177 @@ /** * Class PNS_JOINT - * - * Represents a 2D point on a given set of layers and belonging to a certain net, - * that links together a number of board items. - * A hash table of joints is used by the router to follow connectivity between the items. + * + * Represents a 2D point on a given set of layers and belonging to a certain + * net, that links together a number of board items. + * A hash table of joints is used by the router to follow connectivity between + * the items. **/ - class PNS_JOINT : public PNS_ITEM { public: - typedef std::vector LinkedItems; + typedef std::vector LinkedItems; - ///> joints are hashed by their position, layers and net. Linked items are, obviously, not hashed - struct HashTag { - VECTOR2I pos; - int net; - }; - - PNS_JOINT(): - PNS_ITEM(JOINT) {} + ///> Joints are hashed by their position, layers and net. + /// Linked items are, obviously, not hashed + struct HashTag + { + VECTOR2I pos; + int net; + }; - PNS_JOINT(const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet = -1): - PNS_ITEM(JOINT) - { - m_tag.pos = aPos; - m_tag.net = aNet; - m_layers = aLayers; - } + PNS_JOINT() : + PNS_ITEM( JOINT ) {} - PNS_JOINT(const PNS_JOINT& b): - PNS_ITEM(JOINT) - { - m_layers = b.m_layers; - m_tag.pos = b.m_tag.pos; - m_tag.net = b.m_tag.net; - m_linkedItems = b.m_linkedItems; - m_layers = b.m_layers; - } + PNS_JOINT( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, + int aNet = -1 ) : + PNS_ITEM( JOINT ) + { + m_tag.pos = aPos; + m_tag.net = aNet; + m_layers = aLayers; + } - PNS_ITEM *Clone() const - { - assert(false); - return NULL; - } + PNS_JOINT( const PNS_JOINT& b ) : + PNS_ITEM( JOINT ) + { + m_layers = b.m_layers; + m_tag.pos = b.m_tag.pos; + m_tag.net = b.m_tag.net; + m_linkedItems = b.m_linkedItems; + m_layers = b.m_layers; + } - ///> returns true if the joint is a trivial line corner, connecting two segments of the same net, on the same layer. - bool IsLineCorner() const - { - if(m_linkedItems.size() != 2) - return false; + PNS_ITEM* Clone() const + { + assert( false ); + return NULL; + } - if( m_linkedItems[0]->GetKind() != SEGMENT || m_linkedItems[1]->GetKind() != SEGMENT ) - return false; + ///> Returns true if the joint is a trivial line corner, connecting two + /// segments of the same net, on the same layer. + bool IsLineCorner() const + { + if( m_linkedItems.size() != 2 ) + return false; - PNS_SEGMENT *seg1 = static_cast (m_linkedItems[0]); - PNS_SEGMENT *seg2 = static_cast (m_linkedItems[1]); + if( m_linkedItems[0]->GetKind() != SEGMENT || + m_linkedItems[1]->GetKind() != SEGMENT ) + return false; - // joints between segments of different widths are not trivial. - return (seg1->GetWidth() == seg2->GetWidth()); - } + PNS_SEGMENT* seg1 = static_cast (m_linkedItems[0]); + PNS_SEGMENT* seg2 = static_cast (m_linkedItems[1]); - ///> Links the joint to a given board item (when it's added to the PNS_NODE) - void Link ( PNS_ITEM *aItem ) - { - LinkedItems::iterator f = std::find(m_linkedItems.begin(), m_linkedItems.end(), aItem); - if(f != m_linkedItems.end()) - return; - m_linkedItems.push_back(aItem); - } + // joints between segments of different widths are not trivial. + return seg1->GetWidth() == seg2->GetWidth(); + } - ///> Unlinks a given board item from the joint (upon its removal from a PNS_NODE) - ///> Returns true if the joint became dangling after unlinking. - bool Unlink ( PNS_ITEM *aItem ) - { - LinkedItems::iterator f = std::find(m_linkedItems.begin(), m_linkedItems.end(), aItem); - if(f != m_linkedItems.end()) - m_linkedItems.erase(f); - return (m_linkedItems.size() == 0); - } + ///> Links the joint to a given board item (when it's added to the PNS_NODE) + void Link( PNS_ITEM* aItem ) + { + LinkedItems::iterator f = std::find( m_linkedItems.begin(), + m_linkedItems.end(), aItem ); - ///> For trivial joints, returns the segment adjacent to (aCurrent). For non-trival ones, returns - ///> NULL, indicating the end of line. - PNS_SEGMENT* NextSegment( PNS_SEGMENT* aCurrent) const - { - if(!IsLineCorner()) - return NULL; - - return static_cast (m_linkedItems [ m_linkedItems[0] == aCurrent ? 1 : 0 ] ); - } + if( f != m_linkedItems.end() ) + return; - /// trivial accessors - const HashTag& GetTag() const { return m_tag; } - const VECTOR2I& GetPos() const { return m_tag.pos; } - int GetNet() const { return m_tag.net; } - LinkedItems & GetLinkList() { return m_linkedItems; }; + m_linkedItems.push_back( aItem ); + } - ///> Returns the number of linked items of types listed in aMask. - int LinkCount( int aMask = -1 ) const - { - int n = 0; - for(LinkedItems::const_iterator i = m_linkedItems.begin(); i!= m_linkedItems.end(); ++i) - if( (*i)->GetKind() & aMask ) - n++; - return n; - } + ///> Unlinks a given board item from the joint (upon its removal from a PNS_NODE) + ///> Returns true if the joint became dangling after unlinking. + bool Unlink( PNS_ITEM* aItem ) + { + LinkedItems::iterator f = std::find( m_linkedItems.begin(), + m_linkedItems.end(), aItem ); - void Dump() const; - - bool operator==(const PNS_JOINT& rhs) const - { - return m_tag.pos == rhs.m_tag.pos && m_tag.net == rhs.m_tag.net; - } + if( f != m_linkedItems.end() ) + m_linkedItems.erase( f ); - void Merge( const PNS_JOINT& aJoint ) - { - if(!Overlaps(aJoint)) - return; - - m_layers.Merge (aJoint.m_layers); + return m_linkedItems.size() == 0; + } - // fixme: duplicate links (?) - for(LinkedItems::const_iterator i =aJoint.m_linkedItems.begin(); i!=aJoint.m_linkedItems.end();++i) - m_linkedItems.push_back(*i); - } + ///> For trivial joints, returns the segment adjacent to (aCurrent). For non-trival ones, returns + ///> NULL, indicating the end of line. + PNS_SEGMENT* NextSegment( PNS_SEGMENT* aCurrent ) const + { + if( !IsLineCorner() ) + return NULL; - bool Overlaps(const PNS_JOINT& rhs) const - { - return m_tag.pos == rhs.m_tag.pos && m_tag.net == rhs.m_tag.net && m_layers.Overlaps(rhs.m_layers); - } + return static_cast( m_linkedItems[m_linkedItems[0] == aCurrent ? 1 : 0] ); + } + + /// trivial accessors + const HashTag& GetTag() const { return m_tag; } + const VECTOR2I& GetPos() const { return m_tag.pos; } + int GetNet() const { return m_tag.net; } + LinkedItems& GetLinkList() { return m_linkedItems; }; + + ///> Returns the number of linked items of types listed in aMask. + int LinkCount( int aMask = -1 ) const + { + int n = 0; + + for( LinkedItems::const_iterator i = m_linkedItems.begin(); + i != m_linkedItems.end(); ++i ) + if( (*i)->GetKind() & aMask ) + n++; + + return n; + } + + void Dump() const; + + bool operator==( const PNS_JOINT& rhs ) const + { + return m_tag.pos == rhs.m_tag.pos && m_tag.net == rhs.m_tag.net; + } + + void Merge( const PNS_JOINT& aJoint ) + { + if( !Overlaps( aJoint ) ) + return; + + m_layers.Merge( aJoint.m_layers ); + + // fixme: duplicate links (?) + for( LinkedItems::const_iterator i = aJoint.m_linkedItems.begin(); + i != aJoint.m_linkedItems.end(); ++i ) + m_linkedItems.push_back( *i ); + } + + bool Overlaps( const PNS_JOINT& rhs ) const + { + return m_tag.pos == rhs.m_tag.pos && + m_tag.net == rhs.m_tag.net && m_layers.Overlaps( rhs.m_layers ); + } private: + ///> hash tag for unordered_multimap + HashTag m_tag; - ///> hash tag for unordered_multimap - HashTag m_tag; - - ///> list of items linked to this joint - LinkedItems m_linkedItems; + ///> list of items linked to this joint + LinkedItems m_linkedItems; }; // hash function & comparison operator for boost::unordered_map<> -inline bool operator==(PNS_JOINT::HashTag const& p1, PNS_JOINT::HashTag const& p2) +inline bool operator==( PNS_JOINT::HashTag const& p1, + PNS_JOINT::HashTag const& p2 ) { return p1.pos == p2.pos && p1.net == p2.net; } -inline std::size_t hash_value(PNS_JOINT::HashTag const& p) + +inline std::size_t hash_value( PNS_JOINT::HashTag const& p ) { std::size_t seed = 0; - boost::hash_combine(seed, p.pos.x); - boost::hash_combine(seed, p.pos.y); - boost::hash_combine(seed, p.net); + boost::hash_combine( seed, p.pos.x ); + boost::hash_combine( seed, p.pos.y ); + boost::hash_combine( seed, p.net ); + return seed; } -#endif // __PNS_JOINT_H +#endif // __PNS_JOINT_H + diff --git a/pcbnew/router/pns_layerset.h b/pcbnew/router/pns_layerset.h index 2809eb485c..6baa9b51f8 100644 --- a/pcbnew/router/pns_layerset.h +++ b/pcbnew/router/pns_layerset.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -26,93 +26,95 @@ /** * Class PNS_LAYERSET * - * Represents a contiguous set of PCB layers. + * Represents a contiguous set of PCB layers. */ - class PNS_LAYERSET { - public: +public: + PNS_LAYERSET() : + m_start( -1 ), + m_end( -1 ) + {}; - PNS_LAYERSET(): - m_start(-1), - m_end(-1) - {}; + PNS_LAYERSET( int aStart, int aEnd ) + { + if( aStart > aEnd ) + std::swap( aStart, aEnd ); - PNS_LAYERSET (int aStart, int aEnd) - { - if(aStart > aEnd) - std::swap(aStart, aEnd); - m_start = aStart; - m_end = aEnd; - } + m_start = aStart; + m_end = aEnd; + } - PNS_LAYERSET (int aLayer) - { - m_start = m_end = aLayer; - } + PNS_LAYERSET( int aLayer ) + { + m_start = m_end = aLayer; + } - PNS_LAYERSET(const PNS_LAYERSET &b) : - m_start(b.m_start), - m_end (b.m_end) - {} + PNS_LAYERSET( const PNS_LAYERSET& b ) : + m_start( b.m_start ), + m_end( b.m_end ) + {} - ~PNS_LAYERSET () {}; + ~PNS_LAYERSET() {}; - const PNS_LAYERSET& operator= ( const PNS_LAYERSET& b) - { - m_start = b.m_start; - m_end = b.m_end; - return *this; - } + const PNS_LAYERSET& operator=( const PNS_LAYERSET& b ) + { + m_start = b.m_start; + m_end = b.m_end; + return *this; + } - bool Overlaps ( const PNS_LAYERSET& aOther ) const - { - return m_end >= aOther.m_start && m_start <= aOther.m_end; - } + bool Overlaps( const PNS_LAYERSET& aOther ) const + { + return m_end >= aOther.m_start && m_start <= aOther.m_end; + } - bool Overlaps ( const int aLayer ) const - { - return aLayer >= m_start && aLayer <= m_end; - } + bool Overlaps( const int aLayer ) const + { + return aLayer >= m_start && aLayer <= m_end; + } - bool IsMultilayer ( ) const - { - return m_start != m_end; - } + bool IsMultilayer() const + { + return m_start != m_end; + } - int Start() const { - return m_start; - } + int Start() const + { + return m_start; + } - int End() const { - return m_end; - } + int End() const + { + return m_end; + } - void Merge ( const PNS_LAYERSET& aOther ) - { - if(m_start < 0 || m_end < 0) - { - m_start = aOther.m_start; - m_end = aOther.m_end; - return; - } + void Merge( const PNS_LAYERSET& aOther ) + { + if( m_start < 0 || m_end < 0 ) + { + m_start = aOther.m_start; + m_end = aOther.m_end; + return; + } - if(aOther.m_start < m_start) - m_start = aOther.m_start; - if(aOther.m_end > m_end) - m_end = aOther.m_end; - } + if( aOther.m_start < m_start ) + m_start = aOther.m_start; - ///> Shortcut for comparisons/overlap tests - static PNS_LAYERSET All() - { - return PNS_LAYERSET(0, 256); - } + if( aOther.m_end > m_end ) + m_end = aOther.m_end; + } - private: + ///> Shortcut for comparisons/overlap tests + static PNS_LAYERSET All() + { + return PNS_LAYERSET( 0, 256 ); + } - int m_start; - int m_end; +private: + int m_start; + int m_end; }; -#endif // __PNS_LAYERSET_H +#endif // __PNS_LAYERSET_H + diff --git a/pcbnew/router/pns_line.cpp b/pcbnew/router/pns_line.cpp index cb729f96d0..172a0188a7 100644 --- a/pcbnew/router/pns_line.cpp +++ b/pcbnew/router/pns_line.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -23,7 +23,6 @@ #include - #include "pns_line.h" #include "pns_node.h" #include "pns_via.h" @@ -33,672 +32,732 @@ using namespace std; using boost::optional; -PNS_LINE *PNS_LINE::Clone() const +PNS_LINE* PNS_LINE::Clone() const { - PNS_LINE *l = new PNS_LINE(); + PNS_LINE* l = new PNS_LINE(); - l->m_line = m_line; - l->m_width = m_width; - l->m_layers = m_layers; - l->m_net = m_net; - l->m_movable = m_movable; - l->m_segmentRefs = NULL; - l->m_hasVia = m_hasVia; - l->m_via = m_via; - - return l; + l->m_line = m_line; + l->m_width = m_width; + l->m_layers = m_layers; + l->m_net = m_net; + l->m_movable = m_movable; + l->m_segmentRefs = NULL; + l->m_hasVia = m_hasVia; + l->m_via = m_via; + + return l; } -PNS_LINE *PNS_LINE::CloneProperties() const + +PNS_LINE* PNS_LINE::CloneProperties() const { - PNS_LINE *l = new PNS_LINE(); + PNS_LINE* l = new PNS_LINE(); - l->m_width = m_width; - l->m_layers = m_layers; - l->m_net = m_net; - l->m_movable = m_movable; + l->m_width = m_width; + l->m_layers = m_layers; + l->m_net = m_net; + l->m_movable = m_movable; - return l; -} - -PNS_SEGMENT *PNS_SEGMENT::Clone() const -{ - PNS_SEGMENT *s = new PNS_SEGMENT; - s->m_width = m_width; - s->m_net = m_net; - s->m_shape = m_shape; - s->m_layers = m_layers; - - return s; //assert(false); + return l; } + +PNS_SEGMENT* PNS_SEGMENT::Clone() const +{ + PNS_SEGMENT* s = new PNS_SEGMENT; + + s->m_width = m_width; + s->m_net = m_net; + s->m_shape = m_shape; + s->m_layers = m_layers; + + return s; // assert(false); +} + + #if 1 -bool PNS_LINE::MergeObtuseSegments( ) +bool PNS_LINE::MergeObtuseSegments() { - int step = m_line.PointCount() - 3; - int iter = 0; - - int segs_pre = m_line.SegmentCount(); + int step = m_line.PointCount() - 3; + int iter = 0; - if(step < 0) - return false; + int segs_pre = m_line.SegmentCount(); - SHAPE_LINE_CHAIN current_path (m_line); + if( step < 0 ) + return false; - while(1) - { - iter++; - int n_segs = current_path.SegmentCount(); - int max_step = n_segs - 2; - if(step > max_step) - step = max_step; + SHAPE_LINE_CHAIN current_path( m_line ); - if(step < 2) - { - m_line = current_path; - return current_path.SegmentCount() < segs_pre; - } + while( 1 ) + { + iter++; + int n_segs = current_path.SegmentCount(); + int max_step = n_segs - 2; - bool found_anything = false; - int n = 0; + if( step > max_step ) + step = max_step; - while (n < n_segs - step) - { - const SEG s1 = current_path.CSegment(n); - const SEG s2 = current_path.CSegment(n + step); - SEG s1opt, s2opt; + if( step < 2 ) + { + m_line = current_path; + return current_path.SegmentCount() < segs_pre; + } - if (DIRECTION_45(s1).IsObtuse(DIRECTION_45(s2))) - { - VECTOR2I ip = *s1.IntersectLines(s2); + bool found_anything = false; + int n = 0; - if(s1.Distance(ip) <= 1 || s2.Distance(ip) <= 1) - { - s1opt = SEG(s1.a, ip); - s2opt = SEG(ip, s2.b); - } else { - s1opt = SEG(s1.a, ip); - s2opt = SEG(ip, s2.b); - } - - - if (DIRECTION_45(s1opt).IsObtuse(DIRECTION_45(s2opt))) - { - SHAPE_LINE_CHAIN opt_path; - opt_path.Append(s1opt.a); - opt_path.Append(s1opt.b); - opt_path.Append(s2opt.b); + while( n < n_segs - step ) + { + const SEG s1 = current_path.CSegment( n ); + const SEG s2 = current_path.CSegment( n + step ); + SEG s1opt, s2opt; - PNS_LINE opt_track (*this, opt_path); + if( DIRECTION_45( s1 ).IsObtuse( DIRECTION_45( s2 ) ) ) + { + VECTOR2I ip = *s1.IntersectLines( s2 ); - if(!m_world->CheckColliding(&opt_track, PNS_ITEM::ANY)) - { - current_path.Replace(s1.Index() + 1, s2.Index(), ip); - n_segs = current_path.SegmentCount(); - found_anything = true; - break; - } - } - } - n++; - } + if( s1.Distance( ip ) <= 1 || s2.Distance( ip ) <= 1 ) + { + s1opt = SEG( s1.a, ip ); + s2opt = SEG( ip, s2.b ); + } + else + { + s1opt = SEG( s1.a, ip ); + s2opt = SEG( ip, s2.b ); + } - if(!found_anything) - { - if( step <= 2 ) - { - m_line = current_path; - return m_line.SegmentCount() < segs_pre; - } - step --; - } - } - return m_line.SegmentCount() < segs_pre; -} -bool PNS_LINE::MergeSegments( ) -{ - int step = m_line.PointCount() - 3; - int iter = 0; - - int segs_pre = m_line.SegmentCount(); + if( DIRECTION_45( s1opt ).IsObtuse( DIRECTION_45( s2opt ) ) ) + { + SHAPE_LINE_CHAIN opt_path; + opt_path.Append( s1opt.a ); + opt_path.Append( s1opt.b ); + opt_path.Append( s2opt.b ); - if(step < 0) - return false; + PNS_LINE opt_track( *this, opt_path ); - SHAPE_LINE_CHAIN current_path (m_line); + if( !m_world->CheckColliding( &opt_track, PNS_ITEM::ANY ) ) + { + current_path.Replace( s1.Index() + 1, s2.Index(), ip ); + n_segs = current_path.SegmentCount(); + found_anything = true; + break; + } + } + } - while(1) - { - iter++; - int n_segs = current_path.SegmentCount(); - int max_step = n_segs - 2; - if(step > max_step) - step = max_step; + n++; + } - if(step < 2) - { - m_line = current_path; - return current_path.SegmentCount() < segs_pre; - } + if( !found_anything ) + { + if( step <= 2 ) + { + m_line = current_path; + return m_line.SegmentCount() < segs_pre; + } - bool found_anything = false; - int n = 0; + step--; + } + } - while (n < n_segs - step) - { - const SEG s1 = current_path.CSegment(n); - const SEG s2 = current_path.CSegment(n + step); - SEG s1opt, s2opt; - - if(n > 0) - { - SHAPE_LINE_CHAIN path_straight = DIRECTION_45().BuildInitialTrace(s1.a, s2.a, false); - SHAPE_LINE_CHAIN path_diagonal = DIRECTION_45().BuildInitialTrace(s1.a, s2.a, true); - - - - } - - if (DIRECTION_45(s1) == DIRECTION_45(s2)) - { - if(s1.Collinear(s2)) - { - //printf("Colinear: np %d step %d n1 %d n2 %d\n", n_segs, step, n, n+step); - - SHAPE_LINE_CHAIN opt_path; - opt_path.Append(s1.a); - opt_path.Append(s2.b); - - PNS_LINE tmp (*this, opt_path); - - if(!m_world->CheckColliding(&tmp, PNS_ITEM::ANY)) - { - current_path.Remove(s1.Index() + 1, s2.Index()); - n_segs = current_path.SegmentCount(); - found_anything = true; - break; - } - - } - - - } - else if (DIRECTION_45(s1).IsObtuse(DIRECTION_45(s2))) - { - VECTOR2I ip = *s1.IntersectLines(s2); - - if(s1.Distance(ip) <= 1 || s2.Distance(ip) <= 1) - { - s1opt = SEG(s1.a, ip); - s2opt = SEG(ip, s2.b); - } else { - s1opt = SEG(s1.a, ip); - s2opt = SEG(ip, s2.b); - } - - - if (DIRECTION_45(s1opt).IsObtuse(DIRECTION_45(s2opt))) - { - SHAPE_LINE_CHAIN opt_path; - opt_path.Append(s1opt.a); - opt_path.Append(s1opt.b); - opt_path.Append(s2opt.b); - - PNS_LINE opt_track (*this, opt_path); - - if(!m_world->CheckColliding(&opt_track, PNS_ITEM::ANY)) - { - current_path.Replace(s1.Index() + 1, s2.Index(), ip); - n_segs = current_path.SegmentCount(); - found_anything = true; - break; - } - } - - } - n++; - } - - if(!found_anything) - { - if( step <= 2 ) - { - m_line = current_path; - return m_line.SegmentCount() < segs_pre; - } - step --; - } - } - return m_line.SegmentCount() < segs_pre; + return m_line.SegmentCount() < segs_pre; } +bool PNS_LINE::MergeSegments() +{ + int step = m_line.PointCount() - 3; + int iter = 0; + + int segs_pre = m_line.SegmentCount(); + + if( step < 0 ) + return false; + + SHAPE_LINE_CHAIN current_path( m_line ); + + while( 1 ) + { + iter++; + int n_segs = current_path.SegmentCount(); + int max_step = n_segs - 2; + + if( step > max_step ) + step = max_step; + + if( step < 2 ) + { + m_line = current_path; + return current_path.SegmentCount() < segs_pre; + } + + bool found_anything = false; + int n = 0; + + while( n < n_segs - step ) + { + const SEG s1 = current_path.CSegment( n ); + const SEG s2 = current_path.CSegment( n + step ); + SEG s1opt, s2opt; + + if( n > 0 ) + { + SHAPE_LINE_CHAIN path_straight = DIRECTION_45().BuildInitialTrace( s1.a, + s2.a, + false ); + SHAPE_LINE_CHAIN path_diagonal = DIRECTION_45().BuildInitialTrace( s1.a, + s2.a, + true ); + } + + if( DIRECTION_45( s1 ) == DIRECTION_45( s2 ) ) + { + if( s1.Collinear( s2 ) ) + { + // printf("Colinear: np %d step %d n1 %d n2 %d\n", n_segs, step, n, n+step); + + SHAPE_LINE_CHAIN opt_path; + opt_path.Append( s1.a ); + opt_path.Append( s2.b ); + + PNS_LINE tmp( *this, opt_path ); + + if( !m_world->CheckColliding( &tmp, PNS_ITEM::ANY ) ) + { + current_path.Remove( s1.Index() + 1, s2.Index() ); + n_segs = current_path.SegmentCount(); + found_anything = true; + break; + } + } + } + else if( DIRECTION_45( s1 ).IsObtuse( DIRECTION_45( s2 ) ) ) + { + VECTOR2I ip = *s1.IntersectLines( s2 ); + + if( s1.Distance( ip ) <= 1 || s2.Distance( ip ) <= 1 ) + { + s1opt = SEG( s1.a, ip ); + s2opt = SEG( ip, s2.b ); + } + else + { + s1opt = SEG( s1.a, ip ); + s2opt = SEG( ip, s2.b ); + } + + + if( DIRECTION_45( s1opt ).IsObtuse( DIRECTION_45( s2opt ) ) ) + { + SHAPE_LINE_CHAIN opt_path; + opt_path.Append( s1opt.a ); + opt_path.Append( s1opt.b ); + opt_path.Append( s2opt.b ); + + PNS_LINE opt_track( *this, opt_path ); + + if( !m_world->CheckColliding( &opt_track, PNS_ITEM::ANY ) ) + { + current_path.Replace( s1.Index() + 1, s2.Index(), ip ); + n_segs = current_path.SegmentCount(); + found_anything = true; + break; + } + } + } + + n++; + } + + if( !found_anything ) + { + if( step <= 2 ) + { + m_line = current_path; + return m_line.SegmentCount() < segs_pre; + } + + step--; + } + } + + return m_line.SegmentCount() < segs_pre; +} #endif -int PNS_LINE::CountCorners(int aAngles) + +int PNS_LINE::CountCorners( int aAngles ) { - int count = 0; - for(int i = 0; i < m_line.SegmentCount() - 1; i ++) - { - const SEG seg1 = m_line.CSegment(i); - const SEG seg2 = m_line.CSegment(i + 1); + int count = 0; - const DIRECTION_45 dir1(seg1); - const DIRECTION_45 dir2(seg2); + for( int i = 0; i < m_line.SegmentCount() - 1; i++ ) + { + const SEG seg1 = m_line.CSegment( i ); + const SEG seg2 = m_line.CSegment( i + 1 ); - DIRECTION_45::AngleType a = dir1.Angle(dir2); - if(a & aAngles) - count++; - } - return count; + const DIRECTION_45 dir1( seg1 ); + const DIRECTION_45 dir2( seg2 ); + + DIRECTION_45::AngleType a = dir1.Angle( dir2 ); + + if( a & aAngles ) + count++; + } + + return count; } -//#define DUMP_TEST_CASES + +// #define DUMP_TEST_CASES // fixme: damn f*****g inefficient and incredibly crappily written -void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, - SHAPE_LINE_CHAIN& aPrePath, - SHAPE_LINE_CHAIN& aWalkaroundPath, - SHAPE_LINE_CHAIN& aPostPath, - bool aCw ) const +void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, + SHAPE_LINE_CHAIN& aPrePath, + SHAPE_LINE_CHAIN& aWalkaroundPath, + SHAPE_LINE_CHAIN& aPostPath, + bool aCw ) const { + typedef SHAPE_LINE_CHAIN::Intersection Intersection; - typedef SHAPE_LINE_CHAIN::Intersection Intersection; + SHAPE_LINE_CHAIN l_orig( m_line ); + SHAPE_LINE_CHAIN l_hull; + vector outside, on_edge, inside; + SHAPE_LINE_CHAIN path; - SHAPE_LINE_CHAIN l_orig(m_line); - SHAPE_LINE_CHAIN l_hull; - vector outside, on_edge, inside; - SHAPE_LINE_CHAIN path; - - vector isects; + vector isects; - // don't calculate walkaround for empty lines - if(m_line.PointCount() < 2) - return; + // don't calculate walkaround for empty lines + if( m_line.PointCount() < 2 ) + return; #ifdef DUMP_TEST_CASES - printf("%s\n", m_line.Format().c_str()); - printf("%s\n", aObstacle.Format().c_str()); + printf( "%s\n", m_line.Format().c_str() ); + printf( "%s\n", aObstacle.Format().c_str() ); #endif - aObstacle.Intersect(m_line, isects); - //printf("NewWalk intersectiosn :%d\n" ,isects.size()); - if( !aCw ) - l_hull = aObstacle.Reverse(); - else - l_hull = aObstacle; + aObstacle.Intersect( m_line, isects ); - BOOST_FOREACH( Intersection isect, isects ) - { - l_orig.Split(isect.p); - l_hull.Split(isect.p); - } + // printf("NewWalk intersectiosn :%d\n" ,isects.size()); + if( !aCw ) + l_hull = aObstacle.Reverse(); + else + l_hull = aObstacle; + + BOOST_FOREACH( Intersection isect, isects ) { + l_orig.Split( isect.p ); + l_hull.Split( isect.p ); + } #ifdef DUMP_TEST_CASES - printf("%s\n", m_line.Format().c_str()); - printf("%s\n", aObstacle.Format().c_str()); - printf("%s\n", l_orig.Format().c_str()); - printf("%s\n", l_hull.Format().c_str()); + printf( "%s\n", m_line.Format().c_str() ); + printf( "%s\n", aObstacle.Format().c_str() ); + printf( "%s\n", l_orig.Format().c_str() ); + printf( "%s\n", l_hull.Format().c_str() ); #endif - //printf("Pts: line %d hull %d\n", l_orig.PointCount(), l_hull.PointCount()); + // printf("Pts: line %d hull %d\n", l_orig.PointCount(), l_hull.PointCount()); - int first_post = -1; - int last_pre = -1; + int first_post = -1; + int last_pre = -1; - for (int i = 0; i < l_orig.PointCount(); i++) - { - int ei = l_hull.Find(l_orig.CPoint(i)) ; - bool edge = ei >= 0; - bool in = l_hull.PointInside( l_orig.CPoint(i)) && !edge; - bool out = !( in || edge); - - outside.push_back( out ); - on_edge.push_back( edge ); - inside.push_back( in ); - } - + for( int i = 0; i < l_orig.PointCount(); i++ ) + { + int ei = l_hull.Find( l_orig.CPoint( i ) ); + bool edge = ei >= 0; + bool in = l_hull.PointInside( l_orig.CPoint( i ) ) && !edge; + bool out = !( in || edge); - for(int i = l_orig.PointCount() - 1; i >= 1; i --) - if(inside[i] && outside[i-1]) - { - SHAPE_LINE_CHAIN::Intersections ips; - l_hull.Intersect( SEG( l_orig.CPoint(i), l_orig.CPoint(i - 1) ), ips ); - l_orig.Remove(i, -1); - l_orig.Append(ips[0].p); - break; - } - else if (inside[i] && on_edge[i-1]) - { - l_orig.Remove(i, -1); - //n = i; - } else if(!inside[i]) - break; + outside.push_back( out ); + on_edge.push_back( edge ); + inside.push_back( in ); + } - if(!outside.size() && on_edge.size() < 2) - return; + for( int i = l_orig.PointCount() - 1; i >= 1; i-- ) + if( inside[i] && outside[i - 1] ) + { + SHAPE_LINE_CHAIN::Intersections ips; + l_hull.Intersect( SEG( l_orig.CPoint( i ), l_orig.CPoint( i - 1 ) ), ips ); + l_orig.Remove( i, -1 ); + l_orig.Append( ips[0].p ); + break; + } + else if( inside[i] && on_edge[i - 1] ) + { + l_orig.Remove( i, -1 ); + // n = i; + } + else if( !inside[i] ) + break; - for (int i = 0; i < l_orig.PointCount(); i++) - { - const VECTOR2I p = l_orig.Point(i); - - if( outside[i] || (on_edge[i] && i == (l_orig.PointCount() - 1))) - { - if(last_pre < 0) - aPrePath.Append(p); - path.Append(p); - } - else if ( on_edge[i] ) - { - int li = -1; - if(last_pre < 0) - { - aPrePath.Append(p); - last_pre = path.PointCount(); - } - if( i == l_orig.PointCount() - 1 || outside[i+1]) - { - path.Append(p); - } - else - { - int vi2 = l_hull.Find( l_orig.CPoint(i) ); - - path.Append(l_hull.CPoint(vi2)); - for(int j = (vi2 + 1) % l_hull.PointCount(); j != vi2; j = (j + 1) % l_hull.PointCount()) - { - path.Append(l_hull.CPoint(j)); - li = l_orig.Find(l_hull.CPoint(j)); - if(li >= 0 && (li == (l_orig.PointCount() - 1) || outside[li+1])) - break; - } + if( !outside.size() && on_edge.size() < 2 ) + return; - if(li >= 0) { - if(i >= li) - break; - else { - i = li; - } - } - } + for( int i = 0; i < l_orig.PointCount(); i++ ) + { + const VECTOR2I p = l_orig.Point( i ); - first_post = path.PointCount() - 1; - } - } + if( outside[i] || ( on_edge[i] && i == ( l_orig.PointCount() - 1 ) ) ) + { + if( last_pre < 0 ) + aPrePath.Append( p ); - if(last_pre < 0 && first_post < 0) - return; + path.Append( p ); + } + else if( on_edge[i] ) + { + int li = -1; - aWalkaroundPath = path.Slice( last_pre, first_post ); - if(first_post >= 0) - aPostPath = path.Slice( first_post, -1 ); + if( last_pre < 0 ) + { + aPrePath.Append( p ); + last_pre = path.PointCount(); + } -} + if( i == l_orig.PointCount() - 1 || outside[i + 1] ) + { + path.Append( p ); + } + else + { + int vi2 = l_hull.Find( l_orig.CPoint( i ) ); -bool PNS_LINE::onEdge(const SHAPE_LINE_CHAIN &obstacle, VECTOR2I p, int& ei, bool& is_vertex) const -{ - int vtx = obstacle.Find(p); + path.Append( l_hull.CPoint( vi2 ) ); - if(vtx >= 0) - { - ei = vtx; - is_vertex =true; - return true; - } - - for(int s = 0; s< obstacle.SegmentCount(); s++) - { - if(obstacle.CSegment(s).Contains(p)) - { - ei = s; - is_vertex = false; - return true; - } - } + for( int j = (vi2 + 1) % l_hull.PointCount(); + j != vi2; + j = (j + 1) % l_hull.PointCount() ) + { + path.Append( l_hull.CPoint( j ) ); + li = l_orig.Find( l_hull.CPoint( j ) ); - return false; -} + if( li >= 0 && ( li == (l_orig.PointCount() - 1 ) || + outside[li + 1]) ) + break; + } -bool PNS_LINE::walkScan(const SHAPE_LINE_CHAIN &line, const SHAPE_LINE_CHAIN &obstacle, bool reverse, VECTOR2I &ip, int& index_o, int& index_l, bool& is_vertex) const -{ - int sc = line.SegmentCount(); - for(int i = 0; i < line.SegmentCount(); i++) - { + if( li >= 0 ) + { + if( i >= li ) + break; + else + i = li; + } + } - printf("check-seg rev %d %d/%d %d\n",reverse, i, sc, sc - 1 - i); - SEG tmp = line.CSegment(reverse ? sc - 1 - i : i); - SEG s (tmp.a, tmp.b); - if(reverse) - { - s.a = tmp.b; - s.b = tmp.a; - } + first_post = path.PointCount() - 1; + } + } - if(onEdge(obstacle, s.a, index_o, is_vertex)) - { - index_l = (reverse ? sc-1-i : i); - ip = s.a; - printf("vertex %d on-%s %d\n", index_l, is_vertex?"vertex":"edge",index_o); - return true; - } + if( last_pre < 0 && first_post < 0 ) + return; - if(onEdge(obstacle, s.b, index_o, is_vertex)) - { - index_l = (reverse? sc-1-i-1 : i + 1); - ip = s.b; - printf("vertex %d on-%s %d\n", index_l, is_vertex?"vertex":"edge",index_o); - return true; - } - - SHAPE_LINE_CHAIN::Intersections ips; - int n_is = obstacle.Intersect ( s, ips ); - - if (n_is > 0) - { - index_o = ips[0].our.Index(); - index_l = reverse ?sc-1-i:i; - printf("segment-%d intersects edge-%d\n", index_l, index_o); - ip = ips[0].p; - return true; - } - } - return false; -} - -bool PNS_LINE::Walkaround(SHAPE_LINE_CHAIN obstacle, SHAPE_LINE_CHAIN &pre, SHAPE_LINE_CHAIN &walk, SHAPE_LINE_CHAIN &post, bool cw) const -{ - const SHAPE_LINE_CHAIN &line = GetCLine(); - VECTOR2I ip_start; - int index_o_start, index_l_start; - VECTOR2I ip_end; - int index_o_end, index_l_end; - - bool is_vertex_start, is_vertex_end; - - if(line.SegmentCount() < 1) - return false; - - if(obstacle.PointInside(line.CPoint(0)) || obstacle.PointInside(line.CPoint(-1))) - return false; - -// printf("forward:\n"); - bool found = walkScan(line, obstacle, false, ip_start, index_o_start, index_l_start, is_vertex_start); - //printf("reverse:\n"); - found |= walkScan(line, obstacle, true, ip_end, index_o_end, index_l_end, is_vertex_end); - - if(!found || ip_start == ip_end) - { - pre = line; - return true; - } - - - pre = line.Slice ( 0, index_l_start ); - pre.Append (ip_start); - walk.Clear(); - walk.Append(ip_start); - - if(cw) - { - int is = (index_o_start + 1) % obstacle.PointCount(); - int ie = (is_vertex_end ? index_o_end : index_o_end + 1) % obstacle.PointCount(); - - while(1) - { - printf("is %d\n", is); - walk.Append(obstacle.CPoint(is)); - - if(is == ie) - break; - - is ++; - if (is == obstacle.PointCount() ) - is = 0; - } - } else { - int is = index_o_start; - int ie = (is_vertex_end ? index_o_end : index_o_end) % obstacle.PointCount(); - - while(1) - { - printf("is %d\n", is); - walk.Append(obstacle.CPoint(is)); - if(is == ie) - break; - - is --; - if ( is < 0 ) - is = obstacle.PointCount() - 1; - } - - - } - - walk.Append(ip_end); - - post.Clear(); - post.Append(ip_end); - post.Append(line.Slice (is_vertex_end ? index_l_end : index_l_end + 1 , -1)); - - //for(int i = (index_o_start + 1) % obstacle.PointCount(); - // i != (index_o_end + 1) % obstacle.PointCount(); i=(i+1) % obstacle.PointCount()) - //{ - //printf("append %d\n", i); - //walk.Append(obstacle.CPoint(i)); - //} - - return true; + aWalkaroundPath = path.Slice( last_pre, first_post ); + if( first_post >= 0 ) + aPostPath = path.Slice( first_post, -1 ); } - -void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, - SHAPE_LINE_CHAIN& aPath, - bool aCw ) const +bool PNS_LINE::onEdge( const SHAPE_LINE_CHAIN& obstacle, VECTOR2I p, int& ei, + bool& is_vertex ) const { - SHAPE_LINE_CHAIN walk, post; - NewWalkaround(aObstacle, aPath, walk, post, aCw); - aPath.Append(walk); - aPath.Append(post); - aPath.Simplify(); -} + int vtx = obstacle.Find( p ); -void PNS_LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, - SHAPE_LINE_CHAIN& aPath, - bool aCw ) const -{ - SHAPE_LINE_CHAIN walk, post; - Walkaround(aObstacle, aPath, walk, post, aCw); - aPath.Append(walk); - aPath.Append(post); - aPath.Simplify(); + if( vtx >= 0 ) + { + ei = vtx; + is_vertex = true; + return true; + } + + for( int s = 0; s < obstacle.SegmentCount(); s++ ) + { + if( obstacle.CSegment( s ).Contains( p ) ) + { + ei = s; + is_vertex = false; + return true; + } + } + + return false; } -const SHAPE_LINE_CHAIN PNS_SEGMENT::Hull(int aClearance, int aWalkaroundThickness) const +bool PNS_LINE::walkScan( const SHAPE_LINE_CHAIN& line, + const SHAPE_LINE_CHAIN& obstacle, + bool reverse, + VECTOR2I& ip, + int& index_o, + int& index_l, + bool& is_vertex ) const { - int d = aClearance + 10; - int x = (int) (2.0 / (1.0 + M_SQRT2) * d) + 2; + int sc = line.SegmentCount(); - const VECTOR2I a = m_shape.CPoint(0); - const VECTOR2I b = m_shape.CPoint(1); - - VECTOR2I dir = b - a; + for( int i = 0; i < line.SegmentCount(); i++ ) + { + printf( "check-seg rev %d %d/%d %d\n", reverse, i, sc, sc - 1 - i ); + SEG tmp = line.CSegment( reverse ? sc - 1 - i : i ); + SEG s( tmp.a, tmp.b ); - VECTOR2I p0 = dir.Perpendicular().Resize(d); + if( reverse ) + { + s.a = tmp.b; + s.b = tmp.a; + } - - VECTOR2I ds = dir.Perpendicular().Resize(x / 2); - VECTOR2I pd = dir.Resize(x / 2); - VECTOR2I dp = dir.Resize(d); + if( onEdge( obstacle, s.a, index_o, is_vertex ) ) + { + index_l = (reverse ? sc - 1 - i : i); + ip = s.a; + printf( "vertex %d on-%s %d\n", index_l, + is_vertex ? "vertex" : "edge", index_o ); + return true; + } + + if( onEdge( obstacle, s.b, index_o, is_vertex ) ) + { + index_l = (reverse ? sc - 1 - i - 1 : i + 1); + ip = s.b; + printf( "vertex %d on-%s %d\n", index_l, + is_vertex ? "vertex" : "edge", index_o ); + return true; + } + + SHAPE_LINE_CHAIN::Intersections ips; + int n_is = obstacle.Intersect( s, ips ); + + if( n_is > 0 ) + { + index_o = ips[0].our.Index(); + index_l = reverse ? sc - 1 - i : i; + printf( "segment-%d intersects edge-%d\n", index_l, index_o ); + ip = ips[0].p; + return true; + } + } + + return false; +} - SHAPE_LINE_CHAIN s; - s.SetClosed( true ); +bool PNS_LINE::Walkaround( SHAPE_LINE_CHAIN obstacle, + SHAPE_LINE_CHAIN& pre, + SHAPE_LINE_CHAIN& walk, + SHAPE_LINE_CHAIN& post, + bool cw ) const +{ + const SHAPE_LINE_CHAIN& line = GetCLine(); + VECTOR2I ip_start; + int index_o_start, index_l_start; + VECTOR2I ip_end; + int index_o_end, index_l_end; - s.Append(b + p0 + pd); - s.Append(b + dp + ds); - s.Append(b + dp - ds); - s.Append(b - p0 + pd); - s.Append(a - p0 - pd); - s.Append(a - dp - ds); - s.Append(a - dp + ds); - s.Append(a + p0 - pd); - - // make sure the hull outline is always clockwise - if(s.CSegment(0).Side(a) < 0) - return s.Reverse(); - else - return s; + bool is_vertex_start, is_vertex_end; + if( line.SegmentCount() < 1 ) + return false; + + if( obstacle.PointInside( line.CPoint( 0 ) ) || + obstacle.PointInside( line.CPoint( -1 ) ) ) + return false; + +// printf("forward:\n"); + bool found = walkScan( line, + obstacle, + false, + ip_start, + index_o_start, + index_l_start, + is_vertex_start ); + // printf("reverse:\n"); + found |= walkScan( line, obstacle, true, ip_end, index_o_end, index_l_end, is_vertex_end ); + + if( !found || ip_start == ip_end ) + { + pre = line; + return true; + } + + pre = line.Slice( 0, index_l_start ); + pre.Append( ip_start ); + walk.Clear(); + walk.Append( ip_start ); + + if( cw ) + { + int is = ( index_o_start + 1 ) % obstacle.PointCount(); + int ie = ( is_vertex_end ? index_o_end : index_o_end + 1 ) % obstacle.PointCount(); + + while( 1 ) + { + printf( "is %d\n", is ); + walk.Append( obstacle.CPoint( is ) ); + + if( is == ie ) + break; + + is++; + + if( is == obstacle.PointCount() ) + is = 0; + } + } + else + { + int is = index_o_start; + int ie = ( is_vertex_end ? index_o_end : index_o_end ) % obstacle.PointCount(); + + while( 1 ) + { + printf( "is %d\n", is ); + walk.Append( obstacle.CPoint( is ) ); + + if( is == ie ) + break; + + is--; + + if( is < 0 ) + is = obstacle.PointCount() - 1; + } + } + + walk.Append( ip_end ); + + post.Clear(); + post.Append( ip_end ); + post.Append( line.Slice( is_vertex_end ? index_l_end : index_l_end + 1, -1 ) ); + + // for(int i = (index_o_start + 1) % obstacle.PointCount(); + // i != (index_o_end + 1) % obstacle.PointCount(); i=(i+1) % obstacle.PointCount()) + // { + // printf("append %d\n", i); + // walk.Append(obstacle.CPoint(i)); + // } + + return true; +} + + +void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, + SHAPE_LINE_CHAIN& aPath, + bool aCw ) const +{ + SHAPE_LINE_CHAIN walk, post; + + NewWalkaround( aObstacle, aPath, walk, post, aCw ); + aPath.Append( walk ); + aPath.Append( post ); + aPath.Simplify(); +} + + +void PNS_LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, + SHAPE_LINE_CHAIN& aPath, + bool aCw ) const +{ + SHAPE_LINE_CHAIN walk, post; + + Walkaround( aObstacle, aPath, walk, post, aCw ); + aPath.Append( walk ); + aPath.Append( post ); + aPath.Simplify(); +} + + +const SHAPE_LINE_CHAIN PNS_SEGMENT::Hull( int aClearance, int aWalkaroundThickness ) const +{ + int d = aClearance + 10; + int x = (int)( 2.0 / ( 1.0 + M_SQRT2 ) * d ) + 2; + + const VECTOR2I a = m_shape.CPoint( 0 ); + const VECTOR2I b = m_shape.CPoint( 1 ); + + VECTOR2I dir = b - a; + + VECTOR2I p0 = dir.Perpendicular().Resize( d ); + + VECTOR2I ds = dir.Perpendicular().Resize( x / 2 ); + VECTOR2I pd = dir.Resize( x / 2 ); + VECTOR2I dp = dir.Resize( d ); + + SHAPE_LINE_CHAIN s; + + s.SetClosed( true ); + + s.Append( b + p0 + pd ); + s.Append( b + dp + ds ); + s.Append( b + dp - ds ); + s.Append( b - p0 + pd ); + s.Append( a - p0 - pd ); + s.Append( a - dp - ds ); + s.Append( a - dp + ds ); + s.Append( a + p0 - pd ); + + // make sure the hull outline is always clockwise + if( s.CSegment( 0 ).Side( a ) < 0 ) + return s.Reverse(); + else + return s; } bool PNS_LINE::Is45Degree() { - for(int i = 0; i < m_line.SegmentCount(); i++) - { - const SEG &s = m_line.CSegment(i); + for( int i = 0; i < m_line.SegmentCount(); i++ ) + { + const SEG& s = m_line.CSegment( i ); - double angle = 180.0 / M_PI * atan2((double)s.b.y - (double)s.a.y, (double)s.b.x - (double)s.a.x); - - if(angle < 0) - angle+=360.0; + double angle = 180.0 / M_PI * + atan2( (double) s.b.y - (double) s.a.y, + (double) s.b.x - (double) s.a.x ); - double angle_a = fabs(fmod(angle, 45.0)); - if(angle_a > 1.0 && angle_a < 44.0) - return false; - } - return true; + if( angle < 0 ) + angle += 360.0; + + double angle_a = fabs( fmod( angle, 45.0 ) ); + + if( angle_a > 1.0 && angle_a < 44.0 ) + return false; + } + + return true; } -const PNS_LINE PNS_LINE::ClipToNearestObstacle( PNS_NODE *aNode ) const + +const PNS_LINE PNS_LINE::ClipToNearestObstacle( PNS_NODE* aNode ) const { - PNS_LINE l (*this); + PNS_LINE l( *this ); - PNS_NODE::OptObstacle obs = aNode->NearestObstacle ( &l ); + PNS_NODE::OptObstacle obs = aNode->NearestObstacle( &l ); - if(obs) - { - l.RemoveVia(); - int p = l.GetLine().Split(obs -> ip_first); - l.GetLine().Remove(p + 1, -1); - } + if( obs ) + { + l.RemoveVia(); + int p = l.GetLine().Split( obs->ip_first ); + l.GetLine().Remove( p + 1, -1 ); + } - return l; + return l; } + void PNS_LINE::ShowLinks() { - if(!m_segmentRefs) - { - printf("line %p: no links\n", this); - return; - } - printf("line %p: %d linked segs\n", this, m_segmentRefs->size()); - for (int i= 0; i<(int)m_segmentRefs->size(); i++) printf("seg %d: %p\n", i, (*m_segmentRefs)[i]) ; + if( !m_segmentRefs ) + { + printf( "line %p: no links\n", this ); + return; + } + + printf( "line %p: %d linked segs\n", this, m_segmentRefs->size() ); + + for( int i = 0; i < (int) m_segmentRefs->size(); i++ ) + printf( "seg %d: %p\n", i, (*m_segmentRefs)[i] ); } + diff --git a/pcbnew/router/pns_line.h b/pcbnew/router/pns_line.h index cd47005606..1fb341572c 100644 --- a/pcbnew/router/pns_line.h +++ b/pcbnew/router/pns_line.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -38,214 +38,227 @@ class PNS_VIA; /** * Class PNS_LINE * - * Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads, - * junctions between multiple traces or two traces different widths and combinations of these). - * PNS_LINEs are NOT stored in the model (PNS_NODE) - instead, they are assembled on-the-fly, based on - * a via/pad/segment that belongs/begins them. + * Represents a track on a PCB, connecting two non-trivial joints (that is, + * vias, pads, junctions between multiple traces or two traces different widths + * and combinations of these). PNS_LINEs are NOT stored in the model (PNS_NODE). + * Instead, they are assembled on-the-fly, based on a via/pad/segment that + * belongs/begins them. * - * PNS_LINEs can be either loose (consisting of segments that do not belong to any PNS_NODE) or owned (with segments - * taken from a PNS_NODE) - these are returned by PNS_NODE::AssembleLine and friends. - * - * A PNS_LINE may have a PNS_VIA attached at its and - this is used by via dragging/force propagation stuff. + * PNS_LINEs can be either loose (consisting of segments that do not belong to + * any PNS_NODE) or owned (with segments taken from a PNS_NODE) - these are + * returned by PNS_NODE::AssembleLine and friends. + * + * A PNS_LINE may have a PNS_VIA attached at its and - this is used by via + * dragging/force propagation stuff. */ -class PNS_LINE : public PNS_ITEM +class PNS_LINE : public PNS_ITEM { public: - typedef std::vector LinkedSegments; + typedef std::vector LinkedSegments; - PNS_LINE (): - PNS_ITEM(LINE) - { - m_segmentRefs = NULL; - m_hasVia = false; - m_affectedRangeStart = -1; - }; + PNS_LINE() : + PNS_ITEM( LINE ) + { + m_segmentRefs = NULL; + m_hasVia = false; + m_affectedRangeStart = -1; + }; - PNS_LINE (int aLayer, int aWidth, const SHAPE_LINE_CHAIN& aLine) : - PNS_ITEM(LINE) - { - m_line = aLine; - m_width = aWidth; - m_segmentRefs = NULL; - m_hasVia = false; - m_affectedRangeStart = -1; - SetLayer(aLayer); + PNS_LINE( int aLayer, int aWidth, const SHAPE_LINE_CHAIN& aLine ) : + PNS_ITEM( LINE ) + { + m_line = aLine; + m_width = aWidth; + m_segmentRefs = NULL; + m_hasVia = false; + m_affectedRangeStart = -1; + SetLayer( aLayer ); + } - } + PNS_LINE( const PNS_LINE& aOther ) : + PNS_ITEM( aOther ), + m_line( aOther.m_line ), + m_width( aOther.m_width ) + { + m_net = aOther.m_net; + m_movable = aOther.m_movable; + m_world = aOther.m_world; + m_layers = aOther.m_layers; + m_segmentRefs = NULL; + m_via = aOther.m_via; + m_hasVia = aOther.m_hasVia; + m_affectedRangeStart = -1; + } - PNS_LINE(const PNS_LINE& aOther) : - PNS_ITEM(aOther), - m_line(aOther.m_line), - m_width(aOther.m_width) - { - m_net = aOther.m_net; - m_movable = aOther.m_movable; - m_world = aOther.m_world; - m_layers = aOther.m_layers; - m_segmentRefs = NULL; - m_via = aOther.m_via; - m_hasVia = aOther.m_hasVia; - m_affectedRangeStart = -1; - } + /** + * Constructor + * copies properties (net, layers from a base line), and replaces the shape + * by aLine + **/ + PNS_LINE( const PNS_LINE& aBase, const SHAPE_LINE_CHAIN& aLine ) : + PNS_ITEM( aBase ), + m_line( aLine ), + m_width( aBase.m_width ) + { + m_net = aBase.m_net; + m_layers = aBase.m_layers; + m_segmentRefs = NULL; + m_hasVia = false; + m_affectedRangeStart = -1; + } - /** - * Constructor - * copies properties (net, layers from a base line), and replaces the shape - * by aLine - **/ - PNS_LINE(const PNS_LINE& aBase, const SHAPE_LINE_CHAIN& aLine) : - PNS_ITEM(aBase), - m_line(aLine), - m_width(aBase.m_width) - { - m_net = aBase.m_net; - m_layers = aBase.m_layers; - m_segmentRefs = NULL; - m_hasVia = false; - m_affectedRangeStart = -1; - } + ~PNS_LINE() + { + if( m_segmentRefs ) + delete m_segmentRefs; + }; - ~PNS_LINE () - { - if(m_segmentRefs) - delete m_segmentRefs; - }; - - virtual PNS_LINE *Clone() const ; - - ///> clones the line without cloning the shape (just the properties - net, width, layers, etc.) - PNS_LINE *CloneProperties() const ; - - int GetLayer() const { return GetLayers().Start(); } + virtual PNS_LINE* Clone() const; - ///> Geometry accessors - void SetShape(const SHAPE_LINE_CHAIN& aLine) { m_line = aLine; } - const SHAPE* GetShape() const { return &m_line; } - SHAPE_LINE_CHAIN& GetLine() { return m_line; } - const SHAPE_LINE_CHAIN& GetCLine() const { return m_line; } + ///> clones the line without cloning the shape + ///> (just the properties - net, width, layers, etc.) + PNS_LINE* CloneProperties() const; - ///> Width accessors - void SetWidth( int aWidth ) { m_width = aWidth; } - int GetWidth () const { return m_width; } + int GetLayer() const { return GetLayers().Start(); } - ///> Links a segment from a PNS_NODE to this line, making it owned by the node - void LinkSegment(PNS_SEGMENT *aSeg) - { - if(!m_segmentRefs) - m_segmentRefs = new std::vector (); - m_segmentRefs->push_back(aSeg); - } + ///> Geometry accessors + void SetShape( const SHAPE_LINE_CHAIN& aLine ) { m_line = aLine; } + const SHAPE* GetShape() const { return &m_line; } + SHAPE_LINE_CHAIN& GetLine() { return m_line; } + const SHAPE_LINE_CHAIN& GetCLine() const { return m_line; } - ///> Returns a list of segments from the owning node that constitute this line (or NULL if - ///> the line is loose) - LinkedSegments* GetLinkedSegments() - { - return m_segmentRefs; - } + ///> Width accessors + void SetWidth( int aWidth ) { m_width = aWidth; } + int GetWidth() const { return m_width; } - bool ContainsSegment (PNS_SEGMENT *aSeg) const - { - if (!m_segmentRefs) - return false; + ///> Links a segment from a PNS_NODE to this line, making it owned by the node + void LinkSegment( PNS_SEGMENT* aSeg ) + { + if( !m_segmentRefs ) + m_segmentRefs = new std::vector (); - return std::find( m_segmentRefs->begin(), m_segmentRefs->end(), aSeg) != m_segmentRefs->end(); - } + m_segmentRefs->push_back( aSeg ); + } - ///> Returns this line, but clipped to the nearest obstacle along, to avoid collision. - const PNS_LINE ClipToNearestObstacle( PNS_NODE *aNode ) const; - - ///> DEPRECATED optimization functions (moved to PNS_OPTIMIZER) - bool MergeObtuseSegments(); - bool MergeSegments(); - - ///> Returns the number of corners of angles specified by mask aAngles. - int CountCorners(int aAngles); + ///> Returns a list of segments from the owning node that constitute this + ///> line (or NULL if the line is loose) + LinkedSegments* GetLinkedSegments() + { + return m_segmentRefs; + } + + bool ContainsSegment( PNS_SEGMENT* aSeg ) const + { + if( !m_segmentRefs ) + return false; + + return std::find( m_segmentRefs->begin(), m_segmentRefs->end(), + aSeg ) != m_segmentRefs->end(); + } + + ///> Returns this line, but clipped to the nearest obstacle + ///> along, to avoid collision. + const PNS_LINE ClipToNearestObstacle( PNS_NODE* aNode ) const; + + ///> DEPRECATED optimization functions (moved to PNS_OPTIMIZER) + bool MergeObtuseSegments(); + bool MergeSegments(); + + ///> Returns the number of corners of angles specified by mask aAngles. + int CountCorners( int aAngles ); + + ///> Calculates a line thightly wrapping a convex hull + ///> of an obstacle object (aObstacle). + ///> aPrePath = path from origin to the obstacle + ///> aWalkaroundPath = path around the obstacle + ///> aPostPath = past from obstacle till the end + ///> aCW = whether to walkaround in clockwise or counter-clockwise direction. + void NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, + SHAPE_LINE_CHAIN& aPrePath, + SHAPE_LINE_CHAIN& aWalkaroundPath, + SHAPE_LINE_CHAIN& aPostPath, + bool aCw ) const; + + void NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, + SHAPE_LINE_CHAIN& aPath, + bool aCw ) const; - ///> Calculates a line thightly wrapping a convex hull of an obstacle object (aObstacle). - ///> aPrePath = path from origin to the obstacle - ///> aWalkaroundPath = path around the obstacle - ///> aPostPath = past from obstacle till the end - ///> aCW = whether to walkaround in clockwise or counter-clockwise direction. - void NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, - SHAPE_LINE_CHAIN& aPrePath, - SHAPE_LINE_CHAIN& aWalkaroundPath, - SHAPE_LINE_CHAIN& aPostPath, - bool aCw ) const; + bool Walkaround( SHAPE_LINE_CHAIN obstacle, + SHAPE_LINE_CHAIN& pre, + SHAPE_LINE_CHAIN& walk, + SHAPE_LINE_CHAIN& post, + bool cw ) const; - void NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, - SHAPE_LINE_CHAIN& aPath, - bool aCw ) const; - - - bool Walkaround(SHAPE_LINE_CHAIN obstacle, SHAPE_LINE_CHAIN &pre, SHAPE_LINE_CHAIN &walk, SHAPE_LINE_CHAIN &post, bool cw) const; + void Walkaround( const SHAPE_LINE_CHAIN& aObstacle, + SHAPE_LINE_CHAIN& aPath, + bool aCw ) const; - void Walkaround( const SHAPE_LINE_CHAIN& aObstacle, - SHAPE_LINE_CHAIN& aPath, - bool aCw ) const; - + bool Is45Degree(); - bool Is45Degree(); + ///> Prints out all linked segments + void ShowLinks(); - ///> Prints out all linked segments - void ShowLinks(); + bool EndsWithVia() const { return m_hasVia; } - bool EndsWithVia() const { return m_hasVia; } - - void AppendVia ( const PNS_VIA &aVia ) { - m_hasVia = true; - m_via = aVia; - m_via.SetNet ( m_net ) ; - } + void AppendVia( const PNS_VIA& aVia ) + { + m_hasVia = true; + m_via = aVia; + m_via.SetNet( m_net ); + } - void RemoveVia() { m_hasVia = false; } - const PNS_VIA& GetVia() const { return m_via; } + void RemoveVia() { m_hasVia = false; } + const PNS_VIA& GetVia() const { return m_via; } - void SetAffectedRange ( int aStart, int aEnd ) - { - m_affectedRangeStart = aStart; - m_affectedRangeEnd = aEnd; - } + void SetAffectedRange( int aStart, int aEnd ) + { + m_affectedRangeStart = aStart; + m_affectedRangeEnd = aEnd; + } - void ClearAffectedRange ( ) - { - m_affectedRangeStart = -1; - } + void ClearAffectedRange() + { + m_affectedRangeStart = -1; + } - bool GetAffectedRange ( int& aStart, int& aEnd ) - { - if(m_affectedRangeStart >= 0) - { - aStart = m_affectedRangeStart; - aEnd = m_affectedRangeEnd; - return true; - } else { - aStart = 0; - aEnd = m_line.PointCount(); - return false; - } - } + bool GetAffectedRange( int& aStart, int& aEnd ) + { + if( m_affectedRangeStart >= 0 ) + { + aStart = m_affectedRangeStart; + aEnd = m_affectedRangeEnd; + return true; + } + else + { + aStart = 0; + aEnd = m_line.PointCount(); + return false; + } + } private: - bool onEdge(const SHAPE_LINE_CHAIN &obstacle, VECTOR2I p, int& ei, bool& is_vertex) const; - bool walkScan(const SHAPE_LINE_CHAIN &line, const SHAPE_LINE_CHAIN &obstacle, bool reverse, VECTOR2I &ip, int& index_o, int& index_l, bool& is_vertex) const; - - ///> List of semgments in a PNS_NODE (PNS_ITEM::m_owner) that constitute this line. - LinkedSegments* m_segmentRefs; - - ///> Shape of the line - SHAPE_LINE_CHAIN m_line; - - int m_width; - ///> Via at the end and a flag indicating if it's enabled. - PNS_VIA m_via; - bool m_hasVia; + bool onEdge( const SHAPE_LINE_CHAIN& obstacle, VECTOR2I p, int& ei, bool& is_vertex ) const; + bool walkScan( const SHAPE_LINE_CHAIN& line, const SHAPE_LINE_CHAIN& obstacle, + bool reverse, VECTOR2I& ip, int& index_o, int& index_l, bool& is_vertex ) const; - int m_affectedRangeStart; - int m_affectedRangeEnd; + ///> List of semgments in a PNS_NODE (PNS_ITEM::m_owner) that constitute this line. + LinkedSegments* m_segmentRefs; + + ///> Shape of the line + SHAPE_LINE_CHAIN m_line; + + int m_width; + + ///> Via at the end and a flag indicating if it's enabled. + PNS_VIA m_via; + bool m_hasVia; + + int m_affectedRangeStart; + int m_affectedRangeEnd; }; - -#endif // __PNS_LINE_H +#endif // __PNS_LINE_H diff --git a/pcbnew/router/pns_line_placer.cpp b/pcbnew/router/pns_line_placer.cpp index 1057dc9062..00e5655a4f 100644 --- a/pcbnew/router/pns_line_placer.cpp +++ b/pcbnew/router/pns_line_placer.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -33,683 +33,648 @@ using namespace std; using boost::optional; -PNS_LINE_PLACER::PNS_LINE_PLACER( PNS_NODE *aWorld ) +PNS_LINE_PLACER::PNS_LINE_PLACER( PNS_NODE* aWorld ) { - m_initial_direction = DIRECTION_45(DIRECTION_45::N); - m_follow_mouse = false; - m_smoothing_step = 100000; - m_smooth_mouse = false; - m_iteration = 0; - m_world = aWorld; - m_mode = RM_Smart; - m_follow_mouse = true; - m_shove = NULL; + m_initial_direction = DIRECTION_45( DIRECTION_45::N ); + m_follow_mouse = false; + m_smoothing_step = 100000; + m_smooth_mouse = false; + m_iteration = 0; + m_world = aWorld; + m_mode = RM_Smart; + m_follow_mouse = true; + m_shove = NULL; }; -PNS_LINE_PLACER::~PNS_LINE_PLACER() + +PNS_LINE_PLACER::~PNS_LINE_PLACER() { - if(m_shove) - delete m_shove; -} - -void PNS_LINE_PLACER::ApplySettings ( const PNS_ROUTING_SETTINGS& aSettings ) -{ - m_follow_mouse = aSettings.m_followMouse; - m_mode = aSettings.m_routingMode; - m_walkaroundIterationLimit = aSettings.m_walkaroundIterationLimit; - m_smartPads = aSettings.m_smartPads; -} - -void PNS_LINE_PLACER::StartPlacement(const VECTOR2I& aStart, int aNet, int aWidth, int aLayer ) -{ - m_direction = m_initial_direction; - TRACE(1, "world %p, intitial-direction %s layer %d\n", m_world % m_direction.Format().c_str() % aLayer); - m_head.SetNet(aNet); - m_tail.SetNet(aNet); - m_head.SetWidth(aWidth); - m_tail.SetWidth(aWidth); - m_head.GetLine().Clear(); - m_tail.GetLine().Clear(); - m_head.SetLayer(aLayer); - m_tail.SetLayer(aLayer); - m_iteration = 0; - m_p_start = aStart; - m_currentNode = m_world->Branch(); - m_head.SetWorld(m_currentNode); - m_tail.SetWorld(m_currentNode); - //if(m_shove) - // delete m_shove; - m_shove = new PNS_SHOVE(m_currentNode); - m_placingVia = false; -} - -void PNS_LINE_PLACER::SetInitialDirection(const DIRECTION_45& aDirection) -{ - m_initial_direction = aDirection; - - if(m_tail.GetCLine().SegmentCount() == 0) - m_direction = aDirection; -} - -/** - * Function handleSelfIntersections() - * - * Checks if the head of the track intersects its tail. If so, cuts the tail up to the - * intersecting segment and fixes the head direction to match the last segment before the cut. - * @return true if the line has been changed. - */ -bool PNS_LINE_PLACER::handleSelfIntersections() -{ - SHAPE_LINE_CHAIN::Intersections ips; - SHAPE_LINE_CHAIN& head = m_head.GetLine(); - SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); - - // if there is no tail, there is nothing to intersect with - if(tail.PointCount() < 2) - return false; - - tail.Intersect(head, ips); - - // no intesection points - nothing to reduce - if (ips.empty()) - return false; - - int n = INT_MAX; - VECTOR2I ipoint; - - // if there is more than one intersection, find the one that is - // closest to the beginning of the tail. - BOOST_FOREACH(SHAPE_LINE_CHAIN::Intersection i, ips) - { - if (i.our.Index() < n) - { - n = i.our.Index(); - ipoint = i.p; - } - } - - // ignore the point where head and tail meet - if(ipoint == head.CPoint(0) || ipoint == tail.CPoint(-1)) - return false; - - // Intersection point is on the first or the second segment: just start routing - // from the beginning - if (n < 2) - { - m_p_start = tail.Point(0); - m_direction = m_initial_direction; - tail.Clear(); - head.Clear(); - return true; - } else { - // Clip till the last tail segment before intersection. - // Set the direction to the one of this segment. - const SEG last = tail.CSegment(n - 1); - m_p_start = last.a; - m_direction = DIRECTION_45(last); - tail.Remove(n, -1); - return true; - } - return false; -} - -/** - * Function handlePullback() - * - * Deals with pull-back: reduces the tail if head trace is moved backwards wrs - * to the current tail direction. - * @return true if the line has been changed. - */ -bool PNS_LINE_PLACER::handlePullback() -{ - SHAPE_LINE_CHAIN& head = m_head.GetLine(); - SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); - - int n = tail.PointCount(); - - if(n == 0) - return false; - else if (n == 1) - { - m_p_start = tail.CPoint(0); - tail.Clear(); - return true; - } - - DIRECTION_45 first_head (head.Segment(0)); - DIRECTION_45 last_tail (tail.Segment(-1)); - DIRECTION_45::AngleType angle = first_head.Angle(last_tail); - - // case 1: we have a defined routing direction, and the currently computed head - // goes in different one. - bool pullback_1 = false;//(m_direction != DIRECTION_45::UNDEFINED && m_direction != first_head); - - // case 2: regardless of the current routing direction, if the tail/head extremities form - // an acute or right angle, reduce the tail by one segment (and hope that further iterations) - // will result with a cleaner trace - bool pullback_2 = (angle == DIRECTION_45::ANG_RIGHT || angle == DIRECTION_45::ANG_ACUTE); - - if(pullback_1 || pullback_2) - { - - const SEG last = tail.CSegment(-1); - m_direction = DIRECTION_45(last); - m_p_start = last.a; - - - TRACE(0, "Placer: pullback triggered [%d] [%s %s]", n % last_tail.Format().c_str() % first_head.Format().c_str()); - // erase the last point in the tail, hoping that the next iteration will result with a head - // trace that starts with a segment following our current direction. - if(n < 2) - tail.Clear(); // don't leave a single-point tail - else - tail.Remove(-1, -1); - - if( !tail.SegmentCount() ) - m_direction = m_initial_direction; - - return true; - } - - return false; -} - -/** - * Function reduceTail() - * - * Attempts to reduce the numer of segments in the tail by trying to replace a certain number - * of latest tail segments with a direct trace leading to aEnd that does not collide with anything. - * @param aEnd: current routing destination point. - * @return true if the line has been changed. - */ -bool PNS_LINE_PLACER::reduceTail(const VECTOR2I& aEnd) -{ - SHAPE_LINE_CHAIN& head = m_head.GetLine(); - SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); - - int n = tail.SegmentCount(); - - // Don't attempt this for too short tails - if (n < 2) - return false; - - // Start from the segment farthest from the end of the tail - //int start_index = std::max(n - 1 - ReductionDepth, 0); - - DIRECTION_45 new_direction; - VECTOR2I new_start; - int reduce_index = -1; - - DIRECTION_45 head_dir ( head.Segment(0) ); - - for(int i = tail.SegmentCount() - 1; i >= 0; i--) - { - const SEG s = tail.CSegment(i); - DIRECTION_45 dir (s); - - // calculate a replacement route and check if it matches the direction of the segment to be replaced - SHAPE_LINE_CHAIN replacement = dir.BuildInitialTrace(s.a, aEnd); - - PNS_LINE tmp (m_tail, replacement); - - if (m_currentNode->CheckColliding(&tmp, PNS_ITEM::ANY)) - break; - - if(DIRECTION_45(replacement.Segment(0)) == dir) - { - new_start = s.a; - new_direction = dir; - reduce_index = i; - } - } - - if(reduce_index >= 0) - { - - TRACE(0, "Placer: reducing tail: %d", reduce_index); - SHAPE_LINE_CHAIN reducedLine = new_direction.BuildInitialTrace(new_start, aEnd); - - m_p_start = new_start; - m_direction = new_direction; - tail.Remove(reduce_index+1, -1); - head.Clear(); - return true; - } - - if( !tail.SegmentCount() ) - m_direction = m_initial_direction; - - return false; + if( m_shove ) + delete m_shove; } -/** - * Function checkObtusity() - * - * Helper that checks if segments a and b form an obtuse angle (in 45-degree regime). - * @return true, if angle (a, b) is obtuse - */ -bool PNS_LINE_PLACER::checkObtusity(const SEG& a, const SEG& b) const +void PNS_LINE_PLACER::ApplySettings( const PNS_ROUTING_SETTINGS& aSettings ) { - const DIRECTION_45 dir_a(a); - const DIRECTION_45 dir_b(b); - return dir_a.IsObtuse(dir_b) || dir_a == dir_b; + m_follow_mouse = aSettings.m_followMouse; + m_mode = aSettings.m_routingMode; + m_walkaroundIterationLimit = aSettings.m_walkaroundIterationLimit; + m_smartPads = aSettings.m_smartPads; +} + + +void PNS_LINE_PLACER::StartPlacement( const VECTOR2I& aStart, int aNet, + int aWidth, int aLayer ) +{ + m_direction = m_initial_direction; + TRACE( 1, "world %p, intitial-direction %s layer %d\n", + m_world % m_direction.Format().c_str() % aLayer ); + m_head.SetNet( aNet ); + m_tail.SetNet( aNet ); + m_head.SetWidth( aWidth ); + m_tail.SetWidth( aWidth ); + m_head.GetLine().Clear(); + m_tail.GetLine().Clear(); + m_head.SetLayer( aLayer ); + m_tail.SetLayer( aLayer ); + m_iteration = 0; + m_p_start = aStart; + m_currentNode = m_world->Branch(); + m_head.SetWorld( m_currentNode ); + m_tail.SetWorld( m_currentNode ); + // if(m_shove) + // delete m_shove; + m_shove = new PNS_SHOVE( m_currentNode ); + m_placingVia = false; +} + + +void PNS_LINE_PLACER::SetInitialDirection( const DIRECTION_45& aDirection ) +{ + m_initial_direction = aDirection; + + if( m_tail.GetCLine().SegmentCount() == 0 ) + m_direction = aDirection; +} + + +bool PNS_LINE_PLACER::handleSelfIntersections() +{ + SHAPE_LINE_CHAIN::Intersections ips; + SHAPE_LINE_CHAIN& head = m_head.GetLine(); + SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); + + // if there is no tail, there is nothing to intersect with + if( tail.PointCount() < 2 ) + return false; + + tail.Intersect( head, ips ); + + // no intesection points - nothing to reduce + if( ips.empty() ) + return false; + + int n = INT_MAX; + VECTOR2I ipoint; + + // if there is more than one intersection, find the one that is + // closest to the beginning of the tail. + BOOST_FOREACH( SHAPE_LINE_CHAIN::Intersection i, ips ) + { + if( i.our.Index() < n ) + { + n = i.our.Index(); + ipoint = i.p; + } + } + + // ignore the point where head and tail meet + if( ipoint == head.CPoint( 0 ) || ipoint == tail.CPoint( -1 ) ) + return false; + + // Intersection point is on the first or the second segment: just start routing + // from the beginning + if( n < 2 ) + { + m_p_start = tail.Point( 0 ); + m_direction = m_initial_direction; + tail.Clear(); + head.Clear(); + return true; + } + else + { + // Clip till the last tail segment before intersection. + // Set the direction to the one of this segment. + const SEG last = tail.CSegment( n - 1 ); + m_p_start = last.a; + m_direction = DIRECTION_45( last ); + tail.Remove( n, -1 ); + return true; + } + + return false; +} + + +bool PNS_LINE_PLACER::handlePullback() +{ + SHAPE_LINE_CHAIN& head = m_head.GetLine(); + SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); + + int n = tail.PointCount(); + + if( n == 0 ) + return false; + else if( n == 1 ) + { + m_p_start = tail.CPoint( 0 ); + tail.Clear(); + return true; + } + + DIRECTION_45 first_head( head.Segment( 0 ) ); + DIRECTION_45 last_tail( tail.Segment( -1 ) ); + DIRECTION_45::AngleType angle = first_head.Angle( last_tail ); + + // case 1: we have a defined routing direction, and the currently computed + // head goes in different one. + bool pullback_1 = false; // (m_direction != DIRECTION_45::UNDEFINED && m_direction != first_head); + + // case 2: regardless of the current routing direction, if the tail/head + // extremities form an acute or right angle, reduce the tail by one segment + // (and hope that further iterations) will result with a cleaner trace + bool pullback_2 = (angle == DIRECTION_45::ANG_RIGHT || + angle == DIRECTION_45::ANG_ACUTE); + + if( pullback_1 || pullback_2 ) + { + const SEG last = tail.CSegment( -1 ); + m_direction = DIRECTION_45( last ); + m_p_start = last.a; + + TRACE( 0, "Placer: pullback triggered [%d] [%s %s]", + n % last_tail.Format().c_str() % first_head.Format().c_str() ); + + // erase the last point in the tail, hoping that the next iteration will + // result with a head trace that starts with a segment following our + // current direction. + if( n < 2 ) + tail.Clear(); // don't leave a single-point tail + else + tail.Remove( -1, -1 ); + + if( !tail.SegmentCount() ) + m_direction = m_initial_direction; + + return true; + } + + return false; +} + + +bool PNS_LINE_PLACER::reduceTail( const VECTOR2I& aEnd ) +{ + SHAPE_LINE_CHAIN& head = m_head.GetLine(); + SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); + + int n = tail.SegmentCount(); + + // Don't attempt this for too short tails + if( n < 2 ) + return false; + + // Start from the segment farthest from the end of the tail + // int start_index = std::max(n - 1 - ReductionDepth, 0); + + DIRECTION_45 new_direction; + VECTOR2I new_start; + int reduce_index = -1; + + DIRECTION_45 head_dir( head.Segment( 0 ) ); + + for( int i = tail.SegmentCount() - 1; i >= 0; i-- ) + { + const SEG s = tail.CSegment( i ); + DIRECTION_45 dir( s ); + + // calculate a replacement route and check if it matches + // the direction of the segment to be replaced + SHAPE_LINE_CHAIN replacement = dir.BuildInitialTrace( s.a, aEnd ); + + PNS_LINE tmp( m_tail, replacement ); + + if( m_currentNode->CheckColliding( &tmp, PNS_ITEM::ANY ) ) + break; + + if( DIRECTION_45( replacement.Segment( 0 ) ) == dir ) + { + new_start = s.a; + new_direction = dir; + reduce_index = i; + } + } + + if( reduce_index >= 0 ) + { + TRACE( 0, "Placer: reducing tail: %d", reduce_index ); + SHAPE_LINE_CHAIN reducedLine = new_direction.BuildInitialTrace( new_start, aEnd ); + + m_p_start = new_start; + m_direction = new_direction; + tail.Remove( reduce_index + 1, -1 ); + head.Clear(); + return true; + } + + if( !tail.SegmentCount() ) + m_direction = m_initial_direction; + + return false; +} + + +bool PNS_LINE_PLACER::checkObtusity( const SEG& a, const SEG& b ) const +{ + const DIRECTION_45 dir_a( a ); + const DIRECTION_45 dir_b( b ); + + return dir_a.IsObtuse( dir_b ) || dir_a == dir_b; } -/** - * Function mergeHead() - * - * Moves "estabished" segments from the head to the tail if certain conditions are met. - * @return true, if the line has been changed. - */ bool PNS_LINE_PLACER::mergeHead() { - SHAPE_LINE_CHAIN& head = m_head.GetLine(); - SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); + SHAPE_LINE_CHAIN& head = m_head.GetLine(); + SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); - const int ForbiddenAngles = DIRECTION_45::ANG_ACUTE | DIRECTION_45::ANG_HALF_FULL | DIRECTION_45::ANG_UNDEFINED; + const int ForbiddenAngles = DIRECTION_45::ANG_ACUTE | + DIRECTION_45::ANG_HALF_FULL | + DIRECTION_45::ANG_UNDEFINED; - head.Simplify(); - tail.Simplify(); + head.Simplify(); + tail.Simplify(); - int n_head = head.SegmentCount(); - int n_tail = tail.SegmentCount(); + int n_head = head.SegmentCount(); + int n_tail = tail.SegmentCount(); - if( n_head < 3 ) - { - TRACEn(4, "Merge failed: not enough head segs."); - return false; - } + if( n_head < 3 ) + { + TRACEn( 4, "Merge failed: not enough head segs." ); + return false; + } - if (n_tail && head.CPoint(0) != tail.CPoint(-1)) - { - TRACEn(4, "Merge failed: head and tail discontinuous."); - return false; - } + if( n_tail && head.CPoint( 0 ) != tail.CPoint( -1 ) ) + { + TRACEn( 4, "Merge failed: head and tail discontinuous." ); + return false; + } - if( m_head.CountCorners(ForbiddenAngles) != 0 ) - return false; + if( m_head.CountCorners( ForbiddenAngles ) != 0 ) + return false; - DIRECTION_45 dir_tail, dir_head; + DIRECTION_45 dir_tail, dir_head; - dir_head = DIRECTION_45(head.CSegment(0)); + dir_head = DIRECTION_45( head.CSegment( 0 ) ); - if(n_tail) - { - dir_tail = DIRECTION_45(tail.CSegment(-1)); - if(dir_head.Angle(dir_tail) & ForbiddenAngles) - return false; - } + if( n_tail ) + { + dir_tail = DIRECTION_45( tail.CSegment( -1 ) ); - if(!n_tail) - tail.Append(head.CSegment(0).a); + if( dir_head.Angle( dir_tail ) & ForbiddenAngles ) + return false; + } - for (int i = 0; i < n_head - 2; i++) - { - tail.Append(head.CSegment(i).b); - } + if( !n_tail ) + tail.Append( head.CSegment( 0 ).a ); - tail.Simplify(); + for( int i = 0; i < n_head - 2; i++ ) + { + tail.Append( head.CSegment( i ).b ); + } - SEG last = tail.CSegment(-1); - - m_p_start = last.b; - m_direction = DIRECTION_45(last).Right(); + tail.Simplify(); + SEG last = tail.CSegment( -1 ); - head.Remove(0, n_head - 2); + m_p_start = last.b; + m_direction = DIRECTION_45( last ).Right(); - TRACE(0, "Placer: merge %d, new direction: %s", n_head % m_direction.Format().c_str()); - + head.Remove( 0, n_head - 2 ); - head.Simplify(); - tail.Simplify(); + TRACE( 0, "Placer: merge %d, new direction: %s", n_head % m_direction.Format().c_str() ); - return true; + head.Simplify(); + tail.Simplify(); + + return true; } -bool PNS_LINE_PLACER::handleViaPlacement ( PNS_LINE& aHead ) + +bool PNS_LINE_PLACER::handleViaPlacement( PNS_LINE& aHead ) { - if(!m_placingVia) - return true; + if( !m_placingVia ) + return true; - PNS_LAYERSET allLayers (0, 15); - PNS_VIA v (aHead.GetCLine().CPoint(-1), allLayers, m_viaDiameter, aHead.GetNet()); - v.SetDrill(m_viaDrill); + PNS_LAYERSET allLayers( 0, 15 ); + PNS_VIA v( aHead.GetCLine().CPoint( -1 ), allLayers, m_viaDiameter, aHead.GetNet() ); + v.SetDrill( m_viaDrill ); - VECTOR2I force; - VECTOR2I lead = aHead.GetCLine().CPoint(-1) - aHead.GetCLine().CPoint(0); + VECTOR2I force; + VECTOR2I lead = aHead.GetCLine().CPoint( -1 ) - aHead.GetCLine().CPoint( 0 ); - - if( v.PushoutForce ( m_shove->GetCurrentNode(), lead, force, true, 20 ) ) - { - SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace(aHead.GetCLine().CPoint(0), aHead.GetCLine().CPoint(-1) + force); - aHead = PNS_LINE(aHead, line); + if( v.PushoutForce( m_shove->GetCurrentNode(), lead, force, true, 20 ) ) + { + SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( + aHead.GetCLine().CPoint( 0 ), + aHead.GetCLine().CPoint( -1 ) + force ); + aHead = PNS_LINE( aHead, line ); - v.SetPos(v.GetPos() + force); - return true; - } - - return false; + v.SetPos( v.GetPos() + force ); + return true; + } + + return false; } -/** - * Function routeHead() - * - * Computes the head trace between the current start point (m_p_start) and point aP, - * starting with direction defined in m_direction. The trace walks around all - * colliding solid or non-movable items. Movable segments are ignored, as they'll be handled - * later by the shove algorithm. - */ -bool PNS_LINE_PLACER::routeHead(const VECTOR2I& aP, PNS_LINE& aNewHead, bool aCwWalkaround) + +bool PNS_LINE_PLACER::routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead, + bool aCwWalkaround ) { - // STAGE 1: route a simple two-segment trace between m_p_start and aP... - SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace(m_p_start, aP); + // STAGE 1: route a simple two-segment trace between m_p_start and aP... + SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( m_p_start, aP ); - PNS_LINE initTrack (m_head, line); - PNS_LINE walkFull, walkSolids; + PNS_LINE initTrack( m_head, line ); + PNS_LINE walkFull, walkSolids; + if( m_mode == RM_Ignore ) + { + aNewHead = initTrack; + return true; + } - if(m_mode == RM_Ignore) - { - aNewHead = initTrack; - return true; - } - handleViaPlacement(initTrack); + handleViaPlacement( initTrack ); - m_currentNode = m_shove->GetCurrentNode(); + m_currentNode = m_shove->GetCurrentNode(); - PNS_OPTIMIZER optimizer(m_currentNode); - PNS_WALKAROUND walkaround( m_currentNode ); + PNS_OPTIMIZER optimizer( m_currentNode ); + PNS_WALKAROUND walkaround( m_currentNode ); - walkaround.SetSolidsOnly(false); - walkaround.SetIterationLimit(m_mode == RM_Walkaround ? 8 : 5 ); - //walkaround.SetApproachCursor(true, aP); - - PNS_WALKAROUND::WalkaroundStatus wf = walkaround.Route(initTrack, walkFull); + walkaround.SetSolidsOnly( false ); + walkaround.SetIterationLimit( m_mode == RM_Walkaround ? 8 : 5 ); + // walkaround.SetApproachCursor(true, aP); + + PNS_WALKAROUND::WalkaroundStatus wf = walkaround.Route( initTrack, walkFull ); #if 0 - - if(m_mode == RM_Walkaround) - { - // walkaround. -// PNSDisplayDebugLine (walkFull.GetCLine(), 4); - if(wf == PNS_WALKAROUND::STUCK) - { - aNewHead = m_head; - aNewHead.SetShape(walkFull.GetCLine()); - aNewHead = aNewHead.ClipToNearestObstacle(m_currentNode); - return false; - } - - aNewHead = m_head; - aNewHead.SetShape(walkFull.GetCLine()); + if( m_mode == RM_Walkaround ) + { + // walkaround. +// PNSDisplayDebugLine (walkFull.GetCLine(), 4); + + if( wf == PNS_WALKAROUND::STUCK ) + { + aNewHead = m_head; + aNewHead.SetShape( walkFull.GetCLine() ); + aNewHead = aNewHead.ClipToNearestObstacle( m_currentNode ); + return false; + } + + aNewHead = m_head; + aNewHead.SetShape( walkFull.GetCLine() ); + +// printf("nh w %d l %d\n", aNewHead.GetWidth(), aNewHead.GetLayers().Start()); + return true; + } -// printf("nh w %d l %d\n", aNewHead.GetWidth(), aNewHead.GetLayers().Start()); - return true; - } #endif - PNS_COST_ESTIMATOR cost_walk, cost_orig; - - walkaround.SetApproachCursor ( false, aP ); - walkaround.SetSolidsOnly(true); - walkaround.SetIterationLimit( 10 ); - PNS_WALKAROUND::WalkaroundStatus stat_solids = walkaround.Route(initTrack, walkSolids); + PNS_COST_ESTIMATOR cost_walk, cost_orig; - optimizer.SetEffortLevel ( PNS_OPTIMIZER::MERGE_SEGMENTS ); - optimizer.SetCollisionMask (PNS_ITEM::SOLID); - optimizer.Optimize(&walkSolids); - #if 0 - optimizer.SetCollisionMask (-1); - optimizer.Optimize(&walkFull); - #endif - cost_orig.Add(initTrack); - cost_walk.Add(walkFull); + walkaround.SetApproachCursor( false, aP ); + walkaround.SetSolidsOnly( true ); + walkaround.SetIterationLimit( 10 ); + PNS_WALKAROUND::WalkaroundStatus stat_solids = walkaround.Route( initTrack, walkSolids ); - if(m_mode == RM_Smart || m_mode == RM_Shove) - { - PNS_LINE l2; + optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_SEGMENTS ); + optimizer.SetCollisionMask( PNS_ITEM::SOLID ); + optimizer.Optimize( &walkSolids ); + #if 0 + optimizer.SetCollisionMask( -1 ); + optimizer.Optimize( &walkFull ); + #endif + cost_orig.Add( initTrack ); + cost_walk.Add( walkFull ); - bool walk_better = cost_orig.IsBetter(cost_walk, 1.5, 10.0); - walk_better = false; + if( m_mode == RM_Smart || m_mode == RM_Shove ) + { + PNS_LINE l2; + + bool walk_better = cost_orig.IsBetter( cost_walk, 1.5, 10.0 ); + walk_better = false; #if 0 - printf("RtTrk width %d %d %d", initTrack.GetWidth(), walkFull.GetWidth(), walkSolids.GetWidth()); - printf("init-coll %d\n", m_currentNode->CheckColliding(&initTrack)? 1: 0); - printf("total cost: walk cor %.0f len %.0f orig cor %.0f len %.0f walk-better %d\n", - cost_walk.GetCornerCost(), cost_walk.GetLengthCost(), - cost_orig.GetCornerCost(), cost_orig.GetLengthCost(), - walk_better ); + printf( "RtTrk width %d %d %d", initTrack.GetWidth(), + walkFull.GetWidth(), walkSolids.GetWidth() ); + printf( "init-coll %d\n", m_currentNode->CheckColliding( &initTrack ) ? 1 : 0 ); + printf( "total cost: walk cor %.0f len %.0f orig cor %.0f len %.0f walk-better %d\n", + cost_walk.GetCornerCost(), cost_walk.GetLengthCost(), + cost_orig.GetCornerCost(), cost_orig.GetLengthCost(), + walk_better ); #endif - if(m_mode == RM_Smart && wf == PNS_WALKAROUND::DONE && walk_better && walkFull.GetCLine().CPoint(-1) == initTrack.GetCLine().CPoint(-1)) - l2 = walkFull; - else if (stat_solids == PNS_WALKAROUND::DONE) - l2 = walkSolids; - else - l2 = initTrack.ClipToNearestObstacle(m_shove->GetCurrentNode()); + if( m_mode == RM_Smart && wf == PNS_WALKAROUND::DONE && walk_better + && walkFull.GetCLine().CPoint( -1 ) == initTrack.GetCLine().CPoint( -1 ) ) + l2 = walkFull; + else if( stat_solids == PNS_WALKAROUND::DONE ) + l2 = walkSolids; + else + l2 = initTrack.ClipToNearestObstacle( m_shove->GetCurrentNode() ); - PNS_LINE l ( m_tail ); - l.GetLine().Append( l2.GetCLine() ); - l.GetLine().Simplify(); + PNS_LINE l( m_tail ); + l.GetLine().Append( l2.GetCLine() ); + l.GetLine().Simplify(); - if(m_placingVia) - { - PNS_LAYERSET allLayers(0,15); - PNS_VIA v1( l.GetCLine().CPoint(-1), allLayers, m_viaDiameter ); - PNS_VIA v2( l2.GetCLine().CPoint(-1), allLayers, m_viaDiameter ); - v1.SetDrill(m_viaDrill); - v2.SetDrill(m_viaDrill); - - l.AppendVia ( v1 ); - l2.AppendVia ( v2 ); - } + if( m_placingVia ) + { + PNS_LAYERSET allLayers( 0, 15 ); + PNS_VIA v1( l.GetCLine().CPoint( -1 ), allLayers, m_viaDiameter ); + PNS_VIA v2( l2.GetCLine().CPoint( -1 ), allLayers, m_viaDiameter ); + v1.SetDrill( m_viaDrill ); + v2.SetDrill( m_viaDrill ); - PNS_SHOVE::ShoveStatus status = m_shove->ShoveLines(&l); - m_currentNode = m_shove->GetCurrentNode(); + l.AppendVia( v1 ); + l2.AppendVia( v2 ); + } - if (status == PNS_SHOVE::SH_OK) - { - - optimizer.SetWorld (m_currentNode); - optimizer.ClearCache(); - optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_OBTUSE | PNS_OPTIMIZER::SMART_PADS ); - optimizer.SetCollisionMask (-1); - optimizer.Optimize(&l2); - - aNewHead = l2; - - return true; - } else { - walkaround.SetWorld( m_currentNode ); - walkaround.SetSolidsOnly(false); - walkaround.SetIterationLimit( 10 ); - walkaround.SetApproachCursor ( true, aP ); - walkaround.Route(initTrack, l2); - aNewHead = l2.ClipToNearestObstacle (m_shove->GetCurrentNode()); - //aNewHead = l2; - - return false; - } - - } + PNS_SHOVE::ShoveStatus status = m_shove->ShoveLines( &l ); + m_currentNode = m_shove->GetCurrentNode(); - return false; + if( status == PNS_SHOVE::SH_OK ) + { + optimizer.SetWorld( m_currentNode ); + optimizer.ClearCache(); + optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_OBTUSE | PNS_OPTIMIZER::SMART_PADS ); + optimizer.SetCollisionMask( -1 ); + optimizer.Optimize( &l2 ); + + aNewHead = l2; + + return true; + } + else + { + walkaround.SetWorld( m_currentNode ); + walkaround.SetSolidsOnly( false ); + walkaround.SetIterationLimit( 10 ); + walkaround.SetApproachCursor( true, aP ); + walkaround.Route( initTrack, l2 ); + aNewHead = l2.ClipToNearestObstacle( m_shove->GetCurrentNode() ); + // aNewHead = l2; + + return false; + } + } + + return false; } -/** - * Function optimizeTailHeadTransition() - * - * Tries to reduce the corner count of the most recent part of tail/head by merging - * obtuse/collinear segments. - * @return true, if the line has been changed. - */ bool PNS_LINE_PLACER::optimizeTailHeadTransition() { - SHAPE_LINE_CHAIN& head = m_head.GetLine(); - SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); + SHAPE_LINE_CHAIN& head = m_head.GetLine(); + SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); - const int TailLookbackSegments = 5; - - int threshold = min(tail.PointCount(), TailLookbackSegments + 1); - - if(tail.SegmentCount() < 3) - return false; + const int TailLookbackSegments = 5; - // assemble TailLookbackSegments tail segments with the current head - SHAPE_LINE_CHAIN opt_line = tail.Slice(-threshold, -1); + int threshold = min( tail.PointCount(), TailLookbackSegments + 1 ); - opt_line.Append(head); -// opt_line.Simplify(); + if( tail.SegmentCount() < 3 ) + return false; - PNS_LINE new_head(m_tail, opt_line); - - // and see if it could be made simpler by merging obtuse/collnear segments. If so, - // replace the (threshold) last tail points and the head with the optimized line + // assemble TailLookbackSegments tail segments with the current head + SHAPE_LINE_CHAIN opt_line = tail.Slice( -threshold, -1 ); - //if(PNS_OPTIMIZER::Optimize(&new_head, PNS_OPTIMIZER::MERGE_SEGMENTS)) + opt_line.Append( head ); +// opt_line.Simplify(); + PNS_LINE new_head( m_tail, opt_line ); - if(new_head.MergeSegments()) - { - PNS_LINE tmp(m_tail, opt_line); - - TRACE(0, "Placer: optimize tail-head [%d]", threshold); - - head.Clear(); - tail.Replace(-threshold, -1, new_head.GetCLine()); - tail.Simplify(); + // and see if it could be made simpler by merging obtuse/collnear segments. + // If so, replace the (threshold) last tail points and the head with + // the optimized line - m_p_start = new_head.GetCLine().CPoint(-1); - m_direction = DIRECTION_45(new_head.GetCLine().CSegment(-1)); + // if(PNS_OPTIMIZER::Optimize(&new_head, PNS_OPTIMIZER::MERGE_SEGMENTS)) - return true; - } + if( new_head.MergeSegments() ) + { + PNS_LINE tmp( m_tail, opt_line ); - return false; + TRACE( 0, "Placer: optimize tail-head [%d]", threshold ); + + head.Clear(); + tail.Replace( -threshold, -1, new_head.GetCLine() ); + tail.Simplify(); + + m_p_start = new_head.GetCLine().CPoint( -1 ); + m_direction = DIRECTION_45( new_head.GetCLine().CSegment( -1 ) ); + + return true; + } + + return false; } -/** - * Function routeStep() - * - * Performs a single routing alorithm step, for the end point aP. - * @param aP ending point of current route - * @return true, if the line has been changed. - */ - -void PNS_LINE_PLACER::routeStep(const VECTOR2I& aP) +void PNS_LINE_PLACER::routeStep( const VECTOR2I& aP ) { - bool fail = false; - bool go_back = false; - - int i, n_iter = 1; + bool fail = false; + bool go_back = false; - PNS_LINE new_head; - - m_follow_mouse = true; + int i, n_iter = 1; - TRACE(2,"INIT-DIR: %s head: %d, tail: %d segs\n", m_initial_direction.Format().c_str() % m_head.GetCLine().SegmentCount() % m_tail.GetCLine().SegmentCount()); + PNS_LINE new_head; - for(i = 0; i < n_iter; i++) - { - - if(!go_back && m_follow_mouse) - reduceTail(aP); - - go_back = false; + m_follow_mouse = true; - if(!routeHead(aP, new_head, true)) - fail = true; - - if(!new_head.Is45Degree()) - fail = true; - - if(!m_follow_mouse) - return; - - m_head = new_head; + TRACE( 2, "INIT-DIR: %s head: %d, tail: %d segs\n", + m_initial_direction.Format().c_str() % m_head.GetCLine().SegmentCount() % + m_tail.GetCLine().SegmentCount() ); - if(handleSelfIntersections()) - { - n_iter++; - go_back = true; - } + for( i = 0; i < n_iter; i++ ) + { + if( !go_back && m_follow_mouse ) + reduceTail( aP ); - if(!go_back && handlePullback()) - { - n_iter++; - go_back = true; - } - } + go_back = false; - if(!fail) - { - if(optimizeTailHeadTransition()) - return; - mergeHead(); - } - + if( !routeHead( aP, new_head, true ) ) + fail = true; + + if( !new_head.Is45Degree() ) + fail = true; + + if( !m_follow_mouse ) + return; + + m_head = new_head; + + if( handleSelfIntersections() ) + { + n_iter++; + go_back = true; + } + + if( !go_back && handlePullback() ) + { + n_iter++; + go_back = true; + } + } + + if( !fail ) + { + if( optimizeTailHeadTransition() ) + return; + + mergeHead(); + } } -/** - * Function Route() - * - * Re-routes the current track to point aP. Returns true, when routing has completed - * successfully (i.e. the trace end has reached point aP), and false if the trace was stuck somewhere - * on the way. May call routeStep() repetitively due to mouse smoothing. - * @param aP ending point of current route. - * @return true, if the routing is complete. - */ -bool PNS_LINE_PLACER::Route(const VECTOR2I& aP) + +bool PNS_LINE_PLACER::Route( const VECTOR2I& aP ) { - if(m_smooth_mouse) - { - VECTOR2I p_cur = m_p_start; - VECTOR2I step = (aP - m_p_start).Resize(m_smoothing_step); + if( m_smooth_mouse ) + { + VECTOR2I p_cur = m_p_start; + VECTOR2I step = (aP - m_p_start).Resize( m_smoothing_step ); - do - { - if ((p_cur - aP).EuclideanNorm() <= m_smoothing_step) - p_cur = aP; - else - p_cur += step; + do + { + if( (p_cur - aP).EuclideanNorm() <= m_smoothing_step ) + p_cur = aP; + else + p_cur += step; - routeStep(p_cur); + routeStep( p_cur ); + } while( p_cur != aP ); + } + else + routeStep( aP ); - } while (p_cur != aP); - } else - routeStep(aP); - - return CurrentEnd() == aP; + return CurrentEnd() == aP; } const PNS_LINE PNS_LINE_PLACER::GetTrace() const { - PNS_LINE tmp(m_head); - tmp.SetShape( m_tail.GetCLine() ); - tmp.GetLine().Append( m_head.GetCLine() ); - tmp.GetLine().Simplify(); - return tmp; + PNS_LINE tmp( m_head ); + + tmp.SetShape( m_tail.GetCLine() ); + tmp.GetLine().Append( m_head.GetCLine() ); + tmp.GetLine().Simplify(); + return tmp; } + void PNS_LINE_PLACER::FlipPosture() { - m_initial_direction = m_initial_direction.Right(); - m_direction = m_direction.Right(); -} - -void PNS_LINE_PLACER::GetUpdatedItems( PNS_NODE::ItemVector& aRemoved, PNS_NODE::ItemVector& aAdded) -{ - return m_shove->GetCurrentNode()->GetUpdatedItems(aRemoved, aAdded); + m_initial_direction = m_initial_direction.Right(); + m_direction = m_direction.Right(); } -PNS_NODE *PNS_LINE_PLACER::GetCurrentNode() const + +void PNS_LINE_PLACER::GetUpdatedItems( PNS_NODE::ItemVector& aRemoved, + PNS_NODE::ItemVector& aAdded ) { - return m_shove->GetCurrentNode(); -} \ No newline at end of file + return m_shove->GetCurrentNode()->GetUpdatedItems( aRemoved, aAdded ); +} + + +PNS_NODE* PNS_LINE_PLACER::GetCurrentNode() const +{ + return m_shove->GetCurrentNode(); +} + diff --git a/pcbnew/router/pns_line_placer.h b/pcbnew/router/pns_line_placer.h index 40d769cc88..f9bbfc7524 100644 --- a/pcbnew/router/pns_line_placer.h +++ b/pcbnew/router/pns_line_placer.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -30,7 +30,7 @@ #include "pns_via.h" #include "pns_line.h" #include "pns_routing_settings.h" - + class PNS_ROUTER; class PNS_SHOVE; class PNS_OPTIMIZER; @@ -39,118 +39,217 @@ class PNS_ROUTER_BASE; /** * Class PNS_LINE_PLACER * - * Interactively routes a single track. Runs shove and walkaround algorithms when needed. + * Interactively routes a single track. Runs shove and walkaround + * algorithms when needed. */ class PNS_LINE_PLACER { - public: - PNS_LINE_PLACER( PNS_NODE *aWorld ); - ~PNS_LINE_PLACER(); +public: + PNS_LINE_PLACER( PNS_NODE* aWorld ); + ~PNS_LINE_PLACER(); - ///> Appends a via at the end of currently placed line. - void AddVia ( bool aEnabled, int aDiameter, int aDrill ) - { - m_viaDiameter = aDiameter; - m_viaDrill = aDrill; - m_placingVia = aEnabled; - } + ///> Appends a via at the end of currently placed line. + void AddVia( bool aEnabled, int aDiameter, int aDrill ) + { + m_viaDiameter = aDiameter; + m_viaDrill = aDrill; + m_placingVia = aEnabled; + } - ///> Starts placement of a line at point aStart. - void StartPlacement(const VECTOR2I& aStart, int aNet, int aWidth, int aLayer); - - ///> Updates the routed line with a new ending point. - bool Route(const VECTOR2I& aP); - - ///> Sets initial routing direction/posture - void SetInitialDirection(const DIRECTION_45& aDirection); - - void ApplySettings ( const PNS_ROUTING_SETTINGS& aSettings ); + ///> Starts placement of a line at point aStart. + void StartPlacement( const VECTOR2I& aStart, int aNet, int aWidth, int aLayer ); - ///> Returns the "head" of the line being placed, that is the volatile part that has not been settled yet - const PNS_LINE& GetHead() const { return m_head; } - ///> Returns the "tail" of the line being placed the part that has been fixed already (follow mouse mode only) - const PNS_LINE& GetTail() const { return m_tail; } + /** + * Function Route() + * + * Re-routes the current track to point aP. Returns true, when routing has + * completed successfully (i.e. the trace end has reached point aP), and false + * if the trace was stuck somewhere on the way. May call routeStep() + * repetitively due to mouse smoothing. + * @param aP ending point of current route. + * @return true, if the routing is complete. + */ + bool Route( const VECTOR2I& aP ); - ///> Returns the whole routed line - const PNS_LINE GetTrace() const; + ///> Sets initial routing direction/posture + void SetInitialDirection( const DIRECTION_45& aDirection ); - ///> Returns the current end of the line being placed. It may not be equal to the cursor position due to collisions. - const VECTOR2I& CurrentEnd() const - { - if(m_head.GetCLine().PointCount() > 0) - return m_head.GetCLine().CPoint(-1); - else if(m_tail.GetCLine().PointCount() > 0) - return m_tail.GetCLine().CPoint(-1); - else - return m_p_start; - } + void ApplySettings( const PNS_ROUTING_SETTINGS& aSettings ); + ///> Returns the "head" of the line being placed, that is the volatile part + ///> that has not been settled yet + const PNS_LINE& GetHead() const { return m_head; } + ///> Returns the "tail" of the line being placed the part that has been + ///> fixed already (follow mouse mode only) + const PNS_LINE& GetTail() const { return m_tail; } - ///> Returns all items in the world that have been affected by the routing operation. Used - /// to update data structures of the host application - void GetUpdatedItems( PNS_NODE::ItemVector& aRemoved, PNS_NODE::ItemVector& aAdded); - - ///> Toggles the current posture (straight/diagonal) of the trace head. - void FlipPosture(); + ///> Returns the whole routed line + const PNS_LINE GetTrace() const; - ///> Returns the most recent world state - PNS_NODE *GetCurrentNode() const; + ///> Returns the current end of the line being placed. It may not be equal + ///> to the cursor position due to collisions. + const VECTOR2I& CurrentEnd() const + { + if( m_head.GetCLine().PointCount() > 0 ) + return m_head.GetCLine().CPoint( -1 ); + else if( m_tail.GetCLine().PointCount() > 0 ) + return m_tail.GetCLine().CPoint( -1 ); + else + return m_p_start; + } - private: - - static const double m_shoveLengthThreshold = 1.7; + ///> Returns all items in the world that have been affected by the routing + ///> operation. Used to update data structures of the host application + void GetUpdatedItems( PNS_NODE::ItemVector& aRemoved, + PNS_NODE::ItemVector& aAdded ); - bool handleViaPlacement ( PNS_LINE& aHead ); + ///> Toggles the current posture (straight/diagonal) of the trace head. + void FlipPosture(); - bool checkObtusity(const SEG& a, const SEG& b) const; - bool handleSelfIntersections(); - bool handlePullback(); - bool mergeHead(); - bool reduceTail(const VECTOR2I& aEnd); - void fixHeadPosture(); - bool optimizeTailHeadTransition(); - - bool routeHead(const VECTOR2I& aP, PNS_LINE& aNewHead, bool aCwWalkaround = true); - void routeStep(const VECTOR2I& aP); + ///> Returns the most recent world state + PNS_NODE* GetCurrentNode() const; - ///> routing mode (walkaround, shove, etc.) - PNS_MODE m_mode; - ///> follow mouse trail by attaching new segments to the head as the cursor moves - bool m_follow_mouse; - ///> mouse smoothing active - bool m_smooth_mouse; - ///> mouse smoothing step (in world units) - int m_smoothing_step; - ///> current routing direction - DIRECTION_45 m_direction; - ///> routing direction for new traces - DIRECTION_45 m_initial_direction; - ///> routing "head": volatile part of the track from the previously - /// analyzed point to the current routing destination - PNS_LINE m_head; - ///> routing "tail": part of the track that has been already fixed due to collisions with obstacles - PNS_LINE m_tail; - ///> current algorithm iteration - int m_iteration; - ///> pointer to world to search colliding items - PNS_NODE *m_world; - ///> current routing start point (end of tail, beginning of head) - VECTOR2I m_p_start; - ///> The shove engine - PNS_SHOVE *m_shove; - ///> Current world state - PNS_NODE *m_currentNode; - ///> Are we placing a via? - bool m_placingVia; - ///> current via diameter - int m_viaDiameter; - ///> current via drill - int m_viaDrill; - ///> walkaround algorithm iteration limit - int m_walkaroundIterationLimit; - ///> smart pads optimizer enabled. - bool m_smartPads; +private: + static const double m_shoveLengthThreshold = 1.7; + + bool handleViaPlacement( PNS_LINE& aHead ); + + /** + * Function checkObtusity() + * + * Helper that checks if segments a and b form an obtuse angle + * (in 45-degree regime). + * @return true, if angle (a, b) is obtuse + */ + bool checkObtusity( const SEG& a, const SEG& b ) const; + + /** + * Function handleSelfIntersections() + * + * Checks if the head of the track intersects its tail. If so, cuts the + * tail up to the intersecting segment and fixes the head direction to match + * the last segment before the cut. + * @return true if the line has been changed. + */ + bool handleSelfIntersections(); + + /** + * Function handlePullback() + * + * Deals with pull-back: reduces the tail if head trace is moved backwards + * wrs to the current tail direction. + * @return true if the line has been changed. + */ + bool handlePullback(); + + /** + * Function mergeHead() + * + * Moves "estabished" segments from the head to the tail if certain + * conditions are met. + * @return true, if the line has been changed. + */ + bool mergeHead(); + + /** + * Function reduceTail() + * + * Attempts to reduce the numer of segments in the tail by trying to replace a + * certain number of latest tail segments with a direct trace leading to aEnd + * that does not collide with anything. + * @param aEnd: current routing destination point. + * @return true if the line has been changed. + */ + bool reduceTail( const VECTOR2I& aEnd ); + + void fixHeadPosture(); + + /** + * Function optimizeTailHeadTransition() + * + * Tries to reduce the corner count of the most recent part of tail/head by + * merging obtuse/collinear segments. + * @return true, if the line has been changed. + */ + bool optimizeTailHeadTransition(); + + /** + * Function routeHead() + * + * Computes the head trace between the current start point (m_p_start) and + * point aP, starting with direction defined in m_direction. The trace walks + * around all colliding solid or non-movable items. Movable segments are + * ignored, as they'll be handled later by the shove algorithm. + */ + bool routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead, + bool aCwWalkaround = true ); + + /** + * Function routeStep() + * + * Performs a single routing alorithm step, for the end point aP. + * @param aP ending point of current route + * @return true, if the line has been changed. + */ + void routeStep( const VECTOR2I& aP ); + + ///> routing mode (walkaround, shove, etc.) + PNS_MODE m_mode; + + ///> follow mouse trail by attaching new segments to the head + ///> as the cursor moves + bool m_follow_mouse; + + ///> mouse smoothing active + bool m_smooth_mouse; + + ///> mouse smoothing step (in world units) + int m_smoothing_step; + + ///> current routing direction + DIRECTION_45 m_direction; + + ///> routing direction for new traces + DIRECTION_45 m_initial_direction; + + ///> routing "head": volatile part of the track from the previously + /// analyzed point to the current routing destination + PNS_LINE m_head; + + ///> routing "tail": part of the track that has been already fixed due to collisions with obstacles + PNS_LINE m_tail; + + ///> current algorithm iteration + int m_iteration; + + ///> pointer to world to search colliding items + PNS_NODE* m_world; + + ///> current routing start point (end of tail, beginning of head) + VECTOR2I m_p_start; + + ///> The shove engine + PNS_SHOVE* m_shove; + + ///> Current world state + PNS_NODE* m_currentNode; + + ///> Are we placing a via? + bool m_placingVia; + + ///> current via diameter + int m_viaDiameter; + + ///> current via drill + int m_viaDrill; + + ///> walkaround algorithm iteration limit + int m_walkaroundIterationLimit; + + ///> smart pads optimizer enabled. + bool m_smartPads; }; - -#endif // __PNS_LINE_PLACER_H + +#endif // __PNS_LINE_PLACER_H + diff --git a/pcbnew/router/pns_node.cpp b/pcbnew/router/pns_node.cpp index 5a1932f1e6..d17b053e70 100644 --- a/pcbnew/router/pns_node.cpp +++ b/pcbnew/router/pns_node.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -42,860 +42,946 @@ using namespace std; using boost::unordered_set; using boost::unordered_map; -static boost::unordered_set allocNodes; +static boost::unordered_set allocNodes; PNS_NODE::PNS_NODE() { - //printf("MakeNode [%p, total = %d]\n", this, allocNodes.size()); - m_root = this; - m_parent = NULL; - m_maxClearance = 800000; // fixme: depends on how thick traces are. - m_index = new PNS_INDEX; - allocNodes.insert(this); + // printf("MakeNode [%p, total = %d]\n", this, allocNodes.size()); + m_root = this; + m_parent = NULL; + m_maxClearance = 800000; // fixme: depends on how thick traces are. + m_index = new PNS_INDEX; + allocNodes.insert( this ); } + PNS_NODE::~PNS_NODE() { - if(!m_children.empty()) - { - TRACEn(0, "attempting to free a node that has kids.\n"); - assert(false); - } - - if(allocNodes.find(this) == allocNodes.end()) - { - TRACEn(0, "attempting to free an already-free'd node.\n"); - assert(false); - } + if( !m_children.empty() ) + { + TRACEn( 0, "attempting to free a node that has kids.\n" ); + assert( false ); + } - allocNodes.erase(this); + if( allocNodes.find( this ) == allocNodes.end() ) + { + TRACEn( 0, "attempting to free an already-free'd node.\n" ); + assert( false ); + } - for(PNS_INDEX::ItemSet::iterator i = m_index->begin(); i != m_index->end(); ++i) - if( (*i) ->BelongsTo(this)) - delete *i; + allocNodes.erase( this ); - unlinkParent(); - delete m_index; + for( PNS_INDEX::ItemSet::iterator i = m_index->begin(); + i != m_index->end(); ++i ) + if( (*i)->BelongsTo( this ) ) + delete *i; + + unlinkParent(); + delete m_index; } -int PNS_NODE::GetClearance(const PNS_ITEM *a, const PNS_ITEM *b) const +int PNS_NODE::GetClearance( const PNS_ITEM* a, const PNS_ITEM* b ) const { - int clearance = (* m_clearanceFunctor) (a, b); + int clearance = (*m_clearanceFunctor)( a, b ); - if( a->OfKind (PNS_ITEM::SEGMENT) ) - clearance += static_cast(a) -> GetWidth() / 2; + if( a->OfKind( PNS_ITEM::SEGMENT ) ) + clearance += static_cast(a)->GetWidth() / 2; - if( a->OfKind (PNS_ITEM::LINE) ) - clearance += static_cast(a) -> GetWidth() / 2; + if( a->OfKind( PNS_ITEM::LINE ) ) + clearance += static_cast(a)->GetWidth() / 2; - if( b->OfKind (PNS_ITEM::SEGMENT) ) - clearance += static_cast(b) -> GetWidth() / 2; + if( b->OfKind( PNS_ITEM::SEGMENT ) ) + clearance += static_cast(b)->GetWidth() / 2; - if( b->OfKind (PNS_ITEM::LINE) ) - clearance += static_cast(b) -> GetWidth() / 2; + if( b->OfKind( PNS_ITEM::LINE ) ) + clearance += static_cast(b)->GetWidth() / 2; - return clearance; + return clearance; } + PNS_NODE* PNS_NODE::Branch() { - PNS_NODE *child = new PNS_NODE; - m_children.push_back(child); + PNS_NODE* child = new PNS_NODE; - child->m_parent = this; - child->m_clearanceFunctor = m_clearanceFunctor; - child->m_root = isRoot() ? this : m_root; - - // immmediate offspring of the root branch needs not copy anything. For the rest, - // deep-copy joints, overridden item map and pointers to stored items. - if(!isRoot()) - { - JointMap::iterator j; - - for(PNS_INDEX::ItemSet::iterator i = m_index->begin(); i != m_index->end(); ++i) - child->m_index->Add(*i); + m_children.push_back( child ); - child->m_joints = m_joints; - child->m_override = m_override; - } - - TRACE(2, "%d items, %d joints, %d overrides", child->m_index->Size() % child->m_joints.size() % child->m_override.size()); - - return child; + child->m_parent = this; + child->m_clearanceFunctor = m_clearanceFunctor; + child->m_root = isRoot() ? this : m_root; + + // immmediate offspring of the root branch needs not copy anything. + // For the rest, deep-copy joints, overridden item map and pointers + // to stored items. + if( !isRoot() ) + { + JointMap::iterator j; + + for( PNS_INDEX::ItemSet::iterator i = m_index->begin(); + i != m_index->end(); ++i ) + child->m_index->Add( *i ); + + child->m_joints = m_joints; + child->m_override = m_override; + } + + TRACE( 2, "%d items, %d joints, %d overrides", + child->m_index->Size() % child->m_joints.size() % child->m_override.size() ); + + return child; } - -void PNS_NODE::unlinkParent ( ) + + +void PNS_NODE::unlinkParent() { - if( isRoot() ) - return; + if( isRoot() ) + return; - for( vector::iterator i = m_parent->m_children.begin(); i != m_parent->m_children.end(); ++i) - { - if (*i == this) - { - m_parent->m_children.erase(i); - return; - } - } + for( vector::iterator i = m_parent->m_children.begin(); + i != m_parent->m_children.end(); ++i ) + { + if( *i == this ) + { + m_parent->m_children.erase( i ); + return; + } + } } - -// function object that visits potential obstacles and performs the actual collision refining -struct PNS_NODE::obstacleVisitor { -///> node we are searching in (either root or a branch) - PNS_NODE *m_node; -///> node that overrides root entries - PNS_NODE *m_override; -///> list of encountered obstacles - Obstacles& m_tab; -///> the item we are looking for collisions with - const PNS_ITEM* m_item; -///> acccepted kinds of colliding items (solids, vias, segments, etc...) - int m_kindMask; -///> max number of hits - int m_limitCount; -///> number of items found so far - int m_matchCount; - obstacleVisitor( PNS_NODE::Obstacles& aTab, - const PNS_ITEM* aItem, - int aKindMask ) - : m_tab(aTab), - m_item(aItem), - m_kindMask(aKindMask), - m_limitCount(-1), - m_matchCount(0) - { }; - - void SetCountLimit(int aLimit) - { - m_limitCount = aLimit; - } - - void SetWorld(PNS_NODE *aNode, PNS_NODE *aOverride = NULL) - { - m_node = aNode; - m_override = aOverride; - } - - bool operator()( PNS_ITEM *aItem ) - { - if( !aItem->OfKind(m_kindMask)) - return true; - // check if there is a more recent branch with a newer (possibily modified) version of this item. - if ( m_override && m_override -> overrides (aItem) ) - return true; - - int clearance = m_node->GetClearance(aItem, m_item); - if(!aItem->Collide(m_item, clearance)) - return true; - - PNS_OBSTACLE obs; - - obs.item = aItem; - m_tab.push_back(obs); - - m_matchCount ++; - - if(m_limitCount > 0 && m_matchCount >= m_limitCount) - return false; - return true; - }; -}; - -int PNS_NODE::QueryColliding( const PNS_ITEM* aItem, PNS_NODE::Obstacles& aObstacles, int aKindMask, int aLimitCount) +// function object that visits potential obstacles and performs +// the actual collision refining +struct PNS_NODE::obstacleVisitor { - obstacleVisitor visitor ( aObstacles, aItem, aKindMask ); + ///> node we are searching in (either root or a branch) + PNS_NODE* m_node; - assert(allocNodes.find(this) != allocNodes.end()); + ///> node that overrides root entries + PNS_NODE* m_override; - visitor.SetCountLimit(aLimitCount); - visitor.SetWorld( this, NULL ); + ///> list of encountered obstacles + Obstacles& m_tab; - // first, look for colliding items ourselves - m_index->Query(aItem, m_maxClearance, visitor); + ///> the item we are looking for collisions with + const PNS_ITEM* m_item; - // if we haven't found enough items, look in the root branch as well. - if(!isRoot() && ( visitor.m_matchCount < aLimitCount || aLimitCount < 0) ) - { - visitor.SetWorld ( m_root, this ); - m_root->m_index->Query(aItem, m_maxClearance, visitor); - } + ///> acccepted kinds of colliding items (solids, vias, segments, etc...) + int m_kindMask; - return aObstacles.size(); -} + ///> max number of hits + int m_limitCount; -PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKindMask) + ///> number of items found so far + int m_matchCount; + + obstacleVisitor( PNS_NODE::Obstacles& aTab, const PNS_ITEM* aItem, + int aKindMask ) : + m_tab( aTab ), + m_item( aItem ), + m_kindMask( aKindMask ), + m_limitCount( -1 ), + m_matchCount( 0 ) + {}; + + void SetCountLimit( int aLimit ) + { + m_limitCount = aLimit; + } + + void SetWorld( PNS_NODE* aNode, PNS_NODE* aOverride = NULL ) + { + m_node = aNode; + m_override = aOverride; + } + + bool operator()( PNS_ITEM* aItem ) + { + if( !aItem->OfKind( m_kindMask ) ) + return true; + + // check if there is a more recent branch with a newer + // (possibily modified) version of this item. + if( m_override && m_override->overrides( aItem ) ) + return true; + + int clearance = m_node->GetClearance( aItem, m_item ); + + if( !aItem->Collide( m_item, clearance ) ) + return true; + + PNS_OBSTACLE obs; + + obs.item = aItem; + m_tab.push_back( obs ); + + m_matchCount++; + + if( m_limitCount > 0 && m_matchCount >= m_limitCount ) + return false; + + return true; + }; +}; + + +int PNS_NODE::QueryColliding( const PNS_ITEM* aItem, + PNS_NODE::Obstacles& aObstacles, int aKindMask, int aLimitCount ) { - Obstacles obs_list; - bool found_isects = false; + obstacleVisitor visitor( aObstacles, aItem, aKindMask ); - const SHAPE_LINE_CHAIN &line = aItem->GetCLine(); - - obs_list.reserve(100); + assert( allocNodes.find( this ) != allocNodes.end() ); - int n = 0; - for(int i = 0; i < line.SegmentCount(); i++) - { - const PNS_SEGMENT s ( *aItem, line.CSegment(i)); - n += QueryColliding ( &s, obs_list, aKindMask ); - } + visitor.SetCountLimit( aLimitCount ); + visitor.SetWorld( this, NULL ); - if( aItem->EndsWithVia () ) - n += QueryColliding ( &aItem->GetVia(), obs_list, aKindMask ); + // first, look for colliding items ourselves + m_index->Query( aItem, m_maxClearance, visitor ); - //if(! QueryColliding ( aItem, obs_list, aKindMask )) - if(!n) - return OptObstacle(); + // if we haven't found enough items, look in the root branch as well. + if( !isRoot() && ( visitor.m_matchCount < aLimitCount || aLimitCount < 0) ) + { + visitor.SetWorld( m_root, this ); + m_root->m_index->Query( aItem, m_maxClearance, visitor ); + } - PNS_LINE& aLine = (PNS_LINE&) *aItem; - - PNS_OBSTACLE nearest; - nearest.item = NULL; - nearest.dist_first = INT_MAX; - - BOOST_FOREACH(PNS_OBSTACLE obs, obs_list) - { - VECTOR2I ip_first, ip_last; - int dist_max = INT_MIN; - - vector isect_list; - - int clearance = GetClearance(obs.item, &aLine); - - SHAPE_LINE_CHAIN hull = obs.item->Hull ( clearance ); - - if(aLine.EndsWithVia()) - { - int clearance = GetClearance(obs.item, &aLine.GetVia()); - - SHAPE_LINE_CHAIN viaHull = aLine.GetVia().Hull (clearance); - - viaHull.Intersect(hull, isect_list); - - BOOST_FOREACH(SHAPE_LINE_CHAIN::Intersection isect, isect_list) - { - - int dist = aLine.GetCLine().Length() + (isect.p - aLine.GetVia().GetPos()).EuclideanNorm(); - - if(dist < nearest.dist_first) - { - found_isects = true; - nearest.dist_first = dist; - nearest.ip_first = isect.p; - nearest.item = obs.item; - nearest.hull = hull; - } - - if(dist > dist_max) - { - dist_max = dist; - ip_last = isect.p; - } - } - } - - isect_list.clear(); - - hull.Intersect(aLine.GetCLine(), isect_list); - - BOOST_FOREACH(SHAPE_LINE_CHAIN::Intersection isect, isect_list) - { - - int dist = aLine.GetCLine().PathLength(isect.p); - - if(dist < nearest.dist_first) - { - found_isects = true; - nearest.dist_first = dist; - nearest.ip_first = isect.p; - nearest.item = obs.item; - nearest.hull = hull; - } - - if(dist > dist_max) - { - dist_max = dist; - ip_last = isect.p; - } - - } - - nearest.ip_last = ip_last; - nearest.dist_last = dist_max; - } - - return found_isects ? nearest : OptObstacle(); + return aObstacles.size(); } -PNS_NODE::OptObstacle PNS_NODE::CheckColliding( const PNS_ITEM *aItemA, int aKindMask ) + +PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKindMask ) { - Obstacles obs; - obs.reserve(100); + Obstacles obs_list; + bool found_isects = false; - if(aItemA->GetKind() == PNS_ITEM::LINE) - { - int n = 0; - const PNS_LINE *line = static_cast(aItemA); - const SHAPE_LINE_CHAIN &l = line->GetCLine(); + const SHAPE_LINE_CHAIN& line = aItem->GetCLine(); - for(int i = 0; i < l.SegmentCount(); i++) - { - const PNS_SEGMENT s ( *line, l.CSegment(i)); - n += QueryColliding ( &s, obs, aKindMask, 1 ); - if(n) - return OptObstacle(obs[0]); - } - - if( line->EndsWithVia () ) - { - n += QueryColliding ( &line->GetVia(), obs, aKindMask, 1 ); - if(n) - return OptObstacle(obs[0]); - } + obs_list.reserve( 100 ); - } else if (QueryColliding(aItemA, obs, aKindMask, 1) > 0) - return OptObstacle(obs[0]); - return OptObstacle(); + int n = 0; + + for( int i = 0; i < line.SegmentCount(); i++ ) + { + const PNS_SEGMENT s( *aItem, line.CSegment( i ) ); + n += QueryColliding( &s, obs_list, aKindMask ); + } + + if( aItem->EndsWithVia() ) + n += QueryColliding( &aItem->GetVia(), obs_list, aKindMask ); + + // if(! QueryColliding ( aItem, obs_list, aKindMask )) + if( !n ) + return OptObstacle(); + + PNS_LINE& aLine = (PNS_LINE&) *aItem; + + PNS_OBSTACLE nearest; + nearest.item = NULL; + nearest.dist_first = INT_MAX; + + BOOST_FOREACH( PNS_OBSTACLE obs, obs_list ) + { + VECTOR2I ip_first, ip_last; + int dist_max = INT_MIN; + + vector isect_list; + + int clearance = GetClearance( obs.item, &aLine ); + + SHAPE_LINE_CHAIN hull = obs.item->Hull( clearance ); + + if( aLine.EndsWithVia() ) + { + int clearance = GetClearance( obs.item, &aLine.GetVia() ); + + SHAPE_LINE_CHAIN viaHull = aLine.GetVia().Hull( clearance ); + + viaHull.Intersect( hull, isect_list ); + + BOOST_FOREACH( SHAPE_LINE_CHAIN::Intersection isect, isect_list ) + { + int dist = aLine.GetCLine().Length() + + ( isect.p - aLine.GetVia().GetPos() ).EuclideanNorm(); + + if( dist < nearest.dist_first ) + { + found_isects = true; + nearest.dist_first = dist; + nearest.ip_first = isect.p; + nearest.item = obs.item; + nearest.hull = hull; + } + + if( dist > dist_max ) + { + dist_max = dist; + ip_last = isect.p; + } + } + } + + isect_list.clear(); + + hull.Intersect( aLine.GetCLine(), isect_list ); + + BOOST_FOREACH( SHAPE_LINE_CHAIN::Intersection isect, isect_list ) + { + int dist = aLine.GetCLine().PathLength( isect.p ); + + if( dist < nearest.dist_first ) + { + found_isects = true; + nearest.dist_first = dist; + nearest.ip_first = isect.p; + nearest.item = obs.item; + nearest.hull = hull; + } + + if( dist > dist_max ) + { + dist_max = dist; + ip_last = isect.p; + } + } + + nearest.ip_last = ip_last; + nearest.dist_last = dist_max; + } + + return found_isects ? nearest : OptObstacle(); } -bool PNS_NODE::CheckColliding( const PNS_ITEM *aItemA, const PNS_ITEM *aItemB, int aKindMask ) + +PNS_NODE::OptObstacle PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, int aKindMask ) { - Obstacles dummy; + Obstacles obs; - assert(aItemB); - // return QueryColliding(aItemA, dummy, aKindMask, 1) > 0; + obs.reserve( 100 ); - return aItemA->Collide(aItemB, GetClearance(aItemA, aItemB)); + if( aItemA->GetKind() == PNS_ITEM::LINE ) + { + int n = 0; + const PNS_LINE* line = static_cast(aItemA); + const SHAPE_LINE_CHAIN& l = line->GetCLine(); + + for( int i = 0; i < l.SegmentCount(); i++ ) + { + const PNS_SEGMENT s( *line, l.CSegment( i ) ); + n += QueryColliding( &s, obs, aKindMask, 1 ); + + if( n ) + return OptObstacle( obs[0] ); + } + + if( line->EndsWithVia() ) + { + n += QueryColliding( &line->GetVia(), obs, aKindMask, 1 ); + + if( n ) + return OptObstacle( obs[0] ); + } + } + else if( QueryColliding( aItemA, obs, aKindMask, 1 ) > 0 ) + return OptObstacle( obs[0] ); + + return OptObstacle(); } -struct hitVisitor { - PNS_ITEMSET& m_items; - const VECTOR2I& m_point; - PNS_NODE *m_world; - hitVisitor( PNS_ITEMSET& aTab, - const VECTOR2I& aPoint, - PNS_NODE *aWorld ) - : m_items(aTab), m_point(aPoint), m_world(aWorld) { }; +bool PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, const PNS_ITEM* aItemB, int aKindMask ) +{ + Obstacles dummy; - bool operator()( PNS_ITEM *aItem ) { - SHAPE_CIRCLE cp (m_point, 0); + assert( aItemB ); + // return QueryColliding(aItemA, dummy, aKindMask, 1) > 0; + + return aItemA->Collide( aItemB, GetClearance( aItemA, aItemB ) ); +} + + +struct hitVisitor +{ + PNS_ITEMSET& m_items; + const VECTOR2I& m_point; + PNS_NODE* m_world; + + hitVisitor( PNS_ITEMSET& aTab, const VECTOR2I& aPoint, PNS_NODE* aWorld ) : + m_items( aTab ), m_point( aPoint ), m_world( aWorld ) {}; + + bool operator()( PNS_ITEM* aItem ) + { + SHAPE_CIRCLE cp( m_point, 0 ); + + int cl = 0; + + if( aItem->GetKind() == PNS_ITEM::SEGMENT ) + cl += static_cast(aItem)->GetWidth() / 2; + + if( aItem->GetShape()->Collide( &cp, cl ) ) + m_items.Add( aItem ); + + return true; + } +}; - int cl = 0; - if(aItem->GetKind() == PNS_ITEM::SEGMENT) - cl += static_cast(aItem)->GetWidth() / 2; - - if(aItem->GetShape()->Collide(&cp, cl)) - m_items.Add(aItem); - return true; - } -}; const PNS_ITEMSET PNS_NODE::HitTest( const VECTOR2I& aPoint ) { - PNS_ITEMSET items; - SHAPE_CIRCLE s (aPoint, 0); // fixme: we treat a point as an infinitely small circle - this is inefficient. - hitVisitor visitor ( items, aPoint, this ); - - m_index->Query(&s, m_maxClearance, visitor); - - if( ! isRoot() ) // fixme: could be made cleaner - { - PNS_ITEMSET items_root; - hitVisitor visitor_root ( items_root, aPoint, m_root ); - m_root->m_index->Query( &s, m_maxClearance, visitor_root ); + PNS_ITEMSET items; + // fixme: we treat a point as an infinitely small circle - this is inefficient. + SHAPE_CIRCLE s( aPoint, 0 ); + hitVisitor visitor( items, aPoint, this ); - BOOST_FOREACH(PNS_ITEM *item, items_root.Items()) - { - if (!overrides(item)) - items.Add(item); - } - } + m_index->Query( &s, m_maxClearance, visitor ); - return items; -} + if( !isRoot() ) // fixme: could be made cleaner + { + PNS_ITEMSET items_root; + hitVisitor visitor_root( items_root, aPoint, m_root ); + m_root->m_index->Query( &s, m_maxClearance, visitor_root ); -void PNS_NODE::addSolid(PNS_SOLID *aSolid) -{ - linkJoint( aSolid->GetCenter(), aSolid->GetLayers(), aSolid->GetNet(), aSolid ); - m_index->Add(aSolid); -} + BOOST_FOREACH( PNS_ITEM * item, items_root.Items() ) + { + if( !overrides( item ) ) + items.Add( item ); + } + } -void PNS_NODE::addVia(PNS_VIA *aVia) -{ - linkJoint( aVia->GetPos(), aVia->GetLayers(), aVia->GetNet(), aVia ); - m_index->Add(aVia); -} - -void PNS_NODE::addLine( PNS_LINE *aLine ) -{ - const SHAPE_LINE_CHAIN& l = aLine->GetLine(); - - for(int i = 0; i < l.SegmentCount(); i++) - { - SEG s = l.CSegment(i); - - if(s.a != s.b) - { - PNS_SEGMENT *pseg = new PNS_SEGMENT(*aLine, s); - - pseg->SetOwner(this); - - linkJoint( s.a, pseg->GetLayers(), aLine->GetNet(), pseg ); - linkJoint( s.b, pseg->GetLayers(), aLine->GetNet(), pseg ); - - aLine->LinkSegment(pseg); - - m_index->Add(pseg); - } - } -} - -void PNS_NODE::addSegment( PNS_SEGMENT *aSeg ) -{ - if(aSeg->GetSeg().a == aSeg->GetSeg().b) - { - TRACEn(0, "attempting to add a segment with same end coordinates, ignoring.") - return; - } - - aSeg->SetOwner (this); - - linkJoint( aSeg->GetSeg().a, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); - linkJoint( aSeg->GetSeg().b, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); - - m_index->Add(aSeg); -} - -void PNS_NODE::Add(PNS_ITEM* aItem) -{ - - aItem->SetOwner(this); - - switch(aItem -> GetKind()) - { - case PNS_ITEM::SOLID: - addSolid(static_cast(aItem)); - break; - - case PNS_ITEM::SEGMENT: - addSegment(static_cast(aItem)); - break; - - case PNS_ITEM::LINE: - addLine( static_cast (aItem)); - break; - - case PNS_ITEM::VIA: - addVia (static_cast(aItem)); - break; - - default: - assert (false); - } -} - - -void PNS_NODE::doRemove ( PNS_ITEM *aItem ) -{ - // case 1: removing an item that is stored in the root node from any branch: mark it as overridden, but do not remove - if( aItem->BelongsTo(m_root) && !isRoot() ) - m_override.insert(aItem); - - // case 2: the item belongs to this branch or a parent, non-root branch, or the root itself and we are the root: remove from the index - else if( !aItem->BelongsTo(m_root) || isRoot() ) - m_index->Remove( aItem ); - - // the item belongs to this particular branch: un-reference it - if( aItem->BelongsTo( this )) - aItem->SetOwner(NULL); -} - -void PNS_NODE::removeSegment (PNS_SEGMENT *aSeg ) -{ - unlinkJoint(aSeg->GetSeg().a, aSeg->GetLayers(), aSeg->GetNet(), aSeg); - unlinkJoint(aSeg->GetSeg().b, aSeg->GetLayers(), aSeg->GetNet(), aSeg); - - doRemove(aSeg); -} - -void PNS_NODE::removeLine( PNS_LINE *aLine ) -{ - vector *segRefs = aLine->GetLinkedSegments(); - - if(!segRefs) - return; - - assert ( aLine->GetOwner () ); - - BOOST_FOREACH(PNS_SEGMENT *seg, *segRefs) - { - removeSegment(seg); - } - - aLine->SetOwner(NULL); -} - -void PNS_NODE::removeVia ( PNS_VIA *aVia ) -{ - unlinkJoint(aVia->GetPos(), aVia->GetLayers(), aVia->GetNet(), aVia); - - doRemove(aVia); -} - -void PNS_NODE::Replace(PNS_ITEM *aOldItem, PNS_ITEM *aNewItem) -{ - Remove(aOldItem); - Add(aNewItem); -} - -void PNS_NODE::Remove(PNS_ITEM *aItem) -{ - - switch(aItem -> GetKind()) - { - case PNS_ITEM::SOLID: - assert(false); - break; - case PNS_ITEM::SEGMENT: - removeSegment(static_cast(aItem)); - break; - case PNS_ITEM::LINE: - removeLine(static_cast(aItem)); - break; - case PNS_ITEM::VIA: - removeVia(static_cast(aItem)); - break; - - default: - break; - } -} - -void PNS_NODE::followLine(PNS_SEGMENT *current, bool scanDirection, int& pos, int limit, VECTOR2I *corners, PNS_SEGMENT **segments) -{ - bool prevReversed = false; - - for(;;) - { - const VECTOR2I p = (scanDirection ^ prevReversed) ? current->GetSeg().b : current->GetSeg().a; - const OptJoint jt = FindJoint(p, current->GetLayer(), current->GetNet()); - - assert (jt); - assert (pos > 0 && pos < limit); - - corners [pos] = jt->GetPos(); - segments [pos] = current; - - pos += (scanDirection ? 1 : -1); - - if(!jt->IsLineCorner()) - break; - - current = jt->NextSegment( current ); - prevReversed = (jt->GetPos() == (scanDirection ? current->GetSeg().b : current->GetSeg().a )); - } -} - -PNS_LINE *PNS_NODE::AssembleLine(PNS_SEGMENT *aSeg, const OptJoint& a, const OptJoint& b) -{ - const int MaxVerts = 1024; - - VECTOR2I corners [ MaxVerts + 1 ]; - PNS_SEGMENT *segs [ MaxVerts + 1 ]; - - PNS_LINE *pl = new PNS_LINE; - int i_start = MaxVerts/2, i_end = i_start + 1; - - pl->SetWidth( aSeg->GetWidth() ); - pl->SetLayers( aSeg->GetLayers() ); - pl->SetNet ( aSeg->GetNet() ); - pl->SetOwner(this); - - //pl->LinkSegment(aSeg); - - followLine (aSeg, false, i_start, MaxVerts, corners, segs ); - followLine (aSeg, true, i_end, MaxVerts, corners, segs ); - - - int clip_start = -1, clip_end = -1; - for(int i = i_start+1 ; i < i_end ; i++) - { - const VECTOR2I &p = corners[i]; - - if (a && (p == a->GetPos() || p == b->GetPos() ) ) - { - clip_start = std::min(clip_start, i); - clip_end = std::max(clip_end, i); - } - - pl->GetLine().Append(p); - if(segs[i-1] != segs[i]) - pl->LinkSegment(segs[i]); - } - - return pl; -} - -void PNS_NODE::FindLineEnds (PNS_LINE *aLine, PNS_JOINT& a, PNS_JOINT& b ) -{ - a = *FindJoint(aLine->GetCLine().CPoint(0), aLine->GetLayers().Start(), aLine->GetNet()); - b = *FindJoint(aLine->GetCLine().CPoint(-1), aLine->GetLayers().Start(), aLine->GetNet()); + return items; } -int PNS_NODE::FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b, vector &aLines ) +void PNS_NODE::addSolid( PNS_SOLID* aSolid ) { - BOOST_FOREACH(PNS_ITEM *item, a.GetLinkList()) - { - if(item->GetKind() == PNS_ITEM::SEGMENT) - { - PNS_SEGMENT *seg = static_cast(item); - PNS_LINE *line = AssembleLine(seg); - - PNS_JOINT j_start, j_end; - FindLineEnds( line, j_start, j_end ); - if( (j_start == a && j_end == b )|| (j_end == a && j_start == b)) - aLines.push_back(line); - else - delete line; - } - } - return 0; + linkJoint( aSolid->GetCenter(), aSolid->GetLayers(), aSolid->GetNet(), aSolid ); + m_index->Add( aSolid ); } -const PNS_NODE::OptJoint PNS_NODE::FindJoint(const VECTOR2I &aPos, int aLayer, int aNet ) + +void PNS_NODE::addVia( PNS_VIA* aVia ) { - PNS_JOINT::HashTag tag; - - tag.net = aNet; - tag.pos = aPos; - - JointMap::iterator f = m_joints.find(tag), end = m_joints.end(); - - if(f == end && !isRoot()) - { - end = m_root->m_joints.end(); - f = m_root->m_joints.find(tag); //m_root->FindJoint(aPos, aLayer, aNet); - } - - if(f == end) - return OptJoint(); - - while (f != end) - { - if(f->second.GetLayers().Overlaps(aLayer)) - return f->second; - ++f; - } - return OptJoint(); + linkJoint( aVia->GetPos(), aVia->GetLayers(), aVia->GetNet(), aVia ); + m_index->Add( aVia ); } + +void PNS_NODE::addLine( PNS_LINE* aLine ) +{ + const SHAPE_LINE_CHAIN& l = aLine->GetLine(); + + for( int i = 0; i < l.SegmentCount(); i++ ) + { + SEG s = l.CSegment( i ); + + if( s.a != s.b ) + { + PNS_SEGMENT* pseg = new PNS_SEGMENT( *aLine, s ); + + pseg->SetOwner( this ); + + linkJoint( s.a, pseg->GetLayers(), aLine->GetNet(), pseg ); + linkJoint( s.b, pseg->GetLayers(), aLine->GetNet(), pseg ); + + aLine->LinkSegment( pseg ); + + m_index->Add( pseg ); + } + } +} + + +void PNS_NODE::addSegment( PNS_SEGMENT* aSeg ) +{ + if( aSeg->GetSeg().a == aSeg->GetSeg().b ) + { + TRACEn( 0, "attempting to add a segment with same end coordinates, ignoring." ) + return; + } + + aSeg->SetOwner( this ); + + linkJoint( aSeg->GetSeg().a, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); + linkJoint( aSeg->GetSeg().b, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); + + m_index->Add( aSeg ); +} + + +void PNS_NODE::Add( PNS_ITEM* aItem ) +{ + aItem->SetOwner( this ); + + switch( aItem->GetKind() ) + { + case PNS_ITEM::SOLID: + addSolid( static_cast( aItem ) ); + break; + + case PNS_ITEM::SEGMENT: + addSegment( static_cast( aItem ) ); + break; + + case PNS_ITEM::LINE: + addLine( static_cast (aItem) ); + break; + + case PNS_ITEM::VIA: + addVia( static_cast(aItem) ); + break; + + default: + assert( false ); + } +} + + +void PNS_NODE::doRemove( PNS_ITEM* aItem ) +{ + // case 1: removing an item that is stored in the root node from any branch: + // mark it as overridden, but do not remove + if( aItem->BelongsTo( m_root ) && !isRoot() ) + m_override.insert( aItem ); + + // case 2: the item belongs to this branch or a parent, non-root branch, + // or the root itself and we are the root: remove from the index + else if( !aItem->BelongsTo( m_root ) || isRoot() ) + m_index->Remove( aItem ); + + // the item belongs to this particular branch: un-reference it + if( aItem->BelongsTo( this ) ) + aItem->SetOwner( NULL ); +} + + +void PNS_NODE::removeSegment( PNS_SEGMENT* aSeg ) +{ + unlinkJoint( aSeg->GetSeg().a, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); + unlinkJoint( aSeg->GetSeg().b, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); + + doRemove( aSeg ); +} + + +void PNS_NODE::removeLine( PNS_LINE* aLine ) +{ + vector* segRefs = aLine->GetLinkedSegments(); + + if( !segRefs ) + return; + + assert( aLine->GetOwner() ); + + BOOST_FOREACH( PNS_SEGMENT* seg, *segRefs ) + { + removeSegment( seg ); + } + + aLine->SetOwner( NULL ); +} + + +void PNS_NODE::removeVia( PNS_VIA* aVia ) +{ + unlinkJoint( aVia->GetPos(), aVia->GetLayers(), aVia->GetNet(), aVia ); + + doRemove( aVia ); +} + + +void PNS_NODE::Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ) +{ + Remove( aOldItem ); + Add( aNewItem ); +} + + +void PNS_NODE::Remove( PNS_ITEM* aItem ) +{ + switch( aItem->GetKind() ) + { + case PNS_ITEM::SOLID: + assert( false ); + break; + + case PNS_ITEM::SEGMENT: + removeSegment( static_cast( aItem ) ); + break; + + case PNS_ITEM::LINE: + removeLine( static_cast( aItem ) ); + break; + + case PNS_ITEM::VIA: + removeVia( static_cast( aItem ) ); + break; + + default: + break; + } +} + + +void PNS_NODE::followLine( PNS_SEGMENT* current, bool scanDirection, int& pos, + int limit, VECTOR2I* corners, PNS_SEGMENT** segments ) +{ + bool prevReversed = false; + + for( ; ; ) + { + const VECTOR2I p = + (scanDirection ^ prevReversed) ? current->GetSeg().b : current->GetSeg().a; + const OptJoint jt = FindJoint( p, current->GetLayer(), current->GetNet() ); + + assert( jt ); + assert( pos > 0 && pos < limit ); + + corners[pos] = jt->GetPos(); + segments[pos] = current; + + pos += (scanDirection ? 1 : -1); + + if( !jt->IsLineCorner() ) + break; + + current = jt->NextSegment( current ); + prevReversed = + ( jt->GetPos() == (scanDirection ? current->GetSeg().b : current->GetSeg().a ) ); + } +} + + +PNS_LINE* PNS_NODE::AssembleLine( PNS_SEGMENT* aSeg, const OptJoint& a, const OptJoint& b ) +{ + const int MaxVerts = 1024; + + VECTOR2I corners[MaxVerts + 1]; + PNS_SEGMENT* segs[MaxVerts + 1]; + + PNS_LINE* pl = new PNS_LINE; + int i_start = MaxVerts / 2, i_end = i_start + 1; + + pl->SetWidth( aSeg->GetWidth() ); + pl->SetLayers( aSeg->GetLayers() ); + pl->SetNet( aSeg->GetNet() ); + pl->SetOwner( this ); + + // pl->LinkSegment(aSeg); + + followLine( aSeg, false, i_start, MaxVerts, corners, segs ); + followLine( aSeg, true, i_end, MaxVerts, corners, segs ); + + + int clip_start = -1, clip_end = -1; + + for( int i = i_start + 1; i < i_end; i++ ) + { + const VECTOR2I& p = corners[i]; + + if( a && ( p == a->GetPos() || p == b->GetPos() ) ) + { + clip_start = std::min( clip_start, i ); + clip_end = std::max( clip_end, i ); + } + + pl->GetLine().Append( p ); + + if( segs[i - 1] != segs[i] ) + pl->LinkSegment( segs[i] ); + } + + return pl; +} + + +void PNS_NODE::FindLineEnds( PNS_LINE* aLine, PNS_JOINT& a, PNS_JOINT& b ) +{ + a = *FindJoint( aLine->GetCLine().CPoint( 0 ), aLine->GetLayers().Start(), aLine->GetNet() ); + b = *FindJoint( aLine->GetCLine().CPoint( -1 ), aLine->GetLayers().Start(), aLine->GetNet() ); +} + + +int PNS_NODE::FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b, vector& aLines ) +{ + BOOST_FOREACH( PNS_ITEM * item, a.GetLinkList() ) + { + if( item->GetKind() == PNS_ITEM::SEGMENT ) + { + PNS_SEGMENT* seg = static_cast(item); + PNS_LINE* line = AssembleLine( seg ); + + PNS_JOINT j_start, j_end; + FindLineEnds( line, j_start, j_end ); + + if( (j_start == a && j_end == b )|| (j_end == a && j_start == b) ) + aLines.push_back( line ); + else + delete line; + } + } + + return 0; +} + + +const PNS_NODE::OptJoint PNS_NODE::FindJoint( const VECTOR2I& aPos, int aLayer, int aNet ) +{ + PNS_JOINT::HashTag tag; + + tag.net = aNet; + tag.pos = aPos; + + JointMap::iterator f = m_joints.find( tag ), end = m_joints.end(); + + if( f == end && !isRoot() ) + { + end = m_root->m_joints.end(); + f = m_root->m_joints.find( tag ); // m_root->FindJoint(aPos, aLayer, aNet); + } + + if( f == end ) + return OptJoint(); + + while( f != end ) + { + if( f->second.GetLayers().Overlaps( aLayer ) ) + return f->second; + + ++f; + } + + return OptJoint(); +} + + PNS_JOINT& PNS_NODE::touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet ) { - PNS_JOINT::HashTag tag; - - tag.pos = aPos; - tag.net = aNet; + PNS_JOINT::HashTag tag; - // try to find the joint in this node. - JointMap::iterator f = m_joints.find(tag); + tag.pos = aPos; + tag.net = aNet; - pair range; - - // not found and we are not root? find in the root and copy results here. - if(f == m_joints.end() && !isRoot()) - { - range = m_root->m_joints.equal_range(tag); - for( f = range.first; f != range.second; ++f) - m_joints.insert( *f ); - } + // try to find the joint in this node. + JointMap::iterator f = m_joints.find( tag ); - // now insert and combine overlapping joints - PNS_JOINT jt (aPos, aLayers, aNet); + pair range; - bool merged; + // not found and we are not root? find in the root and copy results here. + if( f == m_joints.end() && !isRoot() ) + { + range = m_root->m_joints.equal_range( tag ); - do - { - merged = false; - range = m_joints.equal_range(tag); + for( f = range.first; f != range.second; ++f ) + m_joints.insert( *f ); + } - if(range.first == m_joints.end()) - break; + // now insert and combine overlapping joints + PNS_JOINT jt( aPos, aLayers, aNet ); - for(f = range.first; f != range.second; ++f) - { - if(aLayers.Overlaps (f->second.GetLayers())) - { - jt.Merge(f->second); - m_joints.erase(f); - merged = true; - break; - } - } - } while (merged); - - return m_joints.insert ( TagJointPair(tag, jt) )->second; + bool merged; + + do + { + merged = false; + range = m_joints.equal_range( tag ); + + if( range.first == m_joints.end() ) + break; + + for( f = range.first; f != range.second; ++f ) + { + if( aLayers.Overlaps( f->second.GetLayers() ) ) + { + jt.Merge( f->second ); + m_joints.erase( f ); + merged = true; + break; + } + } + } while( merged ); + + return m_joints.insert( TagJointPair( tag, jt ) )->second; } + void PNS_JOINT::Dump() const { - printf("joint layers %d-%d, net %d, pos %s, links: %d\n", m_layers.Start(), m_layers.End(), m_tag.net, m_tag.pos.Format().c_str(), LinkCount() ); + printf( "joint layers %d-%d, net %d, pos %s, links: %d\n", m_layers.Start(), + m_layers.End(), m_tag.net, m_tag.pos.Format().c_str(), LinkCount() ); } - -void PNS_NODE::linkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet, PNS_ITEM *aWhere ) + +void PNS_NODE::linkJoint( const VECTOR2I& aPos, + const PNS_LAYERSET& aLayers, + int aNet, + PNS_ITEM* aWhere ) { - PNS_JOINT& jt = touchJoint( aPos, aLayers, aNet ); - jt.Link(aWhere); + PNS_JOINT& jt = touchJoint( aPos, aLayers, aNet ); + + jt.Link( aWhere ); } -void PNS_NODE::unlinkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet, PNS_ITEM *aWhere ) + +void PNS_NODE::unlinkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, + int aNet, PNS_ITEM* aWhere ) { - // fixme: remove dangling joints - PNS_JOINT& jt = touchJoint( aPos, aLayers, aNet ); - jt.Unlink(aWhere); + // fixme: remove dangling joints + PNS_JOINT& jt = touchJoint( aPos, aLayers, aNet ); + + jt.Unlink( aWhere ); } -void PNS_NODE::Dump(bool aLong) +void PNS_NODE::Dump( bool aLong ) { #if 0 - boost::unordered_set all_segs; - SHAPE_INDEX_LIST::iterator i; + boost::unordered_set all_segs; + SHAPE_INDEX_LIST::iterator i; - for(i = m_items.begin(); i != m_items.end() ; i++) - { - if((*i)->GetKind() == PNS_ITEM::SEGMENT) - all_segs.insert(static_cast(*i)); - } + for( i = m_items.begin(); i != m_items.end(); i++ ) + { + if( (*i)->GetKind() == PNS_ITEM::SEGMENT ) + all_segs.insert( static_cast(*i) ); + } - if(!isRoot()) - for(i = m_root->m_items.begin(); i != m_root->m_items.end() ; i++) - { - if((*i)->GetKind() == PNS_ITEM::SEGMENT && !overrides(*i)) - all_segs.insert(static_cast(*i)); - } + if( !isRoot() ) + for( i = m_root->m_items.begin(); i != m_root->m_items.end(); i++ ) + { + if( (*i)->GetKind() == PNS_ITEM::SEGMENT && !overrides( *i ) ) + all_segs.insert( static_cast(*i) ); + } - - JointMap::iterator j; - if(aLong) - for(j=m_joints.begin(); j!=m_joints.end(); ++j) - { - printf("joint : %s, links : %d\n", j->second.GetPos().Format().c_str(), j->second.LinkCount()); - PNS_JOINT::LinkedItems::const_iterator k; - for(k = j->second.GetLinkList().begin(); k != j->second.GetLinkList().end(); ++k) - { - const PNS_ITEM *item = *k; + JointMap::iterator j; - switch(item->GetKind()) - { - case PNS_ITEM::SEGMENT: - { - const PNS_SEGMENT *seg = static_cast(item); - printf(" -> seg %s %s\n", seg->GetSeg().a.Format().c_str(), seg->GetSeg().b.Format().c_str()); - break; - } - default: - break; - } - } - } - - int lines_count = 0; - while(!all_segs.empty()) - { - PNS_SEGMENT *s = *all_segs.begin(); - PNS_LINE *l = AssembleLine(s); - - PNS_LINE::LinkedSegments* seg_refs = l->GetLinkedSegments(); - - if(aLong) - printf("Line: %s, net %d ", l->GetLine().Format().c_str(), l->GetNet() ); - - - for(vector::iterator j = seg_refs->begin(); j != seg_refs->end(); ++j) - { - printf("%s ", (*j)->GetSeg().a.Format().c_str() ); - if(j+1 == seg_refs->end()) - printf("%s\n", (*j)->GetSeg().b.Format().c_str() ); - all_segs.erase(*j); - } - lines_count++; - } - - printf("Local joints: %d, lines : %d \n", m_joints.size(), lines_count); + if( aLong ) + for( j = m_joints.begin(); j!=m_joints.end(); ++j ) + { + printf( "joint : %s, links : %d\n", + j->second.GetPos().Format().c_str(), j->second.LinkCount() ); + PNS_JOINT::LinkedItems::const_iterator k; + + for( k = j->second.GetLinkList().begin(); k != j->second.GetLinkList().end(); ++k ) + { + const PNS_ITEM* item = *k; + + switch( item->GetKind() ) + { + case PNS_ITEM::SEGMENT: + { + const PNS_SEGMENT* seg = static_cast(item); + printf( " -> seg %s %s\n", seg->GetSeg().a.Format().c_str(), + seg->GetSeg().b.Format().c_str() ); + break; + } + + default: + break; + } + } + } + + + + int lines_count = 0; + + while( !all_segs.empty() ) + { + PNS_SEGMENT* s = *all_segs.begin(); + PNS_LINE* l = AssembleLine( s ); + + PNS_LINE::LinkedSegments* seg_refs = l->GetLinkedSegments(); + + if( aLong ) + printf( "Line: %s, net %d ", l->GetLine().Format().c_str(), l->GetNet() ); + + + for( vector::iterator j = seg_refs->begin(); j != seg_refs->end(); ++j ) + { + printf( "%s ", (*j)->GetSeg().a.Format().c_str() ); + + if( j + 1 == seg_refs->end() ) + printf( "%s\n", (*j)->GetSeg().b.Format().c_str() ); + + all_segs.erase( *j ); + } + + lines_count++; + } + + printf( "Local joints: %d, lines : %d \n", m_joints.size(), lines_count ); #endif } -void PNS_NODE::GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded) + +void PNS_NODE::GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded ) { - aRemoved.reserve(m_override.size()); - aAdded.reserve(m_index->Size()); + aRemoved.reserve( m_override.size() ); + aAdded.reserve( m_index->Size() ); - if(isRoot ()) - return; + if( isRoot() ) + return; - BOOST_FOREACH(PNS_ITEM *item, m_override) - aRemoved.push_back(item); - - for(PNS_INDEX::ItemSet::iterator i = m_index->begin(); i!=m_index->end(); ++i) - aAdded.push_back(*i); + BOOST_FOREACH( PNS_ITEM * item, m_override ) + aRemoved.push_back( item ); + + for( PNS_INDEX::ItemSet::iterator i = m_index->begin(); i!=m_index->end(); ++i ) + aAdded.push_back( *i ); } -void PNS_NODE::releaseChildren () -{ - // copy the kids as the PNS_NODE destructor erases the item from the parent node. - vector kids = m_children; - BOOST_FOREACH(PNS_NODE *node, kids) - { - node->releaseChildren(); - delete node; - } +void PNS_NODE::releaseChildren() +{ + // copy the kids as the PNS_NODE destructor erases the item from the parent node. + vector kids = m_children; + + BOOST_FOREACH( PNS_NODE * node, kids ) { + node->releaseChildren(); + delete node; + } } -void PNS_NODE::Commit( PNS_NODE *aNode ) + +void PNS_NODE::Commit( PNS_NODE* aNode ) { + if( aNode->isRoot() ) + return; - if(aNode->isRoot()) - return; + BOOST_FOREACH( PNS_ITEM * item, aNode->m_override ) + Remove( item ); - BOOST_FOREACH( PNS_ITEM *item, aNode->m_override ) - Remove(item); + for( PNS_INDEX::ItemSet::iterator i = aNode->m_index->begin(); + i != aNode->m_index->end(); ++i ) + Add( *i ); - for(PNS_INDEX::ItemSet::iterator i = aNode->m_index->begin(); i!= aNode ->m_index->end(); ++i) - Add(*i); - - releaseChildren(); + releaseChildren(); } + void PNS_NODE::KillChildren() { - assert (isRoot()); + assert( isRoot() ); - releaseChildren(); + releaseChildren(); } - -void PNS_NODE::AllItemsInNet ( int aNet, std::list& aItems) +void PNS_NODE::AllItemsInNet( int aNet, std::list& aItems ) { - PNS_INDEX::NetItemsList* l_cur = m_index->GetItemsForNet ( aNet ); + PNS_INDEX::NetItemsList* l_cur = m_index->GetItemsForNet( aNet ); - if(!l_cur) - return; + if( !l_cur ) + return; - std::copy(aItems.begin(), l_cur->begin(), l_cur->end() ); - if( !isRoot () ) - { - PNS_INDEX::NetItemsList* l_root = m_root->m_index->GetItemsForNet ( aNet ); + std::copy( aItems.begin(), l_cur->begin(), l_cur->end() ); - for(PNS_INDEX::NetItemsList::iterator i = l_root->begin(); i!= l_root->end(); ++i) - if( !overrides( *i )) - aItems.push_back(*i); - } + if( !isRoot() ) + { + PNS_INDEX::NetItemsList* l_root = m_root->m_index->GetItemsForNet( aNet ); + + for( PNS_INDEX::NetItemsList::iterator i = l_root->begin(); i!= l_root->end(); ++i ) + if( !overrides( *i ) ) + aItems.push_back( *i ); + + + } } + diff --git a/pcbnew/router/pns_node.h b/pcbnew/router/pns_node.h index 25056cbd02..67debc3b9f 100644 --- a/pcbnew/router/pns_node.h +++ b/pcbnew/router/pns_node.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -45,9 +45,10 @@ class PNS_INDEX; using boost::shared_ptr; -class PNS_CLEARANCE_FUNC { - public: - virtual int operator() ( const PNS_ITEM *a , const PNS_ITEM *b) = 0; +class PNS_CLEARANCE_FUNC +{ +public: + virtual int operator()( const PNS_ITEM* a, const PNS_ITEM* b ) = 0; }; /** @@ -56,205 +57,225 @@ class PNS_CLEARANCE_FUNC { * Holds an object colliding with another object, along with * some useful data about the collision. **/ -struct PNS_OBSTACLE +struct PNS_OBSTACLE { - ///> Item we search collisions with - PNS_ITEM *head; - - ///> Item found to be colliding with head - PNS_ITEM *item; + ///> Item we search collisions with + PNS_ITEM* head; - ///> Hull of the colliding item - SHAPE_LINE_CHAIN hull; - - ///> First and last intersection point between the head item and the hull of the - //// colliding item - VECTOR2I ip_first, ip_last; - - ///> ... and the distance thereof - int dist_first, dist_last; + ///> Item found to be colliding with head + PNS_ITEM* item; + + ///> Hull of the colliding item + SHAPE_LINE_CHAIN hull; + + ///> First and last intersection point between the head item and the hull + ///> of the colliding item + VECTOR2I ip_first, ip_last; + + ///> ... and the distance thereof + int dist_first, dist_last; }; /** * Class PNS_NODE * - * Keeps the router "world" - i.e. all the tracks, vias, solids in a hierarchical and indexed way. + * Keeps the router "world" - i.e. all the tracks, vias, solids in a + * hierarchical and indexed way. * Features: * - spatial-indexed container for PCB item shapes * - collision search (with clearance checking) * - assembly of lines connecting joints, finding loops and unique paths - * - lightweight cloning/branching (for recursive optimization and shove springback) + * - lightweight cloning/branching (for recursive optimization and shove + * springback) **/ -class PNS_NODE { - +class PNS_NODE +{ public: - - typedef boost::optional OptObstacle; - typedef std::vector ItemVector; - typedef std::vector Obstacles; - typedef boost::optional OptJoint; + typedef boost::optional OptObstacle; + typedef std::vector ItemVector; + typedef std::vector Obstacles; + typedef boost::optional OptJoint; - PNS_NODE (); - ~PNS_NODE (); + PNS_NODE(); + ~PNS_NODE(); - ///> Returns the expected clearance between items a and b. - int GetClearance(const PNS_ITEM *a, const PNS_ITEM *b) const; - - ///> Returns the pre-set worst case clearance between any pair of items - int GetMaxClearance() const - { - return m_maxClearance; - } + ///> Returns the expected clearance between items a and b. + int GetClearance( const PNS_ITEM* a, const PNS_ITEM* b ) const; - void SetMaxClearance( int aClearance ) - { - m_maxClearance = aClearance; - } + ///> Returns the pre-set worst case clearance between any pair of items + int GetMaxClearance() const + { + return m_maxClearance; + } - void SetClearanceFunctor (PNS_CLEARANCE_FUNC *aFunc) - { - m_clearanceFunctor = aFunc; - } + void SetMaxClearance( int aClearance ) + { + m_maxClearance = aClearance; + } - ///> Finds items that collide with aItem and stores collision information in aObstacles. - int QueryColliding( const PNS_ITEM* aItem, Obstacles& aObstacles, int aKindMask = PNS_ITEM::ANY, int aLimitCount = -1); + void SetClearanceFunctor( PNS_CLEARANCE_FUNC* aFunc ) + { + m_clearanceFunctor = aFunc; + } - ///> Finds the nearest item that collides with aItem. - OptObstacle NearestObstacle( const PNS_LINE *aItem, int aKindMask = PNS_ITEM::ANY); + ///> Finds items that collide with aItem and stores collision information + ///> in aObstacles. + int QueryColliding( const PNS_ITEM* aItem, + Obstacles& aObstacles, + int aKindMask = PNS_ITEM::ANY, + int aLimitCount = -1 ); - ///> Checks if the item collides with anything else in the world, and returns it if so. - OptObstacle CheckColliding ( const PNS_ITEM *aItem, int aKindMask = PNS_ITEM::ANY); + ///> Finds the nearest item that collides with aItem. + OptObstacle NearestObstacle( const PNS_LINE* aItem, int aKindMask = PNS_ITEM::ANY ); - ///> Checks if two items collide [deprecated]. - bool CheckColliding( const PNS_ITEM *aItemA, const PNS_ITEM *aItemB, int aKindMask = PNS_ITEM::ANY); + ///> Checks if the item collides with anything else in the world, + ///> and returns it if so. + OptObstacle CheckColliding( const PNS_ITEM* aItem, int aKindMask = PNS_ITEM::ANY ); - ///> Hit detection - const PNS_ITEMSET HitTest( const VECTOR2I& aPoint ); + ///> Checks if two items collide [deprecated]. + bool CheckColliding( const PNS_ITEM* aItemA, + const PNS_ITEM* aItemB, + int aKindMask = PNS_ITEM::ANY ); - void Add(PNS_ITEM *aItem); - void Remove(PNS_ITEM *aItem); - void Replace(PNS_ITEM *aOldItem, PNS_ITEM *aNewItem); + ///> Hit detection + const PNS_ITEMSET HitTest( const VECTOR2I& aPoint ); - ///> Creates a lightweight copy ("branch") of self. Note that if there are any branches - /// in use, their parents must NOT be deleted. - PNS_NODE *Branch(); + void Add( PNS_ITEM* aItem ); + void Remove( PNS_ITEM* aItem ); + void Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ); - ///> Assembles a line connecting two non-trivial joints the segment aSeg belongs to. - PNS_LINE *AssembleLine(PNS_SEGMENT *aSeg, const OptJoint& a = OptJoint(), const OptJoint& b = OptJoint()); - - ///> Dumps the contents and joints structure - void Dump(bool aLong = false); + ///> Creates a lightweight copy ("branch") of self. Note that if there are + ///> any branches in use, their parents must NOT be deleted. + PNS_NODE* Branch(); - ///> Returns the number of joints - int JointCount() const - { - return m_joints.size(); - } + ///> Assembles a line connecting two non-trivial joints the + ///> segment aSeg belongs to. + PNS_LINE* AssembleLine( PNS_SEGMENT* aSeg, + const OptJoint& a = OptJoint(), const OptJoint& b = OptJoint() ); - ///> Returns the lists of items removed and added in this branch, with respect - ///> to the root. - void GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded); + ///> Dumps the contents and joints structure + void Dump( bool aLong = false ); - ///> Copies the changes from a given branch (aNode) to the root. Called on - ///> a non-root branch will fail. - void Commit (PNS_NODE *aNode); + ///> Returns the number of joints + int JointCount() const + { + return m_joints.size(); + } - ///> finds a joint at a given position, layer and nets - const OptJoint FindJoint(const VECTOR2I &aPos, int aLayer, int aNet); + ///> Returns the lists of items removed and added in this branch, with + ///> respect to the root. + void GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded ); - ///> finds all linest between a pair of joints. Used by the loop removal engine. - int FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b, std::vector &aLines ); + ///> Copies the changes from a given branch (aNode) to the root. Called on + ///> a non-root branch will fail. + void Commit( PNS_NODE* aNode ); - ///> finds the joints corresponding to the ends of line aLine - void FindLineEnds (PNS_LINE *aLine, PNS_JOINT& a, PNS_JOINT& b ); + ///> finds a joint at a given position, layer and nets + const OptJoint FindJoint( const VECTOR2I& aPos, int aLayer, int aNet ); - ///> finds all joints that have an (in)direct connection(s) (i.e. segments/vias) with the joint aJoint. - void FindConnectedJoints( const PNS_JOINT& aJoint, std::vector &aConnectedJoints ); + ///> finds all linest between a pair of joints. Used by the loop removal engine. + int FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b, + std::vector& aLines ); - ///> Destroys all child nodes. Applicable only to the root node. - void KillChildren(); + ///> finds the joints corresponding to the ends of line aLine + void FindLineEnds( PNS_LINE* aLine, PNS_JOINT& a, PNS_JOINT& b ); - void AllItemsInNet ( int aNet, std::list& aItems); + ///> finds all joints that have an (in)direct connection(s) + ///> (i.e. segments/vias) with the joint aJoint. + void FindConnectedJoints( const PNS_JOINT& aJoint, + std::vector& aConnectedJoints ); + + ///> Destroys all child nodes. Applicable only to the root node. + void KillChildren(); + + void AllItemsInNet( int aNet, std::list& aItems ); private: + struct obstacleVisitor; + typedef boost::unordered_multimap JointMap; + typedef JointMap::value_type TagJointPair; - struct obstacleVisitor; - typedef boost::unordered_multimap JointMap; - typedef JointMap::value_type TagJointPair; + /// nodes are not copyable + PNS_NODE( const PNS_NODE& b ); + PNS_NODE& operator=( const PNS_NODE& b ); - /// nodes are not copyable - PNS_NODE( const PNS_NODE& b); - PNS_NODE &operator=(const PNS_NODE& b); - - ///> tries to find matching joint and creates a new one if not found - PNS_JOINT& touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet ); - - ///> touches a joint and links it to an item - void linkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet, PNS_ITEM *aWhere ); + ///> tries to find matching joint and creates a new one if not found + PNS_JOINT& touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, + int aNet ); - ///> unlinks an item from a joint - void unlinkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet, PNS_ITEM *aWhere ); - - ///> helpers for adding/removing items + ///> touches a joint and links it to an item + void linkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, + int aNet, PNS_ITEM* aWhere ); - void addSolid( PNS_SOLID *aSeg ); - void addSegment( PNS_SEGMENT *aSeg ); - void addLine( PNS_LINE *aLine ); - void addVia( PNS_VIA *aVia ); - void removeSolid( PNS_SOLID *aSeg ); - void removeLine( PNS_LINE *aLine ); - void removeSegment (PNS_SEGMENT *aSeg ); - void removeVia (PNS_VIA *aVia ); + ///> unlinks an item from a joint + void unlinkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, + int aNet, PNS_ITEM* aWhere ); - void doRemove( PNS_ITEM *aItem ); - void unlinkParent ( ); - void releaseChildren (); - - bool isRoot() const - { - return m_parent == NULL; - } + ///> helpers for adding/removing items + void addSolid( PNS_SOLID* aSeg ); + void addSegment( PNS_SEGMENT* aSeg ); + void addLine( PNS_LINE* aLine ); + void addVia( PNS_VIA* aVia ); + void removeSolid( PNS_SOLID* aSeg ); + void removeLine( PNS_LINE* aLine ); + void removeSegment( PNS_SEGMENT* aSeg ); + void removeVia( PNS_VIA* aVia ); - ///> checks if this branch contains an updated version of the item from the root branch. - bool overrides ( PNS_ITEM * aItem ) const - { - return m_override.find(aItem) != m_override.end(); - } + void doRemove( PNS_ITEM* aItem ); + void unlinkParent(); + void releaseChildren(); - ///> scans the joint map, forming a line starting from segment (current). - void followLine(PNS_SEGMENT *current, bool scanDirection, int& pos, int limit, VECTOR2I *corners, PNS_SEGMENT **segments); + bool isRoot() const + { + return m_parent == NULL; + } - ///> spatial index of all items - //SHAPE_INDEX_LIST m_items; - - ///> hash table with the joints, linking the items. Joints are hashed by their - ///> position, layer set and net. - JointMap m_joints; + ///> checks if this branch contains an updated version of the item + ///> from the root branch. + bool overrides( PNS_ITEM* aItem ) const + { + return m_override.find( aItem ) != m_override.end(); + } - ///> node this node was branched from - PNS_NODE *m_parent; + ///> scans the joint map, forming a line starting from segment (current). + void followLine( PNS_SEGMENT* current, + bool scanDirection, + int& pos, + int limit, + VECTOR2I* corners, + PNS_SEGMENT** segments ); - ///> root node of the whole hierarchy - PNS_NODE *m_root; - - ///> list of nodes branched from this one - std::vector m_children; + ///> spatial index of all items + // SHAPE_INDEX_LIST m_items; - ///> hash of root's items that are more recent in this node - boost::unordered_set m_override; + ///> hash table with the joints, linking the items. Joints are hashed by + ///> their position, layer set and net. + JointMap m_joints; - ///> worst case item-item clearance - int m_maxClearance; - - ///> Clearance resolution functor - PNS_CLEARANCE_FUNC *m_clearanceFunctor; + ///> node this node was branched from + PNS_NODE* m_parent; - ///> Geometric/Net index of the items - PNS_INDEX *m_index; + ///> root node of the whole hierarchy + PNS_NODE* m_root; - ///> list of currently processed obstacles. - Obstacles m_obstacleList; + ///> list of nodes branched from this one + std::vector m_children; + + ///> hash of root's items that are more recent in this node + boost::unordered_set m_override; + + ///> worst case item-item clearance + int m_maxClearance; + + ///> Clearance resolution functor + PNS_CLEARANCE_FUNC* m_clearanceFunctor; + + ///> Geometric/Net index of the items + PNS_INDEX* m_index; + + ///> list of currently processed obstacles. + Obstacles m_obstacleList; }; #endif diff --git a/pcbnew/router/pns_optimizer.cpp b/pcbnew/router/pns_optimizer.cpp index 7291fba1ce..43cbfb52a0 100644 --- a/pcbnew/router/pns_optimizer.cpp +++ b/pcbnew/router/pns_optimizer.cpp @@ -3,20 +3,21 @@ * * Copyright (C) 2013 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 . */ + #include #include @@ -27,678 +28,737 @@ #include "pns_optimizer.h" #include "pns_utils.h" - using namespace std; /** + * + * Cost Estimator Methods + * + **/ -Cost Estimator Methods - -**/ - -int PNS_COST_ESTIMATOR::CornerCost( const SEG& a, const SEG& b) +int PNS_COST_ESTIMATOR::CornerCost( const SEG& a, const SEG& b ) { - DIRECTION_45 dir_a(a), dir_b(b); + DIRECTION_45 dir_a( a ), dir_b( b ); - switch(dir_a.Angle(dir_b)) - { - case DIRECTION_45::ANG_OBTUSE: - return 1; - case DIRECTION_45::ANG_STRAIGHT: - return 0; - case DIRECTION_45::ANG_ACUTE: - return 50; - case DIRECTION_45::ANG_RIGHT: - return 30; - case DIRECTION_45::ANG_HALF_FULL: - return 60; - default: - return 100; - } -} + switch( dir_a.Angle( dir_b ) ) + { + case DIRECTION_45::ANG_OBTUSE: + return 1; -int PNS_COST_ESTIMATOR::CornerCost ( const SHAPE_LINE_CHAIN& aLine ) -{ - int total = 0; - for (int i = 0; i < aLine.SegmentCount() - 1; ++i) - total += CornerCost(aLine.CSegment(i), aLine.CSegment(i + 1)); - return total; + case DIRECTION_45::ANG_STRAIGHT: + return 0; + + case DIRECTION_45::ANG_ACUTE: + return 50; + + case DIRECTION_45::ANG_RIGHT: + return 30; + + case DIRECTION_45::ANG_HALF_FULL: + return 60; + + default: + return 100; + } } -int PNS_COST_ESTIMATOR::CornerCost ( const PNS_LINE& aLine ) +int PNS_COST_ESTIMATOR::CornerCost( const SHAPE_LINE_CHAIN& aLine ) { - return CornerCost(aLine.GetCLine()); -} + int total = 0; -void PNS_COST_ESTIMATOR::Add(PNS_LINE &aLine) -{ - m_lengthCost += aLine.GetCLine().Length(); - m_cornerCost += CornerCost(aLine); -} + for( int i = 0; i < aLine.SegmentCount() - 1; ++i ) + total += CornerCost( aLine.CSegment( i ), aLine.CSegment( i + 1 ) ); -void PNS_COST_ESTIMATOR::Remove(PNS_LINE &aLine) -{ - m_lengthCost -= aLine.GetCLine().Length(); - m_cornerCost -= CornerCost(aLine); -} - -void PNS_COST_ESTIMATOR::Replace(PNS_LINE &aOldLine, PNS_LINE& aNewLine) -{ - m_lengthCost -= aOldLine.GetCLine().Length(); - m_cornerCost -= CornerCost(aOldLine); - m_lengthCost += aNewLine.GetCLine().Length(); - m_cornerCost += CornerCost(aNewLine); + return total; } -bool PNS_COST_ESTIMATOR::IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTollerance, double aCornerTollerance ) const +int PNS_COST_ESTIMATOR::CornerCost( const PNS_LINE& aLine ) { - if(aOther.m_cornerCost < m_cornerCost && aOther.m_lengthCost < m_lengthCost) - return true; - else if(aOther.m_cornerCost < m_cornerCost * aCornerTollerance && aOther.m_lengthCost < m_lengthCost * aLengthTollerance) - return true; + return CornerCost( aLine.GetCLine() ); +} - return false; + +void PNS_COST_ESTIMATOR::Add( PNS_LINE& aLine ) +{ + m_lengthCost += aLine.GetCLine().Length(); + m_cornerCost += CornerCost( aLine ); +} + + +void PNS_COST_ESTIMATOR::Remove( PNS_LINE& aLine ) +{ + m_lengthCost -= aLine.GetCLine().Length(); + m_cornerCost -= CornerCost( aLine ); +} + + +void PNS_COST_ESTIMATOR::Replace( PNS_LINE& aOldLine, PNS_LINE& aNewLine ) +{ + m_lengthCost -= aOldLine.GetCLine().Length(); + m_cornerCost -= CornerCost( aOldLine ); + m_lengthCost += aNewLine.GetCLine().Length(); + m_cornerCost += CornerCost( aNewLine ); +} + + +bool PNS_COST_ESTIMATOR::IsBetter( PNS_COST_ESTIMATOR& aOther, + double aLengthTollerance, + double aCornerTollerance ) const +{ + if( aOther.m_cornerCost < m_cornerCost && aOther.m_lengthCost < m_lengthCost ) + return true; + + else if( aOther.m_cornerCost < m_cornerCost * aCornerTollerance && aOther.m_lengthCost < + m_lengthCost * aLengthTollerance ) + return true; + + return false; } /** - -Optimizer - -**/ - - -PNS_OPTIMIZER::PNS_OPTIMIZER( PNS_NODE *aWorld ) : - m_world( aWorld ), m_collisionKindMask (PNS_ITEM::ANY), m_effortLevel(MERGE_SEGMENTS) - { - // m_cache = new SHAPE_INDEX_LIST(); - } - - -PNS_OPTIMIZER::~PNS_OPTIMIZER ( ) + * + * Optimizer + * + **/ +PNS_OPTIMIZER::PNS_OPTIMIZER( PNS_NODE* aWorld ) : + m_world( aWorld ), m_collisionKindMask( PNS_ITEM::ANY ), m_effortLevel( MERGE_SEGMENTS ) { - //delete m_cache; + // m_cache = new SHAPE_INDEX_LIST(); } -struct PNS_OPTIMIZER::CacheVisitor +PNS_OPTIMIZER::~PNS_OPTIMIZER() { + // delete m_cache; +} - CacheVisitor( const PNS_ITEM * aOurItem, PNS_NODE *aNode, int aMask ) : - m_ourItem(aOurItem), - m_collidingItem(NULL), - m_node(aNode), - m_mask(aMask) - {}; - bool operator() (PNS_ITEM *aOtherItem) - { - if(! m_mask & aOtherItem->GetKind()) - return true; +struct PNS_OPTIMIZER::CacheVisitor +{ + CacheVisitor( const PNS_ITEM* aOurItem, PNS_NODE* aNode, int aMask ) : + m_ourItem( aOurItem ), + m_collidingItem( NULL ), + m_node( aNode ), + m_mask( aMask ) + {}; - int clearance = m_node->GetClearance(aOtherItem, m_ourItem); + bool operator()( PNS_ITEM* aOtherItem ) + { + if( !m_mask & aOtherItem->GetKind() ) + return true; - if(!aOtherItem->Collide(m_ourItem, clearance)) - return true; + int clearance = m_node->GetClearance( aOtherItem, m_ourItem ); - m_collidingItem = aOtherItem; - return false; - } + if( !aOtherItem->Collide( m_ourItem, clearance ) ) + return true; - const PNS_ITEM *m_ourItem; - PNS_ITEM *m_collidingItem; - PNS_NODE *m_node; - int m_mask; + m_collidingItem = aOtherItem; + return false; + } + + const PNS_ITEM* m_ourItem; + PNS_ITEM* m_collidingItem; + PNS_NODE* m_node; + int m_mask; }; -void PNS_OPTIMIZER::cacheAdd( PNS_ITEM *aItem, bool aIsStatic = false) -{ - if(m_cacheTags.find(aItem) != m_cacheTags.end()) - return; - m_cache.Add(aItem); - m_cacheTags[aItem].hits = 1; - m_cacheTags[aItem].isStatic = aIsStatic; +void PNS_OPTIMIZER::cacheAdd( PNS_ITEM* aItem, bool aIsStatic = false ) +{ + if( m_cacheTags.find( aItem ) != m_cacheTags.end() ) + return; + + m_cache.Add( aItem ); + m_cacheTags[aItem].hits = 1; + m_cacheTags[aItem].isStatic = aIsStatic; } -void PNS_OPTIMIZER::removeCachedSegments (PNS_LINE *aLine, int aStartVertex, int aEndVertex) + +void PNS_OPTIMIZER::removeCachedSegments( PNS_LINE* aLine, int aStartVertex, int aEndVertex ) { - std::vector *segs = aLine->GetLinkedSegments(); + std::vector* segs = aLine->GetLinkedSegments(); - if(!segs) - return; + if( !segs ) + return; - if(aEndVertex < 0) - aEndVertex += aLine->GetCLine().PointCount(); + if( aEndVertex < 0 ) + aEndVertex += aLine->GetCLine().PointCount(); - for(int i = aStartVertex; i < aEndVertex - 1; i++) - { - PNS_SEGMENT *s = (*segs)[i]; - m_cacheTags.erase(s); - m_cache.Remove(s); - }//*cacheRemove( (*segs)[i] ); + for( int i = aStartVertex; i < aEndVertex - 1; i++ ) + { + PNS_SEGMENT* s = (*segs)[i]; + m_cacheTags.erase( s ); + m_cache.Remove( s ); + } // *cacheRemove( (*segs)[i] ); } -void PNS_OPTIMIZER::CacheRemove ( PNS_ITEM *aItem ) + +void PNS_OPTIMIZER::CacheRemove( PNS_ITEM* aItem ) { - if(aItem->GetKind() == PNS_ITEM::LINE) - removeCachedSegments(static_cast (aItem)); + if( aItem->GetKind() == PNS_ITEM::LINE ) + removeCachedSegments( static_cast (aItem) ); } -void PNS_OPTIMIZER::CacheStaticItem (PNS_ITEM *aItem) + +void PNS_OPTIMIZER::CacheStaticItem( PNS_ITEM* aItem ) { - cacheAdd(aItem, true); + cacheAdd( aItem, true ); } + void PNS_OPTIMIZER::ClearCache( bool aStaticOnly ) { - if(!aStaticOnly) - { - m_cacheTags.clear(); - m_cache.Clear(); - return; - } - - for(CachedItemTags::iterator i = m_cacheTags.begin(); i!= m_cacheTags.end(); ++i) - { - if(i->second.isStatic) - { - m_cache.Remove(i->first); - m_cacheTags.erase(i->first); - } - } -} + if( !aStaticOnly ) + { + m_cacheTags.clear(); + m_cache.Clear(); + return; + } -bool PNS_OPTIMIZER::checkColliding ( PNS_ITEM *aItem, bool aUpdateCache ) -{ - CacheVisitor v(aItem, m_world, m_collisionKindMask); - - return m_world->CheckColliding(aItem); - - // something is wrong with the cache, need to investigate. - m_cache.Query(aItem->GetShape(), m_world->GetMaxClearance(), v, false); - - if(!v.m_collidingItem) - { - PNS_NODE::OptObstacle obs = m_world->CheckColliding(aItem); - - if(obs) { - - if(aUpdateCache) - cacheAdd(obs->item); - return true; - } - } else { - m_cacheTags[v.m_collidingItem].hits++; - return true; - } - - return false; -} - -bool PNS_OPTIMIZER::checkColliding( PNS_LINE *aLine, const SHAPE_LINE_CHAIN& aOptPath ) -{ - PNS_LINE tmp(*aLine, aOptPath); - return checkColliding(&tmp); -} - -bool PNS_OPTIMIZER::mergeObtuse (PNS_LINE *aLine) -{ - SHAPE_LINE_CHAIN &line = aLine->GetLine(); - - int step = line.PointCount() - 3; - int iter = 0; - int segs_pre = line.SegmentCount(); - - if(step < 0) - return false; - - SHAPE_LINE_CHAIN current_path (line); - - while(1) - { - iter++; - int n_segs = current_path.SegmentCount(); - int max_step = n_segs - 2; - if(step > max_step) - step = max_step; - - if(step < 2) - { - line = current_path; - return current_path.SegmentCount() < segs_pre; - } - - bool found_anything = false; - int n = 0; - - while (n < n_segs - step) - { - const SEG s1 = current_path.CSegment(n); - const SEG s2 = current_path.CSegment(n + step); - SEG s1opt, s2opt; - - if (DIRECTION_45(s1).IsObtuse(DIRECTION_45(s2))) - { - VECTOR2I ip = *s1.IntersectLines(s2); - - if(s1.Distance(ip) <= 1 || s2.Distance(ip) <= 1) - { - s1opt = SEG(s1.a, ip); - s2opt = SEG(ip, s2.b); - } else { - s1opt = SEG(s1.a, ip); - s2opt = SEG(ip, s2.b); - } - - - if (DIRECTION_45(s1opt).IsObtuse(DIRECTION_45(s2opt))) - { - SHAPE_LINE_CHAIN opt_path; - opt_path.Append(s1opt.a); - opt_path.Append(s1opt.b); - opt_path.Append(s2opt.b); - - PNS_LINE opt_track (*aLine, opt_path); - - if(!checkColliding(&opt_track)) - { - current_path.Replace(s1.Index() + 1, s2.Index(), ip); - //removeCachedSegments(aLine, s1.Index(), s2.Index()); - n_segs = current_path.SegmentCount(); - found_anything = true; - break; - } - } - } - n++; - } - - if(!found_anything) - { - if( step <= 2 ) - { - line = current_path; - return line.SegmentCount() < segs_pre; - } - step --; - } - } - return line.SegmentCount() < segs_pre; + for( CachedItemTags::iterator i = m_cacheTags.begin(); i!= m_cacheTags.end(); ++i ) + { + if( i->second.isStatic ) + { + m_cache.Remove( i->first ); + m_cacheTags.erase( i->first ); + } + } } -bool PNS_OPTIMIZER::mergeFull(PNS_LINE *aLine) +bool PNS_OPTIMIZER::checkColliding( PNS_ITEM* aItem, bool aUpdateCache ) { - SHAPE_LINE_CHAIN &line = aLine->GetLine(); - int step = line.SegmentCount() - 1; - - int segs_pre = line.SegmentCount(); + CacheVisitor v( aItem, m_world, m_collisionKindMask ); - line.Simplify(); + return m_world->CheckColliding( aItem ); - if(step < 0) - return false; + // something is wrong with the cache, need to investigate. + m_cache.Query( aItem->GetShape(), m_world->GetMaxClearance(), v, false ); - SHAPE_LINE_CHAIN current_path (line); + if( !v.m_collidingItem ) + { + PNS_NODE::OptObstacle obs = m_world->CheckColliding( aItem ); - while(1) - { - int n_segs = current_path.SegmentCount(); - int max_step = n_segs - 2; - - if(step > max_step) - step = max_step; + if( obs ) + { + if( aUpdateCache ) + cacheAdd( obs->item ); - if(step < 1) - break; - - bool found_anything = mergeStep(aLine, current_path, step); - - if(!found_anything) - step --; + return true; + } + } + else + { + m_cacheTags[v.m_collidingItem].hits++; + return true; + } - - } - - aLine->SetShape(current_path); - - return current_path.SegmentCount() < segs_pre; -} - -bool PNS_OPTIMIZER::Optimize ( PNS_LINE *aLine, PNS_LINE *aResult , int aStartVertex , int aEndVertex ) -{ - if(!aResult) - aResult = aLine; - else - *aResult = *aLine; - - m_keepPostures = false; - - bool rv = false; - if(m_effortLevel & MERGE_SEGMENTS) - rv |= mergeFull(aResult); - if(m_effortLevel & MERGE_OBTUSE) - rv |= mergeObtuse(aResult); - if(m_effortLevel & SMART_PADS) - rv |= runSmartPads(aResult); - - return rv; + return false; } -bool PNS_OPTIMIZER::mergeStep ( PNS_LINE *aLine, SHAPE_LINE_CHAIN& aCurrentPath, int step ) +bool PNS_OPTIMIZER::checkColliding( PNS_LINE* aLine, const SHAPE_LINE_CHAIN& aOptPath ) { - int n = 0; - int n_segs = aCurrentPath.SegmentCount(); - - int cost_orig = PNS_COST_ESTIMATOR::CornerCost(aCurrentPath); + PNS_LINE tmp( *aLine, aOptPath ); - - if(aLine->GetCLine().SegmentCount() < 4) - return false; - - DIRECTION_45 orig_start (aLine->GetCLine().CSegment(0)); - DIRECTION_45 orig_end (aLine->GetCLine().CSegment(-1)); - - while (n < n_segs - step ) - { - const SEG s1 = aCurrentPath.CSegment(n); - const SEG s2 = aCurrentPath.CSegment(n + step); - - SHAPE_LINE_CHAIN path[2], *picked = NULL; - int cost[2]; - - for(int i = 0; i < 2; i++) - { - bool postureMatch = true; - SHAPE_LINE_CHAIN bypass = DIRECTION_45().BuildInitialTrace(s1.a, s2.b, i); - cost[i] = INT_MAX; - - - if ( n == 0 && orig_start != DIRECTION_45( bypass.CSegment(0) ) ) - postureMatch = false; - else if (n == n_segs-step && orig_end != DIRECTION_45( bypass.CSegment(-1))) - postureMatch = false; - - if((postureMatch || !m_keepPostures) && !checkColliding(aLine, bypass)) - { - path[i] = aCurrentPath; - path[i].Replace(s1.Index(), s2.Index(), bypass); - path[i].Simplify(); - cost[i] = PNS_COST_ESTIMATOR::CornerCost(path[i]); - } - } - - if(cost[0] < cost_orig && cost[0] < cost[1]) - picked = &path[0]; - else if (cost[1] < cost_orig) - picked = &path[1]; - - if(picked) - { - n_segs = aCurrentPath.SegmentCount(); - aCurrentPath = *picked; - return true; - } - n++; - } - - return false; -} - -PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::circleBreakouts( int aWidth, const SHAPE *aShape, bool aPermitDiagonal ) const -{ - BreakoutList breakouts; - - for(int angle = 0; angle < 360; angle += 45) - { - const SHAPE_CIRCLE *cir = static_cast (aShape); - SHAPE_LINE_CHAIN l; - VECTOR2I p0 = cir->GetCenter (); - VECTOR2I v0 (cir->GetRadius() * M_SQRT2, 0); - l.Append ( p0 ); - l.Append ( p0 + v0.Rotate ( angle * M_PI / 180.0 ) ); - breakouts.push_back(l); - } - return breakouts; + return checkColliding( &tmp ); } -PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth, const SHAPE *aShape, bool aPermitDiagonal ) const +bool PNS_OPTIMIZER::mergeObtuse( PNS_LINE* aLine ) { - const SHAPE_RECT *rect = static_cast(aShape); - VECTOR2I s = rect->GetSize(), c = rect->GetPosition() + VECTOR2I (s.x / 2, s.y / 2); - BreakoutList breakouts; + SHAPE_LINE_CHAIN& line = aLine->GetLine(); - VECTOR2I d_offset; + int step = line.PointCount() - 3; + int iter = 0; + int segs_pre = line.SegmentCount(); - d_offset.x = (s.x > s.y) ? (s.x - s.y) / 2 : 0; - d_offset.y = (s.x < s.y) ? (s.y - s.x) / 2 : 0; + if( step < 0 ) + return false; - VECTOR2I d_vert = VECTOR2I ( 0, s.y / 2 + aWidth); - VECTOR2I d_horiz = VECTOR2I ( s.x / 2 + aWidth, 0); + SHAPE_LINE_CHAIN current_path( line ); + + while( 1 ) + { + iter++; + int n_segs = current_path.SegmentCount(); + int max_step = n_segs - 2; + + if( step > max_step ) + step = max_step; + + if( step < 2 ) + { + line = current_path; + return current_path.SegmentCount() < segs_pre; + } + + bool found_anything = false; + int n = 0; + + while( n < n_segs - step ) + { + const SEG s1 = current_path.CSegment( n ); + const SEG s2 = current_path.CSegment( n + step ); + SEG s1opt, s2opt; + + if( DIRECTION_45( s1 ).IsObtuse( DIRECTION_45( s2 ) ) ) + { + VECTOR2I ip = *s1.IntersectLines( s2 ); + + if( s1.Distance( ip ) <= 1 || s2.Distance( ip ) <= 1 ) + { + s1opt = SEG( s1.a, ip ); + s2opt = SEG( ip, s2.b ); + } + else + { + s1opt = SEG( s1.a, ip ); + s2opt = SEG( ip, s2.b ); + } - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c + d_horiz ) ); - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c - d_horiz ) ); - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c + d_vert ) ); - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c - d_vert ) ); + if( DIRECTION_45( s1opt ).IsObtuse( DIRECTION_45( s2opt ) ) ) + { + SHAPE_LINE_CHAIN opt_path; + opt_path.Append( s1opt.a ); + opt_path.Append( s1opt.b ); + opt_path.Append( s2opt.b ); - if(aPermitDiagonal) - { - int l = aWidth + std::min(s.x, s.y) / 2; - VECTOR2I d_diag ; - - if(s.x >= s.y) - { - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c + d_offset, c + d_offset + VECTOR2I(l, l))); - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c + d_offset, c + d_offset - VECTOR2I(-l, l))); - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c - d_offset, c - d_offset + VECTOR2I(-l, l))); - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c - d_offset, c - d_offset - VECTOR2I(l, l))); - } else { - // fixme: this could be done more efficiently - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c + d_offset, c + d_offset + VECTOR2I(l, l))); - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c - d_offset, c - d_offset - VECTOR2I(-l, l))); - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c + d_offset, c + d_offset + VECTOR2I(-l, l))); - breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c - d_offset, c - d_offset - VECTOR2I(l, l))); - - } - } + PNS_LINE opt_track( *aLine, opt_path ); - return breakouts; -} - - + if( !checkColliding( &opt_track ) ) + { + current_path.Replace( s1.Index() + 1, s2.Index(), ip ); + // removeCachedSegments(aLine, s1.Index(), s2.Index()); + n_segs = current_path.SegmentCount(); + found_anything = true; + break; + } + } + } -PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::computeBreakouts( int aWidth, const PNS_ITEM *aItem, bool aPermitDiagonal ) const -{ - switch(aItem->GetKind()) - { - case PNS_ITEM::VIA: - { - const PNS_VIA *via = static_cast (aItem); - return circleBreakouts ( aWidth, via->GetShape(), aPermitDiagonal ); - } + n++; + } - case PNS_ITEM::SOLID: - { - const SHAPE *shape = aItem->GetShape(); - switch(shape->Type()) - { - case SH_RECT: - return rectBreakouts (aWidth, shape, aPermitDiagonal); - case SH_CIRCLE: - return circleBreakouts (aWidth, shape, aPermitDiagonal); - default: - break; - } - } - default: - break; - } - return BreakoutList(); + if( !found_anything ) + { + if( step <= 2 ) + { + line = current_path; + return line.SegmentCount() < segs_pre; + } + + step--; + } + } + + return line.SegmentCount() < segs_pre; } -PNS_ITEM *PNS_OPTIMIZER::findPadOrVia ( int aLayer, int aNet, const VECTOR2I& aP) const -{ - PNS_NODE::OptJoint jt = m_world->FindJoint ( aP, aLayer, aNet ); - if(!jt) - return NULL; - BOOST_FOREACH (PNS_ITEM *item, jt->GetLinkList() ) - { - if(item->GetKind() == PNS_ITEM::VIA || item->GetKind() == PNS_ITEM::SOLID) - return item; - } - return NULL; +bool PNS_OPTIMIZER::mergeFull( PNS_LINE* aLine ) +{ + SHAPE_LINE_CHAIN& line = aLine->GetLine(); + int step = line.SegmentCount() - 1; + + int segs_pre = line.SegmentCount(); + + line.Simplify(); + + if( step < 0 ) + return false; + + SHAPE_LINE_CHAIN current_path( line ); + + while( 1 ) + { + int n_segs = current_path.SegmentCount(); + int max_step = n_segs - 2; + + if( step > max_step ) + step = max_step; + + if( step < 1 ) + break; + + bool found_anything = mergeStep( aLine, current_path, step ); + + if( !found_anything ) + step--; + } + + aLine->SetShape( current_path ); + + return current_path.SegmentCount() < segs_pre; } -int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE *aLine, PNS_ITEM *aPad, bool aEnd, int aEndVertex ) + +bool PNS_OPTIMIZER::Optimize( PNS_LINE* aLine, PNS_LINE* aResult, int aStartVertex, int aEndVertex ) { - int min_cost = INT_MAX;//PNS_COST_ESTIMATOR::CornerCost( line ); - int min_len = INT_MAX; - DIRECTION_45 dir; - - const int ForbiddenAngles = DIRECTION_45::ANG_ACUTE | DIRECTION_45::ANG_RIGHT | DIRECTION_45::ANG_HALF_FULL | DIRECTION_45::ANG_UNDEFINED; + if( !aResult ) + aResult = aLine; + else + *aResult = *aLine; - typedef pair RtVariant; - vector variants; + m_keepPostures = false; - BreakoutList breakouts = computeBreakouts( aLine->GetWidth(), aPad, true ); + bool rv = false; - SHAPE_LINE_CHAIN line = (aEnd ? aLine->GetCLine().Reverse() : aLine->GetCLine()); + if( m_effortLevel & MERGE_SEGMENTS ) + rv |= mergeFull( aResult ); - //bool startDiagonal = DIRECTION_45( line.CSegment(0) ).IsDiagonal(); + if( m_effortLevel & MERGE_OBTUSE ) + rv |= mergeObtuse( aResult ); - int p_end = min (aEndVertex, min (3 , line.PointCount() - 1)); + if( m_effortLevel & SMART_PADS ) + rv |= runSmartPads( aResult ); - for (int p = 1; p <= p_end; p++) - { - BOOST_FOREACH(SHAPE_LINE_CHAIN& l, breakouts) - { - //PNSDisplayDebugLine (l, 0); - - - for(int diag = 0; diag < 2; diag++) - { - SHAPE_LINE_CHAIN v; - SHAPE_LINE_CHAIN connect = dir.BuildInitialTrace( l.CPoint(-1), line.CPoint(p), diag == 0); - - DIRECTION_45 dir_bkout ( l.CSegment(-1 )); - //DIRECTION_45 dir_head ( line.CSegment(p + 1)); + return rv; +} - int ang1 = dir_bkout.Angle ( DIRECTION_45(connect.CSegment(0) )); - int ang2 = 0; - //int ang2 = dir_head.Angle ( DIRECTION_45(connect.CSegment(-1) )); - if( (ang1 | ang2) & ForbiddenAngles ) - continue; +bool PNS_OPTIMIZER::mergeStep( PNS_LINE* aLine, SHAPE_LINE_CHAIN& aCurrentPath, int step ) +{ + int n = 0; + int n_segs = aCurrentPath.SegmentCount(); - if(l.Length() > line.Length()) - continue; + int cost_orig = PNS_COST_ESTIMATOR::CornerCost( aCurrentPath ); - v = l; - v.Append ( connect ); + if( aLine->GetCLine().SegmentCount() < 4 ) + return false; - for(int i = p + 1; i < line.PointCount(); i++) - v.Append( line.CPoint(i) ); - - PNS_LINE tmp(*aLine, v); - //tmp.GetLine().Simplify(); - int cc = tmp.CountCorners(ForbiddenAngles); + DIRECTION_45 orig_start( aLine->GetCLine().CSegment( 0 ) ); + DIRECTION_45 orig_end( aLine->GetCLine().CSegment( -1 ) ); - if(cc == 0) - { - RtVariant vp; - vp.first = p; - vp.second = aEnd ? v.Reverse() : v; - vp.second.Simplify(); - variants.push_back(vp); - } - - } - } - } + while( n < n_segs - step ) + { + const SEG s1 = aCurrentPath.CSegment( n ); + const SEG s2 = aCurrentPath.CSegment( n + step ); - SHAPE_LINE_CHAIN l_best; - bool found = false; - int p_best = -1; + SHAPE_LINE_CHAIN path[2], * picked = NULL; + int cost[2]; - BOOST_FOREACH(RtVariant& vp, variants) - { - PNS_LINE tmp (*aLine, vp.second); - int cost = PNS_COST_ESTIMATOR::CornerCost(vp.second); - int len = vp.second.Length(); + for( int i = 0; i < 2; i++ ) + { + bool postureMatch = true; + SHAPE_LINE_CHAIN bypass = DIRECTION_45().BuildInitialTrace( s1.a, s2.b, i ); + cost[i] = INT_MAX; - if(!checkColliding(&tmp)) - { - + if( n == 0 && orig_start != DIRECTION_45( bypass.CSegment( 0 ) ) ) + postureMatch = false; + else if( n == n_segs - step && orig_end != DIRECTION_45( bypass.CSegment( -1 ) ) ) + postureMatch = false; + + if( (postureMatch || !m_keepPostures) && !checkColliding( aLine, bypass ) ) + { + path[i] = aCurrentPath; + path[i].Replace( s1.Index(), s2.Index(), bypass ); + path[i].Simplify(); + cost[i] = PNS_COST_ESTIMATOR::CornerCost( path[i] ); + } + } + + if( cost[0] < cost_orig && cost[0] < cost[1] ) + picked = &path[0]; + else if( cost[1] < cost_orig ) + picked = &path[1]; + + if( picked ) + { + n_segs = aCurrentPath.SegmentCount(); + aCurrentPath = *picked; + return true; + } + + n++; + } + + return false; +} + + +PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::circleBreakouts( int aWidth, + const SHAPE* aShape, bool aPermitDiagonal ) const +{ + BreakoutList breakouts; + + for( int angle = 0; angle < 360; angle += 45 ) + { + const SHAPE_CIRCLE* cir = static_cast( aShape ); + SHAPE_LINE_CHAIN l; + VECTOR2I p0 = cir->GetCenter(); + VECTOR2I v0( cir->GetRadius() * M_SQRT2, 0 ); + l.Append( p0 ); + l.Append( p0 + v0.Rotate( angle * M_PI / 180.0 ) ); + breakouts.push_back( l ); + } + + return breakouts; +} + + +PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth, + const SHAPE* aShape, bool aPermitDiagonal ) const +{ + const SHAPE_RECT* rect = static_cast(aShape); + VECTOR2I s = rect->GetSize(), c = rect->GetPosition() + VECTOR2I( s.x / 2, s.y / 2 ); + BreakoutList breakouts; + + VECTOR2I d_offset; + + d_offset.x = (s.x > s.y) ? (s.x - s.y) / 2 : 0; + d_offset.y = (s.x < s.y) ? (s.y - s.x) / 2 : 0; + + VECTOR2I d_vert = VECTOR2I( 0, s.y / 2 + aWidth ); + VECTOR2I d_horiz = VECTOR2I( s.x / 2 + aWidth, 0 ); + + + breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_horiz ) ); + breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_horiz ) ); + breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_vert ) ); + breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_vert ) ); + + if( aPermitDiagonal ) + { + int l = aWidth + std::min( s.x, s.y ) / 2; + VECTOR2I d_diag; + + if( s.x >= s.y ) + { + breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_offset, + c + d_offset + VECTOR2I( l, l ) ) ); + breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_offset, + c + d_offset - VECTOR2I( -l, l ) ) ); + breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset, + c - d_offset + VECTOR2I( -l, l ) ) ); + breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset, + c - d_offset - VECTOR2I( l, l ) ) ); + } + else + { + // fixme: this could be done more efficiently + breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_offset, + c + d_offset + VECTOR2I( l, l ) ) ); + breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset, + c - d_offset - VECTOR2I( -l, l ) ) ); + breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_offset, + c + d_offset + VECTOR2I( -l, l ) ) ); + breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset, + c - d_offset - VECTOR2I( l, l ) ) ); + } + } + + return breakouts; +} + + +PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::computeBreakouts( int aWidth, + const PNS_ITEM* aItem, bool aPermitDiagonal ) const +{ + switch( aItem->GetKind() ) + { + case PNS_ITEM::VIA: + { + const PNS_VIA* via = static_cast( aItem ); + return circleBreakouts( aWidth, via->GetShape(), aPermitDiagonal ); + } + + case PNS_ITEM::SOLID: + { + const SHAPE* shape = aItem->GetShape(); + + switch( shape->Type() ) + { + case SH_RECT: + return rectBreakouts( aWidth, shape, aPermitDiagonal ); + + case SH_CIRCLE: + return circleBreakouts( aWidth, shape, aPermitDiagonal ); + + default: + break; + } + } + + default: + break; + } + + return BreakoutList(); +} + + +PNS_ITEM* PNS_OPTIMIZER::findPadOrVia( int aLayer, int aNet, const VECTOR2I& aP ) const +{ + PNS_NODE::OptJoint jt = m_world->FindJoint( aP, aLayer, aNet ); + + if( !jt ) + return NULL; + + BOOST_FOREACH( PNS_ITEM * item, jt->GetLinkList() ) + { + if( item->GetKind() == PNS_ITEM::VIA || item->GetKind() == PNS_ITEM::SOLID ) + return item; + } + + return NULL; +} + + +int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, int aEndVertex ) +{ + int min_cost = INT_MAX; // PNS_COST_ESTIMATOR::CornerCost( line ); + int min_len = INT_MAX; + DIRECTION_45 dir; + + const int ForbiddenAngles = DIRECTION_45::ANG_ACUTE | DIRECTION_45::ANG_RIGHT | + DIRECTION_45::ANG_HALF_FULL | DIRECTION_45::ANG_UNDEFINED; + + typedef pair RtVariant; + vector variants; + + BreakoutList breakouts = computeBreakouts( aLine->GetWidth(), aPad, true ); + + SHAPE_LINE_CHAIN line = ( aEnd ? aLine->GetCLine().Reverse() : aLine->GetCLine() ); + + // bool startDiagonal = DIRECTION_45( line.CSegment(0) ).IsDiagonal(); + + int p_end = min( aEndVertex, min( 3, line.PointCount() - 1 ) ); + + for( int p = 1; p <= p_end; p++ ) + { + BOOST_FOREACH( SHAPE_LINE_CHAIN & l, breakouts ) { + // PNSDisplayDebugLine (l, 0); + + + for( int diag = 0; diag < 2; diag++ ) + { + SHAPE_LINE_CHAIN v; + SHAPE_LINE_CHAIN connect = dir.BuildInitialTrace( l.CPoint( -1 ), + line.CPoint( p ), diag == 0 ); + + DIRECTION_45 dir_bkout( l.CSegment( -1 ) ); + // DIRECTION_45 dir_head ( line.CSegment(p + 1)); + + int ang1 = dir_bkout.Angle( DIRECTION_45( connect.CSegment( 0 ) ) ); + int ang2 = 0; + // int ang2 = dir_head.Angle ( DIRECTION_45(connect.CSegment(-1) )); + + if( (ang1 | ang2) & ForbiddenAngles ) + continue; + + if( l.Length() > line.Length() ) + continue; + + v = l; + + v.Append( connect ); + + for( int i = p + 1; i < line.PointCount(); i++ ) + v.Append( line.CPoint( i ) ); + + PNS_LINE tmp( *aLine, v ); + // tmp.GetLine().Simplify(); + int cc = tmp.CountCorners( ForbiddenAngles ); + + if( cc == 0 ) + { + RtVariant vp; + vp.first = p; + vp.second = aEnd ? v.Reverse() : v; + vp.second.Simplify(); + variants.push_back( vp ); + } + } + } + } + + SHAPE_LINE_CHAIN l_best; + bool found = false; + int p_best = -1; + + BOOST_FOREACH( RtVariant & vp, variants ) + { + PNS_LINE tmp( *aLine, vp.second ); + int cost = PNS_COST_ESTIMATOR::CornerCost( vp.second ); + int len = vp.second.Length(); + + if( !checkColliding( &tmp ) ) + { /* if(aEnd) - PNSDisplayDebugLine (l_best, 6); - else - PNSDisplayDebugLine (l_best, 5);*/ + * PNSDisplayDebugLine (l_best, 6); + * else + * PNSDisplayDebugLine (l_best, 5);*/ - if(cost < min_cost || (cost == min_cost && len < min_len)) - { - l_best = vp.second; - p_best = vp.first; - found = true; - - //if(cost == min_cost) - if(cost == min_cost) - min_len = std::min(len, min_len); - min_cost = std::min(cost, min_cost); - } - - } - } + if( cost < min_cost || ( cost == min_cost && len < min_len ) ) + { + l_best = vp.second; + p_best = vp.first; + found = true; - if(found) - { -// printf("end: %d, p-best: %d, p-end: %d, p-total: %d\n", aEnd, p_best, p_end, l_best.PointCount()); + // if(cost == min_cost) + if( cost == min_cost ) + min_len = std::min( len, min_len ); -// if(!aEnd) -// PNSDisplayDebugLine (l_best, 5); -// else + min_cost = std::min( cost, min_cost ); + } + } + } - aLine->SetShape(l_best); - return p_best; - } - return -1; + if( found ) + { +// printf("end: %d, p-best: %d, p-end: %d, p-total: %d\n", aEnd, p_best, p_end, l_best.PointCount()); + +// if(!aEnd) +// PNSDisplayDebugLine (l_best, 5); +// else + + aLine->SetShape( l_best ); + return p_best; + } + + return -1; } -bool PNS_OPTIMIZER::runSmartPads(PNS_LINE *aLine) + +bool PNS_OPTIMIZER::runSmartPads( PNS_LINE* aLine ) { - SHAPE_LINE_CHAIN& line = aLine->GetLine(); + SHAPE_LINE_CHAIN& line = aLine->GetLine(); - if (line.PointCount() < 3) - return false; + if( line.PointCount() < 3 ) + return false; - VECTOR2I p_start = line.CPoint(0), p_end = line.CPoint(-1); + VECTOR2I p_start = line.CPoint( 0 ), p_end = line.CPoint( -1 ); - PNS_ITEM *startPad = findPadOrVia( aLine->GetLayer(), aLine->GetNet(), p_start); - PNS_ITEM *endPad = findPadOrVia( aLine->GetLayer(), aLine->GetNet(), p_end); + PNS_ITEM* startPad = findPadOrVia( aLine->GetLayer(), aLine->GetNet(), p_start ); + PNS_ITEM* endPad = findPadOrVia( aLine->GetLayer(), aLine->GetNet(), p_end ); - int vtx = -1; + int vtx = -1; - if(startPad) - vtx = smartPadsSingle(aLine, startPad, false, 3); - if(endPad) - smartPadsSingle(aLine, endPad, true, vtx < 0 ? line.PointCount() - 1 : line.PointCount() - 1 - vtx); + if( startPad ) + vtx = smartPadsSingle( aLine, startPad, false, 3 ); - aLine->GetLine().Simplify(); - return true; + if( endPad ) + smartPadsSingle( aLine, endPad, true, + vtx < 0 ? line.PointCount() - 1 : line.PointCount() - 1 - vtx ); + + aLine->GetLine().Simplify(); + return true; } -bool PNS_OPTIMIZER::Optimize ( PNS_LINE *aLine, int aEffortLevel, PNS_NODE *aWorld ) + +bool PNS_OPTIMIZER::Optimize( PNS_LINE* aLine, int aEffortLevel, PNS_NODE* aWorld ) { - PNS_OPTIMIZER opt( aWorld ? aWorld : aLine->GetWorld() ); - opt.SetEffortLevel (aEffortLevel); - opt.SetCollisionMask(-1); - return opt.Optimize(aLine); + PNS_OPTIMIZER opt( aWorld ? aWorld : aLine->GetWorld() ); + + opt.SetEffortLevel( aEffortLevel ); + opt.SetCollisionMask( -1 ); + return opt.Optimize( aLine ); } + diff --git a/pcbnew/router/pns_optimizer.h b/pcbnew/router/pns_optimizer.h index f090528273..bafc88bc0a 100644 --- a/pcbnew/router/pns_optimizer.h +++ b/pcbnew/router/pns_optimizer.h @@ -3,20 +3,21 @@ * * Copyright (C) 2013 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_OPTIMIZER_H #define __PNS_OPTIMIZER_H @@ -30,135 +31,137 @@ class PNS_NODE; class PNS_LINE; class PNS_ROUTER; - /** * Class PNS_COST_ESTIMATOR * * Calculates the cost of a given line, taking corner angles and total length into account. - **/ + **/ -class PNS_COST_ESTIMATOR +class PNS_COST_ESTIMATOR { - public: - PNS_COST_ESTIMATOR(): - m_lengthCost (0), - m_cornerCost (0) - {}; +public: + PNS_COST_ESTIMATOR() : + m_lengthCost( 0 ), + m_cornerCost( 0 ) + {}; - PNS_COST_ESTIMATOR(const PNS_COST_ESTIMATOR &b): - m_lengthCost (b.m_lengthCost), - m_cornerCost (b.m_cornerCost) - {}; + PNS_COST_ESTIMATOR( const PNS_COST_ESTIMATOR& b ) : + m_lengthCost( b.m_lengthCost ), + m_cornerCost( b.m_cornerCost ) + {}; - ~PNS_COST_ESTIMATOR() {}; - - static int CornerCost ( const SEG& a, const SEG& b); - static int CornerCost ( const SHAPE_LINE_CHAIN& aLine ); - static int CornerCost ( const PNS_LINE& aLine); + ~PNS_COST_ESTIMATOR() {}; - void Add(PNS_LINE &aLine); - void Remove (PNS_LINE &aLine); - void Replace(PNS_LINE &aOldLine, PNS_LINE& aNewLine); - - bool IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTollerance, double aCornerTollerace ) const; + static int CornerCost( const SEG& a, const SEG& b ); + static int CornerCost( const SHAPE_LINE_CHAIN& aLine ); + static int CornerCost( const PNS_LINE& aLine ); - double GetLengthCost() const { return m_lengthCost; } - double GetCornerCost() const { return m_cornerCost; } + void Add( PNS_LINE& aLine ); + void Remove( PNS_LINE& aLine ); + void Replace( PNS_LINE& aOldLine, PNS_LINE& aNewLine ); - private: - double m_lengthCost; - int m_cornerCost; + bool IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTollerance, + double aCornerTollerace ) const; + + double GetLengthCost() const { return m_lengthCost; } + double GetCornerCost() const { return m_cornerCost; } + +private: + double m_lengthCost; + int m_cornerCost; }; /** * Class PNS_OPTIMIZER - * + * * Performs various optimizations of the lines being routed, attempting to make the lines shorter * and less cornery. There are 3 kinds of optimizations so far: - * - Merging obtuse segments (MERGE_OBTUSE): tries to join together as many + * - Merging obtuse segments (MERGE_OBTUSE): tries to join together as many * obtuse segments as possible without causing collisions * - Rerouting path between pair of line corners with a 2-segment "\__" line and iteratively repeating * the procedure as long as the total cost of the line keeps decreasing - * - "Smart Pads" - that is, rerouting pad/via exits to make them look nice (SMART_PADS). + * - "Smart Pads" - that is, rerouting pad/via exits to make them look nice (SMART_PADS). **/ -class PNS_OPTIMIZER +class PNS_OPTIMIZER { - public: +public: + enum OptimizationEffort + { + MERGE_SEGMENTS = 0x01, + SMART_PADS = 0x02, + MERGE_OBTUSE = 0x04 + }; - enum OptimizationEffort { - MERGE_SEGMENTS = 0x1, - SMART_PADS = 0x2, - MERGE_OBTUSE = 0x4 - }; + PNS_OPTIMIZER( PNS_NODE* aWorld ); + ~PNS_OPTIMIZER(); - PNS_OPTIMIZER( PNS_NODE *aWorld ); - ~PNS_OPTIMIZER(); + ///> a quick shortcut to optmize a line without creating and setting up an optimizer + static bool Optimize( PNS_LINE* aLine, int aEffortLevel, PNS_NODE* aWorld = NULL ); - ///> a quick shortcut to optmize a line without creating and setting up an optimizer - static bool Optimize ( PNS_LINE *aLine, int aEffortLevel, PNS_NODE *aWorld = NULL ); + bool Optimize( PNS_LINE* aLine, PNS_LINE* aResult = NULL, + int aStartVertex = 0, int aEndVertex = -1 ); - bool Optimize ( PNS_LINE *aLine, PNS_LINE *aResult = NULL, int aStartVertex = 0, int aEndVertex = -1); + void SetWorld( PNS_NODE* aNode ) { m_world = aNode; } + void CacheStaticItem( PNS_ITEM* aItem ); + void CacheRemove( PNS_ITEM* aItem ); + void ClearCache( bool aStaticOnly = false ); - void SetWorld(PNS_NODE *aNode) { m_world = aNode; } - void CacheStaticItem (PNS_ITEM *aItem); - void CacheRemove( PNS_ITEM *aItem ); - void ClearCache( bool aStaticOnly = false ); + void SetCollisionMask( int aMask ) + { + m_collisionKindMask = aMask; + } - void SetCollisionMask ( int aMask ) - { - m_collisionKindMask = aMask; - } + void SetEffortLevel( int aEffort ) + { + m_effortLevel = aEffort; + } - void SetEffortLevel ( int aEffort ) - { - m_effortLevel = aEffort; - } - - private: +private: + static const int MaxCachedItems = 256; - static const int MaxCachedItems = 256; + typedef std::vector BreakoutList; - typedef std::vector BreakoutList; + struct CacheVisitor; - struct CacheVisitor; - - struct CachedItem - { - int hits; - bool isStatic; - }; + struct CachedItem + { + int hits; + bool isStatic; + }; - bool mergeObtuse (PNS_LINE *aLine); - bool mergeFull (PNS_LINE *aLine); - bool removeUglyCorners (PNS_LINE *aLine); - bool runSmartPads(PNS_LINE *aLine); - bool mergeStep ( PNS_LINE *aLine, SHAPE_LINE_CHAIN& aCurrentLine, int step ); + bool mergeObtuse( PNS_LINE* aLine ); + bool mergeFull( PNS_LINE* aLine ); + bool removeUglyCorners( PNS_LINE* aLine ); + bool runSmartPads( PNS_LINE* aLine ); + bool mergeStep( PNS_LINE* aLine, SHAPE_LINE_CHAIN& aCurrentLine, int step ); - bool checkColliding( PNS_ITEM *aItem, bool aUpdateCache = true ); - bool checkColliding( PNS_LINE *aLine, const SHAPE_LINE_CHAIN& aOptPath ); + bool checkColliding( PNS_ITEM* aItem, bool aUpdateCache = true ); + bool checkColliding( PNS_LINE* aLine, const SHAPE_LINE_CHAIN& aOptPath ); - void cacheAdd( PNS_ITEM *aItem, bool aIsStatic ); - void removeCachedSegments (PNS_LINE *aLine, int aStartVertex = 0, int aEndVertex = -1); + void cacheAdd( PNS_ITEM* aItem, bool aIsStatic ); + void removeCachedSegments( PNS_LINE* aLine, int aStartVertex = 0, int aEndVertex = -1 ); - BreakoutList circleBreakouts( int aWidth, const SHAPE *aShape, bool aPermitDiagonal ) const; - BreakoutList rectBreakouts( int aWidth, const SHAPE *aShape, bool aPermitDiagonal ) const; - BreakoutList ovalBreakouts( int aWidth, const SHAPE *aShape, bool aPermitDiagonal ) const; - BreakoutList computeBreakouts( int aWidth, const PNS_ITEM *aItem, bool aPermitDiagonal ) const; + BreakoutList circleBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const; + BreakoutList rectBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const; + BreakoutList ovalBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const; + BreakoutList computeBreakouts( int aWidth, const PNS_ITEM* aItem, + bool aPermitDiagonal ) const; - int smartPadsSingle( PNS_LINE *aLine, PNS_ITEM *aPad, bool aEnd, int aEndVertex ); + int smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, int aEndVertex ); - PNS_ITEM *findPadOrVia ( int aLayer, int aNet, const VECTOR2I& aP) const; + PNS_ITEM* findPadOrVia( int aLayer, int aNet, const VECTOR2I& aP ) const; - SHAPE_INDEX_LIST m_cache; + SHAPE_INDEX_LIST m_cache; - typedef boost::unordered_map CachedItemTags; - CachedItemTags m_cacheTags; - PNS_NODE *m_world; - int m_collisionKindMask; - int m_effortLevel; - bool m_keepPostures; + typedef boost::unordered_map CachedItemTags; + CachedItemTags m_cacheTags; + PNS_NODE* m_world; + int m_collisionKindMask; + int m_effortLevel; + bool m_keepPostures; }; #endif + diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 720d4f06e0..8f13031c47 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -3,20 +3,21 @@ * * Copyright (C) 2013 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 . */ + #include #include @@ -33,7 +34,7 @@ #include #include #include - + #include "trace.h" #include "pns_node.h" #include "pns_line_placer.h" @@ -48,727 +49,765 @@ #include #include #include -#include +#include using namespace std; -// an ugly singleton for drawing debug items within the router context. To be fixed sometime in the future. -static PNS_ROUTER *theRouter; +// an ugly singleton for drawing debug items within the router context. +// To be fixed sometime in the future. +static PNS_ROUTER* theRouter; -class PCBNEW_CLEARANCE_FUNC : public PNS_CLEARANCE_FUNC +class PCBNEW_CLEARANCE_FUNC : public PNS_CLEARANCE_FUNC { - public: - PCBNEW_CLEARANCE_FUNC( BOARD *aBoard ) - { - m_clearanceCache.resize(aBoard->GetNetCount()); +public: + PCBNEW_CLEARANCE_FUNC( BOARD* aBoard ) + { + m_clearanceCache.resize( aBoard->GetNetCount() ); - for(unsigned int i = 0; i < aBoard->GetNetCount(); i++) - { - NETINFO_ITEM *ni = aBoard->FindNet(i); - wxString netClassName = ni->GetClassName(); - NETCLASS *nc = aBoard->m_NetClasses.Find(netClassName); - int clearance = nc->GetClearance(); - m_clearanceCache[i] = clearance; - TRACE(1, "Add net %d netclass %s clearance %d", i % netClassName.mb_str() % clearance); - } + for( unsigned int i = 0; i < aBoard->GetNetCount(); i++ ) + { + NETINFO_ITEM* ni = aBoard->FindNet( i ); + wxString netClassName = ni->GetClassName(); + NETCLASS* nc = aBoard->m_NetClasses.Find( netClassName ); + int clearance = nc->GetClearance(); + m_clearanceCache[i] = clearance; + TRACE( 1, "Add net %d netclass %s clearance %d", i % netClassName.mb_str() % + clearance ); + } - m_defaultClearance = 254000;//aBoard->m_NetClasses.Find ("Default clearance")->GetClearance(); - } + m_defaultClearance = 254000; // aBoard->m_NetClasses.Find ("Default clearance")->GetClearance(); + } - int operator() (const PNS_ITEM *a , const PNS_ITEM *b) - { - int net_a = a->GetNet(); - int cl_a = (net_a >= 0 ? m_clearanceCache[net_a] : m_defaultClearance); - int net_b = b->GetNet(); - int cl_b = (net_b >= 0 ? m_clearanceCache[net_b] : m_defaultClearance); - return std::max(cl_a, cl_b); - } - - private: + int operator()( const PNS_ITEM* a, const PNS_ITEM* b ) + { + int net_a = a->GetNet(); + int cl_a = (net_a >= 0 ? m_clearanceCache[net_a] : m_defaultClearance); + int net_b = b->GetNet(); + int cl_b = (net_b >= 0 ? m_clearanceCache[net_b] : m_defaultClearance); - vector m_clearanceCache; - int m_defaultClearance; + return std::max( cl_a, cl_b ); + } + +private: + vector m_clearanceCache; + int m_defaultClearance; }; -PNS_ITEM *PNS_ROUTER::syncPad( D_PAD *aPad ) +PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad ) { - PNS_LAYERSET layers; + PNS_LAYERSET layers; - switch(aPad->GetAttribute()) - { - case PAD_STANDARD: - layers = PNS_LAYERSET(0, 15); - break; - case PAD_SMD: - case PAD_CONN: - { - LAYER_MSK lmsk = aPad->GetLayerMask(); - int i; + switch( aPad->GetAttribute() ) + { + case PAD_STANDARD: + layers = PNS_LAYERSET( 0, 15 ); + break; - for(i = FIRST_COPPER_LAYER; i <= LAST_COPPER_LAYER; i++) - if( lmsk & (1<GetAttribute()); - return NULL; - } + case PAD_SMD: + case PAD_CONN: + { + LAYER_MSK lmsk = aPad->GetLayerMask(); + int i; - PNS_SOLID *solid = new PNS_SOLID; - - solid->SetLayers(layers); - solid->SetNet( aPad->GetNet() ); - wxPoint wx_c = aPad->GetPosition(); - wxSize wx_sz = aPad->GetSize(); - - VECTOR2I c(wx_c.x, wx_c.y); - VECTOR2I sz(wx_sz.x, wx_sz.y); - - solid->SetCenter( c ); - - - double orient = aPad->GetOrientation() / 10.0; - - if(orient == 90.0 || orient == 270.0) - sz = VECTOR2I(sz.y, sz.x); - else if (orient != 0.0 && orient != 180.0) - { - TRACEn(0, "non-orthogonal pad rotations not supported yet"); - delete solid; - return NULL; - } - - switch(aPad->GetShape()) - { - case PAD_CIRCLE: - solid->SetShape ( new SHAPE_CIRCLE ( c, sz.x / 2) ); - break; - case PAD_OVAL: - if(sz.x == sz.y) - solid->SetShape ( new SHAPE_CIRCLE ( c, sz.x / 2) ); - else - solid->SetShape ( new SHAPE_RECT ( c - sz / 2, sz.x, sz.y) ); - break; - - case PAD_RECT: - solid->SetShape ( new SHAPE_RECT ( c - sz / 2, sz.x, sz.y) ); - break; - - default: - TRACEn(0, "unsupported pad shape"); - delete solid; - return NULL; - } + for( i = FIRST_COPPER_LAYER; i <= LAST_COPPER_LAYER; i++ ) + if( lmsk & (1 << i) ) + { + layers = PNS_LAYERSET( i ); + break; + } - solid->SetParent(aPad); - return solid; -} - -PNS_ITEM *PNS_ROUTER::syncTrack( TRACK *aTrack ) -{ + break; + } - PNS_SEGMENT *s = new PNS_SEGMENT( SEG (aTrack->GetStart(), aTrack->GetEnd() ), aTrack->GetNet() ); - - s->SetWidth( aTrack->GetWidth() ); - s->SetLayers (PNS_LAYERSET(aTrack->GetLayer())); - s->SetParent(aTrack); - return s; + default: + TRACE( 0, "unsupported pad type 0x%x", aPad->GetAttribute() ); + return NULL; + } + + PNS_SOLID* solid = new PNS_SOLID; + + solid->SetLayers( layers ); + solid->SetNet( aPad->GetNet() ); + wxPoint wx_c = aPad->GetPosition(); + wxSize wx_sz = aPad->GetSize(); + + VECTOR2I c( wx_c.x, wx_c.y ); + VECTOR2I sz( wx_sz.x, wx_sz.y ); + + solid->SetCenter( c ); + + double orient = aPad->GetOrientation() / 10.0; + + if( orient == 90.0 || orient == 270.0 ) + sz = VECTOR2I( sz.y, sz.x ); + else if( orient != 0.0 && orient != 180.0 ) + { + TRACEn( 0, "non-orthogonal pad rotations not supported yet" ); + delete solid; + return NULL; + } + + switch( aPad->GetShape() ) + { + case PAD_CIRCLE: + solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) ); + break; + + case PAD_OVAL: + if( sz.x == sz.y ) + solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) ); + else + solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) ); + break; + + case PAD_RECT: + solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) ); + break; + + default: + TRACEn( 0, "unsupported pad shape" ); + delete solid; + return NULL; + } + + solid->SetParent( aPad ); + return solid; } - -PNS_ITEM *PNS_ROUTER::syncVia( SEGVIA *aVia ) -{ - PNS_VIA *v = new PNS_VIA( - aVia->GetPosition(), - PNS_LAYERSET(0, 15), - aVia->GetWidth(), - aVia->GetNet()); - v->SetParent(aVia); - return v; +PNS_ITEM* PNS_ROUTER::syncTrack( TRACK* aTrack ) +{ + PNS_SEGMENT* s = + new PNS_SEGMENT( SEG( aTrack->GetStart(), aTrack->GetEnd() ), aTrack->GetNet() ); + + s->SetWidth( aTrack->GetWidth() ); + s->SetLayers( PNS_LAYERSET( aTrack->GetLayer() ) ); + s->SetParent( aTrack ); + return s; } -void PNS_ROUTER::SetBoard( BOARD *aBoard ) + +PNS_ITEM* PNS_ROUTER::syncVia( SEGVIA* aVia ) { - m_board = aBoard; - TRACE(1, "m_board = %p\n", m_board); + PNS_VIA* v = new PNS_VIA( + aVia->GetPosition(), + PNS_LAYERSET( 0, 15 ), + aVia->GetWidth(), + aVia->GetNet() ); + + v->SetParent( aVia ); + return v; } - + + +void PNS_ROUTER::SetBoard( BOARD* aBoard ) +{ + m_board = aBoard; + TRACE( 1, "m_board = %p\n", m_board ); +} + + int PNS_ROUTER::NextCopperLayer( bool aUp ) { - LAYER_MSK mask = m_board->GetEnabledLayers() & m_board->GetVisibleLayers(); - LAYER_NUM l = m_currentLayer; + LAYER_MSK mask = m_board->GetEnabledLayers() & m_board->GetVisibleLayers(); + LAYER_NUM l = m_currentLayer; - do { - l += (aUp ? 1 : -1); - if(l > LAST_COPPER_LAYER) - l = FIRST_COPPER_LAYER; - - if(l < FIRST_COPPER_LAYER) - l = LAST_COPPER_LAYER; + do { + l += ( aUp ? 1 : -1 ); - if(mask & GetLayerMask(l)) - return l; - - } while (l != m_currentLayer); + if( l > LAST_COPPER_LAYER ) + l = FIRST_COPPER_LAYER; - return l; + if( l < FIRST_COPPER_LAYER ) + l = LAST_COPPER_LAYER; + + if( mask & GetLayerMask( l ) ) + return l; + } while( l != m_currentLayer ); + + return l; } + void PNS_ROUTER::SyncWorld() { - vector pads; + vector pads; - if(!m_board) - { - TRACEn(0,"No board attached, aborting sync."); - return; - } - - ClearWorld(); - + if( !m_board ) + { + TRACEn( 0, "No board attached, aborting sync." ); + return; + } - m_clearanceFunc = new PCBNEW_CLEARANCE_FUNC(m_board); - m_world = new PNS_NODE(); - m_world->SetClearanceFunctor ( m_clearanceFunc ); - m_world->SetMaxClearance ( 1000000 ); //m_board->GetBiggestClearanceValue()); - pads = m_board->GetPads(); + ClearWorld(); - BOOST_FOREACH( D_PAD *pad, pads ) - { - PNS_ITEM *solid = syncPad(pad); - if(solid) - m_world->Add(solid); - } - for(TRACK *t = m_board->m_Track; t; t = t->Next()) - { - KICAD_T type = t->Type(); - PNS_ITEM *item = NULL; - if(type == PCB_TRACE_T) - item = syncTrack ( t ); - else if( type == PCB_VIA_T ) - item = syncVia (static_cast (t)); + m_clearanceFunc = new PCBNEW_CLEARANCE_FUNC( m_board ); + m_world = new PNS_NODE(); + m_world->SetClearanceFunctor( m_clearanceFunc ); + m_world->SetMaxClearance( 1000000 ); // m_board->GetBiggestClearanceValue()); + pads = m_board->GetPads(); - if(item) - m_world->Add(item); - } + BOOST_FOREACH( D_PAD * pad, pads ) { + PNS_ITEM* solid = syncPad( pad ); - m_placer = new PNS_LINE_PLACER ( m_world ); + if( solid ) + m_world->Add( solid ); + } + + for( TRACK* t = m_board->m_Track; t; t = t->Next() ) + { + KICAD_T type = t->Type(); + PNS_ITEM* item = NULL; + + if( type == PCB_TRACE_T ) + item = syncTrack( t ); + else if( type == PCB_VIA_T ) + item = syncVia( static_cast (t) ); + + if( item ) + m_world->Add( item ); + } + + m_placer = new PNS_LINE_PLACER( m_world ); } + PNS_ROUTER::PNS_ROUTER() { - theRouter = this; + theRouter = this; - m_clearanceFunc = NULL; + m_clearanceFunc = NULL; - m_currentLayer = 1; - m_placingVia = false; - m_currentNet = -1; - m_state = IDLE; - m_world = NULL; - m_placer = NULL; - m_previewItems = NULL; - m_start_diagonal = false; - m_board = NULL; + m_currentLayer = 1; + m_placingVia = false; + m_currentNet = -1; + m_state = IDLE; + m_world = NULL; + m_placer = NULL; + m_previewItems = NULL; + m_start_diagonal = false; + m_board = NULL; - TRACE(1, "m_board = %p\n", m_board); + TRACE( 1, "m_board = %p\n", m_board ); } -void PNS_ROUTER::SetView(KiGfx::VIEW *aView) +void PNS_ROUTER::SetView( KiGfx::VIEW* aView ) { - if(m_previewItems) - { - m_previewItems->FreeItems(); - delete m_previewItems; - } - - m_view = aView; - m_previewItems = new KiGfx::VIEW_GROUP(m_view); - m_previewItems->SetLayer(ITEM_GAL_LAYER( GP_OVERLAY )); - m_view -> Add (m_previewItems); - m_previewItems->ViewSetVisible(true); + if( m_previewItems ) + { + m_previewItems->FreeItems(); + delete m_previewItems; + } + m_view = aView; + m_previewItems = new KiGfx::VIEW_GROUP( m_view ); + m_previewItems->SetLayer( ITEM_GAL_LAYER( GP_OVERLAY ) ); + m_view->Add( m_previewItems ); + m_previewItems->ViewSetVisible( true ); } -PNS_ROUTER *PNS_ROUTER::GetInstance() + +PNS_ROUTER* PNS_ROUTER::GetInstance() { - return theRouter; + return theRouter; } + PNS_ROUTER::~PNS_ROUTER() { - ClearWorld(); - theRouter = NULL; + ClearWorld(); + theRouter = NULL; } + void PNS_ROUTER::ClearWorld() { - if(m_world) - delete m_world; - if(m_clearanceFunc) - delete m_clearanceFunc; - if(m_placer) - delete m_placer; + if( m_world ) + delete m_world; - m_clearanceFunc = NULL; - m_world = NULL; - m_placer = NULL; + if( m_clearanceFunc ) + delete m_clearanceFunc; + + if( m_placer ) + delete m_placer; + + m_clearanceFunc = NULL; + m_world = NULL; + m_placer = NULL; } -void PNS_ROUTER::SetCurrentWidth (int w ) + +void PNS_ROUTER::SetCurrentWidth( int w ) { - // fixme: change width while routing - m_currentWidth = w; + // fixme: change width while routing + m_currentWidth = w; } + bool PNS_ROUTER::RoutingInProgress() const { - return m_state != IDLE; + return m_state != IDLE; } -const PNS_ITEMSET PNS_ROUTER::QueryHoverItems(const VECTOR2I&aP) +const PNS_ITEMSET PNS_ROUTER::QueryHoverItems( const VECTOR2I& aP ) { - if(m_state == IDLE) - return m_world->HitTest( aP ); - else - return m_placer->GetCurrentNode() -> HitTest(aP); + if( m_state == IDLE ) + return m_world->HitTest( aP ); + else + return m_placer->GetCurrentNode()->HitTest( aP ); } -const VECTOR2I PNS_ROUTER::SnapToItem( PNS_ITEM *item, VECTOR2I aP, bool& aSplitsSegment ) +const VECTOR2I PNS_ROUTER::SnapToItem( PNS_ITEM* item, VECTOR2I aP, bool& aSplitsSegment ) { - VECTOR2I anchor; + VECTOR2I anchor; - if(!item) - { - aSplitsSegment = false; - return aP; - } + if( !item ) + { + aSplitsSegment = false; + return aP; + } - switch(item->GetKind()) - { - case PNS_ITEM::SOLID: - anchor = static_cast(item)->GetCenter(); - aSplitsSegment = false; - break; - case PNS_ITEM::VIA: - anchor = static_cast(item)->GetPos(); - aSplitsSegment = false; - break; - case PNS_ITEM::SEGMENT: - { - PNS_SEGMENT *seg = static_cast(item); - const SEG& s = seg->GetSeg(); - int w = seg->GetWidth(); + switch( item->GetKind() ) + { + case PNS_ITEM::SOLID: + anchor = static_cast(item)->GetCenter(); + aSplitsSegment = false; + break; - aSplitsSegment = false; + case PNS_ITEM::VIA: + anchor = static_cast(item)->GetPos(); + aSplitsSegment = false; + break; - if ((aP - s.a).EuclideanNorm() < w / 2) - anchor = s.a; - else if ((aP - s.b).EuclideanNorm() < w / 2) - anchor = s.b; - else { - anchor = s.NearestPoint(aP); - aSplitsSegment = true; - } - break; - } - default: - break; - } - return anchor; + case PNS_ITEM::SEGMENT: + { + PNS_SEGMENT* seg = static_cast(item); + const SEG& s = seg->GetSeg(); + int w = seg->GetWidth(); + + aSplitsSegment = false; + + if( (aP - s.a).EuclideanNorm() < w / 2 ) + anchor = s.a; + else if( (aP - s.b).EuclideanNorm() < w / 2 ) + anchor = s.b; + else + { + anchor = s.NearestPoint( aP ); + aSplitsSegment = true; + } + + break; + } + + default: + break; + } + + return anchor; } -void PNS_ROUTER::StartRouting(const VECTOR2I& aP, PNS_ITEM *aStartItem) +void PNS_ROUTER::StartRouting( const VECTOR2I& aP, PNS_ITEM* aStartItem ) { - VECTOR2I p; - - static int unknowNetIdx = 0;//-10000; - - m_placingVia = false; - m_startsOnVia = false; - m_currentNet = -1; + VECTOR2I p; - bool splitSeg = false; + static int unknowNetIdx = 0; // -10000; - p = SnapToItem( aStartItem, aP, splitSeg ); + m_placingVia = false; + m_startsOnVia = false; + m_currentNet = -1; - if(!aStartItem || aStartItem->GetNet() < 0) - m_currentNet = unknowNetIdx--; - else - m_currentNet = aStartItem->GetNet(); + bool splitSeg = false; - m_currentStart = p; - m_originalStart = p; - m_currentEnd = p; + p = SnapToItem( aStartItem, aP, splitSeg ); - m_placer->SetInitialDirection(m_start_diagonal ? DIRECTION_45(DIRECTION_45::NE) : DIRECTION_45(DIRECTION_45::N)); - m_placer->StartPlacement(m_originalStart, m_currentNet, m_currentWidth, m_currentLayer); - m_state = ROUTE_TRACK; + if( !aStartItem || aStartItem->GetNet() < 0 ) + m_currentNet = unknowNetIdx--; + else + m_currentNet = aStartItem->GetNet(); - if(splitSeg) - splitAdjacentSegments(m_placer->GetCurrentNode(), aStartItem, p); + m_currentStart = p; + m_originalStart = p; + m_currentEnd = p; + m_placer->SetInitialDirection( m_start_diagonal ? DIRECTION_45( + DIRECTION_45::NE ) : DIRECTION_45( DIRECTION_45::N ) ); + m_placer->StartPlacement( m_originalStart, m_currentNet, m_currentWidth, m_currentLayer ); + m_state = ROUTE_TRACK; + if( splitSeg ) + splitAdjacentSegments( m_placer->GetCurrentNode(), aStartItem, p ); } -const VECTOR2I PNS_ROUTER::GetCurrentEnd( ) const + +const VECTOR2I PNS_ROUTER::GetCurrentEnd() const { - return m_currentEnd; + return m_currentEnd; } + void PNS_ROUTER::EraseView() { - BOOST_FOREACH(BOARD_ITEM *item, m_hiddenItems) - { - item->ViewSetVisible(true); - } - - if(m_previewItems) - m_previewItems->FreeItems(); - m_previewItems->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY ); + BOOST_FOREACH( BOARD_ITEM* item, m_hiddenItems ) + { + item->ViewSetVisible( true ); + } + + if( m_previewItems ) + m_previewItems->FreeItems(); + + m_previewItems->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY ); } -void PNS_ROUTER::DisplayItem(const PNS_ITEM* aItem, bool aIsHead) + +void PNS_ROUTER::DisplayItem( const PNS_ITEM* aItem, bool aIsHead ) { + ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, m_previewItems ); - ROUTER_PREVIEW_ITEM * pitem = new ROUTER_PREVIEW_ITEM (aItem, m_previewItems); - - m_previewItems->Add (pitem); - if(aIsHead) - pitem->MarkAsHead(); + m_previewItems->Add( pitem ); - pitem->ViewSetVisible(true); - m_previewItems->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY | KiGfx::VIEW_ITEM::APPEARANCE ); + if( aIsHead ) + pitem->MarkAsHead(); + + pitem->ViewSetVisible( true ); + m_previewItems->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY | KiGfx::VIEW_ITEM::APPEARANCE ); } -void PNS_ROUTER::DisplayDebugLine ( const SHAPE_LINE_CHAIN &aLine, int aType, int aWidth) + +void PNS_ROUTER::DisplayDebugLine( const SHAPE_LINE_CHAIN& aLine, int aType, int aWidth ) { - ROUTER_PREVIEW_ITEM * pitem = new ROUTER_PREVIEW_ITEM (NULL, m_previewItems); - - pitem->DebugLine (aLine, aWidth, aType ); - m_previewItems->Add (pitem); - pitem->ViewSetVisible(true); - m_previewItems->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY | KiGfx::VIEW_ITEM::APPEARANCE ); + ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( NULL, m_previewItems ); + + pitem->DebugLine( aLine, aWidth, aType ); + m_previewItems->Add( pitem ); + pitem->ViewSetVisible( true ); + m_previewItems->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY | KiGfx::VIEW_ITEM::APPEARANCE ); } -void PNS_ROUTER::DisplayDebugBox ( const BOX2I& aBox, int aType , int aWidth ) + +void PNS_ROUTER::DisplayDebugBox( const BOX2I& aBox, int aType, int aWidth ) { - } - -void PNS_ROUTER::Move(const VECTOR2I& aP, PNS_ITEM *endItem) + +void PNS_ROUTER::Move( const VECTOR2I& aP, PNS_ITEM* endItem ) { - PNS_NODE::ItemVector removed, added; - VECTOR2I p = aP; + PNS_NODE::ItemVector removed, added; + VECTOR2I p = aP; - if(m_state == IDLE) - return; + if( m_state == IDLE ) + return; - if(m_state == START_ROUTING) - { - - } + // TODO is something missing here? + if( m_state == START_ROUTING ) + { + } - EraseView(); + EraseView(); - m_currentEnd = p; - m_placer->Route(p); + m_currentEnd = p; + m_placer->Route( p ); - PNS_LINE current = m_placer->GetTrace(); + PNS_LINE current = m_placer->GetTrace(); - DisplayItem (¤t, true); + DisplayItem( ¤t, true ); - if(current.EndsWithVia()) - DisplayItem( ¤t.GetVia(), true ); + if( current.EndsWithVia() ) + DisplayItem( ¤t.GetVia(), true ); - m_placer->GetCurrentNode()->GetUpdatedItems(removed, added); + m_placer->GetCurrentNode()->GetUpdatedItems( removed, added ); - BOOST_FOREACH(PNS_ITEM *item, added) - { - DisplayItem(item); - } + BOOST_FOREACH( PNS_ITEM* item, added ) { + DisplayItem( item ); + } - BOOST_FOREACH(PNS_ITEM *item, removed) - { - BOARD_ITEM *parent = item->GetParent(); + BOOST_FOREACH( PNS_ITEM* item, removed ) + { + BOARD_ITEM* parent = item->GetParent(); - if(parent) - { - if(parent->ViewIsVisible()) - m_hiddenItems.insert(parent); + if( parent ) + { + if( parent->ViewIsVisible() ) + m_hiddenItems.insert( parent ); - parent->ViewSetVisible(false); - parent->ViewUpdate (KiGfx::VIEW_ITEM::APPEARANCE); - } - } + parent->ViewSetVisible( false ); + parent->ViewUpdate( KiGfx::VIEW_ITEM::APPEARANCE ); + } + } } -void PNS_ROUTER::splitAdjacentSegments(PNS_NODE *aNode, PNS_ITEM *aSeg, const VECTOR2I& aP ) + +void PNS_ROUTER::splitAdjacentSegments( PNS_NODE* aNode, PNS_ITEM* aSeg, const VECTOR2I& aP ) { - if(aSeg && aSeg->OfKind( PNS_ITEM::SEGMENT )) - { - PNS_NODE::OptJoint jt = aNode->FindJoint ( aP, aSeg->GetLayers().Start(), aSeg->GetNet()); + if( aSeg && aSeg->OfKind( PNS_ITEM::SEGMENT ) ) + { + PNS_NODE::OptJoint jt = aNode->FindJoint( aP, aSeg->GetLayers().Start(), aSeg->GetNet() ); - if(jt && jt->LinkCount() >= 1) - return; - - PNS_SEGMENT *s_old = static_cast(aSeg); - PNS_SEGMENT *s_new [2]; + if( jt && jt->LinkCount() >= 1 ) + return; - s_new[0] = s_old->Clone(); - s_new[1] = s_old->Clone(); + PNS_SEGMENT* s_old = static_cast(aSeg); + PNS_SEGMENT* s_new[2]; - s_new[0]->SetEnds (s_old->GetSeg().a, aP); - s_new[1]->SetEnds (aP, s_old->GetSeg().b); + s_new[0] = s_old->Clone(); + s_new[1] = s_old->Clone(); + s_new[0]->SetEnds( s_old->GetSeg().a, aP ); + s_new[1]->SetEnds( aP, s_old->GetSeg().b ); - aNode->Remove( s_old ); - aNode->Add( s_new [0] ); - aNode->Add( s_new [1] ); - } + aNode->Remove( s_old ); + aNode->Add( s_new[0] ); + aNode->Add( s_new[1] ); + } } -void PNS_ROUTER::commitRouting( PNS_NODE *aNode ) + +void PNS_ROUTER::commitRouting( PNS_NODE* aNode ) { - PNS_NODE::ItemVector removed, added; + PNS_NODE::ItemVector removed, added; - aNode->GetUpdatedItems(removed, added); + aNode->GetUpdatedItems( removed, added ); - for(unsigned int i = 0; i < removed.size(); i++) - { - BOARD_ITEM *parent = removed[i]->GetParent(); + for( unsigned int i = 0; i < removed.size(); i++ ) + { + BOARD_ITEM* parent = removed[i]->GetParent(); - if(parent) - { - m_view->Remove(parent); - m_board->Remove(parent); - } - } + if( parent ) + { + m_view->Remove( parent ); + m_board->Remove( parent ); + } + } - BOOST_FOREACH(PNS_ITEM *item, added) - { - BOARD_ITEM *newBI = NULL; - switch(item->GetKind()) - { - case PNS_ITEM::SEGMENT: - { - PNS_SEGMENT *seg = static_cast(item); - TRACK *track = new TRACK(m_board); - const SEG& s = seg->GetSeg(); + BOOST_FOREACH( PNS_ITEM* item, added ) + { + BOARD_ITEM* newBI = NULL; - track->SetStart( wxPoint(s.a.x, s.a.y)); - track->SetEnd( wxPoint(s.b.x, s.b.y )); - track->SetWidth(seg->GetWidth()); - track->SetLayer(seg->GetLayers().Start()); - track->SetNet(seg->GetNet()); - newBI = track; - break; - } - - case PNS_ITEM::VIA: - { - SEGVIA *via_board = new SEGVIA(m_board); - PNS_VIA *via = static_cast(item); - via_board->SetPosition ( wxPoint(via->GetPos().x, via->GetPos().y )); - via_board->SetWidth ( via->GetDiameter() ); - via_board->SetNet ( via->GetNet() ); - newBI = via_board; - break; - } + switch( item->GetKind() ) + { + case PNS_ITEM::SEGMENT: + { + PNS_SEGMENT* seg = static_cast( item ); + TRACK* track = new TRACK( m_board ); + const SEG& s = seg->GetSeg(); - default: - break; - } + track->SetStart( wxPoint( s.a.x, s.a.y ) ); + track->SetEnd( wxPoint( s.b.x, s.b.y ) ); + track->SetWidth( seg->GetWidth() ); + track->SetLayer( seg->GetLayers().Start() ); + track->SetNet( seg->GetNet() ); + newBI = track; + break; + } - if(newBI) - { - item->SetParent(newBI); - newBI->ClearFlags(); - m_view->Add(newBI); - m_board->Add(newBI); - newBI->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY ); - } - } - - m_world->Commit( aNode ); + case PNS_ITEM::VIA: + { + SEGVIA* via_board = new SEGVIA( m_board ); + PNS_VIA* via = static_cast( item ); + via_board->SetPosition( wxPoint( via->GetPos().x, via->GetPos().y ) ); + via_board->SetWidth( via->GetDiameter() ); + via_board->SetNet( via->GetNet() ); + newBI = via_board; + break; + } + + default: + break; + } + + if( newBI ) + { + item->SetParent( newBI ); + newBI->ClearFlags(); + m_view->Add( newBI ); + m_board->Add( newBI ); + newBI->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY ); + } + } + + m_world->Commit( aNode ); } -PNS_VIA *PNS_ROUTER::checkLoneVia ( PNS_JOINT* aJoint ) const + +PNS_VIA* PNS_ROUTER::checkLoneVia( PNS_JOINT* aJoint ) const { - PNS_VIA *theVia = NULL; - PNS_LAYERSET l; + PNS_VIA* theVia = NULL; + PNS_LAYERSET l; - BOOST_FOREACH(PNS_ITEM *item, aJoint->GetLinkList()) - { - if(item->GetKind() == PNS_ITEM::VIA) - theVia = static_cast(item); + BOOST_FOREACH( PNS_ITEM* item, aJoint->GetLinkList() ) + { + if( item->GetKind() == PNS_ITEM::VIA ) + theVia = static_cast( item ); - - l.Merge (item->GetLayers()); - } + l.Merge( item->GetLayers() ); + } - if(l.Start() == l.End()) - return theVia; - return NULL; + if( l.Start() == l.End() ) + return theVia; + + return NULL; } -PNS_NODE *PNS_ROUTER::removeLoops ( PNS_NODE *aNode, PNS_SEGMENT *aLatestSeg ) + +PNS_NODE* PNS_ROUTER::removeLoops( PNS_NODE* aNode, PNS_SEGMENT* aLatestSeg ) { - PNS_LINE *ourLine = aNode->AssembleLine(aLatestSeg); - PNS_NODE *cleaned = aNode->Branch(); - PNS_JOINT a, b; - vector lines; - + PNS_LINE* ourLine = aNode->AssembleLine( aLatestSeg ); + PNS_NODE* cleaned = aNode->Branch(); + PNS_JOINT a, b; - cleaned->FindLineEnds (ourLine, a, b); - cleaned->FindLinesBetweenJoints( a, b, lines); - - BOOST_FOREACH(PNS_LINE *line, lines) - { - if(! (line->ContainsSegment (aLatestSeg) ) ) - { - cleaned->Remove(line); - } - } + vector lines; - return cleaned; + cleaned->FindLineEnds( ourLine, a, b ); + cleaned->FindLinesBetweenJoints( a, b, lines ); + + BOOST_FOREACH( PNS_LINE* line, lines ) + { + if( !( line->ContainsSegment( aLatestSeg ) ) ) + { + cleaned->Remove( line ); + } + } + + return cleaned; } +bool PNS_ROUTER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) +{ + bool real_end = false; -bool PNS_ROUTER::FixRoute(const VECTOR2I& aP, PNS_ITEM *aEndItem) - { - bool real_end = false; - - PNS_LINE pl = m_placer->GetTrace(); - const SHAPE_LINE_CHAIN& l = pl.GetCLine(); + PNS_LINE pl = m_placer->GetTrace(); + const SHAPE_LINE_CHAIN& l = pl.GetCLine(); - if(!l.SegmentCount()) - return true; + if( !l.SegmentCount() ) + return true; - VECTOR2I p_pre_last = l.CPoint(-1); - const VECTOR2I p_last = l.CPoint(-1); - DIRECTION_45 d_last (l.CSegment(-1)); + VECTOR2I p_pre_last = l.CPoint( -1 ); + const VECTOR2I p_last = l.CPoint( -1 ); + DIRECTION_45 d_last( l.CSegment( -1 ) ); - if(l.PointCount() > 2) - p_pre_last = l.CPoint(-2); + if( l.PointCount() > 2 ) + p_pre_last = l.CPoint( -2 ); - if(aEndItem && m_currentNet >= 0 && m_currentNet == aEndItem->GetNet()) - real_end = true; - - int last = (real_end || m_placingVia) ? l.SegmentCount() : max(1, l.SegmentCount() - 1); + if( aEndItem && m_currentNet >= 0 && m_currentNet == aEndItem->GetNet() ) + real_end = true; - PNS_NODE *latest = m_placer->GetCurrentNode(); + int last = ( real_end || m_placingVia ) ? l.SegmentCount() : max( 1, l.SegmentCount() - 1 ); - if(real_end) - splitAdjacentSegments(latest, aEndItem, aP); - - PNS_SEGMENT *lastSeg = NULL; - for (int i = 0; i < last; i++) - { - const SEG& s = pl.GetCLine().CSegment(i); - PNS_SEGMENT *seg = new PNS_SEGMENT( s, m_currentNet ); - seg->SetWidth(pl.GetWidth()); - seg->SetLayer(m_currentLayer); - latest->Add(seg); - lastSeg = seg; - } + PNS_NODE* latest = m_placer->GetCurrentNode(); - if( pl.EndsWithVia() ) - latest->Add(pl.GetVia().Clone()); + if( real_end ) + splitAdjacentSegments( latest, aEndItem, aP ); - if(real_end) - latest = removeLoops( latest, lastSeg ); - - commitRouting(latest); + PNS_SEGMENT* lastSeg = NULL; - EraseView(); - - if(real_end) - { - m_state = IDLE; - //m_world->KillChildren(); - } else { - - m_state = ROUTE_TRACK; - m_placer->SetInitialDirection(d_last); - m_currentStart = m_placingVia ? p_last : p_pre_last; - - if(m_placingVia) - m_currentLayer = NextCopperLayer(true); + for( int i = 0; i < last; i++ ) + { + const SEG& s = pl.GetCLine().CSegment( i ); + PNS_SEGMENT* seg = new PNS_SEGMENT( s, m_currentNet ); + seg->SetWidth( pl.GetWidth() ); + seg->SetLayer( m_currentLayer ); + latest->Add( seg ); + lastSeg = seg; + } - m_placer->StartPlacement(m_currentStart, m_currentNet, m_currentWidth, m_currentLayer); + if( pl.EndsWithVia() ) + latest->Add( pl.GetVia().Clone() ); - m_startsOnVia = m_placingVia; - m_placingVia = false; + if( real_end ) + latest = removeLoops( latest, lastSeg ); - } - + commitRouting( latest ); - return real_end; + EraseView(); + + if( real_end ) + { + m_state = IDLE; + // m_world->KillChildren(); + } + else + { + m_state = ROUTE_TRACK; + m_placer->SetInitialDirection( d_last ); + m_currentStart = m_placingVia ? p_last : p_pre_last; + + if( m_placingVia ) + m_currentLayer = NextCopperLayer( true ); + + m_placer->StartPlacement( m_currentStart, m_currentNet, m_currentWidth, m_currentLayer ); + + m_startsOnVia = m_placingVia; + m_placingVia = false; + } + + return real_end; } + void PNS_ROUTER::StopRouting() { - if(!RoutingInProgress()) - return; + if( !RoutingInProgress() ) + return; - //highlightCurrent(false); - - EraseView(); - - m_state = IDLE; - m_world->KillChildren(); + // highlightCurrent(false); + + EraseView(); + + m_state = IDLE; + m_world->KillChildren(); } + void PNS_ROUTER::FlipPosture() { - if(m_placer->GetTail().GetCLine().SegmentCount() == 0) - { - m_start_diagonal = !m_start_diagonal; - m_placer->SetInitialDirection(m_start_diagonal ? DIRECTION_45(DIRECTION_45::NE) : DIRECTION_45(DIRECTION_45::N)); - } else - m_placer->FlipPosture(); - - Move(m_currentEnd, NULL); + if( m_placer->GetTail().GetCLine().SegmentCount() == 0 ) + { + m_start_diagonal = !m_start_diagonal; + m_placer->SetInitialDirection( m_start_diagonal ? DIRECTION_45( + DIRECTION_45::NE ) : DIRECTION_45( DIRECTION_45::N ) ); + } + else + m_placer->FlipPosture(); + + Move( m_currentEnd, NULL ); } -void PNS_ROUTER::SwitchLayer(int layer) + +void PNS_ROUTER::SwitchLayer( int layer ) { - switch(m_state) - { - case IDLE: - m_currentLayer = layer; - break; - case ROUTE_TRACK: - if(m_startsOnVia) - { - m_currentLayer = layer; - m_placer->StartPlacement(m_currentStart, m_currentNet, m_currentWidth, m_currentLayer); - } - default: - break; - } + switch( m_state ) + { + case IDLE: + m_currentLayer = layer; + break; + + case ROUTE_TRACK: + if( m_startsOnVia ) + { + m_currentLayer = layer; + m_placer->StartPlacement( m_currentStart, m_currentNet, m_currentWidth, + m_currentLayer ); + } + + default: + break; + } } -void PNS_ROUTER::ToggleViaPlacement () -{ - if(m_state == ROUTE_TRACK) - { - m_placingVia = !m_placingVia; - m_placer->AddVia(m_placingVia, m_currentViaDiameter, m_currentViaDrill); - } -} + +void PNS_ROUTER::ToggleViaPlacement() +{ + if( m_state == ROUTE_TRACK ) + { + m_placingVia = !m_placingVia; + m_placer->AddVia( m_placingVia, m_currentViaDiameter, m_currentViaDrill ); + } +} diff --git a/pcbnew/router/pns_router.h b/pcbnew/router/pns_router.h index e0016b2dc8..d762f14783 100644 --- a/pcbnew/router/pns_router.h +++ b/pcbnew/router/pns_router.h @@ -3,20 +3,21 @@ * * Copyright (C) 2013 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_ROUTER_H #define __PNS_ROUTER_H @@ -48,150 +49,146 @@ class PNS_CLEARANCE_FUNC; class VIEW_GROUP; namespace KiGfx { - class VIEW; - class VIEW_GROUP; +class VIEW; +class VIEW_GROUP; }; -/** +/** * Class PNS_ROUTER - * - * Main router class. + * + * Main router class. */ -class PNS_ROUTER { - -private: - enum RouterState { - IDLE, - START_ROUTING, - ROUTE_TRACK, - FINISH_TRACK - }; +class PNS_ROUTER +{ +private: + enum RouterState + { + IDLE, + START_ROUTING, + ROUTE_TRACK, + FINISH_TRACK + }; public: + PNS_ROUTER(); + ~PNS_ROUTER(); - PNS_ROUTER (); - ~PNS_ROUTER (); + static PNS_ROUTER* GetInstance(); - static PNS_ROUTER *GetInstance(); + void ClearWorld(); + void SetBoard( BOARD* aBoard ); + void SyncWorld(); - void ClearWorld(); - void SetBoard( BOARD *aBoard ); - void SyncWorld(); + void SetView( KiGfx::VIEW* aView ); - void SetView(KiGfx::VIEW *aView); + bool RoutingInProgress() const; + void StartRouting( const VECTOR2I& aP, PNS_ITEM* aItem ); + void Move( const VECTOR2I& aP, PNS_ITEM* aItem ); + bool FixRoute( const VECTOR2I& aP, PNS_ITEM* aItem ); - bool RoutingInProgress() const; - void StartRouting(const VECTOR2I& aP, PNS_ITEM *aItem); - void Move(const VECTOR2I& aP, PNS_ITEM *aItem); - bool FixRoute(const VECTOR2I& aP, PNS_ITEM *aItem); + void StopRouting(); - void StopRouting(); + const VECTOR2I GetCurrentEnd() const; - const VECTOR2I GetCurrentEnd() const; + int GetClearance( const PNS_ITEM* a, const PNS_ITEM* b ) const; - int GetClearance(const PNS_ITEM* a, const PNS_ITEM *b ) const; + PNS_NODE* GetWorld() const + { + return m_world; + } - PNS_NODE* GetWorld() const - { - return m_world; - } + void FlipPosture(); - void FlipPosture(); - - void DisplayItem ( const PNS_ITEM *aItem, bool aIsHead = false ); - void DisplayDebugLine ( const SHAPE_LINE_CHAIN &aLine, int aType = 0, int aWidth = 0); - void DisplayDebugBox ( const BOX2I& aBox, int aType = 0, int aWidth = 0); - - void EraseView ( ); - void SwitchLayer (int layer ); - int GetCurrentLayer() const { return m_currentLayer; } - void ToggleViaPlacement (); + void DisplayItem( const PNS_ITEM* aItem, bool aIsHead = false ); + void DisplayDebugLine( const SHAPE_LINE_CHAIN& aLine, int aType = 0, int aWidth = 0 ); + void DisplayDebugBox( const BOX2I& aBox, int aType = 0, int aWidth = 0 ); - void SetCurrentWidth(int w); - void SetCurrentViaDiameter(int d) { m_currentViaDiameter = d;} - void SetCurrentViaDrill(int d) { m_currentViaDrill = d;} - int GetCurrentWidth() const { return m_currentWidth; } - int GetCurrentViaDiameter() const { return m_currentViaDiameter; } - int GetCurrentViaDrill() const { return m_currentViaDrill; } - int GetCurrentNet() const { return m_currentNet; } + void EraseView(); + void SwitchLayer( int layer ); - PNS_CLEARANCE_FUNC *GetClearanceFunc() const - { - return m_clearanceFunc; - } + int GetCurrentLayer() const { return m_currentLayer; } + void ToggleViaPlacement(); - bool IsPlacingVia() const - { - return m_placingVia; - } + void SetCurrentWidth( int w ); + void SetCurrentViaDiameter( int d ) { m_currentViaDiameter = d; } + void SetCurrentViaDrill( int d ) { m_currentViaDrill = d; } + int GetCurrentWidth() const { return m_currentWidth; } + int GetCurrentViaDiameter() const { return m_currentViaDiameter; } + int GetCurrentViaDrill() const { return m_currentViaDrill; } + int GetCurrentNet() const { return m_currentNet; } - int NextCopperLayer( bool aUp ); + PNS_CLEARANCE_FUNC* GetClearanceFunc() const + { + return m_clearanceFunc; + } - //typedef boost::optional optHoverItem; + bool IsPlacingVia() const + { + return m_placingVia; + } - const PNS_ITEMSET QueryHoverItems(const VECTOR2I& aP); - const VECTOR2I SnapToItem( PNS_ITEM *item, VECTOR2I aP, bool& aSplitsSegment ); + int NextCopperLayer( bool aUp ); + // typedef boost::optional optHoverItem; + + const PNS_ITEMSET QueryHoverItems( const VECTOR2I& aP ); + const VECTOR2I SnapToItem( PNS_ITEM* item, VECTOR2I aP, bool& aSplitsSegment ); private: + void clearViewFlags(); + // optHoverItem queryHoverItemEx(const VECTOR2I& aP); + PNS_ITEM* pickSingleItem( PNS_ITEMSET& aItems ) const; // std::vector aItems) const; + void splitAdjacentSegments( PNS_NODE* aNode, PNS_ITEM* aSeg, const VECTOR2I& aP ); // optHoverItem& aItem); + void commitRouting( PNS_NODE* aNode ); + PNS_NODE* removeLoops( PNS_NODE* aNode, PNS_SEGMENT* aLatestSeg ); + PNS_NODE* removeLoops( PNS_NODE* aNode, PNS_LINE* aNewLine ); + PNS_VIA* checkLoneVia( PNS_JOINT* aJoint ) const; - void clearViewFlags(); - - //optHoverItem queryHoverItemEx(const VECTOR2I& aP); - - PNS_ITEM *pickSingleItem ( PNS_ITEMSET &aItems ) const; //std::vector aItems) const; - void splitAdjacentSegments(PNS_NODE *aNode, PNS_ITEM *aSeg, const VECTOR2I& aP ); //optHoverItem& aItem); - void commitRouting ( PNS_NODE *aNode ); - PNS_NODE *removeLoops ( PNS_NODE *aNode, PNS_SEGMENT *aLatestSeg ); - PNS_NODE *removeLoops ( PNS_NODE *aNode, PNS_LINE *aNewLine ); - PNS_VIA *checkLoneVia ( PNS_JOINT* aJoint ) const; + PNS_ITEM* syncPad( D_PAD* aPad ); + PNS_ITEM* syncTrack( TRACK* aTrack ); + PNS_ITEM* syncVia( SEGVIA* aVia ); - PNS_ITEM *syncPad( D_PAD *aPad ); - PNS_ITEM *syncTrack( TRACK *aTrack ); - PNS_ITEM *syncVia( SEGVIA *aVia ); + void commitPad( PNS_SOLID* aPad ); + void commitSegment( PNS_SEGMENT* aTrack ); + void commitVia( PNS_VIA* aVia ); - void commitPad( PNS_SOLID *aPad ); - void commitSegment( PNS_SEGMENT *aTrack ); - void commitVia( PNS_VIA *aVia ); + void highlightCurrent( bool enabled ); - void highlightCurrent( bool enabled ); + int m_currentLayer; + int m_currentNet; + int m_currentWidth; + int m_currentViaDiameter; + int m_currentViaDrill; + bool m_start_diagonal; - int m_currentLayer; - int m_currentNet; - int m_currentWidth; - int m_currentViaDiameter; - int m_currentViaDrill; + RouterState m_state; - bool m_start_diagonal; + BOARD* m_board; + PNS_NODE* m_world; + PNS_LINE_PLACER* m_placer; - RouterState m_state; + KiGfx::VIEW* m_view; + KiGfx::VIEW_GROUP* m_previewItems; - BOARD *m_board; - PNS_NODE *m_world; - PNS_LINE_PLACER *m_placer; + VECTOR2I m_currentEnd; + VECTOR2I m_currentStart; + VECTOR2I m_originalStart; + bool m_placingVia; + bool m_startsOnVia; - KiGfx::VIEW *m_view; - KiGfx::VIEW_GROUP *m_previewItems; +// optHoverItem m_startItem, m_endItem; - VECTOR2I m_currentEnd; - VECTOR2I m_currentStart; - VECTOR2I m_originalStart; - bool m_placingVia; - bool m_startsOnVia; - -// optHoverItem m_startItem, m_endItem; - - PNS_ROUTING_SETTINGS m_settings; - PNS_CLEARANCE_FUNC *m_clearanceFunc; - - boost::unordered_set m_hiddenItems; + PNS_ROUTING_SETTINGS m_settings; + PNS_CLEARANCE_FUNC* m_clearanceFunc; + boost::unordered_set m_hiddenItems; }; -#endif \ No newline at end of file +#endif + diff --git a/pcbnew/router/pns_routing_settings.h b/pcbnew/router/pns_routing_settings.h index 86c955dfc1..e61e69b746 100644 --- a/pcbnew/router/pns_routing_settings.h +++ b/pcbnew/router/pns_routing_settings.h @@ -3,50 +3,51 @@ * * Copyright (C) 2013 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_ROUTER_SETTINGS #define __PNS_ROUTER_SETTINGS ///> Routing modes -enum PNS_MODE { - RM_Ignore = 0, ///> Ignore collisions - RM_Shove, ///> Only shove - RM_Walkaround, ///> Only walkaround - RM_Smart ///> Guess what's better +enum PNS_MODE +{ + RM_Ignore = 0, ///> Ignore collisions + RM_Shove, ///> Only shove + RM_Walkaround, ///> Only walkaround + RM_Smart ///> Guess what's better }; -class PNS_ROUTING_SETTINGS +class PNS_ROUTING_SETTINGS { - public: - PNS_MODE m_routingMode; +public: + PNS_MODE m_routingMode; - bool m_removeLoops; - bool m_smartPads; - bool m_suggestEnding; - bool m_shoveOnRequest; - bool m_changePostures; - bool m_followMouse; + bool m_removeLoops; + bool m_smartPads; + bool m_suggestEnding; + bool m_shoveOnRequest; + bool m_changePostures; + bool m_followMouse; - int m_lineWidth; - int m_viaDiameter; - int m_viaDrill; - int m_preferredLayer; - int m_walkaroundIterationLimit; - int m_shoveIterationLimit; + int m_lineWidth; + int m_viaDiameter; + int m_viaDrill; + int m_preferredLayer; + int m_walkaroundIterationLimit; + int m_shoveIterationLimit; }; #endif diff --git a/pcbnew/router/pns_segment.h b/pcbnew/router/pns_segment.h index 6cef1b15a6..b8e6e43d34 100644 --- a/pcbnew/router/pns_segment.h +++ b/pcbnew/router/pns_segment.h @@ -3,21 +3,21 @@ * * Copyright (C) 2013 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_SEGMENT_H #define __PNS_SEGMENT_H @@ -32,88 +32,94 @@ class PNS_NODE; -class PNS_SEGMENT : public PNS_ITEM { +class PNS_SEGMENT : public PNS_ITEM +{ public: - PNS_SEGMENT (): - PNS_ITEM(SEGMENT) - {}; + PNS_SEGMENT() : + PNS_ITEM( SEGMENT ) + {}; - PNS_SEGMENT (const SEG& aSeg, int aNet): - PNS_ITEM(SEGMENT) - { - m_net = aNet; - m_shape.Clear(); - m_shape.Append(aSeg.a); - m_shape.Append(aSeg.b); - }; - - PNS_SEGMENT (const PNS_LINE &aParentLine, const SEG& aSeg): - PNS_ITEM(SEGMENT) - { - m_net = aParentLine.GetNet(); - m_layers = aParentLine.GetLayers(); - m_width = aParentLine.GetWidth(); - m_shape.Clear(); - m_shape.Append(aSeg.a); - m_shape.Append(aSeg.b); - }; - + PNS_SEGMENT( const SEG& aSeg, int aNet ) : + PNS_ITEM( SEGMENT ) + { + m_net = aNet; + m_shape.Clear(); + m_shape.Append( aSeg.a ); + m_shape.Append( aSeg.b ); + }; - PNS_SEGMENT *Clone() const; - - const SHAPE* GetShape() const { - return static_cast(&m_shape); - } + PNS_SEGMENT( const PNS_LINE& aParentLine, const SEG& aSeg ) : + PNS_ITEM( SEGMENT ) + { + m_net = aParentLine.GetNet(); + m_layers = aParentLine.GetLayers(); + m_width = aParentLine.GetWidth(); + m_shape.Clear(); + m_shape.Append( aSeg.a ); + m_shape.Append( aSeg.b ); + }; - void SetLayer (int aLayer) - { - SetLayers (PNS_LAYERSET ( aLayer )); - } - int GetLayer() const - { - return GetLayers().Start(); - } + PNS_SEGMENT* Clone() const; - const SHAPE_LINE_CHAIN& GetCLine() const - { - return m_shape; - } + const SHAPE* GetShape() const + { + return static_cast( &m_shape ); + } - void SetWidth( int aWidth ) - { - m_width = aWidth; - } + void SetLayer( int aLayer ) + { + SetLayers( PNS_LAYERSET( aLayer ) ); + } - int GetWidth() const { - return m_width; - } - - const SEG GetSeg() const { - assert(m_shape.PointCount() >= 1); - if(m_shape.PointCount() == 1) - return SEG(m_shape.CPoint(0), m_shape.CPoint(0)); - return SEG(m_shape.CPoint(0), m_shape.CPoint(1)); - } + int GetLayer() const + { + return GetLayers().Start(); + } - void SetEnds ( const VECTOR2I& a, const VECTOR2I& b) - { - m_shape.Clear(); - m_shape.Append(a); - m_shape.Append(b); - } + const SHAPE_LINE_CHAIN& GetCLine() const + { + return m_shape; + } - void SwapEnds() - { - m_shape = m_shape.Reverse(); - } + void SetWidth( int aWidth ) + { + m_width = aWidth; + } - const SHAPE_LINE_CHAIN Hull(int aClearance, int aWalkaroundThickness) const; + int GetWidth() const + { + return m_width; + } + + const SEG GetSeg() const + { + assert( m_shape.PointCount() >= 1 ); + + if( m_shape.PointCount() == 1 ) + return SEG( m_shape.CPoint( 0 ), m_shape.CPoint( 0 ) ); + + return SEG( m_shape.CPoint( 0 ), m_shape.CPoint( 1 ) ); + } + + void SetEnds( const VECTOR2I& a, const VECTOR2I& b ) + { + m_shape.Clear(); + m_shape.Append( a ); + m_shape.Append( b ); + } + + void SwapEnds() + { + m_shape = m_shape.Reverse(); + } + + const SHAPE_LINE_CHAIN Hull( int aClearance, int aWalkaroundThickness ) const; private: - - SHAPE_LINE_CHAIN m_shape; - int m_width; + SHAPE_LINE_CHAIN m_shape; + int m_width; }; #endif + diff --git a/pcbnew/router/pns_shove.cpp b/pcbnew/router/pns_shove.cpp index bd3e12b72e..018ff7da35 100644 --- a/pcbnew/router/pns_shove.cpp +++ b/pcbnew/router/pns_shove.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -37,433 +37,458 @@ using namespace std; -PNS_SHOVE::PNS_SHOVE( PNS_NODE *aWorld ) +PNS_SHOVE::PNS_SHOVE( PNS_NODE* aWorld ) { - m_root = aWorld; - m_iterLimit = 100; + m_root = aWorld; + m_iterLimit = 100; }; + PNS_SHOVE::~PNS_SHOVE() { } -struct range { - range() - { - min_v = max_v = -1; - } - void add ( int x ) - { - if(min_v < 0) min_v = x; - if(max_v < 0) max_v = x; +struct range +{ + range() + { + min_v = max_v = -1; + } - if(x < min_v) - min_v = x; - else if (x > max_v) - max_v = x; - } + void add( int x ) + { + if( min_v < 0 ) min_v = x; - int start() - { - return min_v; - } + if( max_v < 0 ) max_v = x; - int end() - { - return max_v; - } + if( x < min_v ) + min_v = x; + else if( x > max_v ) + max_v = x; + } - int min_v, max_v; + int start() + { + return min_v; + } + + int end() + { + return max_v; + } + + int min_v, max_v; }; // fixme: this is damn f***ing inefficient. And fails much too often due to broken direction finding algorithm. -bool PNS_SHOVE::tryShove(PNS_NODE *aNode, PNS_LINE *aHead, PNS_LINE *aObstacle, PNS_SEGMENT& aObstacleSeg, PNS_LINE *aResult, bool aInvertWinding ) +bool PNS_SHOVE::tryShove( PNS_NODE* aNode, PNS_LINE* aHead, PNS_LINE* aObstacle, + PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult, bool aInvertWinding ) { - const SHAPE_LINE_CHAIN &head = aHead->GetCLine(); - bool cw = false; - int i; + const SHAPE_LINE_CHAIN& head = aHead->GetCLine(); + bool cw = false; + int i; - if(aHead->EndsWithVia() && !aHead->GetLayers().Overlaps(aObstacle->GetLayers())) - { - int clearance = aNode->GetClearance(aHead, aObstacle); - SHAPE_LINE_CHAIN hull = aHead->GetVia().Hull( clearance - aObstacle->GetWidth() / 2 ); + if( aHead->EndsWithVia() && !aHead->GetLayers().Overlaps( aObstacle->GetLayers() ) ) + { + int clearance = aNode->GetClearance( aHead, aObstacle ); + SHAPE_LINE_CHAIN hull = aHead->GetVia().Hull( clearance - aObstacle->GetWidth() / 2 ); - //SHAPE_LINE_CHAIN path_pre, path_walk_cw, path_walk_ccw, path_post; + // SHAPE_LINE_CHAIN path_pre, path_walk_cw, path_walk_ccw, path_post; - SHAPE_LINE_CHAIN path_cw, path_ccw, *path; + SHAPE_LINE_CHAIN path_cw, path_ccw, * path; - aObstacle->NewWalkaround(hull, path_cw, true); - aObstacle->NewWalkaround(hull, path_ccw, false); + aObstacle->NewWalkaround( hull, path_cw, true ); + aObstacle->NewWalkaround( hull, path_ccw, false ); - path = path_ccw.Length() < path_cw.Length() ? &path_ccw : &path_cw; - aResult->SetShape(*path); + path = path_ccw.Length() < path_cw.Length() ? &path_ccw : &path_cw; + aResult->SetShape( *path ); - //PNSDisplayDebugLine (*path, 5); + // PNSDisplayDebugLine (*path, 5); - if(!aResult->Is45Degree()) - { - //printf("polyset non-45\npoly %s\nendpolyset\n", aResult->GetCLine().Format().c_str()); - } - /*... special case for vias? */ + if( !aResult->Is45Degree() ) + { + // printf("polyset non-45\npoly %s\nendpolyset\n", aResult->GetCLine().Format().c_str()); + } - return !aNode->CheckColliding(aResult, aHead); - } + /*... special case for vias? */ - int ns = head.SegmentCount(); - if(aHead->EndsWithVia()) - ns ++; + return !aNode->CheckColliding( aResult, aHead ); + } - for(i = 0; i < head.SegmentCount(); i++) - { - const PNS_SEGMENT hs (*aHead, head.CSegment(i)); + int ns = head.SegmentCount(); + + if( aHead->EndsWithVia() ) + ns++; + + for( i = 0; i < head.SegmentCount(); i++ ) + { + const PNS_SEGMENT hs( *aHead, head.CSegment( i ) ); + if( aNode->CheckColliding( &hs, aObstacle ) ) + { + VECTOR2I v1 = hs.GetSeg().b - hs.GetSeg().a; + VECTOR2I v2 = aObstacleSeg.GetSeg().b - aObstacleSeg.GetSeg().a; - if(aNode->CheckColliding(&hs, aObstacle)) - { - VECTOR2I v1 = hs.GetSeg().b - hs.GetSeg().a; - VECTOR2I v2 = aObstacleSeg.GetSeg().b - aObstacleSeg.GetSeg().a; - - VECTOR2I::extended_type det = v1.Cross(v2); + VECTOR2I::extended_type det = v1.Cross( v2 ); - if(det > 0) - cw = true; - else - cw = false; - - break; - } - } + if( det > 0 ) + cw = true; + else + cw = false; - if(aInvertWinding) - { - if(cw) - cw = false; - else - cw = true; - } + break; + } + } - PNS_LINE shoved (*aObstacle); + if( aInvertWinding ) + { + if( cw ) + cw = false; + else + cw = true; + } - int clearance = aNode->GetClearance(aHead, aObstacle); + PNS_LINE shoved( *aObstacle ); - range r; + int clearance = aNode->GetClearance( aHead, aObstacle ); - for(i = 0; i < ns; i++) - { - SHAPE_LINE_CHAIN hull; - - if(i < head.SegmentCount()) - { - const PNS_SEGMENT hs (*aHead, head.CSegment(i)); - hull = hs.Hull( clearance, 0 ); - } else - hull = aHead->GetVia().Hull( clearance - aObstacle->GetWidth() / 2); - - SHAPE_LINE_CHAIN path_pre, path_walk, path_post, tmp; - SHAPE_LINE_CHAIN path_pre2, path_walk2, path_post2; + range r; - //shoved.NewWalkaround(hull, path_pre, path_walk, path_post, cw); - shoved.NewWalkaround(hull, path_pre, path_walk, path_post, cw); + for( i = 0; i < ns; i++ ) + { + SHAPE_LINE_CHAIN hull; - /*if(path_pre != path_pre2 || path_post != path_post2 || path_walk != path_walk2 ) - { - TRACE(5, "polyset orig\npoly %s\npoly %s\npoly %s\nendpolyset\n", path_pre.Format().c_str() % path_walk.Format().c_str() % path_post.Format().c_str()); - TRACE(5, "polyset err\npoly %s\npoly %s\npoly %s\nendpolyset\n", path_pre2.Format().c_str() % path_walk2.Format().c_str() % path_post2.Format().c_str()); - }*/ + if( i < head.SegmentCount() ) + { + const PNS_SEGMENT hs( *aHead, head.CSegment( i ) ); + hull = hs.Hull( clearance, 0 ); + } + else + hull = aHead->GetVia().Hull( clearance - aObstacle->GetWidth() / 2 ); - tmp = shoved.GetCLine(); - if(path_walk.SegmentCount()) - r.add(i); + SHAPE_LINE_CHAIN path_pre, path_walk, path_post, tmp; + SHAPE_LINE_CHAIN path_pre2, path_walk2, path_post2; - path_pre.Append(path_walk); - path_pre.Append(path_post); - path_pre.Simplify(); - shoved.SetShape(path_pre); -// shoved.SetAffectedRange ( start, end ); - *aResult = shoved; - - if(!aResult->Is45Degree()) - { - //TRACE(5, "polyset non-45\npoly %s\npoly %s\npoly %s\nendpolyset\n", tmp.Format().c_str() % hull.Format().c_str() % aResult->GetCLine().Format().c_str()); - } - - } + // shoved.NewWalkaround(hull, path_pre, path_walk, path_post, cw); + shoved.NewWalkaround( hull, path_pre, path_walk, path_post, cw ); - TRACE(2, "CW %d affectedRange %d-%d [total %d]", (cw?1:0) % r.start() % r.end() % ns); + /*if(path_pre != path_pre2 || path_post != path_post2 || path_walk != path_walk2 ) + * { + * TRACE(5, "polyset orig\npoly %s\npoly %s\npoly %s\nendpolyset\n", path_pre.Format().c_str() % path_walk.Format().c_str() % path_post.Format().c_str()); + * TRACE(5, "polyset err\npoly %s\npoly %s\npoly %s\nendpolyset\n", path_pre2.Format().c_str() % path_walk2.Format().c_str() % path_post2.Format().c_str()); + * }*/ - return !aNode->CheckColliding(aResult, aHead); + tmp = shoved.GetCLine(); + + if( path_walk.SegmentCount() ) + r.add( i ); + + path_pre.Append( path_walk ); + path_pre.Append( path_post ); + path_pre.Simplify(); + shoved.SetShape( path_pre ); +// shoved.SetAffectedRange ( start, end ); + *aResult = shoved; + + if( !aResult->Is45Degree() ) + { + // TRACE(5, "polyset non-45\npoly %s\npoly %s\npoly %s\nendpolyset\n", tmp.Format().c_str() % hull.Format().c_str() % aResult->GetCLine().Format().c_str()); + } + } + + TRACE( 2, "CW %d affectedRange %d-%d [total %d]", (cw ? 1 : 0) % r.start() % r.end() % ns ); + + return !aNode->CheckColliding( aResult, aHead ); } -PNS_SHOVE::ShoveStatus PNS_SHOVE::shoveSingleLine(PNS_NODE *aNode, PNS_LINE *aCurrent, PNS_LINE *aObstacle, PNS_SEGMENT& aObstacleSeg, PNS_LINE *aResult ) + +PNS_SHOVE::ShoveStatus PNS_SHOVE::shoveSingleLine( PNS_NODE* aNode, PNS_LINE* aCurrent, + PNS_LINE* aObstacle, PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult ) { - bool rv = tryShove(aNode, aCurrent, aObstacle, aObstacleSeg, aResult, false); + bool rv = tryShove( aNode, aCurrent, aObstacle, aObstacleSeg, aResult, false ); - if( !rv ) - rv = tryShove(aNode, aCurrent, aObstacle, aObstacleSeg, aResult, true); + if( !rv ) + rv = tryShove( aNode, aCurrent, aObstacle, aObstacleSeg, aResult, true ); - if( !rv ) - { - TRACEn(2, "Shove failed" ); - return SH_INCOMPLETE; - } + if( !rv ) + { + TRACEn( 2, "Shove failed" ); + return SH_INCOMPLETE; + } - aResult->GetLine().Simplify(); + aResult->GetLine().Simplify(); - const SHAPE_LINE_CHAIN& sh_shoved = aResult->GetCLine(); - const SHAPE_LINE_CHAIN& sh_orig = aObstacle->GetCLine(); + const SHAPE_LINE_CHAIN& sh_shoved = aResult->GetCLine(); + const SHAPE_LINE_CHAIN& sh_orig = aObstacle->GetCLine(); - if(sh_shoved.SegmentCount() > 1 && sh_shoved.CPoint(0) == sh_orig.CPoint(0) && sh_shoved.CPoint(-1) == sh_orig.CPoint(-1) ) - return SH_OK; - else if (!sh_shoved.SegmentCount()) - return SH_NULL; - else - return SH_INCOMPLETE; + if( sh_shoved.SegmentCount() > 1 && sh_shoved.CPoint( 0 ) == sh_orig.CPoint( 0 ) + && sh_shoved.CPoint( -1 ) == sh_orig.CPoint( -1 ) ) + return SH_OK; + else if( !sh_shoved.SegmentCount() ) + return SH_NULL; + else + return SH_INCOMPLETE; } -bool PNS_SHOVE::reduceSpringback( PNS_LINE *aHead ) -{ - bool rv = false; - - while(!m_nodeStack.empty()) - { - SpringbackTag st_stack = m_nodeStack.back(); - bool tail_ok = true; - - if(!st_stack.node->CheckColliding(aHead) && tail_ok) - { - rv = true; - delete st_stack.node; - m_nodeStack.pop_back(); - } else - break; - } - return rv; +bool PNS_SHOVE::reduceSpringback( PNS_LINE* aHead ) +{ + bool rv = false; + + while( !m_nodeStack.empty() ) + { + SpringbackTag st_stack = m_nodeStack.back(); + bool tail_ok = true; + + if( !st_stack.node->CheckColliding( aHead ) && tail_ok ) + { + rv = true; + delete st_stack.node; + m_nodeStack.pop_back(); + } + else + break; + } + + return rv; } -bool PNS_SHOVE::pushSpringback( PNS_NODE *aNode, PNS_LINE *aHead, const PNS_COST_ESTIMATOR& aCost ) + +bool PNS_SHOVE::pushSpringback( PNS_NODE* aNode, PNS_LINE* aHead, const PNS_COST_ESTIMATOR& aCost ) { - BOX2I headBB = aHead->GetCLine().BBox(); - SpringbackTag st; - - st.node = aNode; - st.cost = aCost; - st.length = std::max(headBB.GetWidth(), headBB.GetHeight());; - m_nodeStack.push_back(st); - return true; + BOX2I headBB = aHead->GetCLine().BBox(); + SpringbackTag st; + + st.node = aNode; + st.cost = aCost; + st.length = std::max( headBB.GetWidth(), headBB.GetHeight() );; + m_nodeStack.push_back( st ); + return true; } + const PNS_COST_ESTIMATOR PNS_SHOVE::TotalCost() const { - if(m_nodeStack.empty()) - return PNS_COST_ESTIMATOR(); - else - return m_nodeStack.back().cost; + if( m_nodeStack.empty() ) + return PNS_COST_ESTIMATOR(); + else + return m_nodeStack.back().cost; } -PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines(PNS_LINE* aCurrentHead) + +PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines( PNS_LINE* aCurrentHead ) { - stack lineStack; - PNS_NODE *node, *parent; - PNS_VIA *headVia = NULL; - bool fail = false; - int iter = 0; + stack lineStack; + PNS_NODE* node, * parent; + PNS_VIA* headVia = NULL; + bool fail = false; + int iter = 0; - PNS_LINE *head = aCurrentHead->Clone(); + PNS_LINE* head = aCurrentHead->Clone(); - reduceSpringback(aCurrentHead); + reduceSpringback( aCurrentHead ); - parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().node; - node = parent->Branch(); + parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().node; + node = parent->Branch(); - lineStack.push(head); + lineStack.push( head ); - //node->Add(tail); - node->Add(head); + // node->Add(tail); + node->Add( head ); - if(head->EndsWithVia()) - { - headVia = head->GetVia().Clone(); - node->Add( headVia ); - } + if( head->EndsWithVia() ) + { + headVia = head->GetVia().Clone(); + node->Add( headVia ); + } - PNS_OPTIMIZER optimizer (node); + PNS_OPTIMIZER optimizer( node ); - optimizer.SetEffortLevel (PNS_OPTIMIZER::MERGE_SEGMENTS | PNS_OPTIMIZER::SMART_PADS); - optimizer.SetCollisionMask( -1 ); - PNS_NODE::OptObstacle nearest; + optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_SEGMENTS | PNS_OPTIMIZER::SMART_PADS ); + optimizer.SetCollisionMask( -1 ); + PNS_NODE::OptObstacle nearest; - optimizer.CacheStaticItem(head); - if(headVia) - optimizer.CacheStaticItem(headVia); + optimizer.CacheStaticItem( head ); - TRACE(1, "ShoveStart [root: %d jts, node: %d jts]", m_root->JointCount() % node->JointCount()); - - //PNS_ITEM *lastWalkSolid = NULL; - prof_counter totalRealTime; + if( headVia ) + optimizer.CacheStaticItem( headVia ); + TRACE( 1, "ShoveStart [root: %d jts, node: %d jts]", m_root->JointCount() % + node->JointCount() ); - wxLongLong t_start = wxGetLocalTimeMillis(); + // PNS_ITEM *lastWalkSolid = NULL; + prof_counter totalRealTime; - while(!lineStack.empty()) - { + wxLongLong t_start = wxGetLocalTimeMillis(); - wxLongLong t_cur = wxGetLocalTimeMillis(); + while( !lineStack.empty() ) + { + wxLongLong t_cur = wxGetLocalTimeMillis(); - if ((t_cur - t_start).ToLong() > ShoveTimeLimit) - { - fail = true; - break; - } + if( (t_cur - t_start).ToLong() > ShoveTimeLimit ) + { + fail = true; + break; + } - iter++; - - if(iter > m_iterLimit) - { - fail = true; - break; - } - - PNS_LINE *currentLine = lineStack.top(); + iter++; - prof_start( &totalRealTime, false ); - nearest = node->NearestObstacle(currentLine, PNS_ITEM::ANY); - prof_end( &totalRealTime ); + if( iter > m_iterLimit ) + { + fail = true; + break; + } - TRACE(2,"t-nearestObstacle %lld us", (totalRealTime.value )); + PNS_LINE* currentLine = lineStack.top(); - if(!nearest) - { - if(lineStack.size() > 1) - { - PNS_LINE *original = lineStack.top(); - PNS_LINE optimized; - int r_start, r_end; + prof_start( &totalRealTime, false ); + nearest = node->NearestObstacle( currentLine, PNS_ITEM::ANY ); + prof_end( &totalRealTime ); - original->GetAffectedRange(r_start, r_end); + TRACE( 2, "t-nearestObstacle %lld us", (totalRealTime.value ) ); - TRACE(1, "Iter %d optimize-line [range %d-%d, total %d]", iter % r_start % r_end % original->GetCLine().PointCount() ); - //lastWalkSolid = NULL; - prof_start( &totalRealTime, false ); + if( !nearest ) + { + if( lineStack.size() > 1 ) + { + PNS_LINE* original = lineStack.top(); + PNS_LINE optimized; + int r_start, r_end; - if( optimizer.Optimize(original, &optimized) ) - { - node->Remove(original); - optimizer.CacheRemove(original); - node->Add(&optimized); + original->GetAffectedRange( r_start, r_end ); - if(original->BelongsTo(node)) - delete original; - } - prof_end( &totalRealTime ); + TRACE( 1, "Iter %d optimize-line [range %d-%d, total %d]", + iter % r_start % r_end % original->GetCLine().PointCount() ); + // lastWalkSolid = NULL; + prof_start( &totalRealTime, false ); - TRACE(2,"t-optimizeObstacle %lld us", (totalRealTime.value )); + if( optimizer.Optimize( original, &optimized ) ) + { + node->Remove( original ); + optimizer.CacheRemove( original ); + node->Add( &optimized ); - } - lineStack.pop(); - } else { + if( original->BelongsTo( node ) ) + delete original; + } - switch(nearest->item->GetKind()) - { - case PNS_ITEM::SEGMENT: - { - TRACE(1, "Iter %d shove-line", iter ); + prof_end( &totalRealTime ); - PNS_SEGMENT *pseg = static_cast(nearest->item); - PNS_LINE *collidingLine = node->AssembleLine(pseg); - PNS_LINE *shovedLine = collidingLine->CloneProperties(); - - prof_start( &totalRealTime, false ); - ShoveStatus st = shoveSingleLine(node, currentLine, collidingLine, *pseg, shovedLine); - prof_end( &totalRealTime ); + TRACE( 2, "t-optimizeObstacle %lld us", (totalRealTime.value ) ); + } - TRACE(2,"t-shoveSingle %lld us", (totalRealTime.value )); + lineStack.pop(); + } + else + { + switch( nearest->item->GetKind() ) + { + case PNS_ITEM::SEGMENT: + { + TRACE( 1, "Iter %d shove-line", iter ); - if(st == SH_OK) - { - node->Replace(collidingLine, shovedLine); + PNS_SEGMENT* pseg = static_cast(nearest->item); + PNS_LINE* collidingLine = node->AssembleLine( pseg ); + PNS_LINE* shovedLine = collidingLine->CloneProperties(); - if(collidingLine->BelongsTo( node )) - delete collidingLine; + prof_start( &totalRealTime, false ); + ShoveStatus st = shoveSingleLine( node, currentLine, collidingLine, + *pseg, shovedLine ); + prof_end( &totalRealTime ); - optimizer.CacheRemove(collidingLine); - lineStack.push( shovedLine ); - } else - fail = true; - - //lastWalkSolid = NULL; + TRACE( 2, "t-shoveSingle %lld us", (totalRealTime.value ) ); - break; - } // case SEGMENT + if( st == SH_OK ) + { + node->Replace( collidingLine, shovedLine ); - case PNS_ITEM::SOLID: - case PNS_ITEM::VIA: - { - TRACE(1, "Iter %d walkaround-solid [%p]", iter % nearest->item ); - - if(lineStack.size() == 1) - { - fail = true; - break; - } + if( collidingLine->BelongsTo( node ) ) + delete collidingLine; + + optimizer.CacheRemove( collidingLine ); + lineStack.push( shovedLine ); + } + else + fail = true; + + // lastWalkSolid = NULL; + + break; + } // case SEGMENT + + case PNS_ITEM::SOLID: + case PNS_ITEM::VIA: + { + TRACE( 1, "Iter %d walkaround-solid [%p]", iter % nearest->item ); + + if( lineStack.size() == 1 ) + { + fail = true; + break; + } /* if(lastWalkSolid == nearest->item) - { - fail = true; - break; - }*/ + * { + * fail = true; + * break; + * }*/ - PNS_WALKAROUND walkaround (node); - PNS_LINE *walkaroundLine = currentLine->CloneProperties(); + PNS_WALKAROUND walkaround( node ); + PNS_LINE* walkaroundLine = currentLine->CloneProperties(); - walkaround.SetSolidsOnly(true); - walkaround.SetSingleDirection(true); - - prof_start( &totalRealTime, false ); - walkaround.Route(*currentLine, *walkaroundLine, false); - prof_end( &totalRealTime ); + walkaround.SetSolidsOnly( true ); + walkaround.SetSingleDirection( true ); - TRACE(2,"t-walkSolid %lld us", (totalRealTime.value )); + prof_start( &totalRealTime, false ); + walkaround.Route( *currentLine, *walkaroundLine, false ); + prof_end( &totalRealTime ); + + TRACE( 2, "t-walkSolid %lld us", (totalRealTime.value ) ); - node->Replace(currentLine, walkaroundLine); + node->Replace( currentLine, walkaroundLine ); - if(currentLine->BelongsTo( node )) - delete currentLine; + if( currentLine->BelongsTo( node ) ) + delete currentLine; - optimizer.CacheRemove(currentLine); - lineStack.top() = walkaroundLine; + optimizer.CacheRemove( currentLine ); + lineStack.top() = walkaroundLine; - //lastWalkSolid = nearest->item; - break; - } - default: - break; - } // switch - if(fail) - break; - } - } - - node->Remove(head); - delete head; - - if(headVia) - { - node->Remove(headVia); - delete headVia; - } + // lastWalkSolid = nearest->item; + break; + } - TRACE(1, "Shove status : %s after %d iterations" , (fail ? "FAILED" : "OK") % iter ); - if(!fail) - { - pushSpringback(node, aCurrentHead, PNS_COST_ESTIMATOR()); - return SH_OK; - } else { - delete node; - return SH_INCOMPLETE; - } + default: + break; + } // switch + + if( fail ) + break; + } + } + + node->Remove( head ); + delete head; + + if( headVia ) + { + node->Remove( headVia ); + delete headVia; + } + + TRACE( 1, "Shove status : %s after %d iterations", (fail ? "FAILED" : "OK") % iter ); + + if( !fail ) + { + pushSpringback( node, aCurrentHead, PNS_COST_ESTIMATOR() ); + return SH_OK; + } + else + { + delete node; + return SH_INCOMPLETE; + } } diff --git a/pcbnew/router/pns_shove.h b/pcbnew/router/pns_shove.h index c40dbe9858..9d5fca0f88 100644 --- a/pcbnew/router/pns_shove.h +++ b/pcbnew/router/pns_shove.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -30,53 +30,57 @@ class PNS_LINE; class PNS_NODE; class PNS_ROUTER; -class PNS_SHOVE { +class PNS_SHOVE +{ +public: + PNS_SHOVE( PNS_NODE* aWorld ); + ~PNS_SHOVE(); - public: - PNS_SHOVE(PNS_NODE *aWorld); - ~PNS_SHOVE(); + enum ShoveStatus + { + SH_OK = 0, + SH_NULL, + SH_INCOMPLETE + }; - enum ShoveStatus { - SH_OK = 0, - SH_NULL, - SH_INCOMPLETE - }; + ShoveStatus ShoveLines( PNS_LINE* aCurrentHead ); - ShoveStatus ShoveLines(PNS_LINE* aCurrentHead); + PNS_NODE* GetCurrentNode() + { + return m_nodeStack.empty() ? m_root : m_nodeStack.back().node; + } - PNS_NODE *GetCurrentNode() - { - return m_nodeStack.empty() ? m_root : m_nodeStack.back().node; - } + const PNS_COST_ESTIMATOR TotalCost() const; - const PNS_COST_ESTIMATOR TotalCost() const; + void Reset(); + void KillChildNodes(); - void Reset(); - void KillChildNodes(); +private: + static const int ShoveTimeLimit = 3000; - private: + bool tryShove( PNS_NODE* aWorld, PNS_LINE* aTrack, PNS_LINE* aObstacle, + PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult, bool aInvertWinding ); - static const int ShoveTimeLimit = 3000; + ShoveStatus shoveSingleLine( PNS_NODE* aNode, PNS_LINE* aCurrent, PNS_LINE* aObstacle, + PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult ); - bool tryShove(PNS_NODE *aWorld, PNS_LINE *aTrack, PNS_LINE * aObstacle, PNS_SEGMENT& aObstacleSeg, PNS_LINE *aResult, bool aInvertWinding ); + bool reduceSpringback( PNS_LINE* aHead ); + bool pushSpringback( PNS_NODE* aNode, PNS_LINE* aHead, const PNS_COST_ESTIMATOR& aCost ); - ShoveStatus shoveSingleLine(PNS_NODE *aNode, PNS_LINE *aCurrent, PNS_LINE *aObstacle, PNS_SEGMENT& aObstacleSeg, PNS_LINE *aResult ); + struct SpringbackTag + { + int64_t length; + int segments; + VECTOR2I p; + PNS_NODE* node; + PNS_COST_ESTIMATOR cost; + }; - bool reduceSpringback( PNS_LINE *aHead ); - bool pushSpringback( PNS_NODE *aNode, PNS_LINE *aHead, const PNS_COST_ESTIMATOR& aCost ); - - struct SpringbackTag { - int64_t length; - int segments; - VECTOR2I p; - PNS_NODE *node; - PNS_COST_ESTIMATOR cost; - }; - - std::vector m_nodeStack; - PNS_NODE *m_root; - PNS_NODE *m_currentNode; - int m_iterLimit; + std::vector m_nodeStack; + PNS_NODE* m_root; + PNS_NODE* m_currentNode; + int m_iterLimit; }; #endif + diff --git a/pcbnew/router/pns_solid.cpp b/pcbnew/router/pns_solid.cpp index e3841e72ca..fb9e1d2a9e 100644 --- a/pcbnew/router/pns_solid.cpp +++ b/pcbnew/router/pns_solid.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -28,37 +28,36 @@ #include "pns_solid.h" #include "pns_utils.h" -const SHAPE_LINE_CHAIN PNS_SOLID::Hull(int aClearance, int aWalkaroundThickness) const +const SHAPE_LINE_CHAIN PNS_SOLID::Hull( int aClearance, int aWalkaroundThickness ) const { - switch(m_shape->Type()) - { - case SH_RECT: - { - SHAPE_RECT *rect = static_cast (m_shape); - return OctagonalHull( rect->GetPosition(), - rect->GetSize(), - aClearance + 1, - 0.2 * aClearance ); - } + switch( m_shape->Type() ) + { + case SH_RECT: + { + SHAPE_RECT* rect = static_cast( m_shape ); + return OctagonalHull( rect->GetPosition(), rect->GetSize(), + aClearance + 1, 0.2 * aClearance ); + } - case SH_CIRCLE: - { - SHAPE_CIRCLE *circle = static_cast (m_shape); - int r = circle->GetRadius(); - return OctagonalHull( circle->GetCenter() - VECTOR2I(r, r), - VECTOR2I(2 * r, 2 * r), - aClearance + 1, - 0.52 * (r + aClearance) ); - } - default: - break; - } + case SH_CIRCLE: + { + SHAPE_CIRCLE* circle = static_cast( m_shape ); + int r = circle->GetRadius(); + return OctagonalHull( circle->GetCenter() - VECTOR2I( r, r ), VECTOR2I( 2 * r, 2 * r ), + aClearance + 1, 0.52 * (r + aClearance) ); + } - return SHAPE_LINE_CHAIN(); + default: + break; + } + + return SHAPE_LINE_CHAIN(); } -PNS_ITEM *PNS_SOLID::Clone() const + +PNS_ITEM* PNS_SOLID::Clone() const { - // solids are never cloned as the shove algorithm never moves them - assert(false); -} \ No newline at end of file + // solids are never cloned as the shove algorithm never moves them + assert( false ); +} + diff --git a/pcbnew/router/pns_solid.h b/pcbnew/router/pns_solid.h index d89135d00f..f2367eb38b 100644 --- a/pcbnew/router/pns_solid.h +++ b/pcbnew/router/pns_solid.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -29,41 +29,42 @@ #include "pns_item.h" -class PNS_SOLID : public PNS_ITEM { +class PNS_SOLID : public PNS_ITEM +{ public: - PNS_SOLID() : PNS_ITEM(SOLID) - { - m_movable = false; - m_shape = NULL; - } - - PNS_ITEM *Clone() const; - - const SHAPE* GetShape() const { return m_shape; } + PNS_SOLID() : PNS_ITEM( SOLID ) + { + m_movable = false; + m_shape = NULL; + } - const SHAPE_LINE_CHAIN Hull(int aClearance = 0, int aWalkaroundThickness = 0) const; + PNS_ITEM* Clone() const; - void SetShape( SHAPE* shape) - { - if(m_shape) - delete m_shape; - m_shape = shape; - } + const SHAPE* GetShape() const { return m_shape; } - const VECTOR2I& GetCenter() const - { - return m_center; - } + const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0 ) const; - void SetCenter( const VECTOR2I& aCenter ) - { - m_center = aCenter; - } + void SetShape( SHAPE* shape ) + { + if( m_shape ) + delete m_shape; + + m_shape = shape; + } + + const VECTOR2I& GetCenter() const + { + return m_center; + } + + void SetCenter( const VECTOR2I& aCenter ) + { + m_center = aCenter; + } private: - - VECTOR2I m_center; - SHAPE* m_shape; + VECTOR2I m_center; + SHAPE* m_shape; }; #endif diff --git a/pcbnew/router/pns_utils.cpp b/pcbnew/router/pns_utils.cpp index 6a2fbb49b3..a91d787c9d 100644 --- a/pcbnew/router/pns_utils.cpp +++ b/pcbnew/router/pns_utils.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -22,21 +22,24 @@ #include "pns_line.h" #include "pns_router.h" -const SHAPE_LINE_CHAIN OctagonalHull(const VECTOR2I& aP0, const VECTOR2I& aSize, int aClearance, int aChamfer) +const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, + const VECTOR2I& aSize, + int aClearance, + int aChamfer ) { - SHAPE_LINE_CHAIN s; + SHAPE_LINE_CHAIN s; - s.SetClosed( true ); - - s.Append(aP0.x - aClearance , aP0.y - aClearance + aChamfer); - s.Append(aP0.x - aClearance + aChamfer, aP0.y - aClearance); - s.Append(aP0.x + aSize.x + aClearance - aChamfer, aP0.y - aClearance); - s.Append(aP0.x + aSize.x + aClearance, aP0.y - aClearance + aChamfer); - s.Append(aP0.x + aSize.x + aClearance, aP0.y + aSize.y + aClearance - aChamfer); - s.Append(aP0.x + aSize.x + aClearance - aChamfer, aP0.y + aSize.y + aClearance); - s.Append(aP0.x - aClearance + aChamfer, aP0.y + aSize.y + aClearance); - s.Append(aP0.x - aClearance, aP0.y + aSize.y + aClearance - aChamfer); - - return s; + s.SetClosed( true ); + + s.Append( aP0.x - aClearance, aP0.y - aClearance + aChamfer ); + s.Append( aP0.x - aClearance + aChamfer, aP0.y - aClearance ); + s.Append( aP0.x + aSize.x + aClearance - aChamfer, aP0.y - aClearance ); + s.Append( aP0.x + aSize.x + aClearance, aP0.y - aClearance + aChamfer ); + s.Append( aP0.x + aSize.x + aClearance, aP0.y + aSize.y + aClearance - aChamfer ); + s.Append( aP0.x + aSize.x + aClearance - aChamfer, aP0.y + aSize.y + aClearance ); + s.Append( aP0.x - aClearance + aChamfer, aP0.y + aSize.y + aClearance ); + s.Append( aP0.x - aClearance, aP0.y + aSize.y + aClearance - aChamfer ); + + return s; } diff --git a/pcbnew/router/pns_utils.h b/pcbnew/router/pns_utils.h index 97ce5d9884..016ce73611 100644 --- a/pcbnew/router/pns_utils.h +++ b/pcbnew/router/pns_utils.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -24,10 +24,10 @@ #include #include - /** Various utility functions */ -const SHAPE_LINE_CHAIN OctagonalHull(const VECTOR2I& aP0, const VECTOR2I& aSize, int aClearance, int aChamfer); +const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, const VECTOR2I& aSize, + int aClearance, int aChamfer ); -#endif // __PNS_UTILS_H +#endif // __PNS_UTILS_H diff --git a/pcbnew/router/pns_via.cpp b/pcbnew/router/pns_via.cpp index 81a3d56ef2..30666d78ab 100644 --- a/pcbnew/router/pns_via.cpp +++ b/pcbnew/router/pns_via.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -26,123 +26,136 @@ static bool Circle2Circle( VECTOR2I p1, VECTOR2I p2, int r1, int r2, VECTOR2I& force ) { + int mindist = r1 + r2; + VECTOR2I delta = p2 - p1; + int dist = delta.EuclideanNorm(); - int mindist = r1 + r2; - VECTOR2I delta = p2 - p1; - int dist = delta.EuclideanNorm(); - - if(dist >= mindist) - return false; - - force = delta.Resize(abs(mindist - dist) + 1); - return true; + if( dist >= mindist ) + return false; + + force = delta.Resize( abs( mindist - dist ) + 1 ); + return true; }; static bool Rect2Circle( VECTOR2I rp0, VECTOR2I rsize, VECTOR2I cc, int cr, VECTOR2I& force ) { - VECTOR2I vts[] = { VECTOR2I(rp0.x, rp0.y), - VECTOR2I(rp0.x, rp0.y + rsize.y), - VECTOR2I(rp0.x + rsize.x, rp0.y + rsize.y), - VECTOR2I(rp0.x + rsize.x, rp0.y), - VECTOR2I(rp0.x, rp0.y) }; + VECTOR2I vts[] = + { + VECTOR2I( rp0.x, rp0.y ), + VECTOR2I( rp0.x, rp0.y + rsize.y ), + VECTOR2I( rp0.x + rsize.x, rp0.y + rsize.y ), + VECTOR2I( rp0.x + rsize.x, rp0.y ), + VECTOR2I( rp0.x, rp0.y ) + }; - int dist = INT_MAX; - VECTOR2I nearest; + int dist = INT_MAX; + VECTOR2I nearest; - for (int i = 0; i < 4; i++) - { - SEG s(vts[i], vts[i+1]); - - VECTOR2I pn = s.NearestPoint( cc ); + for( int i = 0; i < 4; i++ ) + { + SEG s( vts[i], vts[i + 1] ); - int d = (pn - cc).EuclideanNorm(); - if( d < dist ) - { - nearest = pn; - dist = d; - } - } + VECTOR2I pn = s.NearestPoint( cc ); - bool inside = cc.x >= rp0.x && cc.x <= (rp0.x + rsize.x) - && cc.y >= rp0.y && cc.y <= (rp0.y + rsize.y); + int d = (pn - cc).EuclideanNorm(); - VECTOR2I delta = cc - nearest; + if( d < dist ) + { + nearest = pn; + dist = d; + } + } - if(dist >= cr && !inside) - return false; + bool inside = cc.x >= rp0.x && cc.x <= (rp0.x + rsize.x) + && cc.y >= rp0.y && cc.y <= (rp0.y + rsize.y); - if(inside) - force = -delta.Resize(abs(cr + dist) + 1); - else - force = delta.Resize(abs(cr - dist) + 1); + VECTOR2I delta = cc - nearest; - return true; + if( dist >= cr && !inside ) + return false; + + if( inside ) + force = -delta.Resize( abs( cr + dist ) + 1 ); + else + force = delta.Resize( abs( cr - dist ) + 1 ); + + return true; }; -static bool ShPushoutForce ( const SHAPE *shape, VECTOR2I p, int r, VECTOR2I& force, int clearance) +static bool ShPushoutForce( const SHAPE* shape, VECTOR2I p, int r, VECTOR2I& force, int clearance ) { - switch(shape->Type()) - { - case SH_CIRCLE: - { - const SHAPE_CIRCLE *cir = static_cast(shape); - return Circle2Circle( cir->GetCenter(), p, cir->GetRadius(), r + clearance + 1, force ); - } - case SH_RECT: - { - const SHAPE_RECT *rect = static_cast(shape); - return Rect2Circle( rect->GetPosition(), rect->GetSize(), p, r + clearance + 1, force ); - } - default: - return false; + switch( shape->Type() ) + { + case SH_CIRCLE: + { + const SHAPE_CIRCLE* cir = static_cast(shape); + return Circle2Circle( cir->GetCenter(), p, cir->GetRadius(), r + clearance + 1, force ); + } - } - return false; + case SH_RECT: + { + const SHAPE_RECT* rect = static_cast(shape); + return Rect2Circle( rect->GetPosition(), rect->GetSize(), p, r + clearance + 1, force ); + } + + default: + return false; + } + + return false; } -bool PNS_VIA::PushoutForce ( PNS_NODE *aNode, const VECTOR2I &aDirection, VECTOR2I& aForce, bool aSolidsOnly, int aMaxIterations) +bool PNS_VIA::PushoutForce( PNS_NODE* aNode, + const VECTOR2I& aDirection, + VECTOR2I& aForce, + bool aSolidsOnly, + int aMaxIterations ) { - int iter = 0; - PNS_VIA mv ( *this); - VECTOR2I force, totalForce; + int iter = 0; + PNS_VIA mv( *this ); + VECTOR2I force, totalForce; - while(iter < aMaxIterations) - { - PNS_NODE::OptObstacle obs = aNode->CheckColliding( &mv, aSolidsOnly ? PNS_ITEM::SOLID : PNS_ITEM::ANY); - - if(!obs) - break; + while( iter < aMaxIterations ) + { + PNS_NODE::OptObstacle obs = aNode->CheckColliding( &mv, + aSolidsOnly ? PNS_ITEM::SOLID : PNS_ITEM::ANY ); - int clearance = aNode->GetClearance(obs->item, &mv); + if( !obs ) + break; - if(iter > 10) - { - VECTOR2I l = - aDirection.Resize(m_diameter / 4); - totalForce += l; - mv.SetPos(mv.GetPos() + l); - } + int clearance = aNode->GetClearance( obs->item, &mv ); - if( ShPushoutForce(obs->item->GetShape(), mv.GetPos(), mv.GetDiameter() / 2, force, clearance) ) - { - totalForce += force; - mv.SetPos(mv.GetPos() + force); - } + if( iter > 10 ) + { + VECTOR2I l = -aDirection.Resize( m_diameter / 4 ); + totalForce += l; + mv.SetPos( mv.GetPos() + l ); + } + + if( ShPushoutForce( obs->item->GetShape(), mv.GetPos(), mv.GetDiameter() / 2, force, + clearance ) ) + { + totalForce += force; + mv.SetPos( mv.GetPos() + force ); + } - iter++; - } + iter++; + } - if(iter == aMaxIterations) - return false; + if( iter == aMaxIterations ) + return false; - aForce = totalForce; - return true; + aForce = totalForce; + return true; } -const SHAPE_LINE_CHAIN PNS_VIA::Hull(int aClearance, int aWalkaroundThickness) const + +const SHAPE_LINE_CHAIN PNS_VIA::Hull( int aClearance, int aWalkaroundThickness ) const { - return OctagonalHull( m_pos - VECTOR2I(m_diameter/2, m_diameter/2), VECTOR2I(m_diameter, m_diameter), aClearance + 1, (2*aClearance + m_diameter) * 0.26); + return OctagonalHull( m_pos - + VECTOR2I( m_diameter / 2, m_diameter / 2 ), VECTOR2I( m_diameter, + m_diameter ), aClearance + 1, (2 * aClearance + m_diameter) * 0.26 ); } - \ No newline at end of file diff --git a/pcbnew/router/pns_via.h b/pcbnew/router/pns_via.h index 3fdd8f8508..1a0fc2a2bd 100644 --- a/pcbnew/router/pns_via.h +++ b/pcbnew/router/pns_via.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -28,91 +28,96 @@ class PNS_NODE; -class PNS_VIA : public PNS_ITEM +class PNS_VIA : public PNS_ITEM { - public: - PNS_VIA( ): - PNS_ITEM (VIA) {}; +public: + PNS_VIA() : + PNS_ITEM( VIA ) {}; - PNS_VIA( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aDiameter, int aNet = -1) : - PNS_ITEM (VIA) { - SetNet(aNet); - SetLayers(aLayers); - m_pos = aPos; - m_diameter = aDiameter; - m_shape = SHAPE_CIRCLE(aPos, aDiameter/2); - }; + PNS_VIA( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aDiameter, int aNet = -1 ) : + PNS_ITEM( VIA ) + { + SetNet( aNet ); + SetLayers( aLayers ); + m_pos = aPos; + m_diameter = aDiameter; + m_shape = SHAPE_CIRCLE( aPos, aDiameter / 2 ); + }; - PNS_VIA(const PNS_VIA& b) : PNS_ITEM(VIA) - { - SetNet(b.GetNet()); - SetLayers(b.GetLayers()); - m_pos = b.m_pos; - m_diameter = b.m_diameter; - m_shape = SHAPE_CIRCLE(m_pos, m_diameter/2); - } + PNS_VIA( const PNS_VIA& b ) : PNS_ITEM( VIA ) + { + SetNet( b.GetNet() ); + SetLayers( b.GetLayers() ); + m_pos = b.m_pos; + m_diameter = b.m_diameter; + m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 ); + } - const VECTOR2I& GetPos() const - { - return m_pos; - } + const VECTOR2I& GetPos() const + { + return m_pos; + } - void SetPos( const VECTOR2I& aPos ) - { - m_pos = aPos; - m_shape.SetCenter(aPos); - } + void SetPos( const VECTOR2I& aPos ) + { + m_pos = aPos; + m_shape.SetCenter( aPos ); + } - int GetDiameter() const - { - return m_diameter; - } + int GetDiameter() const + { + return m_diameter; + } - void SetDiameter(int aDiameter) - { - m_diameter = aDiameter; - m_shape.SetRadius(m_diameter/2); - } + void SetDiameter( int aDiameter ) + { + m_diameter = aDiameter; + m_shape.SetRadius( m_diameter / 2 ); + } - int GetDrill() const - { - return m_drill; - } + int GetDrill() const + { + return m_drill; + } - void SetDrill(int aDrill) - { - m_drill = aDrill; - } + void SetDrill( int aDrill ) + { + m_drill = aDrill; + } - bool PushoutForce ( PNS_NODE *aNode, const VECTOR2I &aDirection, VECTOR2I& aForce, bool aSolidsOnly = true, int aMaxIterations = 10); + bool PushoutForce( PNS_NODE* aNode, + const VECTOR2I& aDirection, + VECTOR2I& aForce, + bool aSolidsOnly = true, + int aMaxIterations = 10 ); - const SHAPE *GetShape() const - { - return &m_shape; - } + const SHAPE* GetShape() const + { + return &m_shape; + } - PNS_VIA *Clone() const - { - PNS_VIA *v = new PNS_VIA(); + PNS_VIA* Clone() const + { + PNS_VIA* v = new PNS_VIA(); - v->SetNet(GetNet()); - v->SetLayers(GetLayers()); - v->m_pos = m_pos; - v->m_diameter = m_diameter; - v->m_shape = SHAPE_CIRCLE(m_pos, m_diameter/2); - - return v; - } + v->SetNet( GetNet() ); + v->SetLayers( GetLayers() ); + v->m_pos = m_pos; + v->m_diameter = m_diameter; + v->m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 ); - const SHAPE_LINE_CHAIN Hull(int aClearance = 0, int aWalkaroundThickness = 0) const; + return v; + } - private: - - int m_diameter; - int m_drill; - VECTOR2I m_pos; - SHAPE_CIRCLE m_shape; + const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0 ) const; + +private: + + int m_diameter; + int m_drill; + VECTOR2I m_pos; + SHAPE_CIRCLE m_shape; }; #endif diff --git a/pcbnew/router/pns_walkaround.cpp b/pcbnew/router/pns_walkaround.cpp index c384fdbee5..ee3cb9c09c 100644 --- a/pcbnew/router/pns_walkaround.cpp +++ b/pcbnew/router/pns_walkaround.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -35,187 +35,197 @@ using boost::optional; void PNS_WALKAROUND::start( const PNS_LINE& aInitialPath ) { - m_iteration = 0; - m_iteration_limit = 50; + m_iteration = 0; + m_iteration_limit = 50; } -PNS_NODE::OptObstacle PNS_WALKAROUND::nearestObstacle(const PNS_LINE& aPath) +PNS_NODE::OptObstacle PNS_WALKAROUND::nearestObstacle( const PNS_LINE& aPath ) { - return m_world->NearestObstacle ( &aPath, m_solids_only ? (PNS_ITEM::SOLID | PNS_ITEM::VIA) : PNS_ITEM::ANY ); + return m_world->NearestObstacle( &aPath, + m_solids_only ? (PNS_ITEM::SOLID | PNS_ITEM::VIA) : PNS_ITEM::ANY ); } -PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::singleStep(PNS_LINE& aPath, bool aWindingDirection) +PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::singleStep( PNS_LINE& aPath, + bool aWindingDirection ) { - optional& current_obs = aWindingDirection ? m_currentObstacle[0] : m_currentObstacle[1]; - bool& prev_recursive = aWindingDirection ? m_recursiveCollision[0] : m_recursiveCollision[1]; - - if(!current_obs) - return DONE; + optional& current_obs = + aWindingDirection ? m_currentObstacle[0] : m_currentObstacle[1]; + bool& prev_recursive = aWindingDirection ? m_recursiveCollision[0] : m_recursiveCollision[1]; - SHAPE_LINE_CHAIN path_pre[2], path_walk[2], path_post[2]; + if( !current_obs ) + return DONE; - VECTOR2I last = aPath.GetCLine().CPoint(-1); + SHAPE_LINE_CHAIN path_pre[2], path_walk[2], path_post[2]; - if((current_obs->hull).PointInside(last)) - { - m_recursiveBlockageCount ++; + VECTOR2I last = aPath.GetCLine().CPoint( -1 ); - if(m_recursiveBlockageCount < 3) - aPath.GetLine().Append( current_obs->hull.NearestPoint(last) ); - else { - aPath = aPath.ClipToNearestObstacle(m_world); - return STUCK; - } - } + if( ( current_obs->hull ).PointInside( last ) ) + { + m_recursiveBlockageCount++; - aPath.NewWalkaround(current_obs->hull, path_pre[0], path_walk[0], path_post[0], aWindingDirection); - aPath.NewWalkaround(current_obs->hull, path_pre[1], path_walk[1], path_post[1], !aWindingDirection); + if( m_recursiveBlockageCount < 3 ) + aPath.GetLine().Append( current_obs->hull.NearestPoint( last ) ); + else + { + aPath = aPath.ClipToNearestObstacle( m_world ); + return STUCK; + } + } + aPath.NewWalkaround( current_obs->hull, path_pre[0], path_walk[0], + path_post[0], aWindingDirection ); + aPath.NewWalkaround( current_obs->hull, path_pre[1], path_walk[1], + path_post[1], !aWindingDirection ); - int len_pre = path_walk[0].Length(); - int len_alt = path_walk[1].Length(); - - PNS_LINE walk_path (aPath, path_walk[1]); - - bool alt_collides = m_world->CheckColliding(&walk_path, m_solids_only ? PNS_ITEM::SOLID : PNS_ITEM::ANY); + int len_pre = path_walk[0].Length(); + int len_alt = path_walk[1].Length(); - SHAPE_LINE_CHAIN pnew; + PNS_LINE walk_path( aPath, path_walk[1] ); - if(!m_forceSingleDirection && len_alt < len_pre && !alt_collides && !prev_recursive) - { - pnew = path_pre[1]; - pnew.Append(path_walk[1]); - pnew.Append(path_post[1]); - - current_obs = nearestObstacle(PNS_LINE(aPath, path_post[1])); - prev_recursive = false; - } else { - pnew = path_pre[0]; - pnew.Append(path_walk[0]); - pnew.Append(path_post[0]); - - current_obs = nearestObstacle(PNS_LINE(aPath, path_walk[0])); + bool alt_collides = m_world->CheckColliding( &walk_path, + m_solids_only ? PNS_ITEM::SOLID : PNS_ITEM::ANY ); - if(!current_obs) - { - prev_recursive = false; - current_obs = nearestObstacle(PNS_LINE(aPath, path_post[0])); - } else - prev_recursive = true; - } + SHAPE_LINE_CHAIN pnew; - - pnew.Simplify(); - aPath.SetShape(pnew); + if( !m_forceSingleDirection && len_alt < len_pre && !alt_collides && !prev_recursive ) + { + pnew = path_pre[1]; + pnew.Append( path_walk[1] ); + pnew.Append( path_post[1] ); - return IN_PROGRESS; + current_obs = nearestObstacle( PNS_LINE( aPath, path_post[1] ) ); + prev_recursive = false; + } + else + { + pnew = path_pre[0]; + pnew.Append( path_walk[0] ); + pnew.Append( path_post[0] ); + + current_obs = nearestObstacle( PNS_LINE( aPath, path_walk[0] ) ); + + if( !current_obs ) + { + prev_recursive = false; + current_obs = nearestObstacle( PNS_LINE( aPath, path_post[0] ) ); + } + else + prev_recursive = true; + } + + pnew.Simplify(); + aPath.SetShape( pnew ); + + return IN_PROGRESS; } -PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath, bool aOptimize ) + +PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::Route( const PNS_LINE& aInitialPath, + PNS_LINE& aWalkPath, + bool aOptimize ) { - PNS_LINE path_cw(aInitialPath), path_ccw(aInitialPath); - WalkaroundStatus s_cw = IN_PROGRESS, s_ccw = IN_PROGRESS; - SHAPE_LINE_CHAIN best_path; + PNS_LINE path_cw( aInitialPath ), path_ccw( aInitialPath ); + WalkaroundStatus s_cw = IN_PROGRESS, s_ccw = IN_PROGRESS; + SHAPE_LINE_CHAIN best_path; - start(aInitialPath); + start( aInitialPath ); - m_currentObstacle[0] = m_currentObstacle[1] = nearestObstacle(aInitialPath); - m_recursiveBlockageCount = 0; + m_currentObstacle[0] = m_currentObstacle[1] = nearestObstacle( aInitialPath ); + m_recursiveBlockageCount = 0; - aWalkPath = aInitialPath; + aWalkPath = aInitialPath; - while(m_iteration < m_iteration_limit) - { - if(s_cw != STUCK) - s_cw = singleStep(path_cw, true); - - if(s_ccw != STUCK) - s_ccw = singleStep(path_ccw, false); + while( m_iteration < m_iteration_limit ) + { + if( s_cw != STUCK ) + s_cw = singleStep( path_cw, true ); - if((s_cw == DONE && s_ccw == DONE) || (s_cw == STUCK && s_ccw == STUCK)) - { - int len_cw = path_cw.GetCLine().Length(); - int len_ccw = path_ccw.GetCLine().Length(); + if( s_ccw != STUCK ) + s_ccw = singleStep( path_ccw, false ); + + if( ( s_cw == DONE && s_ccw == DONE ) || ( s_cw == STUCK && s_ccw == STUCK ) ) + { + int len_cw = path_cw.GetCLine().Length(); + int len_ccw = path_ccw.GetCLine().Length(); + + if( m_forceLongerPath ) + aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw); + else + aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw); + + break; + } + else if( s_cw == DONE && !m_forceLongerPath ) + { + aWalkPath = path_cw; + break; + } + else if( s_ccw == DONE && !m_forceLongerPath ) + { + aWalkPath = path_ccw; + break; + } + + m_iteration++; + } + + if( m_iteration == m_iteration_limit ) + { + int len_cw = path_cw.GetCLine().Length(); + int len_ccw = path_ccw.GetCLine().Length(); - if(m_forceLongerPath) - aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw); - else - aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw); + if( m_forceLongerPath ) + aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw); + else + aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw); + } - break; - } else if(s_cw == DONE && !m_forceLongerPath) { - aWalkPath = path_cw; - break; - } else if (s_ccw == DONE && !m_forceLongerPath) { - aWalkPath = path_ccw; - break; - } + if( m_cursorApproachMode ) + { + // int len_cw = path_cw.GetCLine().Length(); + // int len_ccw = path_ccw.GetCLine().Length(); + bool found = false; + SHAPE_LINE_CHAIN l = aWalkPath.GetCLine(); - m_iteration++; - } + for( int i = 0; i < l.SegmentCount(); i++ ) + { + const SEG s = l.Segment( i ); - if(m_iteration == m_iteration_limit) - { - int len_cw = path_cw.GetCLine().Length(); - int len_ccw = path_ccw.GetCLine().Length(); + VECTOR2I nearest = s.NearestPoint( m_cursorPos ); + VECTOR2I::extended_type dist_a = (s.a - m_cursorPos).SquaredEuclideanNorm(); + VECTOR2I::extended_type dist_b = (s.b - m_cursorPos).SquaredEuclideanNorm(); + VECTOR2I::extended_type dist_n = (nearest - m_cursorPos).SquaredEuclideanNorm(); + if( dist_n <= dist_a && dist_n < dist_b ) + { + // PNSDisplayDebugLine(l, 3); + l.Remove( i + 1, -1 ); + l.Append( nearest ); + l.Simplify(); + found = true; + break; + } + } - if(m_forceLongerPath) - aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw); - else - aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw); + if( found ) + { + aWalkPath = aInitialPath; + aWalkPath.SetShape( l ); + } + } - } + aWalkPath.SetWorld( m_world ); + aWalkPath.GetLine().Simplify(); - if(m_cursorApproachMode) - { - //int len_cw = path_cw.GetCLine().Length(); - //int len_ccw = path_ccw.GetCLine().Length(); - bool found = false; + WalkaroundStatus st = s_ccw == DONE || s_cw == DONE ? DONE : STUCK; - SHAPE_LINE_CHAIN l = aWalkPath.GetCLine(); + if( aOptimize && st == DONE ) + PNS_OPTIMIZER::Optimize( &aWalkPath, PNS_OPTIMIZER::MERGE_OBTUSE, m_world ); - - for(int i = 0; i < l.SegmentCount(); i++) - { - const SEG s = l.Segment(i); - - VECTOR2I nearest = s.NearestPoint(m_cursorPos); - VECTOR2I::extended_type dist_a = (s.a - m_cursorPos).SquaredEuclideanNorm(); - VECTOR2I::extended_type dist_b = (s.b - m_cursorPos).SquaredEuclideanNorm(); - VECTOR2I::extended_type dist_n = (nearest - m_cursorPos).SquaredEuclideanNorm(); - - - - if(dist_n <= dist_a && dist_n < dist_b) - { - //PNSDisplayDebugLine(l, 3); - l.Remove(i + 1, -1); - l.Append( nearest ); - l.Simplify(); - found = true; - break; - } - } - if(found) - { - aWalkPath = aInitialPath; - aWalkPath.SetShape(l); - } - } - - - aWalkPath.SetWorld(m_world); - aWalkPath.GetLine().Simplify(); - - WalkaroundStatus st = s_ccw == DONE || s_cw == DONE ? DONE : STUCK; - - if(aOptimize && st == DONE) - PNS_OPTIMIZER::Optimize(&aWalkPath, PNS_OPTIMIZER::MERGE_OBTUSE, m_world); - - return st; + return st; } + diff --git a/pcbnew/router/pns_walkaround.h b/pcbnew/router/pns_walkaround.h index 0c71e0f190..830748553d 100644 --- a/pcbnew/router/pns_walkaround.h +++ b/pcbnew/router/pns_walkaround.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -24,76 +24,75 @@ #include "pns_line.h" #include "pns_node.h" -class PNS_WALKAROUND { - - static const int DefaultIterationLimit = 50; +class PNS_WALKAROUND +{ + static const int DefaultIterationLimit = 50; +public: + PNS_WALKAROUND( PNS_NODE* aWorld ) : + m_world( aWorld ), m_iteration_limit( DefaultIterationLimit ) + { + m_forceSingleDirection = false; + m_forceLongerPath = false; + m_cursorApproachMode = false; + }; + ~PNS_WALKAROUND() {}; + enum WalkaroundStatus + { + IN_PROGRESS = 0, + DONE, + STUCK + }; - public: - PNS_WALKAROUND( PNS_NODE *aWorld ): - m_world(aWorld), m_iteration_limit(DefaultIterationLimit) { - m_forceSingleDirection = false; - m_forceLongerPath = false; - m_cursorApproachMode = false; - }; - ~PNS_WALKAROUND() {}; + void SetWorld( PNS_NODE* aNode ) + { + m_world = aNode; + } - enum WalkaroundStatus { - IN_PROGRESS = 0, - DONE, - STUCK - }; + void SetIterationLimit( const int aIterLimit ) + { + m_iteration_limit = aIterLimit; + } - void SetWorld ( PNS_NODE *aNode ) - { - m_world = aNode; - } + void SetSolidsOnly( bool aSolidsOnly ) + { + m_solids_only = aSolidsOnly; + } - void SetIterationLimit( const int aIterLimit ) - { - m_iteration_limit = aIterLimit; - } + void SetSingleDirection( bool aForceSingleDirection ) + { + m_forceSingleDirection = aForceSingleDirection; + m_forceLongerPath = true; + } - void SetSolidsOnly ( bool aSolidsOnly ) - { - m_solids_only = aSolidsOnly; - } + void SetApproachCursor( bool aEnabled, const VECTOR2I& aPos ) + { + m_cursorPos = aPos; + m_cursorApproachMode = aEnabled; + } + WalkaroundStatus Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath, + bool aOptimize = true ); - void SetSingleDirection (bool aForceSingleDirection ) - { - m_forceSingleDirection = aForceSingleDirection; - m_forceLongerPath = true; - } +private: + void start( const PNS_LINE& aInitialPath ); - void SetApproachCursor ( bool aEnabled, const VECTOR2I& aPos ) - { - m_cursorPos = aPos; - m_cursorApproachMode = aEnabled; - } - + WalkaroundStatus singleStep( PNS_LINE& aPath, bool aWindingDirection ); + PNS_NODE::OptObstacle nearestObstacle( const PNS_LINE& aPath ); - WalkaroundStatus Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath, bool aOptimize = true); + PNS_NODE* m_world; - private: - void start( const PNS_LINE& aInitialPath ); - - WalkaroundStatus singleStep(PNS_LINE& aPath, bool aWindingDirection); - PNS_NODE::OptObstacle nearestObstacle(const PNS_LINE& aPath); - - PNS_NODE *m_world; - - int m_recursiveBlockageCount; - int m_iteration; - int m_iteration_limit; - bool m_solids_only; - bool m_forceSingleDirection, m_forceLongerPath; - bool m_cursorApproachMode; - VECTOR2I m_cursorPos; - PNS_NODE::OptObstacle m_currentObstacle[2]; - bool m_recursiveCollision[2]; + int m_recursiveBlockageCount; + int m_iteration; + int m_iteration_limit; + bool m_solids_only; + bool m_forceSingleDirection, m_forceLongerPath; + bool m_cursorApproachMode; + VECTOR2I m_cursorPos; + PNS_NODE::OptObstacle m_currentObstacle[2]; + bool m_recursiveCollision[2]; }; -#endif // __PNS_WALKAROUND_H +#endif // __PNS_WALKAROUND_H diff --git a/pcbnew/router/readme.txt b/pcbnew/router/readme.txt deleted file mode 100644 index 933b93a817..0000000000 --- a/pcbnew/router/readme.txt +++ /dev/null @@ -1,4 +0,0 @@ -You'll see the P&S router sources here, but just not right now. -We are still dealing with some non-technical issues that should be solved by the next week. - -Tom \ No newline at end of file diff --git a/pcbnew/router/router_preview_item.cpp b/pcbnew/router/router_preview_item.cpp index b63233c821..5cae19f317 100644 --- a/pcbnew/router/router_preview_item.cpp +++ b/pcbnew/router/router_preview_item.cpp @@ -3,21 +3,21 @@ * * Copyright (C) 2013 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 . */ - + #include #include "class_track.h" @@ -31,167 +31,200 @@ using namespace KiGfx; -ROUTER_PREVIEW_ITEM::ROUTER_PREVIEW_ITEM( const PNS_ITEM *aItem, VIEW_GROUP *aParent ) - : EDA_ITEM( NOT_USED ) - { - m_Flags = 0; - m_parent = aParent; - if(aItem) - Update(aItem); - } - +ROUTER_PREVIEW_ITEM::ROUTER_PREVIEW_ITEM( const PNS_ITEM* aItem, VIEW_GROUP* aParent ) : + EDA_ITEM( NOT_USED ) +{ + m_Flags = 0; + m_parent = aParent; + + if( aItem ) + Update( aItem ); +} + + ROUTER_PREVIEW_ITEM::~ROUTER_PREVIEW_ITEM() { - } - -void ROUTER_PREVIEW_ITEM::Update(const PNS_ITEM *aItem) + + +void ROUTER_PREVIEW_ITEM::Update( const PNS_ITEM* aItem ) { - m_layer = aItem->GetLayers().Start(); + m_layer = aItem->GetLayers().Start(); + m_color = getLayerColor( m_layer ); + m_color.a = 0.8; - m_color = getLayerColor( m_layer ); - m_color.a = 0.8; - - switch(aItem->GetKind()) - { - case PNS_ITEM::LINE: - m_type = PR_LINE; - m_width = static_cast(aItem)->GetWidth(); - m_line = * static_cast(aItem->GetShape()); - break; + switch( aItem->GetKind() ) + { + case PNS_ITEM::LINE: + m_type = PR_LINE; + m_width = static_cast(aItem)->GetWidth(); + m_line = *static_cast( aItem->GetShape() ); + break; - case PNS_ITEM::SEGMENT: - m_type = PR_LINE; - m_width = static_cast(aItem)->GetWidth(); - m_line = * static_cast(aItem->GetShape()); - break; + case PNS_ITEM::SEGMENT: + m_type = PR_LINE; + m_width = static_cast(aItem)->GetWidth(); + m_line = *static_cast( aItem->GetShape() ); + break; - case PNS_ITEM::VIA: - m_type = PR_VIA; - m_color = COLOR4D(0.7, 0.7, 0.7, 0.8); - m_width = static_cast(aItem)->GetDiameter(); - m_viaCenter = static_cast(aItem)->GetPos(); - break; + case PNS_ITEM::VIA: + m_type = PR_VIA; + m_color = COLOR4D( 0.7, 0.7, 0.7, 0.8 ); + m_width = static_cast(aItem)->GetDiameter(); + m_viaCenter = static_cast(aItem)->GetPos(); + break; - default: - break; - } - - ViewSetVisible(true); - ViewUpdate(GEOMETRY | APPEARANCE); + default: + break; + } + + ViewSetVisible( true ); + ViewUpdate( GEOMETRY | APPEARANCE ); } -void ROUTER_PREVIEW_ITEM::MarkAsHead( ) + +void ROUTER_PREVIEW_ITEM::MarkAsHead() { - if(m_type != PR_VIA) - m_color.Saturate(1.0); + if( m_type != PR_VIA ) + m_color.Saturate( 1.0 ); } -const BOX2I ROUTER_PREVIEW_ITEM::ViewBBox() const + +const BOX2I ROUTER_PREVIEW_ITEM::ViewBBox() const { - BOX2I bbox; + BOX2I bbox; - switch(m_type) - { - case PR_LINE: - bbox = m_line.BBox(); - bbox.Inflate( m_width / 2); - return bbox; - case PR_VIA: - bbox = BOX2I( m_viaCenter, VECTOR2I(0, 0)); - bbox.Inflate( m_width / 2); - return bbox; - default: - break; - } - return bbox; + switch( m_type ) + { + case PR_LINE: + bbox = m_line.BBox(); + bbox.Inflate( m_width / 2 ); + return bbox; + + case PR_VIA: + bbox = BOX2I( m_viaCenter, VECTOR2I( 0, 0 ) ); + bbox.Inflate( m_width / 2 ); + return bbox; + + default: + break; + } + + return bbox; } + void ROUTER_PREVIEW_ITEM::ViewDraw( int aLayer, KiGfx::GAL* aGal ) const { - switch( m_type ) - { - case PR_LINE: + switch( m_type ) + { + case PR_LINE: + aGal->SetLayerDepth( -100.0 ); + aGal->SetLineWidth( m_width ); + aGal->SetStrokeColor( m_color ); + aGal->SetIsStroke( true ); + aGal->SetIsFill( false ); - aGal->SetLayerDepth(-100.0); - aGal->SetLineWidth(m_width); - aGal->SetStrokeColor(m_color); - aGal->SetIsStroke(true); - aGal->SetIsFill(false); - for(int s= 0 ; s < m_line.SegmentCount(); s++) - aGal->DrawLine(m_line.CSegment(s).a, m_line.CSegment(s).b); - if(m_line.IsClosed()) - aGal->DrawLine(m_line.CSegment(-1).b, m_line.CSegment(0).a); - break; - case PR_VIA: - - aGal->SetLayerDepth(-101.0); - aGal->SetIsStroke(false); - aGal->SetIsFill(true); - aGal->SetFillColor(m_color); - aGal->DrawCircle(m_viaCenter, m_width / 2); - break; - default: - break; - } + for( int s = 0; s < m_line.SegmentCount(); s++ ) + aGal->DrawLine( m_line.CSegment( s ).a, m_line.CSegment( s ).b ); + + if( m_line.IsClosed() ) + aGal->DrawLine( m_line.CSegment( -1 ).b, m_line.CSegment( 0 ).a ); + break; + + case PR_VIA: + aGal->SetLayerDepth( -101.0 ); + aGal->SetIsStroke( false ); + aGal->SetIsFill( true ); + aGal->SetFillColor( m_color ); + aGal->DrawCircle( m_viaCenter, m_width / 2 ); + break; + + default: + break; + } } -void ROUTER_PREVIEW_ITEM::DebugLine ( const SHAPE_LINE_CHAIN& aLine, int aWidth , int aStyle ) +void ROUTER_PREVIEW_ITEM::DebugLine( const SHAPE_LINE_CHAIN& aLine, int aWidth, int aStyle ) { #if 0 - m_line = aLine; - m_width = aWidth; - m_color = assignColor(aStyle); - + m_line = aLine; + m_width = aWidth; + m_color = assignColor( aStyle ); - m_type = PR_LINE; - ViewUpdate(GEOMETRY | APPEARANCE); + + m_type = PR_LINE; + ViewUpdate( GEOMETRY | APPEARANCE ); #endif } -void ROUTER_PREVIEW_ITEM::DebugBox ( const BOX2I& aBox, int aStyle ) + +void ROUTER_PREVIEW_ITEM::DebugBox( const BOX2I& aBox, int aStyle ) { #if 0 - assert(false); + assert( false ); - m_line.Clear(); - m_line.Append( aBox.GetX(), aBox.GetY() ); - m_line.Append( aBox.GetX() + aBox.GetWidth(), aBox.GetY() + aBox.GetHeight()); - m_line.Append( aBox.GetX() + aBox.GetWidth(), aBox.GetY() + aBox.GetHeight()); - m_line.Append( aBox.GetX(), aBox.GetY() + aBox.GetHeight()); - m_line.SetClosed(true); - m_width = 20000; - m_color = assignColor(aStyle); - m_type = PR_LINE; - ViewUpdate(GEOMETRY | APPEARANCE); + m_line.Clear(); + m_line.Append( aBox.GetX(), aBox.GetY() ); + m_line.Append( aBox.GetX() + aBox.GetWidth(), aBox.GetY() + aBox.GetHeight() ); + m_line.Append( aBox.GetX() + aBox.GetWidth(), aBox.GetY() + aBox.GetHeight() ); + m_line.Append( aBox.GetX(), aBox.GetY() + aBox.GetHeight() ); + m_line.SetClosed( true ); + m_width = 20000; + m_color = assignColor( aStyle ); + m_type = PR_LINE; + ViewUpdate( GEOMETRY | APPEARANCE ); #endif } - -const COLOR4D ROUTER_PREVIEW_ITEM::getLayerColor (int layer ) const -{ - //assert (m_view != NULL); - PCB_RENDER_SETTINGS *settings = static_cast (m_parent -> GetView() -> GetPainter() -> GetSettings()); - return settings->GetLayerColor(layer); + +const COLOR4D ROUTER_PREVIEW_ITEM::getLayerColor( int aLayer ) const +{ + // assert (m_view != NULL); + + PCB_RENDER_SETTINGS* settings = + static_cast ( m_parent->GetView()->GetPainter()->GetSettings() ); + + return settings->GetLayerColor( aLayer ); } -const COLOR4D ROUTER_PREVIEW_ITEM::assignColor ( int style ) const +const COLOR4D ROUTER_PREVIEW_ITEM::assignColor( int aStyle ) const { - COLOR4D color; - switch(style) - { - case 0: color =COLOR4D(0, 1, 0, 1);break; - case 1: color =COLOR4D(1, 0, 0, 0.3);break; - case 2: color =COLOR4D(1, 0.5, 0.5, 1);break; - case 3: color =COLOR4D(0, 0, 1, 1);break; - case 4: color =COLOR4D(1, 1, 1, 1); break; - case 5: color =COLOR4D(1, 1, 0, 1); break; - case 6: color =COLOR4D(0, 1, 1, 1); break; - case 32: color =COLOR4D(0, 0, 1, 0.5); break; - default: break; - } - return color; + COLOR4D color; + + switch( aStyle ) + { + case 0: + color = COLOR4D( 0, 1, 0, 1 ); break; + + case 1: + color = COLOR4D( 1, 0, 0, 0.3 ); break; + + case 2: + color = COLOR4D( 1, 0.5, 0.5, 1 ); break; + + case 3: + color = COLOR4D( 0, 0, 1, 1 ); break; + + case 4: + color = COLOR4D( 1, 1, 1, 1 ); break; + + case 5: + color = COLOR4D( 1, 1, 0, 1 ); break; + + case 6: + color = COLOR4D( 0, 1, 1, 1 ); break; + + case 32: + color = COLOR4D( 0, 0, 1, 0.5 ); break; + + default: + break; + } + + return color; } + diff --git a/pcbnew/router/router_preview_item.h b/pcbnew/router/router_preview_item.h index bedd8a0c2a..9c5d2e3497 100644 --- a/pcbnew/router/router_preview_item.h +++ b/pcbnew/router/router_preview_item.h @@ -3,21 +3,21 @@ * * Copyright (C) 2013 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 __ROUTER_PREVIEW_ITEM_H #define __ROUTER_PREVIEW_ITEM_H @@ -43,61 +43,61 @@ class PNS_ROUTER; class ROUTER_PREVIEW_ITEM : public EDA_ITEM { - public: - enum ItemType { - PR_VIA, - PR_LINE, - PR_STUCK_MARKER - }; +public: + enum ItemType + { + PR_VIA, + PR_LINE, + PR_STUCK_MARKER + }; - enum ItemFlags { - PR_SUGGESTION = 1 - }; + enum ItemFlags + { + PR_SUGGESTION = 1 + }; - ROUTER_PREVIEW_ITEM( const PNS_ITEM *aItem = NULL, KiGfx::VIEW_GROUP *aParent = NULL ); - ~ROUTER_PREVIEW_ITEM(); - - void Update ( const PNS_ITEM *aItem); + ROUTER_PREVIEW_ITEM( const PNS_ITEM* aItem = NULL, KiGfx::VIEW_GROUP* aParent = NULL ); + ~ROUTER_PREVIEW_ITEM(); - void StuckMarker( VECTOR2I& aPosition ); - void DebugLine ( const SHAPE_LINE_CHAIN& aLine, int aWidth = 0, int aStyle = 0 ); - void DebugBox ( const BOX2I& aBox, int aStyle = 0); - void Show(int a, std::ostream& b) const {}; + void Update( const PNS_ITEM* aItem ); - const BOX2I ViewBBox() const; - - - virtual void ViewDraw( int aLayer, KiGfx::GAL* aGal ) const; - - virtual void ViewGetLayers( int aLayers[], int& aCount ) const - { - aLayers[0] = GP_OVERLAY; - aCount = 1; - } - - void MarkAsHead( ); + void StuckMarker( VECTOR2I& aPosition ); + void DebugLine( const SHAPE_LINE_CHAIN& aLine, int aWidth = 0, int aStyle = 0 ); + void DebugBox( const BOX2I& aBox, int aStyle = 0 ); - private: + void Show( int a, std::ostream& b ) const {}; - const KiGfx::COLOR4D assignColor ( int style ) const; - const KiGfx::COLOR4D getLayerColor (int layer ) const; + const BOX2I ViewBBox() const; - KiGfx::VIEW_GROUP *m_parent; + virtual void ViewDraw( int aLayer, KiGfx::GAL* aGal ) const; - PNS_ROUTER *m_router; - SHAPE_LINE_CHAIN m_line; + virtual void ViewGetLayers( int aLayers[], int& aCount ) const + { + aLayers[0] = GP_OVERLAY; + aCount = 1; + } - ItemType m_type; - int m_style; - int m_width; - int m_layer; + void MarkAsHead(); - KiGfx::COLOR4D m_color; +private: + const KiGfx::COLOR4D assignColor( int aStyle ) const; + const KiGfx::COLOR4D getLayerColor( int aLayer ) const; - VECTOR2I m_stuckPosition; - VECTOR2I m_viaCenter; + KiGfx::VIEW_GROUP* m_parent; + PNS_ROUTER* m_router; + SHAPE_LINE_CHAIN m_line; + + ItemType m_type; + int m_style; + int m_width; + int m_layer; + + KiGfx::COLOR4D m_color; + + VECTOR2I m_stuckPosition; + VECTOR2I m_viaCenter; }; - #endif + diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index 5bc84708ac..6ab7688b59 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -42,70 +42,73 @@ using namespace KiGfx; using namespace std; using boost::optional; -static TOOL_ACTION ACT_AutoEndRoute ( "AutoEndRoute", AS_CONTEXT, 'F' ); -static TOOL_ACTION ACT_PlaceVia ( "PlaceVia", AS_CONTEXT, 'V' ); -static TOOL_ACTION ACT_OpenRouteOptions ( "OpenRouterOptions", AS_CONTEXT, 'E' ); -static TOOL_ACTION ACT_SwitchPosture ( "SwitchPosture", AS_CONTEXT, '/' ); -static TOOL_ACTION ACT_EndTrack ( "SwitchPosture", AS_CONTEXT, WXK_END ); +static TOOL_ACTION ACT_AutoEndRoute( "AutoEndRoute", AS_CONTEXT, 'F' ); +static TOOL_ACTION ACT_PlaceVia( "PlaceVia", AS_CONTEXT, 'V' ); +static TOOL_ACTION ACT_OpenRouteOptions( "OpenRouterOptions", AS_CONTEXT, 'E' ); +static TOOL_ACTION ACT_SwitchPosture( "SwitchPosture", AS_CONTEXT, '/' ); +static TOOL_ACTION ACT_EndTrack( "SwitchPosture", AS_CONTEXT, WXK_END ); ROUTER_TOOL::ROUTER_TOOL() : - TOOL_INTERACTIVE( "pcbnew.InteractiveRouter" ) + TOOL_INTERACTIVE( "pcbnew.InteractiveRouter" ) { - m_router = NULL; - m_menu = new CONTEXT_MENU ; + m_router = NULL; + m_menu = new CONTEXT_MENU; - m_menu->SetTitle( wxT( "Interactive router") ); // fixme: not implemented yet. Sorry. - m_menu->Add( wxT ("Cancel"), 0); - m_menu->Add( wxT ("New track"), 1); - m_menu->Add( wxT ("End track"), 2); - m_menu->Add( wxT ("Auto-end track"), 2); - m_menu->Add( wxT ("Place via"), 3); - m_menu->Add( wxT ("Switch posture"), 4); - - m_menu->Add( wxT ("Routing options..."), 5); + m_menu->SetTitle( wxT( "Interactive router" ) ); // fixme: not implemented yet. Sorry. + m_menu->Add( wxT( "Cancel" ), 0 ); + m_menu->Add( wxT( "New track" ), 1 ); + m_menu->Add( wxT( "End track" ), 2 ); + m_menu->Add( wxT( "Auto-end track" ), 2 ); + m_menu->Add( wxT( "Place via" ), 3 ); + m_menu->Add( wxT( "Switch posture" ), 4 ); + + m_menu->Add( wxT( "Routing options..." ), 5 ); } ROUTER_TOOL::~ROUTER_TOOL() { - delete m_router; + delete m_router; } void ROUTER_TOOL::Reset() { - - if(m_router) + if( m_router ) delete m_router; m_router = new PNS_ROUTER; - TRACEn(0,"Reset"); + TRACEn( 0, "Reset" ); m_router->ClearWorld(); - m_router->SetBoard( getModel (PCB_T) ); + m_router->SetBoard( getModel( PCB_T ) ); m_router->SyncWorld(); - if(getView()) + if( getView() ) m_router->SetView( getView() ); Go( &ROUTER_TOOL::Main, TOOL_EVENT( TC_Command, TA_Action, GetName() ) ); } + int ROUTER_TOOL::getDefaultWidth( int aNetCode ) { int w, d1, d2; - getNetclassDimensions( aNetCode, w, d1, d2); + + getNetclassDimensions( aNetCode, w, d1, d2 ); return w; } -void ROUTER_TOOL::getNetclassDimensions ( int aNetCode, int& aWidth, int& aViaDiameter, int& aViaDrill) + +void ROUTER_TOOL::getNetclassDimensions( int aNetCode, int& aWidth, + int& aViaDiameter, int& aViaDrill ) { - BOARD *board = getModel (PCB_T); - + BOARD* board = getModel( PCB_T ); + NETCLASS* netClass = NULL; - NETINFO_ITEM *ni = board->FindNet(aNetCode); - - if(ni) + NETINFO_ITEM* ni = board->FindNet( aNetCode ); + + if( ni ) { wxString netClassName = ni->GetClassName(); netClass = board->m_NetClasses.Find( netClassName ); @@ -113,26 +116,27 @@ void ROUTER_TOOL::getNetclassDimensions ( int aNetCode, int& aWidth, int& aViaDi if( !netClass ) netClass = board->m_NetClasses.GetDefault(); - + aWidth = netClass->GetTrackWidth(); aViaDiameter = netClass->GetViaDiameter(); aViaDrill = netClass->GetViaDrill(); } -PNS_ITEM *ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer ) +PNS_ITEM* ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer ) { int tl = getView()->GetTopLayer(); - if(aLayer > 0) + if( aLayer > 0 ) tl = aLayer; - PNS_ITEM *picked_seg = NULL, *picked_via = NULL; - PNS_ITEMSET candidates = m_router->QueryHoverItems(aWhere); + PNS_ITEM* picked_seg = NULL; + PNS_ITEM* picked_via = NULL; + PNS_ITEMSET candidates = m_router->QueryHoverItems( aWhere ); - BOOST_FOREACH( PNS_ITEM *item, candidates.Items() ) + BOOST_FOREACH( PNS_ITEM* item, candidates.Items() ) { - if( !IsCopperLayer(item->GetLayers().Start()) ) + if( !IsCopperLayer( item->GetLayers().Start() ) ) continue; if( item->GetParent() && !item->GetParent()->ViewIsVisible() ) @@ -140,108 +144,116 @@ PNS_ITEM *ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLa if( aNet < 0 || item->GetNet() == aNet ) { - if( item->OfKind (PNS_ITEM::VIA | PNS_ITEM::SOLID) ) + if( item->OfKind( PNS_ITEM::VIA | PNS_ITEM::SOLID ) ) { - if(item->GetLayers().Overlaps(tl) || !picked_via) - picked_via = item; - } else { - if(item->GetLayers().Overlaps(tl) || !picked_seg) - picked_seg = item; + if( item->GetLayers().Overlaps( tl ) || !picked_via ) + picked_via = item; + } + else + { + if( item->GetLayers().Overlaps( tl ) || !picked_seg ) + picked_seg = item; } } } if( DisplayOpt.ContrastModeDisplay ) { - if( picked_seg && !picked_seg->GetLayers().Overlaps(tl)) + if( picked_seg && !picked_seg->GetLayers().Overlaps( tl ) ) picked_seg = NULL; } - - PNS_ITEM *rv = picked_via ? picked_via : picked_seg; - if( rv && aLayer >= 0 && !rv-> GetLayers().Overlaps(aLayer) ) + PNS_ITEM* rv = picked_via ? picked_via : picked_seg; + + if( rv && aLayer >= 0 && !rv->GetLayers().Overlaps( aLayer ) ) rv = NULL; - if(rv) - TRACE(0, "%s, layer : %d, tl: %d", rv->GetKindStr().c_str() % rv->GetLayers().Start() % tl); + if( rv ) + TRACE( 0, "%s, layer : %d, tl: %d", rv->GetKindStr().c_str() % rv->GetLayers().Start() % + tl ); return rv; } - -void ROUTER_TOOL::setMsgPanel ( bool enabled, int entry, const wxString& aUpperMessage, const wxString& aLowerMessage ) +void ROUTER_TOOL::setMsgPanel( bool aEnabled, int aEntry, + const wxString& aUpperMessage, const wxString& aLowerMessage ) { - PCB_EDIT_FRAME *frame = getEditFrame (); - - if(m_panelItems.size() <= (unsigned int) entry) - m_panelItems.resize(entry + 1); - - m_panelItems[entry] = MSG_PANEL_ITEM( aUpperMessage, aLowerMessage, BLACK ); - frame->SetMsgPanel(m_panelItems); + PCB_EDIT_FRAME* frame = getEditFrame (); + + if( m_panelItems.size() <= (unsigned int) aEntry ) + m_panelItems.resize( aEntry + 1 ); + + m_panelItems[aEntry] = MSG_PANEL_ITEM( aUpperMessage, aLowerMessage, BLACK ); + frame->SetMsgPanel( m_panelItems ); } + void ROUTER_TOOL::clearMsgPanel() { - PCB_EDIT_FRAME *frame = getEditFrame (); + PCB_EDIT_FRAME* frame = getEditFrame (); frame->ClearMsgPanel(); } -void ROUTER_TOOL::highlightNet(bool enabled, int netcode) + +void ROUTER_TOOL::highlightNet( bool aEnabled, int aNetcode ) { - RENDER_SETTINGS *rs = getView()->GetPainter()->GetSettings(); - - if(netcode >= 0 && enabled) - rs->SetHighlight(true, netcode); - else - rs->SetHighlight(false); + RENDER_SETTINGS* rs = getView()->GetPainter()->GetSettings(); + + if( aNetcode >= 0 && aEnabled ) + rs->SetHighlight( true, aNetcode ); + else + rs->SetHighlight( false ); getView()->UpdateAllLayersColor(); } + void ROUTER_TOOL::updateStartItem( TOOL_EVENT& aEvent ) { - VIEW_CONTROLS *ctls = getViewControls(); + VIEW_CONTROLS* ctls = getViewControls(); int tl = getView()->GetTopLayer(); - PNS_ITEM *startItem = NULL; + PNS_ITEM* startItem = NULL; if( aEvent.IsMotion() || aEvent.IsClick() ) { VECTOR2I p = aEvent.Position(); - startItem = pickSingleItem(p); + startItem = pickSingleItem( p ); - - - if(startItem && startItem->GetNet() >= 0) + if( startItem && startItem->GetNet() >= 0 ) { bool dummy; - VECTOR2I cursorPos = m_router->SnapToItem (startItem, p, dummy); - ctls->ForceCursorPosition(true, cursorPos); + VECTOR2I cursorPos = m_router->SnapToItem( startItem, p, dummy ); + ctls->ForceCursorPosition( true, cursorPos ); m_startSnapPoint = cursorPos; - if(startItem->GetLayers().IsMultilayer()) + + if( startItem->GetLayers().IsMultilayer() ) m_startLayer = tl; else m_startLayer = startItem->GetLayers().Start(); - + m_startItem = startItem; - } else { + } + else + { m_startItem = NULL; m_startSnapPoint = p; m_startLayer = tl; - ctls->ForceCursorPosition(false); + ctls->ForceCursorPosition( false ); } } } + void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) { - VIEW_CONTROLS *ctls = getViewControls(); + VIEW_CONTROLS* ctls = getViewControls(); VECTOR2I p = aEvent.Position(); int layer; - if(m_router->GetCurrentNet() < 0 || !m_startItem) + if( m_router->GetCurrentNet() < 0 || !m_startItem ) { m_endItem = NULL; m_endSnapPoint = p; @@ -250,48 +262,53 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) bool dummy; - if(m_router->IsPlacingVia()) + if( m_router->IsPlacingVia() ) layer = -1; - else + else layer = m_router->GetCurrentLayer(); - - PNS_ITEM *endItem = pickSingleItem(p, m_startItem->GetNet(), layer ); - if(endItem) + PNS_ITEM* endItem = pickSingleItem( p, m_startItem->GetNet(), layer ); + + if( endItem ) { - VECTOR2I cursorPos = m_router->SnapToItem (endItem, p, dummy); - ctls->ForceCursorPosition(true, cursorPos); + VECTOR2I cursorPos = m_router->SnapToItem( endItem, p, dummy ); + ctls->ForceCursorPosition( true, cursorPos ); m_endItem = endItem; m_endSnapPoint = cursorPos; - } else { + } + else + { m_endItem = NULL; m_endSnapPoint = p; - ctls->ForceCursorPosition(false); + ctls->ForceCursorPosition( false ); } - - if(m_endItem) - TRACE(0, "%s, layer : %d", m_endItem->GetKindStr().c_str() % m_endItem->GetLayers().Start() ); + + if( m_endItem ) + TRACE( 0, "%s, layer : %d", m_endItem->GetKindStr().c_str() % + m_endItem->GetLayers().Start() ); } -void ROUTER_TOOL::startRouting ( ) + +void ROUTER_TOOL::startRouting() { - VIEW_CONTROLS *ctls = getViewControls(); - - int width = getDefaultWidth( m_startItem ? m_startItem->GetNet() : -1); - if(m_startItem && m_startItem->OfKind(PNS_ITEM::SEGMENT)) - width = static_cast(m_startItem)->GetWidth(); + VIEW_CONTROLS* ctls = getViewControls(); - m_router->SetCurrentWidth(width); - m_router->SwitchLayer(m_startLayer); + int width = getDefaultWidth( m_startItem ? m_startItem->GetNet() : -1 ); - getEditFrame() -> SetTopLayer (m_startLayer); + if( m_startItem && m_startItem->OfKind( PNS_ITEM::SEGMENT ) ) + width = static_cast( m_startItem )->GetWidth(); - if(m_startItem && m_startItem->GetNet() >= 0) - highlightNet(true, m_startItem->GetNet() ); + m_router->SetCurrentWidth( width ); + m_router->SwitchLayer( m_startLayer ); + + getEditFrame()->SetTopLayer( m_startLayer ); + + if( m_startItem && m_startItem->GetNet() >= 0 ) + highlightNet( true, m_startItem->GetNet() ); + + ctls->ForceCursorPosition( false ); + ctls->SetAutoPan( true ); - ctls->ForceCursorPosition(false); - ctls->SetAutoPan(true); - m_router->StartRouting( m_startSnapPoint, m_startItem ); m_endItem = NULL; @@ -299,93 +316,94 @@ void ROUTER_TOOL::startRouting ( ) while( OPT_TOOL_EVENT evt = Wait() ) { - if( evt->IsCancel() ) - break; - else if (evt->IsMotion()) - { + if( evt->IsCancel() ) + break; + else if( evt->IsMotion() ) + { updateEndItem( *evt ); - m_router->Move ( m_endSnapPoint, m_endItem ); - } - else if (evt->IsClick (MB_Left )) - { + m_router->Move( m_endSnapPoint, m_endItem ); + } + else if( evt->IsClick( MB_Left ) ) + { updateEndItem( *evt ); - if(m_router->FixRoute(m_endSnapPoint, m_endItem)) + + if( m_router->FixRoute( m_endSnapPoint, m_endItem ) ) break; - m_router->Move ( m_endSnapPoint, m_endItem ); - } else if (evt->IsKeyUp()) - { + + m_router->Move( m_endSnapPoint, m_endItem ); + } + else if( evt->IsKeyUp() ) + { switch( evt->KeyCode() ) { - case 'V': - { - int w, diameter, drill; - getNetclassDimensions( m_router->GetCurrentNet(), w, diameter, drill ); - m_router->SetCurrentViaDiameter(diameter); - m_router->SetCurrentViaDrill(drill); - m_router->ToggleViaPlacement(); - getEditFrame() -> SetTopLayer (m_router->GetCurrentLayer()); - m_router->Move ( m_endSnapPoint, m_endItem ); - break; - } - - case '/': - m_router->FlipPosture(); - break; - - case '+': - case '=': - m_router->SwitchLayer ( m_router->NextCopperLayer (true) ); - updateEndItem( *evt ); - getEditFrame() -> SetTopLayer (m_router->GetCurrentLayer()); - m_router->Move ( m_endSnapPoint, m_endItem ); - - break; - - case '-': - m_router->SwitchLayer ( m_router->NextCopperLayer (false) ); - getEditFrame() -> SetTopLayer (m_router->GetCurrentLayer()); - m_router->Move ( m_endSnapPoint, m_endItem ); - break; + case 'V': + { + int w, diameter, drill; + getNetclassDimensions( m_router->GetCurrentNet(), w, diameter, drill ); + m_router->SetCurrentViaDiameter( diameter ); + m_router->SetCurrentViaDrill( drill ); + m_router->ToggleViaPlacement(); + getEditFrame()->SetTopLayer( m_router->GetCurrentLayer() ); + m_router->Move( m_endSnapPoint, m_endItem ); + break; } - } + + case '/': + m_router->FlipPosture(); + break; + + case '+': + case '=': + m_router->SwitchLayer( m_router->NextCopperLayer( true ) ); + updateEndItem( *evt ); + getEditFrame()->SetTopLayer( m_router->GetCurrentLayer() ); + m_router->Move( m_endSnapPoint, m_endItem ); + + break; + + case '-': + m_router->SwitchLayer( m_router->NextCopperLayer( false ) ); + getEditFrame()->SetTopLayer( m_router->GetCurrentLayer() ); + m_router->Move( m_endSnapPoint, m_endItem ); + break; + } + } } - if(m_router->RoutingInProgress()) + if( m_router->RoutingInProgress() ) m_router->StopRouting(); - - ctls->SetAutoPan(false); - ctls->ForceCursorPosition(false); - highlightNet(false); + + ctls->SetAutoPan( false ); + ctls->ForceCursorPosition( false ); + highlightNet( false ); } int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) { - VIEW_CONTROLS *ctls = getViewControls(); + VIEW_CONTROLS* ctls = getViewControls(); - //SetContextMenu ( m_menu ); - //setMsgPanel(true, 0, wxT("KiRouter"), wxT("Pick an item to start routing")); + // SetContextMenu ( m_menu ); + // setMsgPanel(true, 0, wxT("KiRouter"), wxT("Pick an item to start routing")); - ctls->SetSnapping ( true ); + ctls->SetSnapping( true ); ctls->ShowCursor( true ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { - if( evt->IsCancel() ) - break; // Finish - else if( evt->IsMotion( ) ) + break; // Finish + else if( evt->IsMotion() ) updateStartItem( *evt ); - else if( evt->IsClick ( MB_Left ) ) + else if( evt->IsClick( MB_Left ) ) { updateStartItem( *evt ); - startRouting( ); + startRouting(); } } - - //clearMsgPanel(); + // clearMsgPanel(); // Restore the default settings ctls->SetAutoPan( false ); @@ -394,4 +412,3 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) return 0; } - diff --git a/pcbnew/router/router_tool.h b/pcbnew/router/router_tool.h index abf7dabb38..92e2fe208e 100644 --- a/pcbnew/router/router_tool.h +++ b/pcbnew/router/router_tool.h @@ -3,17 +3,17 @@ * * Copyright (C) 2013 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 . */ @@ -45,35 +45,36 @@ public: int Main( TOOL_EVENT& aEvent ); private: - - PNS_ITEM *pickSingleItem( const VECTOR2I& aWhere, int aNet = -1, int aLayer = -1 ); - - void setMsgPanel ( bool enabled, int entry, const wxString& aUpperMessage = wxT(""), const wxString& aLowerMessage = wxT("") ); - void clearMsgPanel(); + PNS_ITEM* pickSingleItem( const VECTOR2I& aWhere, int aNet = -1, int aLayer = -1 ); - int getDefaultWidth( int aNetCode ); - void startRouting ( ); - void highlightNet(bool enabled, int netcode = -1); + void setMsgPanel( bool enabled, int entry, const wxString& aUpperMessage = wxT(""), + const wxString& aLowerMessage = wxT("") ); + void clearMsgPanel(); - void updateStartItem( TOOL_EVENT& aEvent ); - void updateEndItem( TOOL_EVENT& aEvent ); + int getDefaultWidth( int aNetCode ); + void startRouting(); + void highlightNet( bool enabled, int netcode = -1 ); - void getNetclassDimensions ( int aNetCode, int& aWidth, int& aViaDiameter, int& aViaDrill); + void updateStartItem( TOOL_EVENT& aEvent ); + void updateEndItem( TOOL_EVENT& aEvent ); - MSG_PANEL_ITEMS m_panelItems; + void getNetclassDimensions( int aNetCode, int& aWidth, int& aViaDiameter, int& aViaDrill ); - PNS_ROUTER *m_router; + MSG_PANEL_ITEMS m_panelItems; - PNS_ITEM *m_startItem; - int m_startLayer; - VECTOR2I m_startSnapPoint; + PNS_ROUTER* m_router; - PNS_ITEM *m_endItem; - VECTOR2I m_endSnapPoint; + PNS_ITEM* m_startItem; + int m_startLayer; + VECTOR2I m_startSnapPoint; + + PNS_ITEM* m_endItem; + VECTOR2I m_endSnapPoint; /*boost::shared_ptr m_menu;*/ - CONTEXT_MENU * m_menu; + CONTEXT_MENU* m_menu; }; #endif + diff --git a/pcbnew/router/trace.h b/pcbnew/router/trace.h index afce94d148..5b7cbbf2ba 100644 --- a/pcbnew/router/trace.h +++ b/pcbnew/router/trace.h @@ -3,48 +3,45 @@ * * Copyright (C) 2013 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 __TRACE_H #define __TRACE_H - #ifdef DEBUG #include #include #include -static void _trace_print(const char *funcName, int level, const std::string& msg) +static void _trace_print( const char* funcName, int level, const std::string& msg ) { - std::cerr << "trace[" << level << "]: " << funcName << ": " << msg << std::endl; + std::cerr << "trace[" << level << "]: " << funcName << ": " << msg << std::endl; } +#define TRACE( level, fmt, ... ) \ + _trace_print( __FUNCTION__, level, (boost::format( fmt ) % __VA_ARGS__).str() ); - -#define TRACE(level, fmt, ...) \ - _trace_print(__FUNCTION__, level, (boost::format(fmt) % __VA_ARGS__).str() ); - -#define TRACEn(level, msg) \ - _trace_print(__FUNCTION__, level, std::string(msg)); +#define TRACEn( level, msg ) \ + _trace_print( __FUNCTION__, level, std::string( msg ) ); #else -#define TRACE(level, fmt, ...) -#define TRACEn(level, msg) +#define TRACE( level, fmt, ... ) +#define TRACEn( level, msg ) #endif