Commit 5598acb6 authored by Maciej Sumiński's avatar Maciej Sumiński

Uncrustifying push&shove router

parent 87b3f2e4
include_directories(BEFORE ${INC_BEFORE}) include_directories( BEFORE ${INC_BEFORE} )
include_directories( include_directories(
./ ./
../ ../
../../include ../../ include
../../pcbnew ../../ pcbnew
../../polygon ../../ polygon
${INC_AFTER} $ { INC_AFTER }
) )
set(PCBNEW_PNS_SRCS set( PCBNEW_PNS_SRCS
direction.h direction.h
pns_via.h pns_via.h
pns_routing_settings.h pns_routing_settings.h
...@@ -45,6 +45,7 @@ set(PCBNEW_PNS_SRCS ...@@ -45,6 +45,7 @@ set(PCBNEW_PNS_SRCS
router_tool.h router_tool.h
router_preview_item.cpp router_preview_item.cpp
router_preview_item.h router_preview_item.h
) )
add_library( pnsrouter STATIC ${PCBNEW_PNS_SRCS} )
add_library(pnsrouter STATIC ${PCBNEW_PNS_SRCS})
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
class DIRECTION_45 class DIRECTION_45
{ {
public: public:
/** /**
...@@ -39,7 +38,8 @@ public: ...@@ -39,7 +38,8 @@ public:
* Represents available directions - there are 8 of them, as on a rectilinear map (north = up) + * 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. * an extra undefined direction, reserved for traces that don't respect 45-degree routing regime.
*/ */
enum Directions { enum Directions
{
N = 0, N = 0,
NE = 1, NE = 1,
E = 2, E = 2,
...@@ -55,31 +55,32 @@ public: ...@@ -55,31 +55,32 @@ public:
* Enum AngleType * Enum AngleType
* Represents kind of angle formed by vectors heading in two DIRECTION_45s. * Represents kind of angle formed by vectors heading in two DIRECTION_45s.
*/ */
enum AngleType { enum AngleType
ANG_OBTUSE = 0x1, {
ANG_RIGHT = 0x2, ANG_OBTUSE = 0x01,
ANG_ACUTE = 0x4, ANG_RIGHT = 0x02,
ANG_STRAIGHT = 0x8, ANG_ACUTE = 0x04,
ANG_STRAIGHT = 0x08,
ANG_HALF_FULL = 0x10, ANG_HALF_FULL = 0x10,
ANG_UNDEFINED = 0x20 ANG_UNDEFINED = 0x20
}; };
DIRECTION_45(Directions aDir = UNDEFINED): m_dir(aDir) {}; DIRECTION_45( Directions aDir = UNDEFINED ) : m_dir( aDir ) {};
/** /**
* Constructor * Constructor
* @param aVec vector, whose direction will be translated into a DIRECTION_45. * @param aVec vector, whose direction will be translated into a DIRECTION_45.
*/ */
DIRECTION_45(const VECTOR2I& aVec) DIRECTION_45( const VECTOR2I& aVec )
{ {
construct(aVec); construct( aVec );
} }
/** /**
* Constructor * Constructor
* @param aSeg segment, whose direction will be translated into a DIRECTION_45. * @param aSeg segment, whose direction will be translated into a DIRECTION_45.
*/ */
DIRECTION_45(const SEG& aSeg) DIRECTION_45( const SEG& aSeg )
{ {
construct( aSeg.b - aSeg.a ); construct( aSeg.b - aSeg.a );
} }
...@@ -91,18 +92,37 @@ public: ...@@ -91,18 +92,37 @@ public:
*/ */
const std::string Format() const const std::string Format() const
{ {
switch(m_dir) switch( m_dir )
{ {
case N : return "north"; case N:
case NE : return "north-east"; return "north";
case E : return "east";
case SE : return "south-east"; case NE:
case S : return "south"; return "north-east";
case SW : return "south-west";
case W : return "west"; case E:
case NW : return "north-west"; return "east";
case UNDEFINED : return "undefined";
default: return "<Error>"; 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 "<Error>";
} }
} }
...@@ -113,9 +133,10 @@ public: ...@@ -113,9 +133,10 @@ public:
*/ */
DIRECTION_45 Opposite() const DIRECTION_45 Opposite() const
{ {
if(m_dir == UNDEFINED) if( m_dir == UNDEFINED )
return UNDEFINED; return UNDEFINED;
const Directions OppositeMap[] = { S, SW, W, NW, N, NE, E, SE } ;
const Directions OppositeMap[] = { S, SW, W, NW, N, NE, E, SE };
return OppositeMap[m_dir]; return OppositeMap[m_dir];
} }
...@@ -124,20 +145,20 @@ public: ...@@ -124,20 +145,20 @@ public:
* Returns the type of angle between directions (this) and aOther. * Returns the type of angle between directions (this) and aOther.
* @param aOther direction to compare angle with * @param aOther direction to compare angle with
*/ */
AngleType Angle(const DIRECTION_45& aOther) const AngleType Angle( const DIRECTION_45& aOther ) const
{ {
if(m_dir == UNDEFINED || aOther.m_dir == UNDEFINED) if( m_dir == UNDEFINED || aOther.m_dir == UNDEFINED )
return ANG_UNDEFINED; return ANG_UNDEFINED;
int d = std::abs(m_dir - aOther.m_dir); int d = std::abs( m_dir - aOther.m_dir );
if(d == 1 || d == 7) if( d == 1 || d == 7 )
return ANG_OBTUSE; return ANG_OBTUSE;
else if(d == 2 || d == 6) else if( d == 2 || d == 6 )
return ANG_RIGHT; return ANG_RIGHT;
else if(d == 3 || d == 5) else if( d == 3 || d == 5 )
return ANG_ACUTE; return ANG_ACUTE;
else if(d == 4) else if( d == 4 )
return ANG_HALF_FULL; return ANG_HALF_FULL;
else else
return ANG_STRAIGHT; return ANG_STRAIGHT;
...@@ -147,9 +168,9 @@ public: ...@@ -147,9 +168,9 @@ public:
* Function IsObtuse() * Function IsObtuse()
* @return true, when (this) forms an obtuse angle with aOther * @return true, when (this) forms an obtuse angle with aOther
*/ */
bool IsObtuse(const DIRECTION_45& aOther) const bool IsObtuse( const DIRECTION_45& aOther ) const
{ {
return Angle(aOther) == ANG_OBTUSE; return Angle( aOther ) == ANG_OBTUSE;
} }
/** /**
...@@ -159,7 +180,7 @@ public: ...@@ -159,7 +180,7 @@ public:
*/ */
bool IsDiagonal() const bool IsDiagonal() const
{ {
return (m_dir % 2) == 1; return ( m_dir % 2 ) == 1;
} }
/** /**
...@@ -172,51 +193,56 @@ public: ...@@ -172,51 +193,56 @@ public:
* @param aStartDiagonal whether the first segment has to be diagonal * @param aStartDiagonal whether the first segment has to be diagonal
* @return the trace * @return the trace
*/ */
const SHAPE_LINE_CHAIN BuildInitialTrace(const VECTOR2I& aP0, const VECTOR2I &aP1, bool aStartDiagonal = false) const const SHAPE_LINE_CHAIN BuildInitialTrace( const VECTOR2I& aP0,
const VECTOR2I& aP1,
bool aStartDiagonal = false ) const
{ {
int w = abs(aP1.x - aP0.x); int w = abs( aP1.x - aP0.x );
int h = abs(aP1.y - aP0.y); int h = abs( aP1.y - aP0.y );
int sw = sign(aP1.x - aP0.x); int sw = sign( aP1.x - aP0.x );
int sh = sign(aP1.y - aP0.y); int sh = sign( aP1.y - aP0.y );
VECTOR2I mp0, mp1; VECTOR2I mp0, mp1;
// we are more horizontal than vertical? // we are more horizontal than vertical?
if(w > h) if( w > h )
{
mp0 = VECTOR2I( (w - h) * sw, 0 ); // direction: E
mp1 = VECTOR2I( h * sw, h * sh ); // direction: NE
}
else
{ {
mp0 = VECTOR2I((w - h) * sw, 0); // direction: E mp0 = VECTOR2I( 0, sh * (h - w) ); // direction: N
mp1 = VECTOR2I(h * sw, h * sh); // direction: NE mp1 = VECTOR2I( sw * w, sh * w ); // direction: NE
} else {
mp0 = VECTOR2I(0, sh * (h - w)); // direction: N
mp1 = VECTOR2I(sw * w, sh * w); // direction: NE
} }
bool start_diagonal; bool start_diagonal;
if(m_dir == UNDEFINED) if( m_dir == UNDEFINED )
start_diagonal = aStartDiagonal; start_diagonal = aStartDiagonal;
else else
start_diagonal = IsDiagonal(); start_diagonal = IsDiagonal();
SHAPE_LINE_CHAIN pl; SHAPE_LINE_CHAIN pl;
pl.Append(aP0); pl.Append( aP0 );
if (start_diagonal)
pl.Append(aP0 + mp1); if( start_diagonal )
pl.Append( aP0 + mp1 );
else else
pl.Append(aP0 + mp0); pl.Append( aP0 + mp0 );
pl.Append(aP1); pl.Append( aP1 );
pl.Simplify(); pl.Simplify();
return pl; return pl;
}; };
bool operator==(const DIRECTION_45& aOther) const bool operator==( const DIRECTION_45& aOther ) const
{ {
return aOther.m_dir == m_dir; return aOther.m_dir == m_dir;
} }
bool operator!=(const DIRECTION_45& aOther) const bool operator!=( const DIRECTION_45& aOther ) const
{ {
return aOther.m_dir != m_dir; return aOther.m_dir != m_dir;
} }
...@@ -224,16 +250,21 @@ public: ...@@ -224,16 +250,21 @@ public:
const DIRECTION_45 Right() const const DIRECTION_45 Right() const
{ {
DIRECTION_45 r; DIRECTION_45 r;
r.m_dir = (Directions) (m_dir + 1); r.m_dir = (Directions) (m_dir + 1);
if(r.m_dir == NW)
if( r.m_dir == NW )
r.m_dir = N; r.m_dir = N;
return r; return r;
} }
private: private:
template <typename T> int sign(T val) const { template <typename T>
return (T(0) < val) - (val < T(0)); int sign( T val ) const
{
return (T( 0 ) < val) - ( val < T( 0 ) );
} }
/** /**
...@@ -242,47 +273,52 @@ private: ...@@ -242,47 +273,52 @@ private:
* degrees, the direction is rounded to the nearest octant. * degrees, the direction is rounded to the nearest octant.
* @param aVec our vector * @param aVec our vector
*/ */
void construct(const VECTOR2I& aVec) void construct( const VECTOR2I& aVec )
{ {
m_dir = UNDEFINED; m_dir = UNDEFINED;
if(aVec.x == 0 && aVec.y == 0)
if( aVec.x == 0 && aVec.y == 0 )
return; return;
double mag = 360.0 - (180.0 / M_PI * atan2 ((double) aVec.y, (double) aVec.x )) + 90.0; double mag = 360.0 - ( 180.0 / M_PI * atan2( (double) aVec.y, (double) aVec.x ) ) + 90.0;
if (mag >= 360.0)
if( mag >= 360.0 )
mag -= 360.0; mag -= 360.0;
if(mag < 0.0)
if( mag < 0.0 )
mag += 360.0; mag += 360.0;
m_dir = (Directions) ((mag + 22.5) / 45.0); m_dir = (Directions)( ( mag + 22.5 ) / 45.0 );
if( m_dir >= 8 )
m_dir = (Directions)( m_dir - 8 );
if(m_dir >= 8) if( m_dir < 0 )
m_dir = (Directions) (m_dir - 8); m_dir = (Directions)( m_dir + 8 );
if(m_dir < 0)
m_dir = (Directions) (m_dir + 8);
return ; return;
if(aVec.y < 0)
if( aVec.y < 0 )
{ {
if(aVec.x > 0) if( aVec.x > 0 )
m_dir = NE; m_dir = NE;
else if(aVec.x < 0) else if( aVec.x < 0 )
m_dir = NW; m_dir = NW;
else else
m_dir = N; m_dir = N;
} }
else if(aVec.y == 0) else if( aVec.y == 0 )
{ {
if(aVec.x > 0) if( aVec.x > 0 )
m_dir = E; m_dir = E;
else else
m_dir = W; m_dir = W;
} }
else // aVec.y>0 else // aVec.y>0
{ {
if(aVec.x > 0) if( aVec.x > 0 )
m_dir = SE; m_dir = SE;
else if(aVec.x < 0) else if( aVec.x < 0 )
m_dir = SW; m_dir = SW;
else else
m_dir = S; m_dir = S;
...@@ -293,3 +329,4 @@ private: ...@@ -293,3 +329,4 @@ private:
}; };
#endif // __DIRECTION_H #endif // __DIRECTION_H
...@@ -37,42 +37,41 @@ ...@@ -37,42 +37,41 @@
* overlap and improving search time. * overlap and improving search time.
**/ **/
class PNS_INDEX { class PNS_INDEX
{
public: public:
typedef std::list<PNS_ITEM*> NetItemsList;
typedef std::list<PNS_ITEM *> NetItemsList; typedef SHAPE_INDEX<PNS_ITEM*> ItemShapeIndex;
typedef SHAPE_INDEX<PNS_ITEM *> ItemShapeIndex; typedef boost::unordered_set<PNS_ITEM*> ItemSet;
typedef boost::unordered_set<PNS_ITEM *> ItemSet;
PNS_INDEX(); PNS_INDEX();
~PNS_INDEX(); ~PNS_INDEX();
void Add( PNS_ITEM *aItem ); void Add( PNS_ITEM* aItem );
void Remove ( PNS_ITEM *aItem ); void Remove( PNS_ITEM* aItem );
void Replace ( PNS_ITEM *aOldItem, PNS_ITEM *aNewItem ); void Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem );
template<class Visitor> template<class Visitor>
int Query( const PNS_ITEM *aItem, int aMinDistance, Visitor &v); int Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& v );
template<class Visitor> template<class Visitor>
int Query( const SHAPE *aShape, int aMinDistance, Visitor &v); int Query( const SHAPE* aShape, int aMinDistance, Visitor& v );
void Clear(); void Clear();
NetItemsList* GetItemsForNet ( int aNet ) ; NetItemsList* GetItemsForNet( int aNet );
ItemSet::iterator begin() { return m_allItems.begin(); } ItemSet::iterator begin() { return m_allItems.begin(); }
ItemSet::iterator end() { return m_allItems.end(); } ItemSet::iterator end() { return m_allItems.end(); }
bool Contains ( PNS_ITEM *aItem ) const { bool Contains( PNS_ITEM* aItem ) const
return m_allItems.find(aItem) != m_allItems.end(); {
return m_allItems.find( aItem ) != m_allItems.end();
} }
int Size() const { return m_allItems.size(); } int Size() const { return m_allItems.size(); }
private: private:
static const int MaxSubIndices = 64; static const int MaxSubIndices = 64;
static const int SI_Multilayer = 2; static const int SI_Multilayer = 2;
static const int SI_SegDiagonal = 0; static const int SI_SegDiagonal = 0;
...@@ -81,161 +80,184 @@ private: ...@@ -81,161 +80,184 @@ private:
static const int SI_PadsTop = 0; static const int SI_PadsTop = 0;
static const int SI_PadsBottom = 1; static const int SI_PadsBottom = 1;
template<class Visitor> template <class Visitor>
int querySingle( int index, const SHAPE *aShape, int aMinDistance, Visitor &v); 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 ]; ItemShapeIndex* m_subIndices[MaxSubIndices];
std::map<int, NetItemsList> m_netMap; std::map<int, NetItemsList> m_netMap;
ItemSet m_allItems; ItemSet m_allItems;
}; };
PNS_INDEX::PNS_INDEX() 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(); const PNS_LAYERSET l = aItem->GetLayers();
switch(aItem->GetKind()) switch( aItem->GetKind() )
{ {
case PNS_ITEM::VIA: case PNS_ITEM::VIA:
idx_n = SI_Multilayer; idx_n = SI_Multilayer;
break; break;
case PNS_ITEM::SOLID: case PNS_ITEM::SOLID:
{ {
if( l.IsMultilayer() ) if( l.IsMultilayer() )
idx_n = SI_Multilayer; idx_n = SI_Multilayer;
else if (l.Start() == 0) // fixme: use kicad layer codes else if( l.Start() == 0 ) // fixme: use kicad layer codes
idx_n = SI_PadsTop; idx_n = SI_PadsTop;
else if (l.Start() == 15) else if( l.Start() == 15 )
idx_n = SI_PadsBottom; idx_n = SI_PadsBottom;
break; break;
} }
case PNS_ITEM::SEGMENT: case PNS_ITEM::SEGMENT:
case PNS_ITEM::LINE: case PNS_ITEM::LINE:
idx_n = SI_Traces + 2 * l.Start() + SI_SegStraight; idx_n = SI_Traces + 2 * l.Start() + SI_SegStraight;
break; break;
default: default:
break; break;
} }
assert(idx_n >= 0 && idx_n < MaxSubIndices);
if(!m_subIndices[idx_n]) assert( idx_n >= 0 && idx_n < MaxSubIndices );
if( !m_subIndices[idx_n] )
m_subIndices[idx_n] = new ItemShapeIndex; m_subIndices[idx_n] = new ItemShapeIndex;
return m_subIndices[idx_n]; return m_subIndices[idx_n];
} }
void PNS_INDEX::Add( PNS_ITEM *aItem )
{
ItemShapeIndex *idx = getSubindex(aItem);
void PNS_INDEX::Add( PNS_ITEM* aItem )
{
ItemShapeIndex* idx = getSubindex( aItem );
idx->Add(aItem); idx->Add( aItem );
m_allItems.insert(aItem); m_allItems.insert( aItem );
int net = aItem->GetNet(); int net = aItem->GetNet();
if(net >= 0)
if( net >= 0 )
{ {
m_netMap[net].push_back(aItem); m_netMap[net].push_back( aItem );
} }
} }
void PNS_INDEX::Remove( PNS_ITEM *aItem )
void PNS_INDEX::Remove( PNS_ITEM* aItem )
{ {
ItemShapeIndex *idx = getSubindex(aItem); ItemShapeIndex* idx = getSubindex( aItem );
idx->Remove(aItem);
m_allItems.erase (aItem); idx->Remove( aItem );
m_allItems.erase( aItem );
int net = aItem->GetNet(); int net = aItem->GetNet();
if(net >= 0 && m_netMap.find(net) != m_netMap.end()) if( net >= 0 && m_netMap.find( net ) != m_netMap.end() )
m_netMap[net].remove(aItem); 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); Remove( aOldItem );
Add(aNewItem); Add( aNewItem );
} }
template<class Visitor> template<class Visitor>
int PNS_INDEX::querySingle( int index, const SHAPE *aShape, int aMinDistance, Visitor &v) int PNS_INDEX::querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& v )
{ {
if(!m_subIndices[index]) if( !m_subIndices[index] )
return 0; return 0;
return m_subIndices[index] -> Query(aShape, aMinDistance, v, false);
} return m_subIndices[index]->Query( aShape, aMinDistance, v, false );
}
template<class Visitor> template<class Visitor>
int PNS_INDEX::Query( const PNS_ITEM *aItem, int aMinDistance, Visitor &v) int PNS_INDEX::Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& v )
{ {
const SHAPE *shape = aItem->GetShape(); const SHAPE* shape = aItem->GetShape();
int total = 0; int total = 0;
total += querySingle( SI_Multilayer, shape, aMinDistance, v );
total += querySingle(SI_Multilayer, shape, aMinDistance, v);
const PNS_LAYERSET layers = aItem->GetLayers(); const PNS_LAYERSET layers = aItem->GetLayers();
if(layers.IsMultilayer()) if( layers.IsMultilayer() )
{ {
total += querySingle(SI_PadsTop, shape, aMinDistance, v); total += querySingle( SI_PadsTop, shape, aMinDistance, v );
total += querySingle(SI_PadsBottom, shape, aMinDistance, v); total += querySingle( SI_PadsBottom, shape, aMinDistance, v );
for(int i = layers.Start(); i <= layers.End(); ++i )
total += querySingle( SI_Traces + 2 * i + SI_SegStraight, shape, aMinDistance, v);
} else { 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(); int l = layers.Start();
if(l == 0) if( l == 0 )
total += querySingle(SI_PadsTop, shape, aMinDistance, v); total += querySingle( SI_PadsTop, shape, aMinDistance, v );
else if(l == 15) else if( l == 15 )
total += querySingle(SI_PadsBottom, shape, aMinDistance, v); total += querySingle( SI_PadsBottom, shape, aMinDistance, v );
total += querySingle ( SI_Traces + 2 * l + SI_SegStraight, shape, aMinDistance, v);
total += querySingle( SI_Traces + 2 * l + SI_SegStraight, shape, aMinDistance, v );
} }
return total; return total;
} }
template<class Visitor> template<class Visitor>
int PNS_INDEX::Query( const SHAPE *aShape, int aMinDistance, Visitor &v) int PNS_INDEX::Query( const SHAPE* aShape, int aMinDistance, Visitor& v )
{ {
int total = 0; int total = 0;
for(int i = 0; i < MaxSubIndices; i++)
total += querySingle(i, aShape, aMinDistance, v); for( int i = 0; i < MaxSubIndices; i++ )
total += querySingle( i, aShape, aMinDistance, v );
return total; return total;
} }
void PNS_INDEX::Clear() void PNS_INDEX::Clear()
{ {
for(int i = 0; i < MaxSubIndices; ++i) for( int i = 0; i < MaxSubIndices; ++i )
{ {
ItemShapeIndex *idx = m_subIndices[i]; ItemShapeIndex* idx = m_subIndices[i];
if(idx)
if( idx )
delete idx; delete idx;
m_subIndices[i] = NULL; m_subIndices[i] = NULL;
} }
} }
PNS_INDEX::~PNS_INDEX() 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()) if( m_netMap.find( aNet ) == m_netMap.end() )
return NULL; return NULL;
return &m_netMap[aNet]; return &m_netMap[aNet];
} }
#endif #endif
...@@ -21,22 +21,25 @@ ...@@ -21,22 +21,25 @@
#include "pns_item.h" #include "pns_item.h"
#include "pns_line.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! // same nets? no collision!
if( m_net == aOther->m_net ) if( m_net == aOther->m_net )
return false; return false;
// check if we are not on completely different layers first // check if we are not on completely different layers first
if (!m_layers.Overlaps (aOther->m_layers)) if( !m_layers.Overlaps( aOther->m_layers ) )
return false; 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 ) ) if( collideSimple( aOther, aClearance, aNeedMTV, aMTV ) )
return true; return true;
...@@ -44,29 +47,43 @@ bool PNS_ITEM::Collide( const PNS_ITEM *aOther, int aClearance, bool aNeedMTV, V ...@@ -44,29 +47,43 @@ bool PNS_ITEM::Collide( const PNS_ITEM *aOther, int aClearance, bool aNeedMTV, V
// special case for "head" line with a via attached at the end. // special case for "head" line with a via attached at the end.
if( aOther->m_kind == LINE ) if( aOther->m_kind == LINE )
{ {
const PNS_LINE *line = static_cast<const PNS_LINE *> (aOther); const PNS_LINE* line = static_cast<const PNS_LINE*>( aOther );
if(line -> EndsWithVia())
return collideSimple( &line->GetVia(), aClearance - line->GetWidth() / 2, aNeedMTV, aMTV ); if( line->EndsWithVia() )
return collideSimple( &line->GetVia(), aClearance - line->GetWidth() / 2, aNeedMTV,
aMTV );
} }
return false; return false;
} }
const std::string PNS_ITEM::GetKindStr() const const std::string PNS_ITEM::GetKindStr() const
{ {
switch(m_kind) switch( m_kind )
{ {
case LINE: return "line"; case LINE:
case SEGMENT: return "segment"; return "line";
case VIA: return "via";
case JOINT: return "joint"; case SEGMENT:
case SOLID: return "solid"; return "segment";
default: return "unknown";
case VIA:
return "via";
case JOINT:
return "joint";
case SOLID:
return "solid";
default:
return "unknown";
} }
} }
PNS_ITEM::~PNS_ITEM() PNS_ITEM::~PNS_ITEM()
{ {
} }
...@@ -41,11 +41,11 @@ class PNS_NODE; ...@@ -41,11 +41,11 @@ class PNS_NODE;
class PNS_ITEM class PNS_ITEM
{ {
public: public:
static const int UnusedNet = INT_MAX; static const int UnusedNet = INT_MAX;
///> Supported item types ///> Supported item types
enum PnsKind { enum PnsKind
{
SOLID = 1, SOLID = 1,
LINE = 2, LINE = 2,
JOINT = 4, JOINT = 4,
...@@ -54,7 +54,7 @@ public: ...@@ -54,7 +54,7 @@ public:
ANY = 0xff ANY = 0xff
}; };
PNS_ITEM(PnsKind aKind) PNS_ITEM( PnsKind aKind )
{ {
m_net = UnusedNet; m_net = UnusedNet;
m_movable = true; m_movable = true;
...@@ -77,79 +77,82 @@ public: ...@@ -77,79 +77,82 @@ public:
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 ///> Returns a convex polygon "hull" of a the item, that is used as the walkaround
/// path. /// path.
/// aClearance defines how far from the body of the item the hull should be, /// 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. /// 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 virtual const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0 ) const
{ {
return SHAPE_LINE_CHAIN(); return SHAPE_LINE_CHAIN();
}; };
PnsKind GetKind() const { return m_kind; } PnsKind GetKind() const { return m_kind; }
bool OfKind( int aKind ) const { return (aKind & m_kind) != 0; } bool OfKind( int aKind ) const { return (aKind & m_kind) != 0; }
const std::string GetKindStr() const; const std::string GetKindStr() const;
///> Gets/Sets the corresponding parent object in the host application's model (pcbnew) ///> Gets/Sets the corresponding parent object in the host application's model (pcbnew)
void SetParent(BOARD_ITEM *aParent) { m_parent = aParent; } void SetParent( BOARD_ITEM* aParent ) { m_parent = aParent; }
BOARD_ITEM *GetParent() const { return m_parent; } BOARD_ITEM* GetParent() const { return m_parent; }
///> Net accessors ///> Net accessors
int GetNet() const { return m_net; } int GetNet() const { return m_net; }
void SetNet(int aNet) { m_net = aNet; } void SetNet( int aNet ) { m_net = aNet; }
///> Layers accessors ///> Layers accessors
const PNS_LAYERSET& GetLayers() const { return m_layers; } const PNS_LAYERSET& GetLayers() const { return m_layers; }
void SetLayers ( const PNS_LAYERSET& aLayers ) { m_layers = aLayers; } void SetLayers( const PNS_LAYERSET& aLayers ) { m_layers = aLayers; }
void SetLayer ( int aLayer ) { m_layers = PNS_LAYERSET (aLayer, aLayer); } void SetLayer( int aLayer )
{
m_layers = PNS_LAYERSET( aLayer, aLayer );
}
///> Ownership management. An item can belong to a single PNS_NODE or stay unowned. ///> Ownership management. An item can belong to a single PNS_NODE or stay unowned.
void SetOwner (PNS_NODE *aOwner) { m_owner = aOwner; } void SetOwner( PNS_NODE* aOwner ) { m_owner = aOwner; }
bool BelongsTo (PNS_NODE *aNode) const { return m_owner == aNode; } bool BelongsTo( PNS_NODE* aNode ) const { return m_owner == aNode; }
PNS_NODE *GetOwner() const { return m_owner; } PNS_NODE* GetOwner() const { return m_owner; }
///> Sets the world that is used for collision resolution. ///> Sets the world that is used for collision resolution.
void SetWorld (PNS_NODE *aWorld) { m_world = aWorld; } void SetWorld( PNS_NODE* aWorld ) { m_world = aWorld; }
PNS_NODE *GetWorld() const { return m_world; } PNS_NODE* GetWorld() const { return m_world; }
///> Collision function. Checks if the item aOther is closer to us than ///> 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 /// aClearance and returns true if so. It can also calculate a minimum translation vector that
/// collision if needed. /// resolves the collision if needed.
virtual bool Collide( const PNS_ITEM *aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) const; virtual bool Collide( const PNS_ITEM* aOther, int aClearance, bool aNeedMTV,
VECTOR2I& aMTV ) const;
///> A shortcut without MTV calculation ///> A shortcut without MTV calculation
bool Collide( const PNS_ITEM *aOther, int aClearance ) const bool Collide( const PNS_ITEM* aOther, int aClearance ) const
{ {
VECTOR2I dummy; VECTOR2I dummy;
return Collide(aOther, aClearance, false, dummy);
return Collide( aOther, aClearance, false, dummy );
} }
///> Returns the geometric shape of the item ///> Returns the geometric shape of the item
virtual const SHAPE* GetShape() const { virtual const SHAPE* GetShape() const
{
return NULL; return NULL;
} }
private: 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: protected:
PnsKind m_kind; PnsKind m_kind;
BOARD_ITEM *m_parent; BOARD_ITEM* m_parent;
PNS_NODE *m_world; PNS_NODE* m_world;
PNS_NODE *m_owner; PNS_NODE* m_owner;
PNS_LAYERSET m_layers; PNS_LAYERSET m_layers;
bool m_movable; bool m_movable;
int m_net; int m_net;
}; };
#endif // __PNS_ITEM_H #endif // __PNS_ITEM_Ha
...@@ -25,48 +25,57 @@ ...@@ -25,48 +25,57 @@
PNS_ITEMSET::PNS_ITEMSET() PNS_ITEMSET::PNS_ITEMSET()
{ {
} }
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; ItemVector newItems;
PNS_LAYERSET l; PNS_LAYERSET l;
if(aEnd < 0)
l = PNS_LAYERSET(aStart); if( aEnd < 0 )
l = PNS_LAYERSET( aStart );
else else
l = PNS_LAYERSET(aStart, aEnd); l = PNS_LAYERSET( aStart, aEnd );
BOOST_FOREACH( PNS_ITEM * item, m_items )
if( item->GetLayers().Overlaps( l ) )
newItems.push_back( item );
BOOST_FOREACH( PNS_ITEM *item, m_items )
if(item->GetLayers(). Overlaps ( l ))
newItems.push_back(item);
m_items = newItems; m_items = newItems;
return *this; return *this;
} }
PNS_ITEMSET& PNS_ITEMSET::FilterKinds ( int aKindMask )
PNS_ITEMSET& PNS_ITEMSET::FilterKinds( int aKindMask )
{ {
ItemVector newItems; ItemVector newItems;
BOOST_FOREACH( PNS_ITEM *item, m_items ) BOOST_FOREACH( PNS_ITEM * item, m_items )
if(item->GetKind() & aKindMask )
newItems.push_back(item); if( item->GetKind() & aKindMask )
newItems.push_back( item );
m_items = newItems; m_items = newItems;
return *this; return *this;
} }
PNS_ITEMSET& PNS_ITEMSET::FilterNet ( int aNet )
PNS_ITEMSET& PNS_ITEMSET::FilterNet( int aNet )
{ {
ItemVector newItems; ItemVector newItems;
BOOST_FOREACH( PNS_ITEM *item, m_items ) BOOST_FOREACH( PNS_ITEM * item, m_items )
if(item->GetNet() == aNet)
newItems.push_back(item); if( item->GetNet() == aNet )
newItems.push_back( item );
m_items = newItems; m_items = newItems;
return *this; return *this;
} }
......
...@@ -28,35 +28,36 @@ ...@@ -28,35 +28,36 @@
/** /**
* Class PNS_ITEMSET * 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 class PNS_ITEMSET
{ {
public: public:
typedef std::vector<PNS_ITEM*> ItemVector;
typedef std::vector<PNS_ITEM *> 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& FilterLayers( int aStart, int aEnd = -1 );
PNS_ITEMSET& FilterKinds ( int aKindMask ); PNS_ITEMSET& FilterKinds( int aKindMask );
PNS_ITEMSET& FilterNet ( int aNet ); PNS_ITEMSET& FilterNet( int aNet );
int Size() { return m_items.size(); } int Size() { return m_items.size(); }
void Add(PNS_ITEM *item) void Add( PNS_ITEM* item )
{ {
m_items.push_back(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: private:
ItemVector m_items; ItemVector m_items;
}; };
#endif #endif
...@@ -32,35 +32,38 @@ ...@@ -32,35 +32,38 @@
/** /**
* Class PNS_JOINT * Class PNS_JOINT
* *
* Represents a 2D point on a given set of layers and belonging to a certain net, * Represents a 2D point on a given set of layers and belonging to a certain
* that links together a number of board items. * 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. * A hash table of joints is used by the router to follow connectivity between
* the items.
**/ **/
class PNS_JOINT : public PNS_ITEM class PNS_JOINT : public PNS_ITEM
{ {
public: public:
typedef std::vector<PNS_ITEM *> LinkedItems; typedef std::vector<PNS_ITEM*> LinkedItems;
///> joints are hashed by their position, layers and net. Linked items are, obviously, not hashed ///> Joints are hashed by their position, layers and net.
struct HashTag { /// Linked items are, obviously, not hashed
struct HashTag
{
VECTOR2I pos; VECTOR2I pos;
int net; int net;
}; };
PNS_JOINT(): PNS_JOINT() :
PNS_ITEM(JOINT) {} PNS_ITEM( JOINT ) {}
PNS_JOINT(const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet = -1): PNS_JOINT( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
PNS_ITEM(JOINT) int aNet = -1 ) :
PNS_ITEM( JOINT )
{ {
m_tag.pos = aPos; m_tag.pos = aPos;
m_tag.net = aNet; m_tag.net = aNet;
m_layers = aLayers; m_layers = aLayers;
} }
PNS_JOINT(const PNS_JOINT& b): PNS_JOINT( const PNS_JOINT& b ) :
PNS_ITEM(JOINT) PNS_ITEM( JOINT )
{ {
m_layers = b.m_layers; m_layers = b.m_layers;
m_tag.pos = b.m_tag.pos; m_tag.pos = b.m_tag.pos;
...@@ -69,99 +72,111 @@ public: ...@@ -69,99 +72,111 @@ public:
m_layers = b.m_layers; m_layers = b.m_layers;
} }
PNS_ITEM *Clone() const PNS_ITEM* Clone() const
{ {
assert(false); assert( false );
return NULL; return NULL;
} }
///> returns true if the joint is a trivial line corner, connecting two segments of the same net, on the same layer. ///> Returns true if the joint is a trivial line corner, connecting two
/// segments of the same net, on the same layer.
bool IsLineCorner() const bool IsLineCorner() const
{ {
if(m_linkedItems.size() != 2) if( m_linkedItems.size() != 2 )
return false; return false;
if( m_linkedItems[0]->GetKind() != SEGMENT || m_linkedItems[1]->GetKind() != SEGMENT ) if( m_linkedItems[0]->GetKind() != SEGMENT ||
m_linkedItems[1]->GetKind() != SEGMENT )
return false; return false;
PNS_SEGMENT *seg1 = static_cast<PNS_SEGMENT *> (m_linkedItems[0]); PNS_SEGMENT* seg1 = static_cast<PNS_SEGMENT*> (m_linkedItems[0]);
PNS_SEGMENT *seg2 = static_cast<PNS_SEGMENT *> (m_linkedItems[1]); PNS_SEGMENT* seg2 = static_cast<PNS_SEGMENT*> (m_linkedItems[1]);
// joints between segments of different widths are not trivial. // joints between segments of different widths are not trivial.
return (seg1->GetWidth() == seg2->GetWidth()); return seg1->GetWidth() == seg2->GetWidth();
} }
///> Links the joint to a given board item (when it's added to the PNS_NODE) ///> Links the joint to a given board item (when it's added to the PNS_NODE)
void Link ( PNS_ITEM *aItem ) void Link( PNS_ITEM* aItem )
{ {
LinkedItems::iterator f = std::find(m_linkedItems.begin(), m_linkedItems.end(), aItem); LinkedItems::iterator f = std::find( m_linkedItems.begin(),
if(f != m_linkedItems.end()) m_linkedItems.end(), aItem );
if( f != m_linkedItems.end() )
return; return;
m_linkedItems.push_back(aItem);
m_linkedItems.push_back( aItem );
} }
///> Unlinks a given board item from the joint (upon its removal from a PNS_NODE) ///> Unlinks a given board item from the joint (upon its removal from a PNS_NODE)
///> Returns true if the joint became dangling after unlinking. ///> Returns true if the joint became dangling after unlinking.
bool Unlink ( PNS_ITEM *aItem ) bool Unlink( PNS_ITEM* aItem )
{ {
LinkedItems::iterator f = std::find(m_linkedItems.begin(), m_linkedItems.end(), aItem); LinkedItems::iterator f = std::find( m_linkedItems.begin(),
if(f != m_linkedItems.end()) m_linkedItems.end(), aItem );
m_linkedItems.erase(f);
return (m_linkedItems.size() == 0); if( f != m_linkedItems.end() )
m_linkedItems.erase( f );
return m_linkedItems.size() == 0;
} }
///> For trivial joints, returns the segment adjacent to (aCurrent). For non-trival ones, returns ///> For trivial joints, returns the segment adjacent to (aCurrent). For non-trival ones, returns
///> NULL, indicating the end of line. ///> NULL, indicating the end of line.
PNS_SEGMENT* NextSegment( PNS_SEGMENT* aCurrent) const PNS_SEGMENT* NextSegment( PNS_SEGMENT* aCurrent ) const
{ {
if(!IsLineCorner()) if( !IsLineCorner() )
return NULL; return NULL;
return static_cast<PNS_SEGMENT *> (m_linkedItems [ m_linkedItems[0] == aCurrent ? 1 : 0 ] ); return static_cast<PNS_SEGMENT*>( m_linkedItems[m_linkedItems[0] == aCurrent ? 1 : 0] );
} }
/// trivial accessors /// trivial accessors
const HashTag& GetTag() const { return m_tag; } const HashTag& GetTag() const { return m_tag; }
const VECTOR2I& GetPos() const { return m_tag.pos; } const VECTOR2I& GetPos() const { return m_tag.pos; }
int GetNet() const { return m_tag.net; } int GetNet() const { return m_tag.net; }
LinkedItems & GetLinkList() { return m_linkedItems; }; LinkedItems& GetLinkList() { return m_linkedItems; };
///> Returns the number of linked items of types listed in aMask. ///> Returns the number of linked items of types listed in aMask.
int LinkCount( int aMask = -1 ) const int LinkCount( int aMask = -1 ) const
{ {
int n = 0; int n = 0;
for(LinkedItems::const_iterator i = m_linkedItems.begin(); i!= m_linkedItems.end(); ++i)
for( LinkedItems::const_iterator i = m_linkedItems.begin();
i != m_linkedItems.end(); ++i )
if( (*i)->GetKind() & aMask ) if( (*i)->GetKind() & aMask )
n++; n++;
return n; return n;
} }
void Dump() const; void Dump() const;
bool operator==(const PNS_JOINT& rhs) const bool operator==( const PNS_JOINT& rhs ) const
{ {
return m_tag.pos == rhs.m_tag.pos && m_tag.net == rhs.m_tag.net; return m_tag.pos == rhs.m_tag.pos && m_tag.net == rhs.m_tag.net;
} }
void Merge( const PNS_JOINT& aJoint ) void Merge( const PNS_JOINT& aJoint )
{ {
if(!Overlaps(aJoint)) if( !Overlaps( aJoint ) )
return; return;
m_layers.Merge (aJoint.m_layers); m_layers.Merge( aJoint.m_layers );
// fixme: duplicate links (?) // fixme: duplicate links (?)
for(LinkedItems::const_iterator i =aJoint.m_linkedItems.begin(); i!=aJoint.m_linkedItems.end();++i) for( LinkedItems::const_iterator i = aJoint.m_linkedItems.begin();
m_linkedItems.push_back(*i); i != aJoint.m_linkedItems.end(); ++i )
m_linkedItems.push_back( *i );
} }
bool Overlaps(const PNS_JOINT& rhs) const 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 m_tag.pos == rhs.m_tag.pos &&
m_tag.net == rhs.m_tag.net && m_layers.Overlaps( rhs.m_layers );
} }
private: private:
///> hash tag for unordered_multimap ///> hash tag for unordered_multimap
HashTag m_tag; HashTag m_tag;
...@@ -171,18 +186,22 @@ private: ...@@ -171,18 +186,22 @@ private:
// hash function & comparison operator for boost::unordered_map<> // 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; 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; std::size_t seed = 0;
boost::hash_combine(seed, p.pos.x); boost::hash_combine( seed, p.pos.x );
boost::hash_combine(seed, p.pos.y); boost::hash_combine( seed, p.pos.y );
boost::hash_combine(seed, p.net); boost::hash_combine( seed, p.net );
return seed; return seed;
} }
#endif // __PNS_JOINT_H #endif // __PNS_JOINT_H
...@@ -28,91 +28,93 @@ ...@@ -28,91 +28,93 @@
* *
* Represents a contiguous set of PCB layers. * Represents a contiguous set of PCB layers.
*/ */
class PNS_LAYERSET class PNS_LAYERSET
{ {
public: public:
PNS_LAYERSET() :
PNS_LAYERSET(): m_start( -1 ),
m_start(-1), m_end( -1 )
m_end(-1)
{}; {};
PNS_LAYERSET (int aStart, int aEnd) PNS_LAYERSET( int aStart, int aEnd )
{ {
if(aStart > aEnd) if( aStart > aEnd )
std::swap(aStart, aEnd); std::swap( aStart, aEnd );
m_start = aStart; m_start = aStart;
m_end = aEnd; m_end = aEnd;
} }
PNS_LAYERSET (int aLayer) PNS_LAYERSET( int aLayer )
{ {
m_start = m_end = aLayer; m_start = m_end = aLayer;
} }
PNS_LAYERSET(const PNS_LAYERSET &b) : PNS_LAYERSET( const PNS_LAYERSET& b ) :
m_start(b.m_start), m_start( b.m_start ),
m_end (b.m_end) m_end( b.m_end )
{} {}
~PNS_LAYERSET () {}; ~PNS_LAYERSET() {};
const PNS_LAYERSET& operator= ( const PNS_LAYERSET& b) const PNS_LAYERSET& operator=( const PNS_LAYERSET& b )
{ {
m_start = b.m_start; m_start = b.m_start;
m_end = b.m_end; m_end = b.m_end;
return *this; return *this;
} }
bool Overlaps ( const PNS_LAYERSET& aOther ) const bool Overlaps( const PNS_LAYERSET& aOther ) const
{ {
return m_end >= aOther.m_start && m_start <= aOther.m_end; return m_end >= aOther.m_start && m_start <= aOther.m_end;
} }
bool Overlaps ( const int aLayer ) const bool Overlaps( const int aLayer ) const
{ {
return aLayer >= m_start && aLayer <= m_end; return aLayer >= m_start && aLayer <= m_end;
} }
bool IsMultilayer ( ) const bool IsMultilayer() const
{ {
return m_start != m_end; return m_start != m_end;
} }
int Start() const { int Start() const
{
return m_start; return m_start;
} }
int End() const { int End() const
{
return m_end; return m_end;
} }
void Merge ( const PNS_LAYERSET& aOther ) void Merge( const PNS_LAYERSET& aOther )
{ {
if(m_start < 0 || m_end < 0) if( m_start < 0 || m_end < 0 )
{ {
m_start = aOther.m_start; m_start = aOther.m_start;
m_end = aOther.m_end; m_end = aOther.m_end;
return; return;
} }
if(aOther.m_start < m_start) if( aOther.m_start < m_start )
m_start = aOther.m_start; m_start = aOther.m_start;
if(aOther.m_end > m_end)
if( aOther.m_end > m_end )
m_end = aOther.m_end; m_end = aOther.m_end;
} }
///> Shortcut for comparisons/overlap tests ///> Shortcut for comparisons/overlap tests
static PNS_LAYERSET All() static PNS_LAYERSET All()
{ {
return PNS_LAYERSET(0, 256); return PNS_LAYERSET( 0, 256 );
} }
private: private:
int m_start; int m_start;
int m_end; int m_end;
}; };
#endif // __PNS_LAYERSET_H #endif // __PNS_LAYERSET_H
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <math/vector2d.h> #include <math/vector2d.h>
#include "pns_line.h" #include "pns_line.h"
#include "pns_node.h" #include "pns_node.h"
#include "pns_via.h" #include "pns_via.h"
...@@ -33,9 +32,9 @@ ...@@ -33,9 +32,9 @@
using namespace std; using namespace std;
using boost::optional; 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_line = m_line;
l->m_width = m_width; l->m_width = m_width;
...@@ -49,9 +48,10 @@ PNS_LINE *PNS_LINE::Clone() const ...@@ -49,9 +48,10 @@ PNS_LINE *PNS_LINE::Clone() const
return l; 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_width = m_width;
l->m_layers = m_layers; l->m_layers = m_layers;
...@@ -61,39 +61,43 @@ PNS_LINE *PNS_LINE::CloneProperties() const ...@@ -61,39 +61,43 @@ PNS_LINE *PNS_LINE::CloneProperties() const
return l; return l;
} }
PNS_SEGMENT *PNS_SEGMENT::Clone() const
PNS_SEGMENT* PNS_SEGMENT::Clone() const
{ {
PNS_SEGMENT *s = new PNS_SEGMENT; PNS_SEGMENT* s = new PNS_SEGMENT;
s->m_width = m_width; s->m_width = m_width;
s->m_net = m_net; s->m_net = m_net;
s->m_shape = m_shape; s->m_shape = m_shape;
s->m_layers = m_layers; s->m_layers = m_layers;
return s; //assert(false); return s; // assert(false);
} }
#if 1 #if 1
bool PNS_LINE::MergeObtuseSegments( ) bool PNS_LINE::MergeObtuseSegments()
{ {
int step = m_line.PointCount() - 3; int step = m_line.PointCount() - 3;
int iter = 0; int iter = 0;
int segs_pre = m_line.SegmentCount(); int segs_pre = m_line.SegmentCount();
if(step < 0) if( step < 0 )
return false; return false;
SHAPE_LINE_CHAIN current_path (m_line); SHAPE_LINE_CHAIN current_path( m_line );
while(1) while( 1 )
{ {
iter++; iter++;
int n_segs = current_path.SegmentCount(); int n_segs = current_path.SegmentCount();
int max_step = n_segs - 2; int max_step = n_segs - 2;
if(step > max_step)
if( step > max_step )
step = max_step; step = max_step;
if(step < 2) if( step < 2 )
{ {
m_line = current_path; m_line = current_path;
return current_path.SegmentCount() < segs_pre; return current_path.SegmentCount() < segs_pre;
...@@ -102,81 +106,88 @@ bool PNS_LINE::MergeObtuseSegments( ) ...@@ -102,81 +106,88 @@ bool PNS_LINE::MergeObtuseSegments( )
bool found_anything = false; bool found_anything = false;
int n = 0; int n = 0;
while (n < n_segs - step) while( n < n_segs - step )
{ {
const SEG s1 = current_path.CSegment(n); const SEG s1 = current_path.CSegment( n );
const SEG s2 = current_path.CSegment(n + step); const SEG s2 = current_path.CSegment( n + step );
SEG s1opt, s2opt; SEG s1opt, s2opt;
if (DIRECTION_45(s1).IsObtuse(DIRECTION_45(s2))) if( DIRECTION_45( s1 ).IsObtuse( DIRECTION_45( s2 ) ) )
{ {
VECTOR2I ip = *s1.IntersectLines(s2); VECTOR2I ip = *s1.IntersectLines( s2 );
if(s1.Distance(ip) <= 1 || s2.Distance(ip) <= 1) if( s1.Distance( ip ) <= 1 || s2.Distance( ip ) <= 1 )
{ {
s1opt = SEG(s1.a, ip); s1opt = SEG( s1.a, ip );
s2opt = SEG(ip, s2.b); s2opt = SEG( ip, s2.b );
} else { }
s1opt = SEG(s1.a, ip); else
s2opt = SEG(ip, s2.b); {
s1opt = SEG( s1.a, ip );
s2opt = SEG( ip, s2.b );
} }
if (DIRECTION_45(s1opt).IsObtuse(DIRECTION_45(s2opt))) if( DIRECTION_45( s1opt ).IsObtuse( DIRECTION_45( s2opt ) ) )
{ {
SHAPE_LINE_CHAIN opt_path; SHAPE_LINE_CHAIN opt_path;
opt_path.Append(s1opt.a); opt_path.Append( s1opt.a );
opt_path.Append(s1opt.b); opt_path.Append( s1opt.b );
opt_path.Append(s2opt.b); opt_path.Append( s2opt.b );
PNS_LINE opt_track (*this, opt_path); PNS_LINE opt_track( *this, opt_path );
if(!m_world->CheckColliding(&opt_track, PNS_ITEM::ANY)) if( !m_world->CheckColliding( &opt_track, PNS_ITEM::ANY ) )
{ {
current_path.Replace(s1.Index() + 1, s2.Index(), ip); current_path.Replace( s1.Index() + 1, s2.Index(), ip );
n_segs = current_path.SegmentCount(); n_segs = current_path.SegmentCount();
found_anything = true; found_anything = true;
break; break;
} }
} }
} }
n++; n++;
} }
if(!found_anything) if( !found_anything )
{ {
if( step <= 2 ) if( step <= 2 )
{ {
m_line = current_path; m_line = current_path;
return m_line.SegmentCount() < segs_pre; return m_line.SegmentCount() < segs_pre;
} }
step --;
step--;
} }
} }
return m_line.SegmentCount() < segs_pre; return m_line.SegmentCount() < segs_pre;
} }
bool PNS_LINE::MergeSegments( )
bool PNS_LINE::MergeSegments()
{ {
int step = m_line.PointCount() - 3; int step = m_line.PointCount() - 3;
int iter = 0; int iter = 0;
int segs_pre = m_line.SegmentCount(); int segs_pre = m_line.SegmentCount();
if(step < 0) if( step < 0 )
return false; return false;
SHAPE_LINE_CHAIN current_path (m_line); SHAPE_LINE_CHAIN current_path( m_line );
while(1) while( 1 )
{ {
iter++; iter++;
int n_segs = current_path.SegmentCount(); int n_segs = current_path.SegmentCount();
int max_step = n_segs - 2; int max_step = n_segs - 2;
if(step > max_step)
if( step > max_step )
step = max_step; step = max_step;
if(step < 2) if( step < 2 )
{ {
m_line = current_path; m_line = current_path;
return current_path.SegmentCount() < segs_pre; return current_path.SegmentCount() < segs_pre;
...@@ -185,116 +196,121 @@ bool PNS_LINE::MergeSegments( ) ...@@ -185,116 +196,121 @@ bool PNS_LINE::MergeSegments( )
bool found_anything = false; bool found_anything = false;
int n = 0; int n = 0;
while (n < n_segs - step) while( n < n_segs - step )
{ {
const SEG s1 = current_path.CSegment(n); const SEG s1 = current_path.CSegment( n );
const SEG s2 = current_path.CSegment(n + step); const SEG s2 = current_path.CSegment( n + step );
SEG s1opt, s2opt; SEG s1opt, s2opt;
if(n > 0) if( n > 0 )
{ {
SHAPE_LINE_CHAIN path_straight = DIRECTION_45().BuildInitialTrace(s1.a, s2.a, false); SHAPE_LINE_CHAIN path_straight = DIRECTION_45().BuildInitialTrace( s1.a,
SHAPE_LINE_CHAIN path_diagonal = DIRECTION_45().BuildInitialTrace(s1.a, s2.a, true); s2.a,
false );
SHAPE_LINE_CHAIN path_diagonal = DIRECTION_45().BuildInitialTrace( s1.a,
s2.a,
true );
} }
if (DIRECTION_45(s1) == DIRECTION_45(s2)) if( DIRECTION_45( s1 ) == DIRECTION_45( s2 ) )
{ {
if(s1.Collinear(s2)) if( s1.Collinear( s2 ) )
{ {
//printf("Colinear: np %d step %d n1 %d n2 %d\n", n_segs, step, n, n+step); // printf("Colinear: np %d step %d n1 %d n2 %d\n", n_segs, step, n, n+step);
SHAPE_LINE_CHAIN opt_path; SHAPE_LINE_CHAIN opt_path;
opt_path.Append(s1.a); opt_path.Append( s1.a );
opt_path.Append(s2.b); opt_path.Append( s2.b );
PNS_LINE tmp (*this, opt_path); PNS_LINE tmp( *this, opt_path );
if(!m_world->CheckColliding(&tmp, PNS_ITEM::ANY)) if( !m_world->CheckColliding( &tmp, PNS_ITEM::ANY ) )
{ {
current_path.Remove(s1.Index() + 1, s2.Index()); current_path.Remove( s1.Index() + 1, s2.Index() );
n_segs = current_path.SegmentCount(); n_segs = current_path.SegmentCount();
found_anything = true; found_anything = true;
break; break;
} }
} }
} }
else if (DIRECTION_45(s1).IsObtuse(DIRECTION_45(s2))) else if( DIRECTION_45( s1 ).IsObtuse( DIRECTION_45( s2 ) ) )
{ {
VECTOR2I ip = *s1.IntersectLines(s2); VECTOR2I ip = *s1.IntersectLines( s2 );
if(s1.Distance(ip) <= 1 || s2.Distance(ip) <= 1) if( s1.Distance( ip ) <= 1 || s2.Distance( ip ) <= 1 )
{ {
s1opt = SEG(s1.a, ip); s1opt = SEG( s1.a, ip );
s2opt = SEG(ip, s2.b); s2opt = SEG( ip, s2.b );
} else { }
s1opt = SEG(s1.a, ip); else
s2opt = SEG(ip, s2.b); {
s1opt = SEG( s1.a, ip );
s2opt = SEG( ip, s2.b );
} }
if (DIRECTION_45(s1opt).IsObtuse(DIRECTION_45(s2opt))) if( DIRECTION_45( s1opt ).IsObtuse( DIRECTION_45( s2opt ) ) )
{ {
SHAPE_LINE_CHAIN opt_path; SHAPE_LINE_CHAIN opt_path;
opt_path.Append(s1opt.a); opt_path.Append( s1opt.a );
opt_path.Append(s1opt.b); opt_path.Append( s1opt.b );
opt_path.Append(s2opt.b); opt_path.Append( s2opt.b );
PNS_LINE opt_track (*this, opt_path); PNS_LINE opt_track( *this, opt_path );
if(!m_world->CheckColliding(&opt_track, PNS_ITEM::ANY)) if( !m_world->CheckColliding( &opt_track, PNS_ITEM::ANY ) )
{ {
current_path.Replace(s1.Index() + 1, s2.Index(), ip); current_path.Replace( s1.Index() + 1, s2.Index(), ip );
n_segs = current_path.SegmentCount(); n_segs = current_path.SegmentCount();
found_anything = true; found_anything = true;
break; break;
} }
} }
} }
n++; n++;
} }
if(!found_anything) if( !found_anything )
{ {
if( step <= 2 ) if( step <= 2 )
{ {
m_line = current_path; m_line = current_path;
return m_line.SegmentCount() < segs_pre; return m_line.SegmentCount() < segs_pre;
} }
step --;
step--;
} }
} }
return m_line.SegmentCount() < segs_pre; return m_line.SegmentCount() < segs_pre;
} }
#endif #endif
int PNS_LINE::CountCorners(int aAngles)
int PNS_LINE::CountCorners( int aAngles )
{ {
int count = 0; int count = 0;
for(int i = 0; i < m_line.SegmentCount() - 1; i ++)
for( int i = 0; i < m_line.SegmentCount() - 1; i++ )
{ {
const SEG seg1 = m_line.CSegment(i); const SEG seg1 = m_line.CSegment( i );
const SEG seg2 = m_line.CSegment(i + 1); const SEG seg2 = m_line.CSegment( i + 1 );
const DIRECTION_45 dir1( seg1 );
const DIRECTION_45 dir2( seg2 );
const DIRECTION_45 dir1(seg1); DIRECTION_45::AngleType a = dir1.Angle( dir2 );
const DIRECTION_45 dir2(seg2);
DIRECTION_45::AngleType a = dir1.Angle(dir2); if( a & aAngles )
if(a & aAngles)
count++; count++;
} }
return count; return count;
} }
//#define DUMP_TEST_CASES
// #define DUMP_TEST_CASES
// fixme: damn f*****g inefficient and incredibly crappily written // fixme: damn f*****g inefficient and incredibly crappily written
void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle,
...@@ -303,10 +319,9 @@ void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, ...@@ -303,10 +319,9 @@ void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle,
SHAPE_LINE_CHAIN& aPostPath, SHAPE_LINE_CHAIN& aPostPath,
bool aCw ) const 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_orig( m_line );
SHAPE_LINE_CHAIN l_hull; SHAPE_LINE_CHAIN l_hull;
vector<bool> outside, on_edge, inside; vector<bool> outside, on_edge, inside;
SHAPE_LINE_CHAIN path; SHAPE_LINE_CHAIN path;
...@@ -314,46 +329,46 @@ void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, ...@@ -314,46 +329,46 @@ void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle,
vector<Intersection> isects; vector<Intersection> isects;
// don't calculate walkaround for empty lines // don't calculate walkaround for empty lines
if(m_line.PointCount() < 2) if( m_line.PointCount() < 2 )
return; return;
#ifdef DUMP_TEST_CASES #ifdef DUMP_TEST_CASES
printf("%s\n", m_line.Format().c_str()); printf( "%s\n", m_line.Format().c_str() );
printf("%s\n", aObstacle.Format().c_str()); printf( "%s\n", aObstacle.Format().c_str() );
#endif #endif
aObstacle.Intersect(m_line, isects); aObstacle.Intersect( m_line, isects );
//printf("NewWalk intersectiosn :%d\n" ,isects.size());
// printf("NewWalk intersectiosn :%d\n" ,isects.size());
if( !aCw ) if( !aCw )
l_hull = aObstacle.Reverse(); l_hull = aObstacle.Reverse();
else else
l_hull = aObstacle; l_hull = aObstacle;
BOOST_FOREACH( Intersection isect, isects ) BOOST_FOREACH( Intersection isect, isects ) {
{ l_orig.Split( isect.p );
l_orig.Split(isect.p); l_hull.Split( isect.p );
l_hull.Split(isect.p);
} }
#ifdef DUMP_TEST_CASES #ifdef DUMP_TEST_CASES
printf("%s\n", m_line.Format().c_str()); printf( "%s\n", m_line.Format().c_str() );
printf("%s\n", aObstacle.Format().c_str()); printf( "%s\n", aObstacle.Format().c_str() );
printf("%s\n", l_orig.Format().c_str()); printf( "%s\n", l_orig.Format().c_str() );
printf("%s\n", l_hull.Format().c_str()); printf( "%s\n", l_hull.Format().c_str() );
#endif #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 first_post = -1;
int last_pre = -1; int last_pre = -1;
for (int i = 0; i < l_orig.PointCount(); i++) for( int i = 0; i < l_orig.PointCount(); i++ )
{ {
int ei = l_hull.Find(l_orig.CPoint(i)) ; int ei = l_hull.Find( l_orig.CPoint( i ) );
bool edge = ei >= 0; bool edge = ei >= 0;
bool in = l_hull.PointInside( l_orig.CPoint(i)) && !edge; bool in = l_hull.PointInside( l_orig.CPoint( i ) ) && !edge;
bool out = !( in || edge); bool out = !( in || edge);
outside.push_back( out ); outside.push_back( out );
...@@ -361,97 +376,107 @@ void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, ...@@ -361,97 +376,107 @@ void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle,
inside.push_back( in ); inside.push_back( in );
} }
for( int i = l_orig.PointCount() - 1; i >= 1; i-- )
for(int i = l_orig.PointCount() - 1; i >= 1; i --) if( inside[i] && outside[i - 1] )
if(inside[i] && outside[i-1])
{ {
SHAPE_LINE_CHAIN::Intersections ips; SHAPE_LINE_CHAIN::Intersections ips;
l_hull.Intersect( SEG( l_orig.CPoint(i), l_orig.CPoint(i - 1) ), ips ); l_hull.Intersect( SEG( l_orig.CPoint( i ), l_orig.CPoint( i - 1 ) ), ips );
l_orig.Remove(i, -1); l_orig.Remove( i, -1 );
l_orig.Append(ips[0].p); l_orig.Append( ips[0].p );
break; break;
} }
else if (inside[i] && on_edge[i-1]) else if( inside[i] && on_edge[i - 1] )
{ {
l_orig.Remove(i, -1); l_orig.Remove( i, -1 );
//n = i; // n = i;
} else if(!inside[i]) }
else if( !inside[i] )
break; break;
if(!outside.size() && on_edge.size() < 2) if( !outside.size() && on_edge.size() < 2 )
return; return;
for (int i = 0; i < l_orig.PointCount(); i++) for( int i = 0; i < l_orig.PointCount(); i++ )
{ {
const VECTOR2I p = l_orig.Point(i); const VECTOR2I p = l_orig.Point( i );
if( outside[i] || (on_edge[i] && i == (l_orig.PointCount() - 1))) if( outside[i] || ( on_edge[i] && i == ( l_orig.PointCount() - 1 ) ) )
{ {
if(last_pre < 0) if( last_pre < 0 )
aPrePath.Append(p); aPrePath.Append( p );
path.Append(p);
path.Append( p );
} }
else if ( on_edge[i] ) else if( on_edge[i] )
{ {
int li = -1; int li = -1;
if(last_pre < 0)
if( last_pre < 0 )
{ {
aPrePath.Append(p); aPrePath.Append( p );
last_pre = path.PointCount(); last_pre = path.PointCount();
} }
if( i == l_orig.PointCount() - 1 || outside[i+1])
if( i == l_orig.PointCount() - 1 || outside[i + 1] )
{ {
path.Append(p); path.Append( p );
} }
else else
{ {
int vi2 = l_hull.Find( l_orig.CPoint(i) ); int vi2 = l_hull.Find( l_orig.CPoint( i ) );
path.Append( l_hull.CPoint( vi2 ) );
path.Append(l_hull.CPoint(vi2)); for( int j = (vi2 + 1) % l_hull.PointCount();
for(int j = (vi2 + 1) % l_hull.PointCount(); j != vi2; j = (j + 1) % l_hull.PointCount()) j != vi2;
j = (j + 1) % l_hull.PointCount() )
{ {
path.Append(l_hull.CPoint(j)); path.Append( l_hull.CPoint( j ) );
li = l_orig.Find(l_hull.CPoint(j)); li = l_orig.Find( l_hull.CPoint( j ) );
if(li >= 0 && (li == (l_orig.PointCount() - 1) || outside[li+1]))
if( li >= 0 && ( li == (l_orig.PointCount() - 1 ) ||
outside[li + 1]) )
break; break;
} }
if(li >= 0) { if( li >= 0 )
if(i >= li) {
if( i >= li )
break; break;
else { else
i = li; i = li;
} }
} }
}
first_post = path.PointCount() - 1; first_post = path.PointCount() - 1;
} }
} }
if(last_pre < 0 && first_post < 0) if( last_pre < 0 && first_post < 0 )
return; return;
aWalkaroundPath = path.Slice( last_pre, first_post ); aWalkaroundPath = path.Slice( last_pre, first_post );
if(first_post >= 0)
aPostPath = path.Slice( first_post, -1 );
if( first_post >= 0 )
aPostPath = path.Slice( first_post, -1 );
} }
bool PNS_LINE::onEdge(const SHAPE_LINE_CHAIN &obstacle, VECTOR2I p, int& ei, bool& is_vertex) const
bool PNS_LINE::onEdge( const SHAPE_LINE_CHAIN& obstacle, VECTOR2I p, int& ei,
bool& is_vertex ) const
{ {
int vtx = obstacle.Find(p); int vtx = obstacle.Find( p );
if(vtx >= 0) if( vtx >= 0 )
{ {
ei = vtx; ei = vtx;
is_vertex =true; is_vertex = true;
return true; return true;
} }
for(int s = 0; s< obstacle.SegmentCount(); s++) for( int s = 0; s < obstacle.SegmentCount(); s++ )
{ {
if(obstacle.CSegment(s).Contains(p)) if( obstacle.CSegment( s ).Contains( p ) )
{ {
ei = s; ei = s;
is_vertex = false; is_vertex = false;
...@@ -462,55 +487,71 @@ bool PNS_LINE::onEdge(const SHAPE_LINE_CHAIN &obstacle, VECTOR2I p, int& ei, boo ...@@ -462,55 +487,71 @@ bool PNS_LINE::onEdge(const SHAPE_LINE_CHAIN &obstacle, VECTOR2I p, int& ei, boo
return false; return false;
} }
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
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(); int sc = line.SegmentCount();
for(int i = 0; i < line.SegmentCount(); i++)
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 );
printf("check-seg rev %d %d/%d %d\n",reverse, i, sc, sc - 1 - i); if( reverse )
SEG tmp = line.CSegment(reverse ? sc - 1 - i : i);
SEG s (tmp.a, tmp.b);
if(reverse)
{ {
s.a = tmp.b; s.a = tmp.b;
s.b = tmp.a; s.b = tmp.a;
} }
if(onEdge(obstacle, s.a, index_o, is_vertex)) if( onEdge( obstacle, s.a, index_o, is_vertex ) )
{ {
index_l = (reverse ? sc-1-i : i); index_l = (reverse ? sc - 1 - i : i);
ip = s.a; ip = s.a;
printf("vertex %d on-%s %d\n", index_l, is_vertex?"vertex":"edge",index_o); printf( "vertex %d on-%s %d\n", index_l,
is_vertex ? "vertex" : "edge", index_o );
return true; return true;
} }
if(onEdge(obstacle, s.b, index_o, is_vertex)) if( onEdge( obstacle, s.b, index_o, is_vertex ) )
{ {
index_l = (reverse? sc-1-i-1 : i + 1); index_l = (reverse ? sc - 1 - i - 1 : i + 1);
ip = s.b; ip = s.b;
printf("vertex %d on-%s %d\n", index_l, is_vertex?"vertex":"edge",index_o); printf( "vertex %d on-%s %d\n", index_l,
is_vertex ? "vertex" : "edge", index_o );
return true; return true;
} }
SHAPE_LINE_CHAIN::Intersections ips; SHAPE_LINE_CHAIN::Intersections ips;
int n_is = obstacle.Intersect ( s, ips ); int n_is = obstacle.Intersect( s, ips );
if (n_is > 0) if( n_is > 0 )
{ {
index_o = ips[0].our.Index(); index_o = ips[0].our.Index();
index_l = reverse ?sc-1-i:i; index_l = reverse ? sc - 1 - i : i;
printf("segment-%d intersects edge-%d\n", index_l, index_o); printf( "segment-%d intersects edge-%d\n", index_l, index_o );
ip = ips[0].p; ip = ips[0].p;
return true; return true;
} }
} }
return false; 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
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(); const SHAPE_LINE_CHAIN& line = GetCLine();
VECTOR2I ip_start; VECTOR2I ip_start;
int index_o_start, index_l_start; int index_o_start, index_l_start;
VECTOR2I ip_end; VECTOR2I ip_end;
...@@ -518,187 +559,205 @@ bool PNS_LINE::Walkaround(SHAPE_LINE_CHAIN obstacle, SHAPE_LINE_CHAIN &pre, SHAP ...@@ -518,187 +559,205 @@ bool PNS_LINE::Walkaround(SHAPE_LINE_CHAIN obstacle, SHAPE_LINE_CHAIN &pre, SHAP
bool is_vertex_start, is_vertex_end; bool is_vertex_start, is_vertex_end;
if(line.SegmentCount() < 1) if( line.SegmentCount() < 1 )
return false; return false;
if(obstacle.PointInside(line.CPoint(0)) || obstacle.PointInside(line.CPoint(-1))) if( obstacle.PointInside( line.CPoint( 0 ) ) ||
obstacle.PointInside( line.CPoint( -1 ) ) )
return false; return false;
// printf("forward:\n"); // printf("forward:\n");
bool found = walkScan(line, obstacle, false, ip_start, index_o_start, index_l_start, is_vertex_start); bool found = walkScan( line,
//printf("reverse:\n"); obstacle,
found |= walkScan(line, obstacle, true, ip_end, index_o_end, index_l_end, is_vertex_end); false,
ip_start,
if(!found || ip_start == ip_end) 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; pre = line;
return true; return true;
} }
pre = line.Slice( 0, index_l_start );
pre = line.Slice ( 0, index_l_start ); pre.Append( ip_start );
pre.Append (ip_start);
walk.Clear(); walk.Clear();
walk.Append(ip_start); walk.Append( ip_start );
if(cw) if( cw )
{ {
int is = (index_o_start + 1) % obstacle.PointCount(); int is = ( index_o_start + 1 ) % obstacle.PointCount();
int ie = (is_vertex_end ? index_o_end : index_o_end + 1) % obstacle.PointCount(); int ie = ( is_vertex_end ? index_o_end : index_o_end + 1 ) % obstacle.PointCount();
while(1) while( 1 )
{ {
printf("is %d\n", is); printf( "is %d\n", is );
walk.Append(obstacle.CPoint(is)); walk.Append( obstacle.CPoint( is ) );
if(is == ie) if( is == ie )
break; break;
is ++; is++;
if (is == obstacle.PointCount() )
if( is == obstacle.PointCount() )
is = 0; is = 0;
} }
} else { }
else
{
int is = index_o_start; int is = index_o_start;
int ie = (is_vertex_end ? index_o_end : index_o_end) % obstacle.PointCount(); int ie = ( is_vertex_end ? index_o_end : index_o_end ) % obstacle.PointCount();
while(1) while( 1 )
{ {
printf("is %d\n", is); printf( "is %d\n", is );
walk.Append(obstacle.CPoint(is)); walk.Append( obstacle.CPoint( is ) );
if(is == ie)
if( is == ie )
break; break;
is --; is--;
if ( is < 0 )
if( is < 0 )
is = obstacle.PointCount() - 1; is = obstacle.PointCount() - 1;
} }
} }
walk.Append(ip_end); walk.Append( ip_end );
post.Clear(); post.Clear();
post.Append(ip_end); post.Append( ip_end );
post.Append(line.Slice (is_vertex_end ? index_l_end : index_l_end + 1 , -1)); post.Append( line.Slice( is_vertex_end ? index_l_end : index_l_end + 1, -1 ) );
//for(int i = (index_o_start + 1) % obstacle.PointCount(); // for(int i = (index_o_start + 1) % obstacle.PointCount();
// i != (index_o_end + 1) % obstacle.PointCount(); i=(i+1) % obstacle.PointCount()) // i != (index_o_end + 1) % obstacle.PointCount(); i=(i+1) % obstacle.PointCount())
//{ // {
//printf("append %d\n", i); // printf("append %d\n", i);
//walk.Append(obstacle.CPoint(i)); // walk.Append(obstacle.CPoint(i));
//} // }
return true; return true;
} }
void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle, void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle,
SHAPE_LINE_CHAIN& aPath, SHAPE_LINE_CHAIN& aPath,
bool aCw ) const bool aCw ) const
{ {
SHAPE_LINE_CHAIN walk, post; SHAPE_LINE_CHAIN walk, post;
NewWalkaround(aObstacle, aPath, walk, post, aCw);
aPath.Append(walk); NewWalkaround( aObstacle, aPath, walk, post, aCw );
aPath.Append(post); aPath.Append( walk );
aPath.Append( post );
aPath.Simplify(); aPath.Simplify();
} }
void PNS_LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle, void PNS_LINE::Walkaround( const SHAPE_LINE_CHAIN& aObstacle,
SHAPE_LINE_CHAIN& aPath, SHAPE_LINE_CHAIN& aPath,
bool aCw ) const bool aCw ) const
{ {
SHAPE_LINE_CHAIN walk, post; SHAPE_LINE_CHAIN walk, post;
Walkaround(aObstacle, aPath, walk, post, aCw);
aPath.Append(walk); Walkaround( aObstacle, aPath, walk, post, aCw );
aPath.Append(post); aPath.Append( walk );
aPath.Append( post );
aPath.Simplify(); aPath.Simplify();
} }
const SHAPE_LINE_CHAIN PNS_SEGMENT::Hull(int aClearance, int aWalkaroundThickness) const const SHAPE_LINE_CHAIN PNS_SEGMENT::Hull( int aClearance, int aWalkaroundThickness ) const
{ {
int d = aClearance + 10; int d = aClearance + 10;
int x = (int) (2.0 / (1.0 + M_SQRT2) * d) + 2; int x = (int)( 2.0 / ( 1.0 + M_SQRT2 ) * d ) + 2;
const VECTOR2I a = m_shape.CPoint(0); const VECTOR2I a = m_shape.CPoint( 0 );
const VECTOR2I b = m_shape.CPoint(1); const VECTOR2I b = m_shape.CPoint( 1 );
VECTOR2I dir = b - a; VECTOR2I dir = b - a;
VECTOR2I p0 = dir.Perpendicular().Resize(d); VECTOR2I p0 = dir.Perpendicular().Resize( d );
VECTOR2I ds = dir.Perpendicular().Resize(x / 2);
VECTOR2I pd = dir.Resize(x / 2);
VECTOR2I dp = dir.Resize(d);
VECTOR2I ds = dir.Perpendicular().Resize( x / 2 );
VECTOR2I pd = dir.Resize( x / 2 );
VECTOR2I dp = dir.Resize( d );
SHAPE_LINE_CHAIN s; SHAPE_LINE_CHAIN s;
s.SetClosed( true ); s.SetClosed( true );
s.Append(b + p0 + pd); s.Append( b + p0 + pd );
s.Append(b + dp + ds); s.Append( b + dp + ds );
s.Append(b + dp - ds); s.Append( b + dp - ds );
s.Append(b - p0 + pd); s.Append( b - p0 + pd );
s.Append(a - p0 - pd); s.Append( a - p0 - pd );
s.Append(a - dp - ds); s.Append( a - dp - ds );
s.Append(a - dp + ds); s.Append( a - dp + ds );
s.Append(a + p0 - pd); s.Append( a + p0 - pd );
// make sure the hull outline is always clockwise // make sure the hull outline is always clockwise
if(s.CSegment(0).Side(a) < 0) if( s.CSegment( 0 ).Side( a ) < 0 )
return s.Reverse(); return s.Reverse();
else else
return s; return s;
} }
bool PNS_LINE::Is45Degree() bool PNS_LINE::Is45Degree()
{ {
for(int i = 0; i < m_line.SegmentCount(); i++) for( int i = 0; i < m_line.SegmentCount(); i++ )
{ {
const SEG &s = m_line.CSegment(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); 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) if( angle < 0 )
angle+=360.0; angle += 360.0;
double angle_a = fabs(fmod(angle, 45.0)); double angle_a = fabs( fmod( angle, 45.0 ) );
if(angle_a > 1.0 && angle_a < 44.0)
if( angle_a > 1.0 && angle_a < 44.0 )
return false; return false;
} }
return true; 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) if( obs )
{ {
l.RemoveVia(); l.RemoveVia();
int p = l.GetLine().Split(obs -> ip_first); int p = l.GetLine().Split( obs->ip_first );
l.GetLine().Remove(p + 1, -1); l.GetLine().Remove( p + 1, -1 );
} }
return l; return l;
} }
void PNS_LINE::ShowLinks() void PNS_LINE::ShowLinks()
{ {
if(!m_segmentRefs) if( !m_segmentRefs )
{ {
printf("line %p: no links\n", this); printf( "line %p: no links\n", this );
return; 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]) ; 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] );
} }
...@@ -38,46 +38,48 @@ class PNS_VIA; ...@@ -38,46 +38,48 @@ class PNS_VIA;
/** /**
* Class PNS_LINE * Class PNS_LINE
* *
* Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads, * Represents a track on a PCB, connecting two non-trivial joints (that is,
* junctions between multiple traces or two traces different widths and combinations of these). * vias, pads, junctions between multiple traces or two traces different widths
* PNS_LINEs are NOT stored in the model (PNS_NODE) - instead, they are assembled on-the-fly, based on * and combinations of these). PNS_LINEs are NOT stored in the model (PNS_NODE).
* a via/pad/segment that belongs/begins them. * 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 * PNS_LINEs can be either loose (consisting of segments that do not belong to
* taken from a PNS_NODE) - these are returned by PNS_NODE::AssembleLine and friends. * 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. * 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: public:
typedef std::vector<PNS_SEGMENT *> LinkedSegments; typedef std::vector<PNS_SEGMENT*> LinkedSegments;
PNS_LINE (): PNS_LINE() :
PNS_ITEM(LINE) PNS_ITEM( LINE )
{ {
m_segmentRefs = NULL; m_segmentRefs = NULL;
m_hasVia = false; m_hasVia = false;
m_affectedRangeStart = -1; m_affectedRangeStart = -1;
}; };
PNS_LINE (int aLayer, int aWidth, const SHAPE_LINE_CHAIN& aLine) : PNS_LINE( int aLayer, int aWidth, const SHAPE_LINE_CHAIN& aLine ) :
PNS_ITEM(LINE) PNS_ITEM( LINE )
{ {
m_line = aLine; m_line = aLine;
m_width = aWidth; m_width = aWidth;
m_segmentRefs = NULL; m_segmentRefs = NULL;
m_hasVia = false; m_hasVia = false;
m_affectedRangeStart = -1; m_affectedRangeStart = -1;
SetLayer(aLayer); SetLayer( aLayer );
} }
PNS_LINE(const PNS_LINE& aOther) : PNS_LINE( const PNS_LINE& aOther ) :
PNS_ITEM(aOther), PNS_ITEM( aOther ),
m_line(aOther.m_line), m_line( aOther.m_line ),
m_width(aOther.m_width) m_width( aOther.m_width )
{ {
m_net = aOther.m_net; m_net = aOther.m_net;
m_movable = aOther.m_movable; m_movable = aOther.m_movable;
...@@ -94,10 +96,10 @@ public: ...@@ -94,10 +96,10 @@ public:
* copies properties (net, layers from a base line), and replaces the shape * copies properties (net, layers from a base line), and replaces the shape
* by aLine * by aLine
**/ **/
PNS_LINE(const PNS_LINE& aBase, const SHAPE_LINE_CHAIN& aLine) : PNS_LINE( const PNS_LINE& aBase, const SHAPE_LINE_CHAIN& aLine ) :
PNS_ITEM(aBase), PNS_ITEM( aBase ),
m_line(aLine), m_line( aLine ),
m_width(aBase.m_width) m_width( aBase.m_width )
{ {
m_net = aBase.m_net; m_net = aBase.m_net;
m_layers = aBase.m_layers; m_layers = aBase.m_layers;
...@@ -106,64 +108,68 @@ public: ...@@ -106,64 +108,68 @@ public:
m_affectedRangeStart = -1; m_affectedRangeStart = -1;
} }
~PNS_LINE () ~PNS_LINE()
{ {
if(m_segmentRefs) if( m_segmentRefs )
delete m_segmentRefs; delete m_segmentRefs;
}; };
virtual PNS_LINE *Clone() const ; virtual PNS_LINE* Clone() const;
///> clones the line without cloning the shape (just the properties - net, width, layers, etc.) ///> clones the line without cloning the shape
PNS_LINE *CloneProperties() const ; ///> (just the properties - net, width, layers, etc.)
PNS_LINE* CloneProperties() const;
int GetLayer() const { return GetLayers().Start(); } int GetLayer() const { return GetLayers().Start(); }
///> Geometry accessors ///> Geometry accessors
void SetShape(const SHAPE_LINE_CHAIN& aLine) { m_line = aLine; } void SetShape( const SHAPE_LINE_CHAIN& aLine ) { m_line = aLine; }
const SHAPE* GetShape() const { return &m_line; } const SHAPE* GetShape() const { return &m_line; }
SHAPE_LINE_CHAIN& GetLine() { return m_line; } SHAPE_LINE_CHAIN& GetLine() { return m_line; }
const SHAPE_LINE_CHAIN& GetCLine() const { return m_line; } const SHAPE_LINE_CHAIN& GetCLine() const { return m_line; }
///> Width accessors ///> Width accessors
void SetWidth( int aWidth ) { m_width = aWidth; } void SetWidth( int aWidth ) { m_width = aWidth; }
int GetWidth () const { return m_width; } int GetWidth() const { return m_width; }
///> Links a segment from a PNS_NODE to this line, making it owned by the node ///> Links a segment from a PNS_NODE to this line, making it owned by the node
void LinkSegment(PNS_SEGMENT *aSeg) void LinkSegment( PNS_SEGMENT* aSeg )
{ {
if(!m_segmentRefs) if( !m_segmentRefs )
m_segmentRefs = new std::vector<PNS_SEGMENT *> (); m_segmentRefs = new std::vector<PNS_SEGMENT*> ();
m_segmentRefs->push_back(aSeg);
m_segmentRefs->push_back( aSeg );
} }
///> Returns a list of segments from the owning node that constitute this line (or NULL if ///> Returns a list of segments from the owning node that constitute this
///> the line is loose) ///> line (or NULL if the line is loose)
LinkedSegments* GetLinkedSegments() LinkedSegments* GetLinkedSegments()
{ {
return m_segmentRefs; return m_segmentRefs;
} }
bool ContainsSegment (PNS_SEGMENT *aSeg) const bool ContainsSegment( PNS_SEGMENT* aSeg ) const
{ {
if (!m_segmentRefs) if( !m_segmentRefs )
return false; return false;
return std::find( m_segmentRefs->begin(), m_segmentRefs->end(), aSeg) != m_segmentRefs->end(); 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. ///> Returns this line, but clipped to the nearest obstacle
const PNS_LINE ClipToNearestObstacle( PNS_NODE *aNode ) const; ///> along, to avoid collision.
const PNS_LINE ClipToNearestObstacle( PNS_NODE* aNode ) const;
///> DEPRECATED optimization functions (moved to PNS_OPTIMIZER) ///> DEPRECATED optimization functions (moved to PNS_OPTIMIZER)
bool MergeObtuseSegments(); bool MergeObtuseSegments();
bool MergeSegments(); bool MergeSegments();
///> Returns the number of corners of angles specified by mask aAngles. ///> Returns the number of corners of angles specified by mask aAngles.
int CountCorners(int aAngles); int CountCorners( int aAngles );
///> Calculates a line thightly wrapping a convex hull of an obstacle object (aObstacle). ///> Calculates a line thightly wrapping a convex hull
///> of an obstacle object (aObstacle).
///> aPrePath = path from origin to the obstacle ///> aPrePath = path from origin to the obstacle
///> aWalkaroundPath = path around the obstacle ///> aWalkaroundPath = path around the obstacle
///> aPostPath = past from obstacle till the end ///> aPostPath = past from obstacle till the end
...@@ -179,13 +185,16 @@ public: ...@@ -179,13 +185,16 @@ public:
bool aCw ) const; bool aCw ) const;
bool Walkaround(SHAPE_LINE_CHAIN obstacle, SHAPE_LINE_CHAIN &pre, SHAPE_LINE_CHAIN &walk, SHAPE_LINE_CHAIN &post, bool cw) 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, void Walkaround( const SHAPE_LINE_CHAIN& aObstacle,
SHAPE_LINE_CHAIN& aPath, SHAPE_LINE_CHAIN& aPath,
bool aCw ) const; bool aCw ) const;
bool Is45Degree(); bool Is45Degree();
///> Prints out all linked segments ///> Prints out all linked segments
...@@ -193,34 +202,37 @@ public: ...@@ -193,34 +202,37 @@ public:
bool EndsWithVia() const { return m_hasVia; } bool EndsWithVia() const { return m_hasVia; }
void AppendVia ( const PNS_VIA &aVia ) { void AppendVia( const PNS_VIA& aVia )
{
m_hasVia = true; m_hasVia = true;
m_via = aVia; m_via = aVia;
m_via.SetNet ( m_net ) ; m_via.SetNet( m_net );
} }
void RemoveVia() { m_hasVia = false; } void RemoveVia() { m_hasVia = false; }
const PNS_VIA& GetVia() const { return m_via; } const PNS_VIA& GetVia() const { return m_via; }
void SetAffectedRange ( int aStart, int aEnd ) void SetAffectedRange( int aStart, int aEnd )
{ {
m_affectedRangeStart = aStart; m_affectedRangeStart = aStart;
m_affectedRangeEnd = aEnd; m_affectedRangeEnd = aEnd;
} }
void ClearAffectedRange ( ) void ClearAffectedRange()
{ {
m_affectedRangeStart = -1; m_affectedRangeStart = -1;
} }
bool GetAffectedRange ( int& aStart, int& aEnd ) bool GetAffectedRange( int& aStart, int& aEnd )
{ {
if(m_affectedRangeStart >= 0) if( m_affectedRangeStart >= 0 )
{ {
aStart = m_affectedRangeStart; aStart = m_affectedRangeStart;
aEnd = m_affectedRangeEnd; aEnd = m_affectedRangeEnd;
return true; return true;
} else { }
else
{
aStart = 0; aStart = 0;
aEnd = m_line.PointCount(); aEnd = m_line.PointCount();
return false; return false;
...@@ -228,8 +240,9 @@ public: ...@@ -228,8 +240,9 @@ public:
} }
private: private:
bool onEdge(const SHAPE_LINE_CHAIN &obstacle, VECTOR2I p, int& ei, bool& is_vertex) const; 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; 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. ///> List of semgments in a PNS_NODE (PNS_ITEM::m_owner) that constitute this line.
LinkedSegments* m_segmentRefs; LinkedSegments* m_segmentRefs;
...@@ -238,6 +251,7 @@ private: ...@@ -238,6 +251,7 @@ private:
SHAPE_LINE_CHAIN m_line; SHAPE_LINE_CHAIN m_line;
int m_width; int m_width;
///> Via at the end and a flag indicating if it's enabled. ///> Via at the end and a flag indicating if it's enabled.
PNS_VIA m_via; PNS_VIA m_via;
bool m_hasVia; bool m_hasVia;
...@@ -246,6 +260,5 @@ private: ...@@ -246,6 +260,5 @@ private:
int m_affectedRangeEnd; int m_affectedRangeEnd;
}; };
#endif // __PNS_LINE_H #endif // __PNS_LINE_H
...@@ -33,9 +33,9 @@ ...@@ -33,9 +33,9 @@
using namespace std; using namespace std;
using boost::optional; 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_initial_direction = DIRECTION_45( DIRECTION_45::N );
m_follow_mouse = false; m_follow_mouse = false;
m_smoothing_step = 100000; m_smoothing_step = 100000;
m_smooth_mouse = false; m_smooth_mouse = false;
...@@ -46,13 +46,15 @@ PNS_LINE_PLACER::PNS_LINE_PLACER( PNS_NODE *aWorld ) ...@@ -46,13 +46,15 @@ PNS_LINE_PLACER::PNS_LINE_PLACER( PNS_NODE *aWorld )
m_shove = NULL; m_shove = NULL;
}; };
PNS_LINE_PLACER::~PNS_LINE_PLACER() PNS_LINE_PLACER::~PNS_LINE_PLACER()
{ {
if(m_shove) if( m_shove )
delete m_shove; delete m_shove;
} }
void PNS_LINE_PLACER::ApplySettings ( const PNS_ROUTING_SETTINGS& aSettings )
void PNS_LINE_PLACER::ApplySettings( const PNS_ROUTING_SETTINGS& aSettings )
{ {
m_follow_mouse = aSettings.m_followMouse; m_follow_mouse = aSettings.m_followMouse;
m_mode = aSettings.m_routingMode; m_mode = aSettings.m_routingMode;
...@@ -60,44 +62,42 @@ void PNS_LINE_PLACER::ApplySettings ( const PNS_ROUTING_SETTINGS& aSettings ) ...@@ -60,44 +62,42 @@ void PNS_LINE_PLACER::ApplySettings ( const PNS_ROUTING_SETTINGS& aSettings )
m_smartPads = aSettings.m_smartPads; m_smartPads = aSettings.m_smartPads;
} }
void PNS_LINE_PLACER::StartPlacement(const VECTOR2I& aStart, int aNet, int aWidth, int aLayer )
void PNS_LINE_PLACER::StartPlacement( const VECTOR2I& aStart, int aNet,
int aWidth, int aLayer )
{ {
m_direction = m_initial_direction; m_direction = m_initial_direction;
TRACE(1, "world %p, intitial-direction %s layer %d\n", m_world % m_direction.Format().c_str() % aLayer); TRACE( 1, "world %p, intitial-direction %s layer %d\n",
m_head.SetNet(aNet); m_world % m_direction.Format().c_str() % aLayer );
m_tail.SetNet(aNet); m_head.SetNet( aNet );
m_head.SetWidth(aWidth); m_tail.SetNet( aNet );
m_tail.SetWidth(aWidth); m_head.SetWidth( aWidth );
m_tail.SetWidth( aWidth );
m_head.GetLine().Clear(); m_head.GetLine().Clear();
m_tail.GetLine().Clear(); m_tail.GetLine().Clear();
m_head.SetLayer(aLayer); m_head.SetLayer( aLayer );
m_tail.SetLayer(aLayer); m_tail.SetLayer( aLayer );
m_iteration = 0; m_iteration = 0;
m_p_start = aStart; m_p_start = aStart;
m_currentNode = m_world->Branch(); m_currentNode = m_world->Branch();
m_head.SetWorld(m_currentNode); m_head.SetWorld( m_currentNode );
m_tail.SetWorld(m_currentNode); m_tail.SetWorld( m_currentNode );
//if(m_shove) // if(m_shove)
// delete m_shove; // delete m_shove;
m_shove = new PNS_SHOVE(m_currentNode); m_shove = new PNS_SHOVE( m_currentNode );
m_placingVia = false; m_placingVia = false;
} }
void PNS_LINE_PLACER::SetInitialDirection(const DIRECTION_45& aDirection)
void PNS_LINE_PLACER::SetInitialDirection( const DIRECTION_45& aDirection )
{ {
m_initial_direction = aDirection; m_initial_direction = aDirection;
if(m_tail.GetCLine().SegmentCount() == 0) if( m_tail.GetCLine().SegmentCount() == 0 )
m_direction = aDirection; 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() bool PNS_LINE_PLACER::handleSelfIntersections()
{ {
SHAPE_LINE_CHAIN::Intersections ips; SHAPE_LINE_CHAIN::Intersections ips;
...@@ -105,13 +105,13 @@ bool PNS_LINE_PLACER::handleSelfIntersections() ...@@ -105,13 +105,13 @@ bool PNS_LINE_PLACER::handleSelfIntersections()
SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); SHAPE_LINE_CHAIN& tail = m_tail.GetLine();
// if there is no tail, there is nothing to intersect with // if there is no tail, there is nothing to intersect with
if(tail.PointCount() < 2) if( tail.PointCount() < 2 )
return false; return false;
tail.Intersect(head, ips); tail.Intersect( head, ips );
// no intesection points - nothing to reduce // no intesection points - nothing to reduce
if (ips.empty()) if( ips.empty() )
return false; return false;
int n = INT_MAX; int n = INT_MAX;
...@@ -119,9 +119,9 @@ bool PNS_LINE_PLACER::handleSelfIntersections() ...@@ -119,9 +119,9 @@ bool PNS_LINE_PLACER::handleSelfIntersections()
// if there is more than one intersection, find the one that is // if there is more than one intersection, find the one that is
// closest to the beginning of the tail. // closest to the beginning of the tail.
BOOST_FOREACH(SHAPE_LINE_CHAIN::Intersection i, ips) BOOST_FOREACH( SHAPE_LINE_CHAIN::Intersection i, ips )
{ {
if (i.our.Index() < n) if( i.our.Index() < n )
{ {
n = i.our.Index(); n = i.our.Index();
ipoint = i.p; ipoint = i.p;
...@@ -129,37 +129,34 @@ bool PNS_LINE_PLACER::handleSelfIntersections() ...@@ -129,37 +129,34 @@ bool PNS_LINE_PLACER::handleSelfIntersections()
} }
// ignore the point where head and tail meet // ignore the point where head and tail meet
if(ipoint == head.CPoint(0) || ipoint == tail.CPoint(-1)) if( ipoint == head.CPoint( 0 ) || ipoint == tail.CPoint( -1 ) )
return false; return false;
// Intersection point is on the first or the second segment: just start routing // Intersection point is on the first or the second segment: just start routing
// from the beginning // from the beginning
if (n < 2) if( n < 2 )
{ {
m_p_start = tail.Point(0); m_p_start = tail.Point( 0 );
m_direction = m_initial_direction; m_direction = m_initial_direction;
tail.Clear(); tail.Clear();
head.Clear(); head.Clear();
return true; return true;
} else { }
else
{
// Clip till the last tail segment before intersection. // Clip till the last tail segment before intersection.
// Set the direction to the one of this segment. // Set the direction to the one of this segment.
const SEG last = tail.CSegment(n - 1); const SEG last = tail.CSegment( n - 1 );
m_p_start = last.a; m_p_start = last.a;
m_direction = DIRECTION_45(last); m_direction = DIRECTION_45( last );
tail.Remove(n, -1); tail.Remove( n, -1 );
return true; return true;
} }
return false; 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() bool PNS_LINE_PLACER::handlePullback()
{ {
SHAPE_LINE_CHAIN& head = m_head.GetLine(); SHAPE_LINE_CHAIN& head = m_head.GetLine();
...@@ -167,43 +164,45 @@ bool PNS_LINE_PLACER::handlePullback() ...@@ -167,43 +164,45 @@ bool PNS_LINE_PLACER::handlePullback()
int n = tail.PointCount(); int n = tail.PointCount();
if(n == 0) if( n == 0 )
return false; return false;
else if (n == 1) else if( n == 1 )
{ {
m_p_start = tail.CPoint(0); m_p_start = tail.CPoint( 0 );
tail.Clear(); tail.Clear();
return true; return true;
} }
DIRECTION_45 first_head (head.Segment(0)); DIRECTION_45 first_head( head.Segment( 0 ) );
DIRECTION_45 last_tail (tail.Segment(-1)); DIRECTION_45 last_tail( tail.Segment( -1 ) );
DIRECTION_45::AngleType angle = first_head.Angle(last_tail); DIRECTION_45::AngleType angle = first_head.Angle( last_tail );
// case 1: we have a defined routing direction, and the currently computed head // case 1: we have a defined routing direction, and the currently computed
// goes in different one. // head goes in different one.
bool pullback_1 = false;//(m_direction != DIRECTION_45::UNDEFINED && m_direction != first_head); 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 // case 2: regardless of the current routing direction, if the tail/head
// an acute or right angle, reduce the tail by one segment (and hope that further iterations) // extremities form an acute or right angle, reduce the tail by one segment
// will result with a cleaner trace // (and hope that further iterations) will result with a cleaner trace
bool pullback_2 = (angle == DIRECTION_45::ANG_RIGHT || angle == DIRECTION_45::ANG_ACUTE); bool pullback_2 = (angle == DIRECTION_45::ANG_RIGHT ||
angle == DIRECTION_45::ANG_ACUTE);
if(pullback_1 || pullback_2) if( pullback_1 || pullback_2 )
{ {
const SEG last = tail.CSegment( -1 );
const SEG last = tail.CSegment(-1); m_direction = DIRECTION_45( last );
m_direction = DIRECTION_45(last);
m_p_start = last.a; m_p_start = last.a;
TRACE( 0, "Placer: pullback triggered [%d] [%s %s]",
n % last_tail.Format().c_str() % first_head.Format().c_str() );
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
// erase the last point in the tail, hoping that the next iteration will result with a head // result with a head trace that starts with a segment following our
// trace that starts with a segment following our current direction. // current direction.
if(n < 2) if( n < 2 )
tail.Clear(); // don't leave a single-point tail tail.Clear(); // don't leave a single-point tail
else else
tail.Remove(-1, -1); tail.Remove( -1, -1 );
if( !tail.SegmentCount() ) if( !tail.SegmentCount() )
m_direction = m_initial_direction; m_direction = m_initial_direction;
...@@ -214,15 +213,8 @@ bool PNS_LINE_PLACER::handlePullback() ...@@ -214,15 +213,8 @@ bool PNS_LINE_PLACER::handlePullback()
return false; return false;
} }
/**
* Function reduceTail() bool PNS_LINE_PLACER::reduceTail( const VECTOR2I& aEnd )
*
* 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& head = m_head.GetLine();
SHAPE_LINE_CHAIN& tail = m_tail.GetLine(); SHAPE_LINE_CHAIN& tail = m_tail.GetLine();
...@@ -230,32 +222,33 @@ bool PNS_LINE_PLACER::reduceTail(const VECTOR2I& aEnd) ...@@ -230,32 +222,33 @@ bool PNS_LINE_PLACER::reduceTail(const VECTOR2I& aEnd)
int n = tail.SegmentCount(); int n = tail.SegmentCount();
// Don't attempt this for too short tails // Don't attempt this for too short tails
if (n < 2) if( n < 2 )
return false; return false;
// Start from the segment farthest from the end of the tail // Start from the segment farthest from the end of the tail
//int start_index = std::max(n - 1 - ReductionDepth, 0); // int start_index = std::max(n - 1 - ReductionDepth, 0);
DIRECTION_45 new_direction; DIRECTION_45 new_direction;
VECTOR2I new_start; VECTOR2I new_start;
int reduce_index = -1; int reduce_index = -1;
DIRECTION_45 head_dir ( head.Segment(0) ); DIRECTION_45 head_dir( head.Segment( 0 ) );
for(int i = tail.SegmentCount() - 1; i >= 0; i--) for( int i = tail.SegmentCount() - 1; i >= 0; i-- )
{ {
const SEG s = tail.CSegment(i); const SEG s = tail.CSegment( i );
DIRECTION_45 dir (s); DIRECTION_45 dir( s );
// calculate a replacement route and check if it matches the direction of the segment to be replaced // calculate a replacement route and check if it matches
SHAPE_LINE_CHAIN replacement = dir.BuildInitialTrace(s.a, aEnd); // the direction of the segment to be replaced
SHAPE_LINE_CHAIN replacement = dir.BuildInitialTrace( s.a, aEnd );
PNS_LINE tmp (m_tail, replacement); PNS_LINE tmp( m_tail, replacement );
if (m_currentNode->CheckColliding(&tmp, PNS_ITEM::ANY)) if( m_currentNode->CheckColliding( &tmp, PNS_ITEM::ANY ) )
break; break;
if(DIRECTION_45(replacement.Segment(0)) == dir) if( DIRECTION_45( replacement.Segment( 0 ) ) == dir )
{ {
new_start = s.a; new_start = s.a;
new_direction = dir; new_direction = dir;
...@@ -263,15 +256,14 @@ bool PNS_LINE_PLACER::reduceTail(const VECTOR2I& aEnd) ...@@ -263,15 +256,14 @@ bool PNS_LINE_PLACER::reduceTail(const VECTOR2I& aEnd)
} }
} }
if(reduce_index >= 0) if( reduce_index >= 0 )
{ {
TRACE( 0, "Placer: reducing tail: %d", reduce_index );
TRACE(0, "Placer: reducing tail: %d", reduce_index); SHAPE_LINE_CHAIN reducedLine = new_direction.BuildInitialTrace( new_start, aEnd );
SHAPE_LINE_CHAIN reducedLine = new_direction.BuildInitialTrace(new_start, aEnd);
m_p_start = new_start; m_p_start = new_start;
m_direction = new_direction; m_direction = new_direction;
tail.Remove(reduce_index+1, -1); tail.Remove( reduce_index + 1, -1 );
head.Clear(); head.Clear();
return true; return true;
} }
...@@ -283,32 +275,23 @@ bool PNS_LINE_PLACER::reduceTail(const VECTOR2I& aEnd) ...@@ -283,32 +275,23 @@ bool PNS_LINE_PLACER::reduceTail(const VECTOR2I& aEnd)
} }
/** bool PNS_LINE_PLACER::checkObtusity( const SEG& a, const SEG& b ) const
* 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
{ {
const DIRECTION_45 dir_a(a); const DIRECTION_45 dir_a( a );
const DIRECTION_45 dir_b(b); const DIRECTION_45 dir_b( b );
return dir_a.IsObtuse(dir_b) || dir_a == dir_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() bool PNS_LINE_PLACER::mergeHead()
{ {
SHAPE_LINE_CHAIN& head = m_head.GetLine(); SHAPE_LINE_CHAIN& head = m_head.GetLine();
SHAPE_LINE_CHAIN& tail = m_tail.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(); head.Simplify();
tail.Simplify(); tail.Simplify();
...@@ -318,50 +301,49 @@ bool PNS_LINE_PLACER::mergeHead() ...@@ -318,50 +301,49 @@ bool PNS_LINE_PLACER::mergeHead()
if( n_head < 3 ) if( n_head < 3 )
{ {
TRACEn(4, "Merge failed: not enough head segs."); TRACEn( 4, "Merge failed: not enough head segs." );
return false; return false;
} }
if (n_tail && head.CPoint(0) != tail.CPoint(-1)) if( n_tail && head.CPoint( 0 ) != tail.CPoint( -1 ) )
{ {
TRACEn(4, "Merge failed: head and tail discontinuous."); TRACEn( 4, "Merge failed: head and tail discontinuous." );
return false; return false;
} }
if( m_head.CountCorners(ForbiddenAngles) != 0 ) if( m_head.CountCorners( ForbiddenAngles ) != 0 )
return false; 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) if( n_tail )
{ {
dir_tail = DIRECTION_45(tail.CSegment(-1)); dir_tail = DIRECTION_45( tail.CSegment( -1 ) );
if(dir_head.Angle(dir_tail) & ForbiddenAngles)
if( dir_head.Angle( dir_tail ) & ForbiddenAngles )
return false; return false;
} }
if(!n_tail) if( !n_tail )
tail.Append(head.CSegment(0).a); tail.Append( head.CSegment( 0 ).a );
for (int i = 0; i < n_head - 2; i++) for( int i = 0; i < n_head - 2; i++ )
{ {
tail.Append(head.CSegment(i).b); tail.Append( head.CSegment( i ).b );
} }
tail.Simplify(); tail.Simplify();
SEG last = tail.CSegment(-1); SEG last = tail.CSegment( -1 );
m_p_start = last.b; m_p_start = last.b;
m_direction = DIRECTION_45(last).Right(); m_direction = DIRECTION_45( last ).Right();
head.Remove(0, n_head - 2);
TRACE(0, "Placer: merge %d, new direction: %s", n_head % m_direction.Format().c_str()); head.Remove( 0, n_head - 2 );
TRACE( 0, "Placer: merge %d, new direction: %s", n_head % m_direction.Format().c_str() );
head.Simplify(); head.Simplify();
tail.Simplify(); tail.Simplify();
...@@ -369,185 +351,177 @@ bool PNS_LINE_PLACER::mergeHead() ...@@ -369,185 +351,177 @@ bool PNS_LINE_PLACER::mergeHead()
return true; return true;
} }
bool PNS_LINE_PLACER::handleViaPlacement ( PNS_LINE& aHead )
bool PNS_LINE_PLACER::handleViaPlacement( PNS_LINE& aHead )
{ {
if(!m_placingVia) if( !m_placingVia )
return true; return true;
PNS_LAYERSET allLayers (0, 15); PNS_LAYERSET allLayers( 0, 15 );
PNS_VIA v (aHead.GetCLine().CPoint(-1), allLayers, m_viaDiameter, aHead.GetNet()); PNS_VIA v( aHead.GetCLine().CPoint( -1 ), allLayers, m_viaDiameter, aHead.GetNet() );
v.SetDrill(m_viaDrill); v.SetDrill( m_viaDrill );
VECTOR2I force; VECTOR2I force;
VECTOR2I lead = aHead.GetCLine().CPoint(-1) - aHead.GetCLine().CPoint(0); VECTOR2I lead = aHead.GetCLine().CPoint( -1 ) - aHead.GetCLine().CPoint( 0 );
if( v.PushoutForce ( m_shove->GetCurrentNode(), lead, force, true, 20 ) ) 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); SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace(
aHead = PNS_LINE(aHead, line); aHead.GetCLine().CPoint( 0 ),
aHead.GetCLine().CPoint( -1 ) + force );
aHead = PNS_LINE( aHead, line );
v.SetPos(v.GetPos() + force); v.SetPos( v.GetPos() + force );
return true; return true;
} }
return false; return false;
} }
/**
* Function routeHead() bool PNS_LINE_PLACER::routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead,
* bool aCwWalkaround )
* 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)
{ {
// STAGE 1: route a simple two-segment trace between m_p_start and 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); SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( m_p_start, aP );
PNS_LINE initTrack (m_head, line); PNS_LINE initTrack( m_head, line );
PNS_LINE walkFull, walkSolids; PNS_LINE walkFull, walkSolids;
if( m_mode == RM_Ignore )
if(m_mode == RM_Ignore)
{ {
aNewHead = initTrack; aNewHead = initTrack;
return true; return true;
} }
handleViaPlacement(initTrack);
handleViaPlacement( initTrack );
m_currentNode = m_shove->GetCurrentNode(); m_currentNode = m_shove->GetCurrentNode();
PNS_OPTIMIZER optimizer(m_currentNode); PNS_OPTIMIZER optimizer( m_currentNode );
PNS_WALKAROUND walkaround( m_currentNode ); PNS_WALKAROUND walkaround( m_currentNode );
walkaround.SetSolidsOnly(false); walkaround.SetSolidsOnly( false );
walkaround.SetIterationLimit(m_mode == RM_Walkaround ? 8 : 5 ); walkaround.SetIterationLimit( m_mode == RM_Walkaround ? 8 : 5 );
//walkaround.SetApproachCursor(true, aP); // walkaround.SetApproachCursor(true, aP);
PNS_WALKAROUND::WalkaroundStatus wf = walkaround.Route(initTrack, walkFull); PNS_WALKAROUND::WalkaroundStatus wf = walkaround.Route( initTrack, walkFull );
#if 0 #if 0
if(m_mode == RM_Walkaround) if( m_mode == RM_Walkaround )
{ {
// walkaround. // walkaround.
// PNSDisplayDebugLine (walkFull.GetCLine(), 4); // PNSDisplayDebugLine (walkFull.GetCLine(), 4);
if(wf == PNS_WALKAROUND::STUCK) if( wf == PNS_WALKAROUND::STUCK )
{ {
aNewHead = m_head; aNewHead = m_head;
aNewHead.SetShape(walkFull.GetCLine()); aNewHead.SetShape( walkFull.GetCLine() );
aNewHead = aNewHead.ClipToNearestObstacle(m_currentNode); aNewHead = aNewHead.ClipToNearestObstacle( m_currentNode );
return false; return false;
} }
aNewHead = m_head; aNewHead = m_head;
aNewHead.SetShape(walkFull.GetCLine()); aNewHead.SetShape( walkFull.GetCLine() );
// printf("nh w %d l %d\n", aNewHead.GetWidth(), aNewHead.GetLayers().Start()); // printf("nh w %d l %d\n", aNewHead.GetWidth(), aNewHead.GetLayers().Start());
return true; return true;
} }
#endif #endif
PNS_COST_ESTIMATOR cost_walk, cost_orig; PNS_COST_ESTIMATOR cost_walk, cost_orig;
walkaround.SetApproachCursor ( false, aP ); walkaround.SetApproachCursor( false, aP );
walkaround.SetSolidsOnly(true); walkaround.SetSolidsOnly( true );
walkaround.SetIterationLimit( 10 ); walkaround.SetIterationLimit( 10 );
PNS_WALKAROUND::WalkaroundStatus stat_solids = walkaround.Route(initTrack, walkSolids); PNS_WALKAROUND::WalkaroundStatus stat_solids = walkaround.Route( initTrack, walkSolids );
optimizer.SetEffortLevel ( PNS_OPTIMIZER::MERGE_SEGMENTS ); optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_SEGMENTS );
optimizer.SetCollisionMask (PNS_ITEM::SOLID); optimizer.SetCollisionMask( PNS_ITEM::SOLID );
optimizer.Optimize(&walkSolids); optimizer.Optimize( &walkSolids );
#if 0 #if 0
optimizer.SetCollisionMask (-1); optimizer.SetCollisionMask( -1 );
optimizer.Optimize(&walkFull); optimizer.Optimize( &walkFull );
#endif #endif
cost_orig.Add(initTrack); cost_orig.Add( initTrack );
cost_walk.Add(walkFull); cost_walk.Add( walkFull );
if(m_mode == RM_Smart || m_mode == RM_Shove) if( m_mode == RM_Smart || m_mode == RM_Shove )
{ {
PNS_LINE l2; PNS_LINE l2;
bool walk_better = cost_orig.IsBetter(cost_walk, 1.5, 10.0); bool walk_better = cost_orig.IsBetter( cost_walk, 1.5, 10.0 );
walk_better = false; walk_better = false;
#if 0 #if 0
printf("RtTrk width %d %d %d", initTrack.GetWidth(), walkFull.GetWidth(), walkSolids.GetWidth()); printf( "RtTrk width %d %d %d", initTrack.GetWidth(),
printf("init-coll %d\n", m_currentNode->CheckColliding(&initTrack)? 1: 0); walkFull.GetWidth(), walkSolids.GetWidth() );
printf("total cost: walk cor %.0f len %.0f orig cor %.0f len %.0f walk-better %d\n", 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_walk.GetCornerCost(), cost_walk.GetLengthCost(),
cost_orig.GetCornerCost(), cost_orig.GetLengthCost(), cost_orig.GetCornerCost(), cost_orig.GetLengthCost(),
walk_better ); walk_better );
#endif #endif
if(m_mode == RM_Smart && wf == PNS_WALKAROUND::DONE && walk_better && walkFull.GetCLine().CPoint(-1) == initTrack.GetCLine().CPoint(-1)) if( m_mode == RM_Smart && wf == PNS_WALKAROUND::DONE && walk_better
&& walkFull.GetCLine().CPoint( -1 ) == initTrack.GetCLine().CPoint( -1 ) )
l2 = walkFull; l2 = walkFull;
else if (stat_solids == PNS_WALKAROUND::DONE) else if( stat_solids == PNS_WALKAROUND::DONE )
l2 = walkSolids; l2 = walkSolids;
else else
l2 = initTrack.ClipToNearestObstacle(m_shove->GetCurrentNode()); l2 = initTrack.ClipToNearestObstacle( m_shove->GetCurrentNode() );
PNS_LINE l ( m_tail ); PNS_LINE l( m_tail );
l.GetLine().Append( l2.GetCLine() ); l.GetLine().Append( l2.GetCLine() );
l.GetLine().Simplify(); l.GetLine().Simplify();
if(m_placingVia) if( m_placingVia )
{ {
PNS_LAYERSET allLayers(0,15); PNS_LAYERSET allLayers( 0, 15 );
PNS_VIA v1( l.GetCLine().CPoint(-1), allLayers, m_viaDiameter ); PNS_VIA v1( l.GetCLine().CPoint( -1 ), allLayers, m_viaDiameter );
PNS_VIA v2( l2.GetCLine().CPoint(-1), allLayers, m_viaDiameter ); PNS_VIA v2( l2.GetCLine().CPoint( -1 ), allLayers, m_viaDiameter );
v1.SetDrill(m_viaDrill); v1.SetDrill( m_viaDrill );
v2.SetDrill(m_viaDrill); v2.SetDrill( m_viaDrill );
l.AppendVia ( v1 ); l.AppendVia( v1 );
l2.AppendVia ( v2 ); l2.AppendVia( v2 );
} }
PNS_SHOVE::ShoveStatus status = m_shove->ShoveLines(&l); PNS_SHOVE::ShoveStatus status = m_shove->ShoveLines( &l );
m_currentNode = m_shove->GetCurrentNode(); m_currentNode = m_shove->GetCurrentNode();
if (status == PNS_SHOVE::SH_OK) if( status == PNS_SHOVE::SH_OK )
{ {
optimizer.SetWorld( m_currentNode );
optimizer.SetWorld (m_currentNode);
optimizer.ClearCache(); optimizer.ClearCache();
optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_OBTUSE | PNS_OPTIMIZER::SMART_PADS ); optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_OBTUSE | PNS_OPTIMIZER::SMART_PADS );
optimizer.SetCollisionMask (-1); optimizer.SetCollisionMask( -1 );
optimizer.Optimize(&l2); optimizer.Optimize( &l2 );
aNewHead = l2; aNewHead = l2;
return true; return true;
} else { }
else
{
walkaround.SetWorld( m_currentNode ); walkaround.SetWorld( m_currentNode );
walkaround.SetSolidsOnly(false); walkaround.SetSolidsOnly( false );
walkaround.SetIterationLimit( 10 ); walkaround.SetIterationLimit( 10 );
walkaround.SetApproachCursor ( true, aP ); walkaround.SetApproachCursor( true, aP );
walkaround.Route(initTrack, l2); walkaround.Route( initTrack, l2 );
aNewHead = l2.ClipToNearestObstacle (m_shove->GetCurrentNode()); aNewHead = l2.ClipToNearestObstacle( m_shove->GetCurrentNode() );
//aNewHead = l2; // aNewHead = l2;
return false; return false;
} }
} }
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() bool PNS_LINE_PLACER::optimizeTailHeadTransition()
{ {
SHAPE_LINE_CHAIN& head = m_head.GetLine(); SHAPE_LINE_CHAIN& head = m_head.GetLine();
...@@ -555,37 +529,37 @@ bool PNS_LINE_PLACER::optimizeTailHeadTransition() ...@@ -555,37 +529,37 @@ bool PNS_LINE_PLACER::optimizeTailHeadTransition()
const int TailLookbackSegments = 5; const int TailLookbackSegments = 5;
int threshold = min(tail.PointCount(), TailLookbackSegments + 1); int threshold = min( tail.PointCount(), TailLookbackSegments + 1 );
if(tail.SegmentCount() < 3) if( tail.SegmentCount() < 3 )
return false; return false;
// assemble TailLookbackSegments tail segments with the current head // assemble TailLookbackSegments tail segments with the current head
SHAPE_LINE_CHAIN opt_line = tail.Slice(-threshold, -1); SHAPE_LINE_CHAIN opt_line = tail.Slice( -threshold, -1 );
opt_line.Append(head); opt_line.Append( head );
// opt_line.Simplify(); // opt_line.Simplify();
PNS_LINE new_head(m_tail, opt_line); PNS_LINE new_head( m_tail, opt_line );
// and see if it could be made simpler by merging obtuse/collnear segments. If so, // and see if it could be made simpler by merging obtuse/collnear segments.
// replace the (threshold) last tail points and the head with the optimized line // If so, replace the (threshold) last tail points and the head with
// the optimized line
//if(PNS_OPTIMIZER::Optimize(&new_head, PNS_OPTIMIZER::MERGE_SEGMENTS)) // if(PNS_OPTIMIZER::Optimize(&new_head, PNS_OPTIMIZER::MERGE_SEGMENTS))
if( new_head.MergeSegments() )
if(new_head.MergeSegments())
{ {
PNS_LINE tmp(m_tail, opt_line); PNS_LINE tmp( m_tail, opt_line );
TRACE(0, "Placer: optimize tail-head [%d]", threshold); TRACE( 0, "Placer: optimize tail-head [%d]", threshold );
head.Clear(); head.Clear();
tail.Replace(-threshold, -1, new_head.GetCLine()); tail.Replace( -threshold, -1, new_head.GetCLine() );
tail.Simplify(); tail.Simplify();
m_p_start = new_head.GetCLine().CPoint(-1); m_p_start = new_head.GetCLine().CPoint( -1 );
m_direction = DIRECTION_45(new_head.GetCLine().CSegment(-1)); m_direction = DIRECTION_45( new_head.GetCLine().CSegment( -1 ) );
return true; return true;
} }
...@@ -593,16 +567,8 @@ bool PNS_LINE_PLACER::optimizeTailHeadTransition() ...@@ -593,16 +567,8 @@ bool PNS_LINE_PLACER::optimizeTailHeadTransition()
return false; 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 fail = false;
bool go_back = false; bool go_back = false;
...@@ -613,77 +579,70 @@ void PNS_LINE_PLACER::routeStep(const VECTOR2I& aP) ...@@ -613,77 +579,70 @@ void PNS_LINE_PLACER::routeStep(const VECTOR2I& aP)
m_follow_mouse = true; m_follow_mouse = true;
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()); 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() );
for(i = 0; i < n_iter; i++) for( i = 0; i < n_iter; i++ )
{ {
if( !go_back && m_follow_mouse )
if(!go_back && m_follow_mouse) reduceTail( aP );
reduceTail(aP);
go_back = false; go_back = false;
if(!routeHead(aP, new_head, true)) if( !routeHead( aP, new_head, true ) )
fail = true; fail = true;
if(!new_head.Is45Degree()) if( !new_head.Is45Degree() )
fail = true; fail = true;
if(!m_follow_mouse) if( !m_follow_mouse )
return; return;
m_head = new_head; m_head = new_head;
if(handleSelfIntersections()) if( handleSelfIntersections() )
{ {
n_iter++; n_iter++;
go_back = true; go_back = true;
} }
if(!go_back && handlePullback()) if( !go_back && handlePullback() )
{ {
n_iter++; n_iter++;
go_back = true; go_back = true;
} }
} }
if(!fail) if( !fail )
{ {
if(optimizeTailHeadTransition()) if( optimizeTailHeadTransition() )
return; return;
mergeHead(); mergeHead();
} }
} }
/**
* Function Route() bool PNS_LINE_PLACER::Route( const VECTOR2I& aP )
*
* 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)
{ {
if(m_smooth_mouse) if( m_smooth_mouse )
{ {
VECTOR2I p_cur = m_p_start; VECTOR2I p_cur = m_p_start;
VECTOR2I step = (aP - m_p_start).Resize(m_smoothing_step); VECTOR2I step = (aP - m_p_start).Resize( m_smoothing_step );
do do
{ {
if ((p_cur - aP).EuclideanNorm() <= m_smoothing_step) if( (p_cur - aP).EuclideanNorm() <= m_smoothing_step )
p_cur = aP; p_cur = aP;
else else
p_cur += step; p_cur += step;
routeStep(p_cur); routeStep( p_cur );
} while( p_cur != aP );
} while (p_cur != aP); }
} else else
routeStep(aP); routeStep( aP );
return CurrentEnd() == aP; return CurrentEnd() == aP;
} }
...@@ -691,25 +650,31 @@ bool PNS_LINE_PLACER::Route(const VECTOR2I& aP) ...@@ -691,25 +650,31 @@ bool PNS_LINE_PLACER::Route(const VECTOR2I& aP)
const PNS_LINE PNS_LINE_PLACER::GetTrace() const const PNS_LINE PNS_LINE_PLACER::GetTrace() const
{ {
PNS_LINE tmp(m_head); PNS_LINE tmp( m_head );
tmp.SetShape( m_tail.GetCLine() ); tmp.SetShape( m_tail.GetCLine() );
tmp.GetLine().Append( m_head.GetCLine() ); tmp.GetLine().Append( m_head.GetCLine() );
tmp.GetLine().Simplify(); tmp.GetLine().Simplify();
return tmp; return tmp;
} }
void PNS_LINE_PLACER::FlipPosture() void PNS_LINE_PLACER::FlipPosture()
{ {
m_initial_direction = m_initial_direction.Right(); m_initial_direction = m_initial_direction.Right();
m_direction = m_direction.Right(); m_direction = m_direction.Right();
} }
void PNS_LINE_PLACER::GetUpdatedItems( PNS_NODE::ItemVector& aRemoved, PNS_NODE::ItemVector& aAdded)
void PNS_LINE_PLACER::GetUpdatedItems( PNS_NODE::ItemVector& aRemoved,
PNS_NODE::ItemVector& aAdded )
{ {
return m_shove->GetCurrentNode()->GetUpdatedItems(aRemoved, aAdded); return m_shove->GetCurrentNode()->GetUpdatedItems( aRemoved, aAdded );
} }
PNS_NODE *PNS_LINE_PLACER::GetCurrentNode() const
PNS_NODE* PNS_LINE_PLACER::GetCurrentNode() const
{ {
return m_shove->GetCurrentNode(); return m_shove->GetCurrentNode();
} }
...@@ -39,17 +39,18 @@ class PNS_ROUTER_BASE; ...@@ -39,17 +39,18 @@ class PNS_ROUTER_BASE;
/** /**
* Class PNS_LINE_PLACER * 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 class PNS_LINE_PLACER
{ {
public: public:
PNS_LINE_PLACER( PNS_NODE *aWorld ); PNS_LINE_PLACER( PNS_NODE* aWorld );
~PNS_LINE_PLACER(); ~PNS_LINE_PLACER();
///> Appends a via at the end of currently placed line. ///> Appends a via at the end of currently placed line.
void AddVia ( bool aEnabled, int aDiameter, int aDrill ) void AddVia( bool aEnabled, int aDiameter, int aDrill )
{ {
m_viaDiameter = aDiameter; m_viaDiameter = aDiameter;
m_viaDrill = aDrill; m_viaDrill = aDrill;
...@@ -57,100 +58,198 @@ class PNS_LINE_PLACER ...@@ -57,100 +58,198 @@ class PNS_LINE_PLACER
} }
///> Starts placement of a line at point aStart. ///> Starts placement of a line at point aStart.
void StartPlacement(const VECTOR2I& aStart, int aNet, int aWidth, int aLayer); 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); * 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 );
///> Sets initial routing direction/posture ///> Sets initial routing direction/posture
void SetInitialDirection(const DIRECTION_45& aDirection); void SetInitialDirection( const DIRECTION_45& aDirection );
void ApplySettings ( const PNS_ROUTING_SETTINGS& aSettings ); 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 ///> 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; } 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) ///> 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; } const PNS_LINE& GetTail() const { return m_tail; }
///> Returns the whole routed line ///> Returns the whole routed line
const PNS_LINE GetTrace() const; const PNS_LINE GetTrace() const;
///> Returns the current end of the line being placed. It may not be equal to the cursor position due to collisions. ///> 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 const VECTOR2I& CurrentEnd() const
{ {
if(m_head.GetCLine().PointCount() > 0) if( m_head.GetCLine().PointCount() > 0 )
return m_head.GetCLine().CPoint(-1); return m_head.GetCLine().CPoint( -1 );
else if(m_tail.GetCLine().PointCount() > 0) else if( m_tail.GetCLine().PointCount() > 0 )
return m_tail.GetCLine().CPoint(-1); return m_tail.GetCLine().CPoint( -1 );
else else
return m_p_start; return m_p_start;
} }
///> Returns all items in the world that have been affected by the routing
///> Returns all items in the world that have been affected by the routing operation. Used ///> operation. Used to update data structures of the host application
/// to update data structures of the host application void GetUpdatedItems( PNS_NODE::ItemVector& aRemoved,
void GetUpdatedItems( PNS_NODE::ItemVector& aRemoved, PNS_NODE::ItemVector& aAdded); PNS_NODE::ItemVector& aAdded );
///> Toggles the current posture (straight/diagonal) of the trace head. ///> Toggles the current posture (straight/diagonal) of the trace head.
void FlipPosture(); void FlipPosture();
///> Returns the most recent world state ///> Returns the most recent world state
PNS_NODE *GetCurrentNode() const; PNS_NODE* GetCurrentNode() const;
private:
private:
static const double m_shoveLengthThreshold = 1.7; static const double m_shoveLengthThreshold = 1.7;
bool handleViaPlacement ( PNS_LINE& aHead ); 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;
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(); 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(); 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(); bool mergeHead();
bool reduceTail(const VECTOR2I& aEnd);
/**
* 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(); 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(); bool optimizeTailHeadTransition();
bool routeHead(const VECTOR2I& aP, PNS_LINE& aNewHead, bool aCwWalkaround = true); /**
void routeStep(const VECTOR2I& aP); * 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.) ///> routing mode (walkaround, shove, etc.)
PNS_MODE m_mode; PNS_MODE m_mode;
///> follow mouse trail by attaching new segments to the head as the cursor moves
///> follow mouse trail by attaching new segments to the head
///> as the cursor moves
bool m_follow_mouse; bool m_follow_mouse;
///> mouse smoothing active ///> mouse smoothing active
bool m_smooth_mouse; bool m_smooth_mouse;
///> mouse smoothing step (in world units) ///> mouse smoothing step (in world units)
int m_smoothing_step; int m_smoothing_step;
///> current routing direction ///> current routing direction
DIRECTION_45 m_direction; DIRECTION_45 m_direction;
///> routing direction for new traces ///> routing direction for new traces
DIRECTION_45 m_initial_direction; DIRECTION_45 m_initial_direction;
///> routing "head": volatile part of the track from the previously ///> routing "head": volatile part of the track from the previously
/// analyzed point to the current routing destination /// analyzed point to the current routing destination
PNS_LINE m_head; PNS_LINE m_head;
///> routing "tail": part of the track that has been already fixed due to collisions with obstacles ///> routing "tail": part of the track that has been already fixed due to collisions with obstacles
PNS_LINE m_tail; PNS_LINE m_tail;
///> current algorithm iteration ///> current algorithm iteration
int m_iteration; int m_iteration;
///> pointer to world to search colliding items ///> pointer to world to search colliding items
PNS_NODE *m_world; PNS_NODE* m_world;
///> current routing start point (end of tail, beginning of head) ///> current routing start point (end of tail, beginning of head)
VECTOR2I m_p_start; VECTOR2I m_p_start;
///> The shove engine ///> The shove engine
PNS_SHOVE *m_shove; PNS_SHOVE* m_shove;
///> Current world state ///> Current world state
PNS_NODE *m_currentNode; PNS_NODE* m_currentNode;
///> Are we placing a via? ///> Are we placing a via?
bool m_placingVia; bool m_placingVia;
///> current via diameter ///> current via diameter
int m_viaDiameter; int m_viaDiameter;
///> current via drill ///> current via drill
int m_viaDrill; int m_viaDrill;
///> walkaround algorithm iteration limit ///> walkaround algorithm iteration limit
int m_walkaroundIterationLimit; int m_walkaroundIterationLimit;
///> smart pads optimizer enabled. ///> smart pads optimizer enabled.
bool m_smartPads; bool m_smartPads;
}; };
#endif // __PNS_LINE_PLACER_H #endif // __PNS_LINE_PLACER_H
...@@ -42,36 +42,38 @@ using namespace std; ...@@ -42,36 +42,38 @@ using namespace std;
using boost::unordered_set; using boost::unordered_set;
using boost::unordered_map; using boost::unordered_map;
static boost::unordered_set<PNS_NODE *> allocNodes; static boost::unordered_set<PNS_NODE*> allocNodes;
PNS_NODE::PNS_NODE() PNS_NODE::PNS_NODE()
{ {
//printf("MakeNode [%p, total = %d]\n", this, allocNodes.size()); // printf("MakeNode [%p, total = %d]\n", this, allocNodes.size());
m_root = this; m_root = this;
m_parent = NULL; m_parent = NULL;
m_maxClearance = 800000; // fixme: depends on how thick traces are. m_maxClearance = 800000; // fixme: depends on how thick traces are.
m_index = new PNS_INDEX; m_index = new PNS_INDEX;
allocNodes.insert(this); allocNodes.insert( this );
} }
PNS_NODE::~PNS_NODE() PNS_NODE::~PNS_NODE()
{ {
if(!m_children.empty()) if( !m_children.empty() )
{ {
TRACEn(0, "attempting to free a node that has kids.\n"); TRACEn( 0, "attempting to free a node that has kids.\n" );
assert(false); assert( false );
} }
if(allocNodes.find(this) == allocNodes.end()) if( allocNodes.find( this ) == allocNodes.end() )
{ {
TRACEn(0, "attempting to free an already-free'd node.\n"); TRACEn( 0, "attempting to free an already-free'd node.\n" );
assert(false); assert( false );
} }
allocNodes.erase(this); allocNodes.erase( this );
for(PNS_INDEX::ItemSet::iterator i = m_index->begin(); i != m_index->end(); ++i) for( PNS_INDEX::ItemSet::iterator i = m_index->begin();
if( (*i) ->BelongsTo(this)) i != m_index->end(); ++i )
if( (*i)->BelongsTo( this ) )
delete *i; delete *i;
unlinkParent(); unlinkParent();
...@@ -79,174 +81,196 @@ PNS_NODE::~PNS_NODE() ...@@ -79,174 +81,196 @@ PNS_NODE::~PNS_NODE()
} }
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) ) if( a->OfKind( PNS_ITEM::SEGMENT ) )
clearance += static_cast<const PNS_SEGMENT *>(a) -> GetWidth() / 2; clearance += static_cast<const PNS_SEGMENT*>(a)->GetWidth() / 2;
if( a->OfKind (PNS_ITEM::LINE) ) if( a->OfKind( PNS_ITEM::LINE ) )
clearance += static_cast<const PNS_LINE *>(a) -> GetWidth() / 2; clearance += static_cast<const PNS_LINE*>(a)->GetWidth() / 2;
if( b->OfKind (PNS_ITEM::SEGMENT) ) if( b->OfKind( PNS_ITEM::SEGMENT ) )
clearance += static_cast<const PNS_SEGMENT *>(b) -> GetWidth() / 2; clearance += static_cast<const PNS_SEGMENT*>(b)->GetWidth() / 2;
if( b->OfKind (PNS_ITEM::LINE) ) if( b->OfKind( PNS_ITEM::LINE ) )
clearance += static_cast<const PNS_LINE *>(b) -> GetWidth() / 2; clearance += static_cast<const PNS_LINE*>(b)->GetWidth() / 2;
return clearance; return clearance;
} }
PNS_NODE* PNS_NODE::Branch() PNS_NODE* PNS_NODE::Branch()
{ {
PNS_NODE *child = new PNS_NODE; PNS_NODE* child = new PNS_NODE;
m_children.push_back(child);
m_children.push_back( child );
child->m_parent = this; child->m_parent = this;
child->m_clearanceFunctor = m_clearanceFunctor; child->m_clearanceFunctor = m_clearanceFunctor;
child->m_root = isRoot() ? this : m_root; child->m_root = isRoot() ? this : m_root;
// immmediate offspring of the root branch needs not copy anything. For the rest, // immmediate offspring of the root branch needs not copy anything.
// deep-copy joints, overridden item map and pointers to stored items. // For the rest, deep-copy joints, overridden item map and pointers
if(!isRoot()) // to stored items.
if( !isRoot() )
{ {
JointMap::iterator j; JointMap::iterator j;
for(PNS_INDEX::ItemSet::iterator i = m_index->begin(); i != m_index->end(); ++i) for( PNS_INDEX::ItemSet::iterator i = m_index->begin();
child->m_index->Add(*i); i != m_index->end(); ++i )
child->m_index->Add( *i );
child->m_joints = m_joints; child->m_joints = m_joints;
child->m_override = m_override; 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()); TRACE( 2, "%d items, %d joints, %d overrides",
child->m_index->Size() % child->m_joints.size() % child->m_override.size() );
return child; return child;
} }
void PNS_NODE::unlinkParent ( )
void PNS_NODE::unlinkParent()
{ {
if( isRoot() ) if( isRoot() )
return; return;
for( vector<PNS_NODE *>::iterator i = m_parent->m_children.begin(); i != m_parent->m_children.end(); ++i) for( vector<PNS_NODE*>::iterator i = m_parent->m_children.begin();
i != m_parent->m_children.end(); ++i )
{ {
if (*i == this) if( *i == this )
{ {
m_parent->m_children.erase(i); m_parent->m_children.erase( i );
return; return;
} }
} }
} }
// function object that visits potential obstacles and performs the actual collision refining // function object that visits potential obstacles and performs
struct PNS_NODE::obstacleVisitor { // the actual collision refining
///> node we are searching in (either root or a branch) struct PNS_NODE::obstacleVisitor
PNS_NODE *m_node; {
///> node that overrides root entries ///> node we are searching in (either root or a branch)
PNS_NODE *m_override; PNS_NODE* m_node;
///> list of encountered obstacles
///> node that overrides root entries
PNS_NODE* m_override;
///> list of encountered obstacles
Obstacles& m_tab; Obstacles& m_tab;
///> the item we are looking for collisions with
///> the item we are looking for collisions with
const PNS_ITEM* m_item; const PNS_ITEM* m_item;
///> acccepted kinds of colliding items (solids, vias, segments, etc...)
///> acccepted kinds of colliding items (solids, vias, segments, etc...)
int m_kindMask; int m_kindMask;
///> max number of hits
///> max number of hits
int m_limitCount; int m_limitCount;
///> number of items found so far
///> number of items found so far
int m_matchCount; int m_matchCount;
obstacleVisitor( PNS_NODE::Obstacles& aTab, obstacleVisitor( PNS_NODE::Obstacles& aTab, const PNS_ITEM* aItem,
const PNS_ITEM* aItem, int aKindMask ) :
int aKindMask ) m_tab( aTab ),
: m_tab(aTab), m_item( aItem ),
m_item(aItem), m_kindMask( aKindMask ),
m_kindMask(aKindMask), m_limitCount( -1 ),
m_limitCount(-1), m_matchCount( 0 )
m_matchCount(0) {};
{ };
void SetCountLimit(int aLimit) void SetCountLimit( int aLimit )
{ {
m_limitCount = aLimit; m_limitCount = aLimit;
} }
void SetWorld(PNS_NODE *aNode, PNS_NODE *aOverride = NULL) void SetWorld( PNS_NODE* aNode, PNS_NODE* aOverride = NULL )
{ {
m_node = aNode; m_node = aNode;
m_override = aOverride; m_override = aOverride;
} }
bool operator()( PNS_ITEM *aItem ) bool operator()( PNS_ITEM* aItem )
{ {
if( !aItem->OfKind(m_kindMask)) if( !aItem->OfKind( m_kindMask ) )
return true; 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) ) // 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; return true;
int clearance = m_node->GetClearance(aItem, m_item); int clearance = m_node->GetClearance( aItem, m_item );
if(!aItem->Collide(m_item, clearance))
if( !aItem->Collide( m_item, clearance ) )
return true; return true;
PNS_OBSTACLE obs; PNS_OBSTACLE obs;
obs.item = aItem; obs.item = aItem;
m_tab.push_back(obs); m_tab.push_back( obs );
m_matchCount ++; m_matchCount++;
if(m_limitCount > 0 && m_matchCount >= m_limitCount) if( m_limitCount > 0 && m_matchCount >= m_limitCount )
return false; return false;
return true; return true;
}; };
}; };
int PNS_NODE::QueryColliding( const PNS_ITEM* aItem, PNS_NODE::Obstacles& aObstacles, int aKindMask, int aLimitCount)
int PNS_NODE::QueryColliding( const PNS_ITEM* aItem,
PNS_NODE::Obstacles& aObstacles, int aKindMask, int aLimitCount )
{ {
obstacleVisitor visitor ( aObstacles, aItem, aKindMask ); obstacleVisitor visitor( aObstacles, aItem, aKindMask );
assert(allocNodes.find(this) != allocNodes.end()); assert( allocNodes.find( this ) != allocNodes.end() );
visitor.SetCountLimit(aLimitCount); visitor.SetCountLimit( aLimitCount );
visitor.SetWorld( this, NULL ); visitor.SetWorld( this, NULL );
// first, look for colliding items ourselves // first, look for colliding items ourselves
m_index->Query(aItem, m_maxClearance, visitor); m_index->Query( aItem, m_maxClearance, visitor );
// if we haven't found enough items, look in the root branch as well. // if we haven't found enough items, look in the root branch as well.
if(!isRoot() && ( visitor.m_matchCount < aLimitCount || aLimitCount < 0) ) if( !isRoot() && ( visitor.m_matchCount < aLimitCount || aLimitCount < 0) )
{ {
visitor.SetWorld ( m_root, this ); visitor.SetWorld( m_root, this );
m_root->m_index->Query(aItem, m_maxClearance, visitor); m_root->m_index->Query( aItem, m_maxClearance, visitor );
} }
return aObstacles.size(); return aObstacles.size();
} }
PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKindMask)
PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE* aItem, int aKindMask )
{ {
Obstacles obs_list; Obstacles obs_list;
bool found_isects = false; bool found_isects = false;
const SHAPE_LINE_CHAIN &line = aItem->GetCLine(); const SHAPE_LINE_CHAIN& line = aItem->GetCLine();
obs_list.reserve(100); obs_list.reserve( 100 );
int n = 0; int n = 0;
for(int i = 0; i < line.SegmentCount(); i++)
for( int i = 0; i < line.SegmentCount(); i++ )
{ {
const PNS_SEGMENT s ( *aItem, line.CSegment(i)); const PNS_SEGMENT s( *aItem, line.CSegment( i ) );
n += QueryColliding ( &s, obs_list, aKindMask ); n += QueryColliding( &s, obs_list, aKindMask );
} }
if( aItem->EndsWithVia () ) if( aItem->EndsWithVia() )
n += QueryColliding ( &aItem->GetVia(), obs_list, aKindMask ); n += QueryColliding( &aItem->GetVia(), obs_list, aKindMask );
//if(! QueryColliding ( aItem, obs_list, aKindMask )) // if(! QueryColliding ( aItem, obs_list, aKindMask ))
if(!n) if( !n )
return OptObstacle(); return OptObstacle();
PNS_LINE& aLine = (PNS_LINE&) *aItem; PNS_LINE& aLine = (PNS_LINE&) *aItem;
...@@ -255,31 +279,31 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKin ...@@ -255,31 +279,31 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKin
nearest.item = NULL; nearest.item = NULL;
nearest.dist_first = INT_MAX; nearest.dist_first = INT_MAX;
BOOST_FOREACH(PNS_OBSTACLE obs, obs_list) BOOST_FOREACH( PNS_OBSTACLE obs, obs_list )
{ {
VECTOR2I ip_first, ip_last; VECTOR2I ip_first, ip_last;
int dist_max = INT_MIN; int dist_max = INT_MIN;
vector<SHAPE_LINE_CHAIN::Intersection> isect_list; vector<SHAPE_LINE_CHAIN::Intersection> isect_list;
int clearance = GetClearance(obs.item, &aLine); int clearance = GetClearance( obs.item, &aLine );
SHAPE_LINE_CHAIN hull = obs.item->Hull ( clearance ); SHAPE_LINE_CHAIN hull = obs.item->Hull( clearance );
if(aLine.EndsWithVia()) if( aLine.EndsWithVia() )
{ {
int clearance = GetClearance(obs.item, &aLine.GetVia()); int clearance = GetClearance( obs.item, &aLine.GetVia() );
SHAPE_LINE_CHAIN viaHull = aLine.GetVia().Hull (clearance); SHAPE_LINE_CHAIN viaHull = aLine.GetVia().Hull( clearance );
viaHull.Intersect(hull, isect_list); viaHull.Intersect( hull, isect_list );
BOOST_FOREACH(SHAPE_LINE_CHAIN::Intersection isect, isect_list) BOOST_FOREACH( SHAPE_LINE_CHAIN::Intersection isect, isect_list )
{ {
int dist = aLine.GetCLine().Length() +
( isect.p - aLine.GetVia().GetPos() ).EuclideanNorm();
int dist = aLine.GetCLine().Length() + (isect.p - aLine.GetVia().GetPos()).EuclideanNorm(); if( dist < nearest.dist_first )
if(dist < nearest.dist_first)
{ {
found_isects = true; found_isects = true;
nearest.dist_first = dist; nearest.dist_first = dist;
...@@ -288,7 +312,7 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKin ...@@ -288,7 +312,7 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKin
nearest.hull = hull; nearest.hull = hull;
} }
if(dist > dist_max) if( dist > dist_max )
{ {
dist_max = dist; dist_max = dist;
ip_last = isect.p; ip_last = isect.p;
...@@ -298,14 +322,13 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKin ...@@ -298,14 +322,13 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKin
isect_list.clear(); isect_list.clear();
hull.Intersect(aLine.GetCLine(), isect_list); hull.Intersect( aLine.GetCLine(), isect_list );
BOOST_FOREACH(SHAPE_LINE_CHAIN::Intersection isect, isect_list) BOOST_FOREACH( SHAPE_LINE_CHAIN::Intersection isect, isect_list )
{ {
int dist = aLine.GetCLine().PathLength( isect.p );
int dist = aLine.GetCLine().PathLength(isect.p); if( dist < nearest.dist_first )
if(dist < nearest.dist_first)
{ {
found_isects = true; found_isects = true;
nearest.dist_first = dist; nearest.dist_first = dist;
...@@ -314,12 +337,11 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKin ...@@ -314,12 +337,11 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKin
nearest.hull = hull; nearest.hull = hull;
} }
if(dist > dist_max) if( dist > dist_max )
{ {
dist_max = dist; dist_max = dist;
ip_last = isect.p; ip_last = isect.p;
} }
} }
nearest.ip_last = ip_last; nearest.ip_last = ip_last;
...@@ -329,244 +351,268 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKin ...@@ -329,244 +351,268 @@ PNS_NODE::OptObstacle PNS_NODE::NearestObstacle( const PNS_LINE *aItem, int aKin
return found_isects ? nearest : OptObstacle(); return found_isects ? nearest : OptObstacle();
} }
PNS_NODE::OptObstacle PNS_NODE::CheckColliding( const PNS_ITEM *aItemA, int aKindMask )
PNS_NODE::OptObstacle PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, int aKindMask )
{ {
Obstacles obs; Obstacles obs;
obs.reserve(100);
if(aItemA->GetKind() == PNS_ITEM::LINE) obs.reserve( 100 );
if( aItemA->GetKind() == PNS_ITEM::LINE )
{ {
int n = 0; int n = 0;
const PNS_LINE *line = static_cast<const PNS_LINE *>(aItemA); const PNS_LINE* line = static_cast<const PNS_LINE*>(aItemA);
const SHAPE_LINE_CHAIN &l = line->GetCLine(); const SHAPE_LINE_CHAIN& l = line->GetCLine();
for(int i = 0; i < l.SegmentCount(); i++) for( int i = 0; i < l.SegmentCount(); i++ )
{ {
const PNS_SEGMENT s ( *line, l.CSegment(i)); const PNS_SEGMENT s( *line, l.CSegment( i ) );
n += QueryColliding ( &s, obs, aKindMask, 1 ); n += QueryColliding( &s, obs, aKindMask, 1 );
if(n)
return OptObstacle(obs[0]); if( n )
return OptObstacle( obs[0] );
} }
if( line->EndsWithVia () ) if( line->EndsWithVia() )
{ {
n += QueryColliding ( &line->GetVia(), obs, aKindMask, 1 ); n += QueryColliding( &line->GetVia(), obs, aKindMask, 1 );
if(n)
return OptObstacle(obs[0]); if( n )
return OptObstacle( obs[0] );
}
} }
else if( QueryColliding( aItemA, obs, aKindMask, 1 ) > 0 )
return OptObstacle( obs[0] );
} else if (QueryColliding(aItemA, obs, aKindMask, 1) > 0)
return OptObstacle(obs[0]);
return OptObstacle(); return OptObstacle();
} }
bool PNS_NODE::CheckColliding( const PNS_ITEM *aItemA, const PNS_ITEM *aItemB, int aKindMask )
bool PNS_NODE::CheckColliding( const PNS_ITEM* aItemA, const PNS_ITEM* aItemB, int aKindMask )
{ {
Obstacles dummy; Obstacles dummy;
assert(aItemB); assert( aItemB );
// return QueryColliding(aItemA, dummy, aKindMask, 1) > 0; // return QueryColliding(aItemA, dummy, aKindMask, 1) > 0;
return aItemA->Collide(aItemB, GetClearance(aItemA, aItemB)); return aItemA->Collide( aItemB, GetClearance( aItemA, aItemB ) );
} }
struct hitVisitor {
struct hitVisitor
{
PNS_ITEMSET& m_items; PNS_ITEMSET& m_items;
const VECTOR2I& m_point; const VECTOR2I& m_point;
PNS_NODE *m_world; PNS_NODE* m_world;
hitVisitor( PNS_ITEMSET& aTab, hitVisitor( PNS_ITEMSET& aTab, const VECTOR2I& aPoint, PNS_NODE* aWorld ) :
const VECTOR2I& aPoint, m_items( aTab ), m_point( aPoint ), m_world( aWorld ) {};
PNS_NODE *aWorld )
: m_items(aTab), m_point(aPoint), m_world(aWorld) { };
bool operator()( PNS_ITEM *aItem ) { bool operator()( PNS_ITEM* aItem )
SHAPE_CIRCLE cp (m_point, 0); {
SHAPE_CIRCLE cp( m_point, 0 );
int cl = 0; int cl = 0;
if(aItem->GetKind() == PNS_ITEM::SEGMENT)
if( aItem->GetKind() == PNS_ITEM::SEGMENT )
cl += static_cast<PNS_SEGMENT*>(aItem)->GetWidth() / 2; cl += static_cast<PNS_SEGMENT*>(aItem)->GetWidth() / 2;
if(aItem->GetShape()->Collide(&cp, cl)) if( aItem->GetShape()->Collide( &cp, cl ) )
m_items.Add(aItem); m_items.Add( aItem );
return true; return true;
} }
}; };
const PNS_ITEMSET PNS_NODE::HitTest( const VECTOR2I& aPoint ) const PNS_ITEMSET PNS_NODE::HitTest( const VECTOR2I& aPoint )
{ {
PNS_ITEMSET items; PNS_ITEMSET items;
SHAPE_CIRCLE s (aPoint, 0); // fixme: we treat a point as an infinitely small circle - this is inefficient. // fixme: we treat a point as an infinitely small circle - this is inefficient.
hitVisitor visitor ( items, aPoint, this ); SHAPE_CIRCLE s( aPoint, 0 );
hitVisitor visitor( items, aPoint, this );
m_index->Query(&s, m_maxClearance, visitor); m_index->Query( &s, m_maxClearance, visitor );
if( ! isRoot() ) // fixme: could be made cleaner if( !isRoot() ) // fixme: could be made cleaner
{ {
PNS_ITEMSET items_root; PNS_ITEMSET items_root;
hitVisitor visitor_root ( items_root, aPoint, m_root ); hitVisitor visitor_root( items_root, aPoint, m_root );
m_root->m_index->Query( &s, m_maxClearance, visitor_root ); m_root->m_index->Query( &s, m_maxClearance, visitor_root );
BOOST_FOREACH(PNS_ITEM *item, items_root.Items()) BOOST_FOREACH( PNS_ITEM * item, items_root.Items() )
{ {
if (!overrides(item)) if( !overrides( item ) )
items.Add(item); items.Add( item );
} }
} }
return items; return items;
} }
void PNS_NODE::addSolid(PNS_SOLID *aSolid)
void PNS_NODE::addSolid( PNS_SOLID* aSolid )
{ {
linkJoint( aSolid->GetCenter(), aSolid->GetLayers(), aSolid->GetNet(), aSolid ); linkJoint( aSolid->GetCenter(), aSolid->GetLayers(), aSolid->GetNet(), aSolid );
m_index->Add(aSolid); m_index->Add( aSolid );
} }
void PNS_NODE::addVia(PNS_VIA *aVia)
void PNS_NODE::addVia( PNS_VIA* aVia )
{ {
linkJoint( aVia->GetPos(), aVia->GetLayers(), aVia->GetNet(), aVia ); linkJoint( aVia->GetPos(), aVia->GetLayers(), aVia->GetNet(), aVia );
m_index->Add(aVia); m_index->Add( aVia );
} }
void PNS_NODE::addLine( PNS_LINE *aLine )
void PNS_NODE::addLine( PNS_LINE* aLine )
{ {
const SHAPE_LINE_CHAIN& l = aLine->GetLine(); const SHAPE_LINE_CHAIN& l = aLine->GetLine();
for(int i = 0; i < l.SegmentCount(); i++) for( int i = 0; i < l.SegmentCount(); i++ )
{ {
SEG s = l.CSegment(i); SEG s = l.CSegment( i );
if(s.a != s.b) if( s.a != s.b )
{ {
PNS_SEGMENT *pseg = new PNS_SEGMENT(*aLine, s); PNS_SEGMENT* pseg = new PNS_SEGMENT( *aLine, s );
pseg->SetOwner(this); pseg->SetOwner( this );
linkJoint( s.a, pseg->GetLayers(), aLine->GetNet(), pseg ); linkJoint( s.a, pseg->GetLayers(), aLine->GetNet(), pseg );
linkJoint( s.b, pseg->GetLayers(), aLine->GetNet(), pseg ); linkJoint( s.b, pseg->GetLayers(), aLine->GetNet(), pseg );
aLine->LinkSegment(pseg); aLine->LinkSegment( pseg );
m_index->Add(pseg); m_index->Add( pseg );
} }
} }
} }
void PNS_NODE::addSegment( PNS_SEGMENT *aSeg )
void PNS_NODE::addSegment( PNS_SEGMENT* aSeg )
{ {
if(aSeg->GetSeg().a == aSeg->GetSeg().b) if( aSeg->GetSeg().a == aSeg->GetSeg().b )
{ {
TRACEn(0, "attempting to add a segment with same end coordinates, ignoring.") TRACEn( 0, "attempting to add a segment with same end coordinates, ignoring." )
return; return;
} }
aSeg->SetOwner (this); aSeg->SetOwner( this );
linkJoint( aSeg->GetSeg().a, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); linkJoint( aSeg->GetSeg().a, aSeg->GetLayers(), aSeg->GetNet(), aSeg );
linkJoint( aSeg->GetSeg().b, aSeg->GetLayers(), aSeg->GetNet(), aSeg ); linkJoint( aSeg->GetSeg().b, aSeg->GetLayers(), aSeg->GetNet(), aSeg );
m_index->Add(aSeg); m_index->Add( aSeg );
} }
void PNS_NODE::Add(PNS_ITEM* aItem)
{
aItem->SetOwner(this); void PNS_NODE::Add( PNS_ITEM* aItem )
{
aItem->SetOwner( this );
switch(aItem -> GetKind()) switch( aItem->GetKind() )
{ {
case PNS_ITEM::SOLID: case PNS_ITEM::SOLID:
addSolid(static_cast<PNS_SOLID*>(aItem)); addSolid( static_cast<PNS_SOLID*>( aItem ) );
break; break;
case PNS_ITEM::SEGMENT: case PNS_ITEM::SEGMENT:
addSegment(static_cast<PNS_SEGMENT*>(aItem)); addSegment( static_cast<PNS_SEGMENT*>( aItem ) );
break; break;
case PNS_ITEM::LINE: case PNS_ITEM::LINE:
addLine( static_cast<PNS_LINE*> (aItem)); addLine( static_cast<PNS_LINE*> (aItem) );
break; break;
case PNS_ITEM::VIA: case PNS_ITEM::VIA:
addVia (static_cast<PNS_VIA*>(aItem)); addVia( static_cast<PNS_VIA*>(aItem) );
break; break;
default: default:
assert (false); assert( false );
} }
} }
void PNS_NODE::doRemove ( PNS_ITEM *aItem ) 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 // case 1: removing an item that is stored in the root node from any branch:
if( aItem->BelongsTo(m_root) && !isRoot() ) // mark it as overridden, but do not remove
m_override.insert(aItem); 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 // case 2: the item belongs to this branch or a parent, non-root branch,
else if( !aItem->BelongsTo(m_root) || isRoot() ) // or the root itself and we are the root: remove from the index
else if( !aItem->BelongsTo( m_root ) || isRoot() )
m_index->Remove( aItem ); m_index->Remove( aItem );
// the item belongs to this particular branch: un-reference it // the item belongs to this particular branch: un-reference it
if( aItem->BelongsTo( this )) if( aItem->BelongsTo( this ) )
aItem->SetOwner(NULL); aItem->SetOwner( NULL );
} }
void PNS_NODE::removeSegment (PNS_SEGMENT *aSeg )
void PNS_NODE::removeSegment( PNS_SEGMENT* aSeg )
{ {
unlinkJoint(aSeg->GetSeg().a, aSeg->GetLayers(), aSeg->GetNet(), aSeg); unlinkJoint( aSeg->GetSeg().a, aSeg->GetLayers(), aSeg->GetNet(), aSeg );
unlinkJoint(aSeg->GetSeg().b, aSeg->GetLayers(), aSeg->GetNet(), aSeg); unlinkJoint( aSeg->GetSeg().b, aSeg->GetLayers(), aSeg->GetNet(), aSeg );
doRemove(aSeg); doRemove( aSeg );
} }
void PNS_NODE::removeLine( PNS_LINE *aLine )
void PNS_NODE::removeLine( PNS_LINE* aLine )
{ {
vector<PNS_SEGMENT *> *segRefs = aLine->GetLinkedSegments(); vector<PNS_SEGMENT*>* segRefs = aLine->GetLinkedSegments();
if(!segRefs) if( !segRefs )
return; return;
assert ( aLine->GetOwner () ); assert( aLine->GetOwner() );
BOOST_FOREACH(PNS_SEGMENT *seg, *segRefs) BOOST_FOREACH( PNS_SEGMENT* seg, *segRefs )
{ {
removeSegment(seg); removeSegment( seg );
} }
aLine->SetOwner(NULL); aLine->SetOwner( NULL );
} }
void PNS_NODE::removeVia ( PNS_VIA *aVia )
void PNS_NODE::removeVia( PNS_VIA* aVia )
{ {
unlinkJoint(aVia->GetPos(), aVia->GetLayers(), aVia->GetNet(), aVia); unlinkJoint( aVia->GetPos(), aVia->GetLayers(), aVia->GetNet(), aVia );
doRemove(aVia); doRemove( aVia );
} }
void PNS_NODE::Replace(PNS_ITEM *aOldItem, PNS_ITEM *aNewItem)
void PNS_NODE::Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem )
{ {
Remove(aOldItem); Remove( aOldItem );
Add(aNewItem); Add( aNewItem );
} }
void PNS_NODE::Remove(PNS_ITEM *aItem)
{
switch(aItem -> GetKind()) void PNS_NODE::Remove( PNS_ITEM* aItem )
{
switch( aItem->GetKind() )
{ {
case PNS_ITEM::SOLID: case PNS_ITEM::SOLID:
assert(false); assert( false );
break; break;
case PNS_ITEM::SEGMENT: case PNS_ITEM::SEGMENT:
removeSegment(static_cast<PNS_SEGMENT*>(aItem)); removeSegment( static_cast<PNS_SEGMENT*>( aItem ) );
break; break;
case PNS_ITEM::LINE: case PNS_ITEM::LINE:
removeLine(static_cast<PNS_LINE *>(aItem)); removeLine( static_cast<PNS_LINE*>( aItem ) );
break; break;
case PNS_ITEM::VIA: case PNS_ITEM::VIA:
removeVia(static_cast<PNS_VIA *>(aItem)); removeVia( static_cast<PNS_VIA*>( aItem ) );
break; break;
default: default:
...@@ -574,125 +620,139 @@ void PNS_NODE::Remove(PNS_ITEM *aItem) ...@@ -574,125 +620,139 @@ void PNS_NODE::Remove(PNS_ITEM *aItem)
} }
} }
void PNS_NODE::followLine(PNS_SEGMENT *current, bool scanDirection, int& pos, int limit, VECTOR2I *corners, PNS_SEGMENT **segments)
void PNS_NODE::followLine( PNS_SEGMENT* current, bool scanDirection, int& pos,
int limit, VECTOR2I* corners, PNS_SEGMENT** segments )
{ {
bool prevReversed = false; bool prevReversed = false;
for(;;) for( ; ; )
{ {
const VECTOR2I p = (scanDirection ^ prevReversed) ? current->GetSeg().b : current->GetSeg().a; const VECTOR2I p =
const OptJoint jt = FindJoint(p, current->GetLayer(), current->GetNet()); (scanDirection ^ prevReversed) ? current->GetSeg().b : current->GetSeg().a;
const OptJoint jt = FindJoint( p, current->GetLayer(), current->GetNet() );
assert (jt); assert( jt );
assert (pos > 0 && pos < limit); assert( pos > 0 && pos < limit );
corners [pos] = jt->GetPos(); corners[pos] = jt->GetPos();
segments [pos] = current; segments[pos] = current;
pos += (scanDirection ? 1 : -1); pos += (scanDirection ? 1 : -1);
if(!jt->IsLineCorner()) if( !jt->IsLineCorner() )
break; break;
current = jt->NextSegment( current ); current = jt->NextSegment( current );
prevReversed = (jt->GetPos() == (scanDirection ? current->GetSeg().b : current->GetSeg().a )); prevReversed =
( jt->GetPos() == (scanDirection ? current->GetSeg().b : current->GetSeg().a ) );
} }
} }
PNS_LINE *PNS_NODE::AssembleLine(PNS_SEGMENT *aSeg, const OptJoint& a, const OptJoint& b)
PNS_LINE* PNS_NODE::AssembleLine( PNS_SEGMENT* aSeg, const OptJoint& a, const OptJoint& b )
{ {
const int MaxVerts = 1024; const int MaxVerts = 1024;
VECTOR2I corners [ MaxVerts + 1 ]; VECTOR2I corners[MaxVerts + 1];
PNS_SEGMENT *segs [ MaxVerts + 1 ]; PNS_SEGMENT* segs[MaxVerts + 1];
PNS_LINE *pl = new PNS_LINE; PNS_LINE* pl = new PNS_LINE;
int i_start = MaxVerts/2, i_end = i_start + 1; int i_start = MaxVerts / 2, i_end = i_start + 1;
pl->SetWidth( aSeg->GetWidth() ); pl->SetWidth( aSeg->GetWidth() );
pl->SetLayers( aSeg->GetLayers() ); pl->SetLayers( aSeg->GetLayers() );
pl->SetNet ( aSeg->GetNet() ); pl->SetNet( aSeg->GetNet() );
pl->SetOwner(this); pl->SetOwner( this );
//pl->LinkSegment(aSeg); // pl->LinkSegment(aSeg);
followLine (aSeg, false, i_start, MaxVerts, corners, segs ); followLine( aSeg, false, i_start, MaxVerts, corners, segs );
followLine (aSeg, true, i_end, MaxVerts, corners, segs ); followLine( aSeg, true, i_end, MaxVerts, corners, segs );
int clip_start = -1, clip_end = -1; int clip_start = -1, clip_end = -1;
for(int i = i_start+1 ; i < i_end ; i++)
for( int i = i_start + 1; i < i_end; i++ )
{ {
const VECTOR2I &p = corners[i]; const VECTOR2I& p = corners[i];
if (a && (p == a->GetPos() || p == b->GetPos() ) ) if( a && ( p == a->GetPos() || p == b->GetPos() ) )
{ {
clip_start = std::min(clip_start, i); clip_start = std::min( clip_start, i );
clip_end = std::max(clip_end, i); clip_end = std::max( clip_end, i );
} }
pl->GetLine().Append(p); pl->GetLine().Append( p );
if(segs[i-1] != segs[i])
pl->LinkSegment(segs[i]); if( segs[i - 1] != segs[i] )
pl->LinkSegment( segs[i] );
} }
return pl; return pl;
} }
void PNS_NODE::FindLineEnds (PNS_LINE *aLine, PNS_JOINT& a, PNS_JOINT& b )
void PNS_NODE::FindLineEnds( PNS_LINE* aLine, PNS_JOINT& a, PNS_JOINT& b )
{ {
a = *FindJoint(aLine->GetCLine().CPoint(0), aLine->GetLayers().Start(), aLine->GetNet()); a = *FindJoint( aLine->GetCLine().CPoint( 0 ), aLine->GetLayers().Start(), aLine->GetNet() );
b = *FindJoint(aLine->GetCLine().CPoint(-1), 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<PNS_LINE *> &aLines ) int PNS_NODE::FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b, vector<PNS_LINE*>& aLines )
{ {
BOOST_FOREACH(PNS_ITEM *item, a.GetLinkList()) BOOST_FOREACH( PNS_ITEM * item, a.GetLinkList() )
{ {
if(item->GetKind() == PNS_ITEM::SEGMENT) if( item->GetKind() == PNS_ITEM::SEGMENT )
{ {
PNS_SEGMENT *seg = static_cast<PNS_SEGMENT*>(item); PNS_SEGMENT* seg = static_cast<PNS_SEGMENT*>(item);
PNS_LINE *line = AssembleLine(seg); PNS_LINE* line = AssembleLine( seg );
PNS_JOINT j_start, j_end; PNS_JOINT j_start, j_end;
FindLineEnds( line, 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); if( (j_start == a && j_end == b )|| (j_end == a && j_start == b) )
aLines.push_back( line );
else else
delete line; delete line;
} }
} }
return 0; return 0;
} }
const PNS_NODE::OptJoint PNS_NODE::FindJoint(const VECTOR2I &aPos, int aLayer, int aNet )
const PNS_NODE::OptJoint PNS_NODE::FindJoint( const VECTOR2I& aPos, int aLayer, int aNet )
{ {
PNS_JOINT::HashTag tag; PNS_JOINT::HashTag tag;
tag.net = aNet; tag.net = aNet;
tag.pos = aPos; tag.pos = aPos;
JointMap::iterator f = m_joints.find(tag), end = m_joints.end(); JointMap::iterator f = m_joints.find( tag ), end = m_joints.end();
if(f == end && !isRoot()) if( f == end && !isRoot() )
{ {
end = m_root->m_joints.end(); end = m_root->m_joints.end();
f = m_root->m_joints.find(tag); //m_root->FindJoint(aPos, aLayer, aNet); f = m_root->m_joints.find( tag ); // m_root->FindJoint(aPos, aLayer, aNet);
} }
if(f == end) if( f == end )
return OptJoint(); return OptJoint();
while (f != end) while( f != end )
{ {
if(f->second.GetLayers().Overlaps(aLayer)) if( f->second.GetLayers().Overlaps( aLayer ) )
return f->second; return f->second;
++f; ++f;
} }
return OptJoint(); return OptJoint();
} }
PNS_JOINT& PNS_NODE::touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet ) PNS_JOINT& PNS_NODE::touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet )
{ {
PNS_JOINT::HashTag tag; PNS_JOINT::HashTag tag;
...@@ -701,201 +761,227 @@ PNS_JOINT& PNS_NODE::touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLaye ...@@ -701,201 +761,227 @@ PNS_JOINT& PNS_NODE::touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLaye
tag.net = aNet; tag.net = aNet;
// try to find the joint in this node. // try to find the joint in this node.
JointMap::iterator f = m_joints.find(tag); JointMap::iterator f = m_joints.find( tag );
pair<JointMap::iterator, JointMap::iterator> range; pair<JointMap::iterator, JointMap::iterator> range;
// not found and we are not root? find in the root and copy results here. // not found and we are not root? find in the root and copy results here.
if(f == m_joints.end() && !isRoot()) if( f == m_joints.end() && !isRoot() )
{ {
range = m_root->m_joints.equal_range(tag); range = m_root->m_joints.equal_range( tag );
for( f = range.first; f != range.second; ++f)
for( f = range.first; f != range.second; ++f )
m_joints.insert( *f ); m_joints.insert( *f );
} }
// now insert and combine overlapping joints // now insert and combine overlapping joints
PNS_JOINT jt (aPos, aLayers, aNet); PNS_JOINT jt( aPos, aLayers, aNet );
bool merged; bool merged;
do do
{ {
merged = false; merged = false;
range = m_joints.equal_range(tag); range = m_joints.equal_range( tag );
if(range.first == m_joints.end()) if( range.first == m_joints.end() )
break; break;
for(f = range.first; f != range.second; ++f) for( f = range.first; f != range.second; ++f )
{ {
if(aLayers.Overlaps (f->second.GetLayers())) if( aLayers.Overlaps( f->second.GetLayers() ) )
{ {
jt.Merge(f->second); jt.Merge( f->second );
m_joints.erase(f); m_joints.erase( f );
merged = true; merged = true;
break; break;
} }
} }
} while (merged); } while( merged );
return m_joints.insert ( TagJointPair(tag, jt) )->second; return m_joints.insert( TagJointPair( tag, jt ) )->second;
} }
void PNS_JOINT::Dump() const 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 ); PNS_JOINT& jt = touchJoint( aPos, aLayers, aNet );
jt.Link(aWhere);
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 // fixme: remove dangling joints
PNS_JOINT& jt = touchJoint( aPos, aLayers, aNet ); PNS_JOINT& jt = touchJoint( aPos, aLayers, aNet );
jt.Unlink(aWhere);
jt.Unlink( aWhere );
} }
void PNS_NODE::Dump(bool aLong) void PNS_NODE::Dump( bool aLong )
{ {
#if 0 #if 0
boost::unordered_set<PNS_SEGMENT *> all_segs; boost::unordered_set<PNS_SEGMENT*> all_segs;
SHAPE_INDEX_LIST<PNS_ITEM *>::iterator i; SHAPE_INDEX_LIST<PNS_ITEM*>::iterator i;
for(i = m_items.begin(); i != m_items.end() ; i++) for( i = m_items.begin(); i != m_items.end(); i++ )
{ {
if((*i)->GetKind() == PNS_ITEM::SEGMENT) if( (*i)->GetKind() == PNS_ITEM::SEGMENT )
all_segs.insert(static_cast<PNS_SEGMENT*>(*i)); all_segs.insert( static_cast<PNS_SEGMENT*>(*i) );
} }
if(!isRoot()) if( !isRoot() )
for(i = m_root->m_items.begin(); i != m_root->m_items.end() ; i++) for( i = m_root->m_items.begin(); i != m_root->m_items.end(); i++ )
{ {
if((*i)->GetKind() == PNS_ITEM::SEGMENT && !overrides(*i)) if( (*i)->GetKind() == PNS_ITEM::SEGMENT && !overrides( *i ) )
all_segs.insert(static_cast<PNS_SEGMENT*>(*i)); all_segs.insert( static_cast<PNS_SEGMENT*>(*i) );
} }
JointMap::iterator j; JointMap::iterator j;
if(aLong)
for(j=m_joints.begin(); j!=m_joints.end(); ++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()); printf( "joint : %s, links : %d\n",
j->second.GetPos().Format().c_str(), j->second.LinkCount() );
PNS_JOINT::LinkedItems::const_iterator k; PNS_JOINT::LinkedItems::const_iterator k;
for(k = j->second.GetLinkList().begin(); k != j->second.GetLinkList().end(); ++k)
for( k = j->second.GetLinkList().begin(); k != j->second.GetLinkList().end(); ++k )
{ {
const PNS_ITEM *item = *k; const PNS_ITEM* item = *k;
switch(item->GetKind()) switch( item->GetKind() )
{ {
case PNS_ITEM::SEGMENT: case PNS_ITEM::SEGMENT:
{ {
const PNS_SEGMENT *seg = static_cast<const PNS_SEGMENT *>(item); const PNS_SEGMENT* seg = static_cast<const PNS_SEGMENT*>(item);
printf(" -> seg %s %s\n", seg->GetSeg().a.Format().c_str(), seg->GetSeg().b.Format().c_str()); printf( " -> seg %s %s\n", seg->GetSeg().a.Format().c_str(),
seg->GetSeg().b.Format().c_str() );
break; break;
} }
default: default:
break; break;
} }
} }
} }
int lines_count = 0; int lines_count = 0;
while(!all_segs.empty())
while( !all_segs.empty() )
{ {
PNS_SEGMENT *s = *all_segs.begin(); PNS_SEGMENT* s = *all_segs.begin();
PNS_LINE *l = AssembleLine(s); PNS_LINE* l = AssembleLine( s );
PNS_LINE::LinkedSegments* seg_refs = l->GetLinkedSegments(); PNS_LINE::LinkedSegments* seg_refs = l->GetLinkedSegments();
if(aLong) if( aLong )
printf("Line: %s, net %d ", l->GetLine().Format().c_str(), l->GetNet() ); printf( "Line: %s, net %d ", l->GetLine().Format().c_str(), l->GetNet() );
for(vector<PNS_SEGMENT *>::iterator j = seg_refs->begin(); j != seg_refs->end(); ++j) for( vector<PNS_SEGMENT*>::iterator j = seg_refs->begin(); j != seg_refs->end(); ++j )
{ {
printf("%s ", (*j)->GetSeg().a.Format().c_str() ); printf( "%s ", (*j)->GetSeg().a.Format().c_str() );
if(j+1 == seg_refs->end())
printf("%s\n", (*j)->GetSeg().b.Format().c_str() ); if( j + 1 == seg_refs->end() )
all_segs.erase(*j); printf( "%s\n", (*j)->GetSeg().b.Format().c_str() );
all_segs.erase( *j );
} }
lines_count++; lines_count++;
} }
printf("Local joints: %d, lines : %d \n", m_joints.size(), lines_count); printf( "Local joints: %d, lines : %d \n", m_joints.size(), lines_count );
#endif #endif
} }
void PNS_NODE::GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded)
void PNS_NODE::GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded )
{ {
aRemoved.reserve(m_override.size()); aRemoved.reserve( m_override.size() );
aAdded.reserve(m_index->Size()); aAdded.reserve( m_index->Size() );
if(isRoot ()) if( isRoot() )
return; return;
BOOST_FOREACH(PNS_ITEM *item, m_override) BOOST_FOREACH( PNS_ITEM * item, m_override )
aRemoved.push_back(item); aRemoved.push_back( item );
for(PNS_INDEX::ItemSet::iterator i = m_index->begin(); i!=m_index->end(); ++i) for( PNS_INDEX::ItemSet::iterator i = m_index->begin(); i!=m_index->end(); ++i )
aAdded.push_back(*i); aAdded.push_back( *i );
} }
void PNS_NODE::releaseChildren ()
void PNS_NODE::releaseChildren()
{ {
// copy the kids as the PNS_NODE destructor erases the item from the parent node. // copy the kids as the PNS_NODE destructor erases the item from the parent node.
vector<PNS_NODE *> kids = m_children; vector<PNS_NODE*> kids = m_children;
BOOST_FOREACH(PNS_NODE *node, kids) BOOST_FOREACH( PNS_NODE * node, kids ) {
{
node->releaseChildren(); node->releaseChildren();
delete node; delete node;
} }
} }
void PNS_NODE::Commit( PNS_NODE *aNode )
{
if(aNode->isRoot()) void PNS_NODE::Commit( PNS_NODE* aNode )
{
if( aNode->isRoot() )
return; return;
BOOST_FOREACH( PNS_ITEM *item, aNode->m_override ) BOOST_FOREACH( PNS_ITEM * item, aNode->m_override )
Remove(item); Remove( item );
for(PNS_INDEX::ItemSet::iterator i = aNode->m_index->begin(); i!= aNode ->m_index->end(); ++i) for( PNS_INDEX::ItemSet::iterator i = aNode->m_index->begin();
Add(*i); i != aNode->m_index->end(); ++i )
Add( *i );
releaseChildren(); releaseChildren();
} }
void PNS_NODE::KillChildren() void PNS_NODE::KillChildren()
{ {
assert (isRoot()); assert( isRoot() );
releaseChildren(); releaseChildren();
} }
void PNS_NODE::AllItemsInNet( int aNet, std::list<PNS_ITEM*>& aItems )
void PNS_NODE::AllItemsInNet ( int aNet, std::list<PNS_ITEM *>& aItems)
{ {
PNS_INDEX::NetItemsList* l_cur = m_index->GetItemsForNet ( aNet ); PNS_INDEX::NetItemsList* l_cur = m_index->GetItemsForNet( aNet );
if(!l_cur) if( !l_cur )
return; return;
std::copy(aItems.begin(), l_cur->begin(), l_cur->end() ); std::copy( aItems.begin(), l_cur->begin(), l_cur->end() );
if( !isRoot () )
if( !isRoot() )
{ {
PNS_INDEX::NetItemsList* l_root = m_root->m_index->GetItemsForNet ( aNet ); 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 );
for(PNS_INDEX::NetItemsList::iterator i = l_root->begin(); i!= l_root->end(); ++i)
if( !overrides( *i ))
aItems.push_back(*i);
} }
} }
...@@ -45,9 +45,10 @@ class PNS_INDEX; ...@@ -45,9 +45,10 @@ class PNS_INDEX;
using boost::shared_ptr; using boost::shared_ptr;
class PNS_CLEARANCE_FUNC { class PNS_CLEARANCE_FUNC
public: {
virtual int operator() ( const PNS_ITEM *a , const PNS_ITEM *b) = 0; public:
virtual int operator()( const PNS_ITEM* a, const PNS_ITEM* b ) = 0;
}; };
/** /**
...@@ -59,16 +60,16 @@ class PNS_CLEARANCE_FUNC { ...@@ -59,16 +60,16 @@ class PNS_CLEARANCE_FUNC {
struct PNS_OBSTACLE struct PNS_OBSTACLE
{ {
///> Item we search collisions with ///> Item we search collisions with
PNS_ITEM *head; PNS_ITEM* head;
///> Item found to be colliding with head ///> Item found to be colliding with head
PNS_ITEM *item; PNS_ITEM* item;
///> Hull of the colliding item ///> Hull of the colliding item
SHAPE_LINE_CHAIN hull; SHAPE_LINE_CHAIN hull;
///> First and last intersection point between the head item and the hull of the ///> First and last intersection point between the head item and the hull
//// colliding item ///> of the colliding item
VECTOR2I ip_first, ip_last; VECTOR2I ip_first, ip_last;
///> ... and the distance thereof ///> ... and the distance thereof
...@@ -78,28 +79,29 @@ struct PNS_OBSTACLE ...@@ -78,28 +79,29 @@ struct PNS_OBSTACLE
/** /**
* Class PNS_NODE * 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: * Features:
* - spatial-indexed container for PCB item shapes * - spatial-indexed container for PCB item shapes
* - collision search (with clearance checking) * - collision search (with clearance checking)
* - assembly of lines connecting joints, finding loops and unique paths * - 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: public:
typedef boost::optional<PNS_OBSTACLE> OptObstacle; typedef boost::optional<PNS_OBSTACLE> OptObstacle;
typedef std::vector<PNS_ITEM *> ItemVector; typedef std::vector<PNS_ITEM*> ItemVector;
typedef std::vector<PNS_OBSTACLE> Obstacles; typedef std::vector<PNS_OBSTACLE> Obstacles;
typedef boost::optional<PNS_JOINT> OptJoint; typedef boost::optional<PNS_JOINT> OptJoint;
PNS_NODE (); PNS_NODE();
~PNS_NODE (); ~PNS_NODE();
///> Returns the expected clearance between items a and b. ///> Returns the expected clearance between items a and b.
int GetClearance(const PNS_ITEM *a, const PNS_ITEM *b) const; int GetClearance( const PNS_ITEM* a, const PNS_ITEM* b ) const;
///> Returns the pre-set worst case clearance between any pair of items ///> Returns the pre-set worst case clearance between any pair of items
int GetMaxClearance() const int GetMaxClearance() const
...@@ -112,39 +114,48 @@ public: ...@@ -112,39 +114,48 @@ public:
m_maxClearance = aClearance; m_maxClearance = aClearance;
} }
void SetClearanceFunctor (PNS_CLEARANCE_FUNC *aFunc) void SetClearanceFunctor( PNS_CLEARANCE_FUNC* aFunc )
{ {
m_clearanceFunctor = aFunc; m_clearanceFunctor = aFunc;
} }
///> Finds items that collide with aItem and stores collision information in aObstacles. ///> Finds items that collide with aItem and stores collision information
int QueryColliding( const PNS_ITEM* aItem, Obstacles& aObstacles, int aKindMask = PNS_ITEM::ANY, int aLimitCount = -1); ///> in aObstacles.
int QueryColliding( const PNS_ITEM* aItem,
Obstacles& aObstacles,
int aKindMask = PNS_ITEM::ANY,
int aLimitCount = -1 );
///> Finds the nearest item that collides with aItem. ///> Finds the nearest item that collides with aItem.
OptObstacle NearestObstacle( const PNS_LINE *aItem, int aKindMask = PNS_ITEM::ANY); OptObstacle NearestObstacle( const PNS_LINE* aItem, int aKindMask = PNS_ITEM::ANY );
///> Checks if the item collides with anything else in the world, and returns it if so. ///> Checks if the item collides with anything else in the world,
OptObstacle CheckColliding ( const PNS_ITEM *aItem, int aKindMask = PNS_ITEM::ANY); ///> and returns it if so.
OptObstacle CheckColliding( const PNS_ITEM* aItem, int aKindMask = PNS_ITEM::ANY );
///> Checks if two items collide [deprecated]. ///> Checks if two items collide [deprecated].
bool CheckColliding( const PNS_ITEM *aItemA, const PNS_ITEM *aItemB, int aKindMask = PNS_ITEM::ANY); bool CheckColliding( const PNS_ITEM* aItemA,
const PNS_ITEM* aItemB,
int aKindMask = PNS_ITEM::ANY );
///> Hit detection ///> Hit detection
const PNS_ITEMSET HitTest( const VECTOR2I& aPoint ); const PNS_ITEMSET HitTest( const VECTOR2I& aPoint );
void Add(PNS_ITEM *aItem); void Add( PNS_ITEM* aItem );
void Remove(PNS_ITEM *aItem); void Remove( PNS_ITEM* aItem );
void Replace(PNS_ITEM *aOldItem, PNS_ITEM *aNewItem); void Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem );
///> Creates a lightweight copy ("branch") of self. Note that if there are any branches ///> Creates a lightweight copy ("branch") of self. Note that if there are
/// in use, their parents must NOT be deleted. ///> any branches in use, their parents must NOT be deleted.
PNS_NODE *Branch(); PNS_NODE* Branch();
///> Assembles a line connecting two non-trivial joints the segment aSeg belongs to. ///> Assembles a line connecting two non-trivial joints the
PNS_LINE *AssembleLine(PNS_SEGMENT *aSeg, const OptJoint& a = OptJoint(), const OptJoint& b = OptJoint()); ///> segment aSeg belongs to.
PNS_LINE* AssembleLine( PNS_SEGMENT* aSeg,
const OptJoint& a = OptJoint(), const OptJoint& b = OptJoint() );
///> Dumps the contents and joints structure ///> Dumps the contents and joints structure
void Dump(bool aLong = false); void Dump( bool aLong = false );
///> Returns the number of joints ///> Returns the number of joints
int JointCount() const int JointCount() const
...@@ -152,106 +163,116 @@ public: ...@@ -152,106 +163,116 @@ public:
return m_joints.size(); return m_joints.size();
} }
///> Returns the lists of items removed and added in this branch, with respect ///> Returns the lists of items removed and added in this branch, with
///> to the root. ///> respect to the root.
void GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded); void GetUpdatedItems( ItemVector& aRemoved, ItemVector& aAdded );
///> Copies the changes from a given branch (aNode) to the root. Called on ///> Copies the changes from a given branch (aNode) to the root. Called on
///> a non-root branch will fail. ///> a non-root branch will fail.
void Commit (PNS_NODE *aNode); void Commit( PNS_NODE* aNode );
///> finds a joint at a given position, layer and nets ///> finds a joint at a given position, layer and nets
const OptJoint FindJoint(const VECTOR2I &aPos, int aLayer, int aNet); const OptJoint FindJoint( const VECTOR2I& aPos, int aLayer, int aNet );
///> finds all linest between a pair of joints. Used by the loop removal engine. ///> finds all linest between a pair of joints. Used by the loop removal engine.
int FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b, std::vector<PNS_LINE *> &aLines ); int FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b,
std::vector<PNS_LINE*>& aLines );
///> finds the joints corresponding to the ends of line aLine ///> finds the joints corresponding to the ends of line aLine
void FindLineEnds (PNS_LINE *aLine, PNS_JOINT& a, PNS_JOINT& b ); void FindLineEnds( PNS_LINE* aLine, PNS_JOINT& a, PNS_JOINT& b );
///> finds all joints that have an (in)direct connection(s) (i.e. segments/vias) with the joint aJoint. ///> finds all joints that have an (in)direct connection(s)
void FindConnectedJoints( const PNS_JOINT& aJoint, std::vector<PNS_JOINT *> &aConnectedJoints ); ///> (i.e. segments/vias) with the joint aJoint.
void FindConnectedJoints( const PNS_JOINT& aJoint,
std::vector<PNS_JOINT*>& aConnectedJoints );
///> Destroys all child nodes. Applicable only to the root node. ///> Destroys all child nodes. Applicable only to the root node.
void KillChildren(); void KillChildren();
void AllItemsInNet ( int aNet, std::list<PNS_ITEM *>& aItems); void AllItemsInNet( int aNet, std::list<PNS_ITEM*>& aItems );
private: private:
struct obstacleVisitor; struct obstacleVisitor;
typedef boost::unordered_multimap<PNS_JOINT::HashTag, PNS_JOINT> JointMap; typedef boost::unordered_multimap<PNS_JOINT::HashTag, PNS_JOINT> JointMap;
typedef JointMap::value_type TagJointPair; typedef JointMap::value_type TagJointPair;
/// nodes are not copyable /// nodes are not copyable
PNS_NODE( const PNS_NODE& b); PNS_NODE( const PNS_NODE& b );
PNS_NODE &operator=(const PNS_NODE& b); PNS_NODE& operator=( const PNS_NODE& b );
///> tries to find matching joint and creates a new one if not found ///> 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 ); PNS_JOINT& touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
int aNet );
///> touches a joint and links it to an item ///> touches a joint and links it to an item
void linkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet, PNS_ITEM *aWhere ); void linkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
int aNet, PNS_ITEM* aWhere );
///> unlinks an item from a joint ///> unlinks an item from a joint
void unlinkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aNet, PNS_ITEM *aWhere ); void unlinkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
int aNet, PNS_ITEM* aWhere );
///> helpers for adding/removing items ///> helpers for adding/removing items
void addSolid( PNS_SOLID* aSeg );
void addSolid( PNS_SOLID *aSeg ); void addSegment( PNS_SEGMENT* aSeg );
void addSegment( PNS_SEGMENT *aSeg ); void addLine( PNS_LINE* aLine );
void addLine( PNS_LINE *aLine ); void addVia( PNS_VIA* aVia );
void addVia( PNS_VIA *aVia ); void removeSolid( PNS_SOLID* aSeg );
void removeSolid( PNS_SOLID *aSeg ); void removeLine( PNS_LINE* aLine );
void removeLine( PNS_LINE *aLine ); void removeSegment( PNS_SEGMENT* aSeg );
void removeSegment (PNS_SEGMENT *aSeg ); void removeVia( PNS_VIA* aVia );
void removeVia (PNS_VIA *aVia );
void doRemove( PNS_ITEM* aItem );
void doRemove( PNS_ITEM *aItem ); void unlinkParent();
void unlinkParent ( ); void releaseChildren();
void releaseChildren ();
bool isRoot() const bool isRoot() const
{ {
return m_parent == NULL; return m_parent == NULL;
} }
///> checks if this branch contains an updated version of the item from the root branch. ///> checks if this branch contains an updated version of the item
bool overrides ( PNS_ITEM * aItem ) const ///> from the root branch.
bool overrides( PNS_ITEM* aItem ) const
{ {
return m_override.find(aItem) != m_override.end(); return m_override.find( aItem ) != m_override.end();
} }
///> scans the joint map, forming a line starting from segment (current). ///> 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); void followLine( PNS_SEGMENT* current,
bool scanDirection,
int& pos,
int limit,
VECTOR2I* corners,
PNS_SEGMENT** segments );
///> spatial index of all items ///> spatial index of all items
//SHAPE_INDEX_LIST<PNS_ITEM *> m_items; // SHAPE_INDEX_LIST<PNS_ITEM *> m_items;
///> hash table with the joints, linking the items. Joints are hashed by their ///> hash table with the joints, linking the items. Joints are hashed by
///> position, layer set and net. ///> their position, layer set and net.
JointMap m_joints; JointMap m_joints;
///> node this node was branched from ///> node this node was branched from
PNS_NODE *m_parent; PNS_NODE* m_parent;
///> root node of the whole hierarchy ///> root node of the whole hierarchy
PNS_NODE *m_root; PNS_NODE* m_root;
///> list of nodes branched from this one ///> list of nodes branched from this one
std::vector<PNS_NODE *> m_children; std::vector<PNS_NODE*> m_children;
///> hash of root's items that are more recent in this node ///> hash of root's items that are more recent in this node
boost::unordered_set<PNS_ITEM *> m_override; boost::unordered_set<PNS_ITEM*> m_override;
///> worst case item-item clearance ///> worst case item-item clearance
int m_maxClearance; int m_maxClearance;
///> Clearance resolution functor ///> Clearance resolution functor
PNS_CLEARANCE_FUNC *m_clearanceFunctor; PNS_CLEARANCE_FUNC* m_clearanceFunctor;
///> Geometric/Net index of the items ///> Geometric/Net index of the items
PNS_INDEX *m_index; PNS_INDEX* m_index;
///> list of currently processed obstacles. ///> list of currently processed obstacles.
Obstacles m_obstacleList; Obstacles m_obstacleList;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License along * You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>. * with this program. If not, see <http://www.gnu.or/licenses/>.
*/ */
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <geometry/shape_line_chain.h> #include <geometry/shape_line_chain.h>
...@@ -27,76 +28,90 @@ ...@@ -27,76 +28,90 @@
#include "pns_optimizer.h" #include "pns_optimizer.h"
#include "pns_utils.h" #include "pns_utils.h"
using namespace std; 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)) switch( dir_a.Angle( dir_b ) )
{ {
case DIRECTION_45::ANG_OBTUSE: case DIRECTION_45::ANG_OBTUSE:
return 1; return 1;
case DIRECTION_45::ANG_STRAIGHT: case DIRECTION_45::ANG_STRAIGHT:
return 0; return 0;
case DIRECTION_45::ANG_ACUTE: case DIRECTION_45::ANG_ACUTE:
return 50; return 50;
case DIRECTION_45::ANG_RIGHT: case DIRECTION_45::ANG_RIGHT:
return 30; return 30;
case DIRECTION_45::ANG_HALF_FULL: case DIRECTION_45::ANG_HALF_FULL:
return 60; return 60;
default: default:
return 100; return 100;
} }
} }
int PNS_COST_ESTIMATOR::CornerCost ( const SHAPE_LINE_CHAIN& aLine )
int PNS_COST_ESTIMATOR::CornerCost( const SHAPE_LINE_CHAIN& aLine )
{ {
int total = 0; int total = 0;
for (int i = 0; i < aLine.SegmentCount() - 1; ++i)
total += CornerCost(aLine.CSegment(i), aLine.CSegment(i + 1)); for( int i = 0; i < aLine.SegmentCount() - 1; ++i )
total += CornerCost( aLine.CSegment( i ), aLine.CSegment( i + 1 ) );
return total; return total;
} }
int PNS_COST_ESTIMATOR::CornerCost ( const PNS_LINE& aLine ) int PNS_COST_ESTIMATOR::CornerCost( const PNS_LINE& aLine )
{ {
return CornerCost(aLine.GetCLine()); return CornerCost( aLine.GetCLine() );
} }
void PNS_COST_ESTIMATOR::Add(PNS_LINE &aLine)
void PNS_COST_ESTIMATOR::Add( PNS_LINE& aLine )
{ {
m_lengthCost += aLine.GetCLine().Length(); m_lengthCost += aLine.GetCLine().Length();
m_cornerCost += CornerCost(aLine); m_cornerCost += CornerCost( aLine );
} }
void PNS_COST_ESTIMATOR::Remove(PNS_LINE &aLine)
void PNS_COST_ESTIMATOR::Remove( PNS_LINE& aLine )
{ {
m_lengthCost -= aLine.GetCLine().Length(); m_lengthCost -= aLine.GetCLine().Length();
m_cornerCost -= CornerCost(aLine); m_cornerCost -= CornerCost( aLine );
} }
void PNS_COST_ESTIMATOR::Replace(PNS_LINE &aOldLine, PNS_LINE& aNewLine)
void PNS_COST_ESTIMATOR::Replace( PNS_LINE& aOldLine, PNS_LINE& aNewLine )
{ {
m_lengthCost -= aOldLine.GetCLine().Length(); m_lengthCost -= aOldLine.GetCLine().Length();
m_cornerCost -= CornerCost(aOldLine); m_cornerCost -= CornerCost( aOldLine );
m_lengthCost += aNewLine.GetCLine().Length(); m_lengthCost += aNewLine.GetCLine().Length();
m_cornerCost += CornerCost(aNewLine); m_cornerCost += CornerCost( aNewLine );
} }
bool PNS_COST_ESTIMATOR::IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTollerance, double aCornerTollerance ) const 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) if( aOther.m_cornerCost < m_cornerCost && aOther.m_lengthCost < m_lengthCost )
return true; return true;
else if(aOther.m_cornerCost < m_cornerCost * aCornerTollerance && aOther.m_lengthCost < m_lengthCost * aLengthTollerance)
else if( aOther.m_cornerCost < m_cornerCost * aCornerTollerance && aOther.m_lengthCost <
m_lengthCost * aLengthTollerance )
return true; return true;
return false; return false;
...@@ -104,133 +119,139 @@ bool PNS_COST_ESTIMATOR::IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTol ...@@ -104,133 +119,139 @@ bool PNS_COST_ESTIMATOR::IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTol
/** /**
*
Optimizer * Optimizer
*
**/ **/
PNS_OPTIMIZER::PNS_OPTIMIZER( PNS_NODE* aWorld ) :
m_world( aWorld ), m_collisionKindMask( PNS_ITEM::ANY ), m_effortLevel( MERGE_SEGMENTS )
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_ITEM*>(); // m_cache = new SHAPE_INDEX_LIST<PNS_ITEM*>();
} }
PNS_OPTIMIZER::~PNS_OPTIMIZER ( ) PNS_OPTIMIZER::~PNS_OPTIMIZER()
{ {
//delete m_cache; // delete m_cache;
} }
struct PNS_OPTIMIZER::CacheVisitor struct PNS_OPTIMIZER::CacheVisitor
{ {
CacheVisitor( const PNS_ITEM* aOurItem, PNS_NODE* aNode, int aMask ) :
CacheVisitor( const PNS_ITEM * aOurItem, PNS_NODE *aNode, int aMask ) : m_ourItem( aOurItem ),
m_ourItem(aOurItem), m_collidingItem( NULL ),
m_collidingItem(NULL), m_node( aNode ),
m_node(aNode), m_mask( aMask )
m_mask(aMask)
{}; {};
bool operator() (PNS_ITEM *aOtherItem) bool operator()( PNS_ITEM* aOtherItem )
{ {
if(! m_mask & aOtherItem->GetKind()) if( !m_mask & aOtherItem->GetKind() )
return true; return true;
int clearance = m_node->GetClearance(aOtherItem, m_ourItem); int clearance = m_node->GetClearance( aOtherItem, m_ourItem );
if(!aOtherItem->Collide(m_ourItem, clearance)) if( !aOtherItem->Collide( m_ourItem, clearance ) )
return true; return true;
m_collidingItem = aOtherItem; m_collidingItem = aOtherItem;
return false; return false;
} }
const PNS_ITEM *m_ourItem; const PNS_ITEM* m_ourItem;
PNS_ITEM *m_collidingItem; PNS_ITEM* m_collidingItem;
PNS_NODE *m_node; PNS_NODE* m_node;
int m_mask; int m_mask;
}; };
void PNS_OPTIMIZER::cacheAdd( PNS_ITEM *aItem, bool aIsStatic = false)
void PNS_OPTIMIZER::cacheAdd( PNS_ITEM* aItem, bool aIsStatic = false )
{ {
if(m_cacheTags.find(aItem) != m_cacheTags.end()) if( m_cacheTags.find( aItem ) != m_cacheTags.end() )
return; return;
m_cache.Add(aItem); m_cache.Add( aItem );
m_cacheTags[aItem].hits = 1; m_cacheTags[aItem].hits = 1;
m_cacheTags[aItem].isStatic = aIsStatic; 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<PNS_SEGMENT *> *segs = aLine->GetLinkedSegments(); std::vector<PNS_SEGMENT*>* segs = aLine->GetLinkedSegments();
if(!segs) if( !segs )
return; return;
if(aEndVertex < 0) if( aEndVertex < 0 )
aEndVertex += aLine->GetCLine().PointCount(); aEndVertex += aLine->GetCLine().PointCount();
for(int i = aStartVertex; i < aEndVertex - 1; i++) for( int i = aStartVertex; i < aEndVertex - 1; i++ )
{ {
PNS_SEGMENT *s = (*segs)[i]; PNS_SEGMENT* s = (*segs)[i];
m_cacheTags.erase(s); m_cacheTags.erase( s );
m_cache.Remove(s); m_cache.Remove( s );
}//*cacheRemove( (*segs)[i] ); } // *cacheRemove( (*segs)[i] );
} }
void PNS_OPTIMIZER::CacheRemove ( PNS_ITEM *aItem )
void PNS_OPTIMIZER::CacheRemove( PNS_ITEM* aItem )
{ {
if(aItem->GetKind() == PNS_ITEM::LINE) if( aItem->GetKind() == PNS_ITEM::LINE )
removeCachedSegments(static_cast<PNS_LINE *> (aItem)); removeCachedSegments( static_cast<PNS_LINE*> (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 ) void PNS_OPTIMIZER::ClearCache( bool aStaticOnly )
{ {
if(!aStaticOnly) if( !aStaticOnly )
{ {
m_cacheTags.clear(); m_cacheTags.clear();
m_cache.Clear(); m_cache.Clear();
return; return;
} }
for(CachedItemTags::iterator i = m_cacheTags.begin(); i!= m_cacheTags.end(); ++i) for( CachedItemTags::iterator i = m_cacheTags.begin(); i!= m_cacheTags.end(); ++i )
{ {
if(i->second.isStatic) if( i->second.isStatic )
{ {
m_cache.Remove(i->first); m_cache.Remove( i->first );
m_cacheTags.erase(i->first); m_cacheTags.erase( i->first );
} }
} }
} }
bool PNS_OPTIMIZER::checkColliding ( PNS_ITEM *aItem, bool aUpdateCache )
bool PNS_OPTIMIZER::checkColliding( PNS_ITEM* aItem, bool aUpdateCache )
{ {
CacheVisitor v(aItem, m_world, m_collisionKindMask); CacheVisitor v( aItem, m_world, m_collisionKindMask );
return m_world->CheckColliding(aItem); return m_world->CheckColliding( aItem );
// something is wrong with the cache, need to investigate. // something is wrong with the cache, need to investigate.
m_cache.Query(aItem->GetShape(), m_world->GetMaxClearance(), v, false); m_cache.Query( aItem->GetShape(), m_world->GetMaxClearance(), v, false );
if(!v.m_collidingItem) if( !v.m_collidingItem )
{ {
PNS_NODE::OptObstacle obs = m_world->CheckColliding(aItem); PNS_NODE::OptObstacle obs = m_world->CheckColliding( aItem );
if(obs) { if( obs )
{
if( aUpdateCache )
cacheAdd( obs->item );
if(aUpdateCache)
cacheAdd(obs->item);
return true; return true;
} }
} else { }
else
{
m_cacheTags[v.m_collidingItem].hits++; m_cacheTags[v.m_collidingItem].hits++;
return true; return true;
} }
...@@ -238,34 +259,38 @@ bool PNS_OPTIMIZER::checkColliding ( PNS_ITEM *aItem, bool aUpdateCache ) ...@@ -238,34 +259,38 @@ bool PNS_OPTIMIZER::checkColliding ( PNS_ITEM *aItem, bool aUpdateCache )
return false; return false;
} }
bool PNS_OPTIMIZER::checkColliding( PNS_LINE *aLine, const SHAPE_LINE_CHAIN& aOptPath )
bool PNS_OPTIMIZER::checkColliding( PNS_LINE* aLine, const SHAPE_LINE_CHAIN& aOptPath )
{ {
PNS_LINE tmp(*aLine, aOptPath); PNS_LINE tmp( *aLine, aOptPath );
return checkColliding(&tmp);
return checkColliding( &tmp );
} }
bool PNS_OPTIMIZER::mergeObtuse (PNS_LINE *aLine)
bool PNS_OPTIMIZER::mergeObtuse( PNS_LINE* aLine )
{ {
SHAPE_LINE_CHAIN &line = aLine->GetLine(); SHAPE_LINE_CHAIN& line = aLine->GetLine();
int step = line.PointCount() - 3; int step = line.PointCount() - 3;
int iter = 0; int iter = 0;
int segs_pre = line.SegmentCount(); int segs_pre = line.SegmentCount();
if(step < 0) if( step < 0 )
return false; return false;
SHAPE_LINE_CHAIN current_path (line); SHAPE_LINE_CHAIN current_path( line );
while(1) while( 1 )
{ {
iter++; iter++;
int n_segs = current_path.SegmentCount(); int n_segs = current_path.SegmentCount();
int max_step = n_segs - 2; int max_step = n_segs - 2;
if(step > max_step)
if( step > max_step )
step = max_step; step = max_step;
if(step < 2) if( step < 2 )
{ {
line = current_path; line = current_path;
return current_path.SegmentCount() < segs_pre; return current_path.SegmentCount() < segs_pre;
...@@ -274,103 +299,107 @@ bool PNS_OPTIMIZER::mergeObtuse (PNS_LINE *aLine) ...@@ -274,103 +299,107 @@ bool PNS_OPTIMIZER::mergeObtuse (PNS_LINE *aLine)
bool found_anything = false; bool found_anything = false;
int n = 0; int n = 0;
while (n < n_segs - step) while( n < n_segs - step )
{ {
const SEG s1 = current_path.CSegment(n); const SEG s1 = current_path.CSegment( n );
const SEG s2 = current_path.CSegment(n + step); const SEG s2 = current_path.CSegment( n + step );
SEG s1opt, s2opt; SEG s1opt, s2opt;
if (DIRECTION_45(s1).IsObtuse(DIRECTION_45(s2))) if( DIRECTION_45( s1 ).IsObtuse( DIRECTION_45( s2 ) ) )
{ {
VECTOR2I ip = *s1.IntersectLines(s2); VECTOR2I ip = *s1.IntersectLines( s2 );
if(s1.Distance(ip) <= 1 || s2.Distance(ip) <= 1) if( s1.Distance( ip ) <= 1 || s2.Distance( ip ) <= 1 )
{ {
s1opt = SEG(s1.a, ip); s1opt = SEG( s1.a, ip );
s2opt = SEG(ip, s2.b); s2opt = SEG( ip, s2.b );
} else { }
s1opt = SEG(s1.a, ip); else
s2opt = SEG(ip, s2.b); {
s1opt = SEG( s1.a, ip );
s2opt = SEG( ip, s2.b );
} }
if (DIRECTION_45(s1opt).IsObtuse(DIRECTION_45(s2opt))) if( DIRECTION_45( s1opt ).IsObtuse( DIRECTION_45( s2opt ) ) )
{ {
SHAPE_LINE_CHAIN opt_path; SHAPE_LINE_CHAIN opt_path;
opt_path.Append(s1opt.a); opt_path.Append( s1opt.a );
opt_path.Append(s1opt.b); opt_path.Append( s1opt.b );
opt_path.Append(s2opt.b); opt_path.Append( s2opt.b );
PNS_LINE opt_track (*aLine, opt_path); PNS_LINE opt_track( *aLine, opt_path );
if(!checkColliding(&opt_track)) if( !checkColliding( &opt_track ) )
{ {
current_path.Replace(s1.Index() + 1, s2.Index(), ip); current_path.Replace( s1.Index() + 1, s2.Index(), ip );
//removeCachedSegments(aLine, s1.Index(), s2.Index()); // removeCachedSegments(aLine, s1.Index(), s2.Index());
n_segs = current_path.SegmentCount(); n_segs = current_path.SegmentCount();
found_anything = true; found_anything = true;
break; break;
} }
} }
} }
n++; n++;
} }
if(!found_anything) if( !found_anything )
{ {
if( step <= 2 ) if( step <= 2 )
{ {
line = current_path; line = current_path;
return line.SegmentCount() < segs_pre; return line.SegmentCount() < segs_pre;
} }
step --;
step--;
} }
} }
return line.SegmentCount() < segs_pre; return line.SegmentCount() < segs_pre;
} }
bool PNS_OPTIMIZER::mergeFull(PNS_LINE *aLine) bool PNS_OPTIMIZER::mergeFull( PNS_LINE* aLine )
{ {
SHAPE_LINE_CHAIN &line = aLine->GetLine(); SHAPE_LINE_CHAIN& line = aLine->GetLine();
int step = line.SegmentCount() - 1; int step = line.SegmentCount() - 1;
int segs_pre = line.SegmentCount(); int segs_pre = line.SegmentCount();
line.Simplify(); line.Simplify();
if(step < 0) if( step < 0 )
return false; return false;
SHAPE_LINE_CHAIN current_path (line); SHAPE_LINE_CHAIN current_path( line );
while(1) while( 1 )
{ {
int n_segs = current_path.SegmentCount(); int n_segs = current_path.SegmentCount();
int max_step = n_segs - 2; int max_step = n_segs - 2;
if(step > max_step) if( step > max_step )
step = max_step; step = max_step;
if(step < 1) if( step < 1 )
break; break;
bool found_anything = mergeStep(aLine, current_path, step); bool found_anything = mergeStep( aLine, current_path, step );
if(!found_anything)
step --;
if( !found_anything )
step--;
} }
aLine->SetShape(current_path); aLine->SetShape( current_path );
return current_path.SegmentCount() < segs_pre; return current_path.SegmentCount() < segs_pre;
} }
bool PNS_OPTIMIZER::Optimize ( PNS_LINE *aLine, PNS_LINE *aResult , int aStartVertex , int aEndVertex )
bool PNS_OPTIMIZER::Optimize( PNS_LINE* aLine, PNS_LINE* aResult, int aStartVertex, int aEndVertex )
{ {
if(!aResult) if( !aResult )
aResult = aLine; aResult = aLine;
else else
*aResult = *aLine; *aResult = *aLine;
...@@ -378,99 +407,107 @@ bool PNS_OPTIMIZER::Optimize ( PNS_LINE *aLine, PNS_LINE *aResult , int aStartVe ...@@ -378,99 +407,107 @@ bool PNS_OPTIMIZER::Optimize ( PNS_LINE *aLine, PNS_LINE *aResult , int aStartVe
m_keepPostures = false; m_keepPostures = false;
bool rv = false; bool rv = false;
if(m_effortLevel & MERGE_SEGMENTS)
rv |= mergeFull(aResult); if( m_effortLevel & MERGE_SEGMENTS )
if(m_effortLevel & MERGE_OBTUSE) rv |= mergeFull( aResult );
rv |= mergeObtuse(aResult);
if(m_effortLevel & SMART_PADS) if( m_effortLevel & MERGE_OBTUSE )
rv |= runSmartPads(aResult); rv |= mergeObtuse( aResult );
if( m_effortLevel & SMART_PADS )
rv |= runSmartPads( aResult );
return rv; return rv;
} }
bool PNS_OPTIMIZER::mergeStep ( PNS_LINE *aLine, SHAPE_LINE_CHAIN& aCurrentPath, int step ) bool PNS_OPTIMIZER::mergeStep( PNS_LINE* aLine, SHAPE_LINE_CHAIN& aCurrentPath, int step )
{ {
int n = 0; int n = 0;
int n_segs = aCurrentPath.SegmentCount(); int n_segs = aCurrentPath.SegmentCount();
int cost_orig = PNS_COST_ESTIMATOR::CornerCost(aCurrentPath); int cost_orig = PNS_COST_ESTIMATOR::CornerCost( aCurrentPath );
if(aLine->GetCLine().SegmentCount() < 4) if( aLine->GetCLine().SegmentCount() < 4 )
return false; return false;
DIRECTION_45 orig_start (aLine->GetCLine().CSegment(0)); DIRECTION_45 orig_start( aLine->GetCLine().CSegment( 0 ) );
DIRECTION_45 orig_end (aLine->GetCLine().CSegment(-1)); DIRECTION_45 orig_end( aLine->GetCLine().CSegment( -1 ) );
while (n < n_segs - step ) while( n < n_segs - step )
{ {
const SEG s1 = aCurrentPath.CSegment(n); const SEG s1 = aCurrentPath.CSegment( n );
const SEG s2 = aCurrentPath.CSegment(n + step); const SEG s2 = aCurrentPath.CSegment( n + step );
SHAPE_LINE_CHAIN path[2], *picked = NULL; SHAPE_LINE_CHAIN path[2], * picked = NULL;
int cost[2]; int cost[2];
for(int i = 0; i < 2; i++) for( int i = 0; i < 2; i++ )
{ {
bool postureMatch = true; bool postureMatch = true;
SHAPE_LINE_CHAIN bypass = DIRECTION_45().BuildInitialTrace(s1.a, s2.b, i); SHAPE_LINE_CHAIN bypass = DIRECTION_45().BuildInitialTrace( s1.a, s2.b, i );
cost[i] = INT_MAX; cost[i] = INT_MAX;
if ( n == 0 && orig_start != DIRECTION_45( bypass.CSegment(0) ) ) if( n == 0 && orig_start != DIRECTION_45( bypass.CSegment( 0 ) ) )
postureMatch = false; postureMatch = false;
else if (n == n_segs-step && orig_end != DIRECTION_45( bypass.CSegment(-1))) else if( n == n_segs - step && orig_end != DIRECTION_45( bypass.CSegment( -1 ) ) )
postureMatch = false; postureMatch = false;
if((postureMatch || !m_keepPostures) && !checkColliding(aLine, bypass)) if( (postureMatch || !m_keepPostures) && !checkColliding( aLine, bypass ) )
{ {
path[i] = aCurrentPath; path[i] = aCurrentPath;
path[i].Replace(s1.Index(), s2.Index(), bypass); path[i].Replace( s1.Index(), s2.Index(), bypass );
path[i].Simplify(); path[i].Simplify();
cost[i] = PNS_COST_ESTIMATOR::CornerCost(path[i]); cost[i] = PNS_COST_ESTIMATOR::CornerCost( path[i] );
} }
} }
if(cost[0] < cost_orig && cost[0] < cost[1]) if( cost[0] < cost_orig && cost[0] < cost[1] )
picked = &path[0]; picked = &path[0];
else if (cost[1] < cost_orig) else if( cost[1] < cost_orig )
picked = &path[1]; picked = &path[1];
if(picked) if( picked )
{ {
n_segs = aCurrentPath.SegmentCount(); n_segs = aCurrentPath.SegmentCount();
aCurrentPath = *picked; aCurrentPath = *picked;
return true; return true;
} }
n++; n++;
} }
return false; return false;
} }
PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::circleBreakouts( int aWidth, const SHAPE *aShape, bool aPermitDiagonal ) const
PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::circleBreakouts( int aWidth,
const SHAPE* aShape, bool aPermitDiagonal ) const
{ {
BreakoutList breakouts; BreakoutList breakouts;
for(int angle = 0; angle < 360; angle += 45) for( int angle = 0; angle < 360; angle += 45 )
{ {
const SHAPE_CIRCLE *cir = static_cast<const SHAPE_CIRCLE *> (aShape); const SHAPE_CIRCLE* cir = static_cast<const SHAPE_CIRCLE*>( aShape );
SHAPE_LINE_CHAIN l; SHAPE_LINE_CHAIN l;
VECTOR2I p0 = cir->GetCenter (); VECTOR2I p0 = cir->GetCenter();
VECTOR2I v0 (cir->GetRadius() * M_SQRT2, 0); VECTOR2I v0( cir->GetRadius() * M_SQRT2, 0 );
l.Append ( p0 ); l.Append( p0 );
l.Append ( p0 + v0.Rotate ( angle * M_PI / 180.0 ) ); l.Append( p0 + v0.Rotate( angle * M_PI / 180.0 ) );
breakouts.push_back(l); breakouts.push_back( l );
} }
return breakouts; return breakouts;
} }
PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth, const SHAPE *aShape, bool aPermitDiagonal ) const PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth,
const SHAPE* aShape, bool aPermitDiagonal ) const
{ {
const SHAPE_RECT *rect = static_cast<const SHAPE_RECT *>(aShape); const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>(aShape);
VECTOR2I s = rect->GetSize(), c = rect->GetPosition() + VECTOR2I (s.x / 2, s.y / 2); VECTOR2I s = rect->GetSize(), c = rect->GetPosition() + VECTOR2I( s.x / 2, s.y / 2 );
BreakoutList breakouts; BreakoutList breakouts;
VECTOR2I d_offset; VECTOR2I d_offset;
...@@ -478,33 +515,42 @@ PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth, const SHAP ...@@ -478,33 +515,42 @@ PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth, const SHAP
d_offset.x = (s.x > s.y) ? (s.x - s.y) / 2 : 0; 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; d_offset.y = (s.x < s.y) ? (s.y - s.x) / 2 : 0;
VECTOR2I d_vert = VECTOR2I ( 0, s.y / 2 + aWidth); VECTOR2I d_vert = VECTOR2I( 0, s.y / 2 + aWidth );
VECTOR2I d_horiz = VECTOR2I ( s.x / 2 + aWidth, 0); 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_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 ) );
breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c - d_vert ) ); breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_vert ) );
if(aPermitDiagonal) if( aPermitDiagonal )
{ {
int l = aWidth + std::min(s.x, s.y) / 2; int l = aWidth + std::min( s.x, s.y ) / 2;
VECTOR2I d_diag ; VECTOR2I d_diag;
if(s.x >= s.y) 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
{ {
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 // 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,
breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c - d_offset, c - d_offset - VECTOR2I(-l, l))); 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,
breakouts.push_back ( SHAPE_LINE_CHAIN ( c, c - d_offset, c - d_offset - VECTOR2I(l, l))); 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 ) ) );
} }
} }
...@@ -512,114 +558,123 @@ PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth, const SHAP ...@@ -512,114 +558,123 @@ PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth, const SHAP
} }
PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::computeBreakouts( int aWidth,
PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::computeBreakouts( int aWidth, const PNS_ITEM *aItem, bool aPermitDiagonal ) const const PNS_ITEM* aItem, bool aPermitDiagonal ) const
{ {
switch(aItem->GetKind()) switch( aItem->GetKind() )
{ {
case PNS_ITEM::VIA: case PNS_ITEM::VIA:
{ {
const PNS_VIA *via = static_cast<const PNS_VIA *> (aItem); const PNS_VIA* via = static_cast<const PNS_VIA*>( aItem );
return circleBreakouts ( aWidth, via->GetShape(), aPermitDiagonal ); return circleBreakouts( aWidth, via->GetShape(), aPermitDiagonal );
} }
case PNS_ITEM::SOLID: case PNS_ITEM::SOLID:
{ {
const SHAPE *shape = aItem->GetShape(); const SHAPE* shape = aItem->GetShape();
switch(shape->Type())
switch( shape->Type() )
{ {
case SH_RECT: case SH_RECT:
return rectBreakouts (aWidth, shape, aPermitDiagonal); return rectBreakouts( aWidth, shape, aPermitDiagonal );
case SH_CIRCLE: case SH_CIRCLE:
return circleBreakouts (aWidth, shape, aPermitDiagonal); return circleBreakouts( aWidth, shape, aPermitDiagonal );
default: default:
break; break;
} }
} }
default: default:
break; break;
} }
return BreakoutList(); return BreakoutList();
} }
PNS_ITEM *PNS_OPTIMIZER::findPadOrVia ( int aLayer, int aNet, const VECTOR2I& aP) const
PNS_ITEM* PNS_OPTIMIZER::findPadOrVia( int aLayer, int aNet, const VECTOR2I& aP ) const
{ {
PNS_NODE::OptJoint jt = m_world->FindJoint ( aP, aLayer, aNet ); PNS_NODE::OptJoint jt = m_world->FindJoint( aP, aLayer, aNet );
if(!jt)
if( !jt )
return NULL; return NULL;
BOOST_FOREACH (PNS_ITEM *item, jt->GetLinkList() ) BOOST_FOREACH( PNS_ITEM * item, jt->GetLinkList() )
{ {
if(item->GetKind() == PNS_ITEM::VIA || item->GetKind() == PNS_ITEM::SOLID) if( item->GetKind() == PNS_ITEM::VIA || item->GetKind() == PNS_ITEM::SOLID )
return item; return item;
} }
return NULL; return NULL;
} }
int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE *aLine, PNS_ITEM *aPad, bool aEnd, int aEndVertex )
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_cost = INT_MAX; // PNS_COST_ESTIMATOR::CornerCost( line );
int min_len = INT_MAX; int min_len = INT_MAX;
DIRECTION_45 dir; DIRECTION_45 dir;
const int ForbiddenAngles = DIRECTION_45::ANG_ACUTE | DIRECTION_45::ANG_RIGHT | DIRECTION_45::ANG_HALF_FULL | DIRECTION_45::ANG_UNDEFINED; const int ForbiddenAngles = DIRECTION_45::ANG_ACUTE | DIRECTION_45::ANG_RIGHT |
DIRECTION_45::ANG_HALF_FULL | DIRECTION_45::ANG_UNDEFINED;
typedef pair<int, SHAPE_LINE_CHAIN> RtVariant; typedef pair<int, SHAPE_LINE_CHAIN> RtVariant;
vector<RtVariant> variants; vector<RtVariant> variants;
BreakoutList breakouts = computeBreakouts( aLine->GetWidth(), aPad, true ); BreakoutList breakouts = computeBreakouts( aLine->GetWidth(), aPad, true );
SHAPE_LINE_CHAIN line = (aEnd ? aLine->GetCLine().Reverse() : aLine->GetCLine()); SHAPE_LINE_CHAIN line = ( aEnd ? aLine->GetCLine().Reverse() : aLine->GetCLine() );
//bool startDiagonal = DIRECTION_45( line.CSegment(0) ).IsDiagonal(); // bool startDiagonal = DIRECTION_45( line.CSegment(0) ).IsDiagonal();
int p_end = min (aEndVertex, min (3 , line.PointCount() - 1)); int p_end = min( aEndVertex, min( 3, line.PointCount() - 1 ) );
for (int p = 1; p <= p_end; p++) for( int p = 1; p <= p_end; p++ )
{
BOOST_FOREACH(SHAPE_LINE_CHAIN& l, breakouts)
{ {
//PNSDisplayDebugLine (l, 0); BOOST_FOREACH( SHAPE_LINE_CHAIN & l, breakouts ) {
// PNSDisplayDebugLine (l, 0);
for(int diag = 0; diag < 2; diag++) for( int diag = 0; diag < 2; diag++ )
{ {
SHAPE_LINE_CHAIN v; SHAPE_LINE_CHAIN v;
SHAPE_LINE_CHAIN connect = dir.BuildInitialTrace( l.CPoint(-1), line.CPoint(p), diag == 0); SHAPE_LINE_CHAIN connect = dir.BuildInitialTrace( l.CPoint( -1 ),
line.CPoint( p ), diag == 0 );
DIRECTION_45 dir_bkout ( l.CSegment(-1 )); DIRECTION_45 dir_bkout( l.CSegment( -1 ) );
//DIRECTION_45 dir_head ( line.CSegment(p + 1)); // DIRECTION_45 dir_head ( line.CSegment(p + 1));
int ang1 = dir_bkout.Angle ( DIRECTION_45(connect.CSegment(0) )); int ang1 = dir_bkout.Angle( DIRECTION_45( connect.CSegment( 0 ) ) );
int ang2 = 0; int ang2 = 0;
//int ang2 = dir_head.Angle ( DIRECTION_45(connect.CSegment(-1) )); // int ang2 = dir_head.Angle ( DIRECTION_45(connect.CSegment(-1) ));
if( (ang1 | ang2) & ForbiddenAngles ) if( (ang1 | ang2) & ForbiddenAngles )
continue; continue;
if(l.Length() > line.Length()) if( l.Length() > line.Length() )
continue; continue;
v = l; v = l;
v.Append ( connect ); v.Append( connect );
for(int i = p + 1; i < line.PointCount(); i++) for( int i = p + 1; i < line.PointCount(); i++ )
v.Append( line.CPoint(i) ); v.Append( line.CPoint( i ) );
PNS_LINE tmp(*aLine, v); PNS_LINE tmp( *aLine, v );
//tmp.GetLine().Simplify(); // tmp.GetLine().Simplify();
int cc = tmp.CountCorners(ForbiddenAngles); int cc = tmp.CountCorners( ForbiddenAngles );
if(cc == 0) if( cc == 0 )
{ {
RtVariant vp; RtVariant vp;
vp.first = p; vp.first = p;
vp.second = aEnd ? v.Reverse() : v; vp.second = aEnd ? v.Reverse() : v;
vp.second.Simplify(); vp.second.Simplify();
variants.push_back(vp); variants.push_back( vp );
} }
} }
} }
} }
...@@ -628,37 +683,35 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE *aLine, PNS_ITEM *aPad, bool aEnd, ...@@ -628,37 +683,35 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE *aLine, PNS_ITEM *aPad, bool aEnd,
bool found = false; bool found = false;
int p_best = -1; int p_best = -1;
BOOST_FOREACH(RtVariant& vp, variants) BOOST_FOREACH( RtVariant & vp, variants )
{ {
PNS_LINE tmp (*aLine, vp.second); PNS_LINE tmp( *aLine, vp.second );
int cost = PNS_COST_ESTIMATOR::CornerCost(vp.second); int cost = PNS_COST_ESTIMATOR::CornerCost( vp.second );
int len = vp.second.Length(); int len = vp.second.Length();
if(!checkColliding(&tmp)) if( !checkColliding( &tmp ) )
{ {
/* if(aEnd) /* if(aEnd)
PNSDisplayDebugLine (l_best, 6); * PNSDisplayDebugLine (l_best, 6);
else * else
PNSDisplayDebugLine (l_best, 5);*/ * PNSDisplayDebugLine (l_best, 5);*/
if(cost < min_cost || (cost == min_cost && len < min_len)) if( cost < min_cost || ( cost == min_cost && len < min_len ) )
{ {
l_best = vp.second; l_best = vp.second;
p_best = vp.first; p_best = vp.first;
found = true; found = true;
//if(cost == min_cost) // if(cost == min_cost)
if(cost == min_cost) if( cost == min_cost )
min_len = std::min(len, min_len); min_len = std::min( len, min_len );
min_cost = std::min(cost, min_cost);
}
min_cost = std::min( cost, min_cost );
}
} }
} }
if(found) if( found )
{ {
// printf("end: %d, p-best: %d, p-end: %d, p-total: %d\n", aEnd, p_best, p_end, l_best.PointCount()); // printf("end: %d, p-best: %d, p-end: %d, p-total: %d\n", aEnd, p_best, p_end, l_best.PointCount());
...@@ -666,39 +719,46 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE *aLine, PNS_ITEM *aPad, bool aEnd, ...@@ -666,39 +719,46 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE *aLine, PNS_ITEM *aPad, bool aEnd,
// PNSDisplayDebugLine (l_best, 5); // PNSDisplayDebugLine (l_best, 5);
// else // else
aLine->SetShape(l_best); aLine->SetShape( l_best );
return p_best; return p_best;
} }
return -1; 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) if( line.PointCount() < 3 )
return false; 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* startPad = findPadOrVia( aLine->GetLayer(), aLine->GetNet(), p_start );
PNS_ITEM *endPad = findPadOrVia( aLine->GetLayer(), aLine->GetNet(), p_end); PNS_ITEM* endPad = findPadOrVia( aLine->GetLayer(), aLine->GetNet(), p_end );
int vtx = -1; int vtx = -1;
if(startPad) if( startPad )
vtx = smartPadsSingle(aLine, startPad, false, 3); vtx = smartPadsSingle( aLine, startPad, false, 3 );
if(endPad)
smartPadsSingle(aLine, endPad, true, vtx < 0 ? line.PointCount() - 1 : line.PointCount() - 1 - vtx); if( endPad )
smartPadsSingle( aLine, endPad, true,
vtx < 0 ? line.PointCount() - 1 : line.PointCount() - 1 - vtx );
aLine->GetLine().Simplify(); aLine->GetLine().Simplify();
return true; 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() ); PNS_OPTIMIZER opt( aWorld ? aWorld : aLine->GetWorld() );
opt.SetEffortLevel (aEffortLevel);
opt.SetCollisionMask(-1); opt.SetEffortLevel( aEffortLevel );
return opt.Optimize(aLine); opt.SetCollisionMask( -1 );
return opt.Optimize( aLine );
} }
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License along * You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>. * with this program. If not, see <http://www.gnu.or/licenses/>.
*/ */
#ifndef __PNS_OPTIMIZER_H #ifndef __PNS_OPTIMIZER_H
#define __PNS_OPTIMIZER_H #define __PNS_OPTIMIZER_H
...@@ -30,7 +31,6 @@ class PNS_NODE; ...@@ -30,7 +31,6 @@ class PNS_NODE;
class PNS_LINE; class PNS_LINE;
class PNS_ROUTER; class PNS_ROUTER;
/** /**
* Class PNS_COST_ESTIMATOR * Class PNS_COST_ESTIMATOR
* *
...@@ -39,33 +39,34 @@ class PNS_ROUTER; ...@@ -39,33 +39,34 @@ class PNS_ROUTER;
class PNS_COST_ESTIMATOR class PNS_COST_ESTIMATOR
{ {
public: public:
PNS_COST_ESTIMATOR(): PNS_COST_ESTIMATOR() :
m_lengthCost (0), m_lengthCost( 0 ),
m_cornerCost (0) m_cornerCost( 0 )
{}; {};
PNS_COST_ESTIMATOR(const PNS_COST_ESTIMATOR &b): PNS_COST_ESTIMATOR( const PNS_COST_ESTIMATOR& b ) :
m_lengthCost (b.m_lengthCost), m_lengthCost( b.m_lengthCost ),
m_cornerCost (b.m_cornerCost) m_cornerCost( b.m_cornerCost )
{}; {};
~PNS_COST_ESTIMATOR() {}; ~PNS_COST_ESTIMATOR() {};
static int CornerCost ( const SEG& a, const SEG& b); static int CornerCost( const SEG& a, const SEG& b );
static int CornerCost ( const SHAPE_LINE_CHAIN& aLine ); static int CornerCost( const SHAPE_LINE_CHAIN& aLine );
static int CornerCost ( const PNS_LINE& aLine); static int CornerCost( const PNS_LINE& aLine );
void Add(PNS_LINE &aLine); void Add( PNS_LINE& aLine );
void Remove (PNS_LINE &aLine); void Remove( PNS_LINE& aLine );
void Replace(PNS_LINE &aOldLine, PNS_LINE& aNewLine); void Replace( PNS_LINE& aOldLine, PNS_LINE& aNewLine );
bool IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTollerance, double aCornerTollerace ) const; bool IsBetter( PNS_COST_ESTIMATOR& aOther, double aLengthTollerance,
double aCornerTollerace ) const;
double GetLengthCost() const { return m_lengthCost; } double GetLengthCost() const { return m_lengthCost; }
double GetCornerCost() const { return m_cornerCost; } double GetCornerCost() const { return m_cornerCost; }
private: private:
double m_lengthCost; double m_lengthCost;
int m_cornerCost; int m_cornerCost;
}; };
...@@ -84,39 +85,39 @@ class PNS_COST_ESTIMATOR ...@@ -84,39 +85,39 @@ class PNS_COST_ESTIMATOR
class PNS_OPTIMIZER class PNS_OPTIMIZER
{ {
public: public:
enum OptimizationEffort
enum OptimizationEffort { {
MERGE_SEGMENTS = 0x1, MERGE_SEGMENTS = 0x01,
SMART_PADS = 0x2, SMART_PADS = 0x02,
MERGE_OBTUSE = 0x4 MERGE_OBTUSE = 0x04
}; };
PNS_OPTIMIZER( PNS_NODE *aWorld ); PNS_OPTIMIZER( PNS_NODE* aWorld );
~PNS_OPTIMIZER(); ~PNS_OPTIMIZER();
///> a quick shortcut to optmize a line without creating and setting up an 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 ); 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 SetWorld( PNS_NODE* aNode ) { m_world = aNode; }
void CacheStaticItem (PNS_ITEM *aItem); void CacheStaticItem( PNS_ITEM* aItem );
void CacheRemove( PNS_ITEM *aItem ); void CacheRemove( PNS_ITEM* aItem );
void ClearCache( bool aStaticOnly = false ); void ClearCache( bool aStaticOnly = false );
void SetCollisionMask ( int aMask ) void SetCollisionMask( int aMask )
{ {
m_collisionKindMask = aMask; m_collisionKindMask = aMask;
} }
void SetEffortLevel ( int aEffort ) void SetEffortLevel( int aEffort )
{ {
m_effortLevel = aEffort; m_effortLevel = aEffort;
} }
private: private:
static const int MaxCachedItems = 256; static const int MaxCachedItems = 256;
typedef std::vector<SHAPE_LINE_CHAIN> BreakoutList; typedef std::vector<SHAPE_LINE_CHAIN> BreakoutList;
...@@ -129,36 +130,38 @@ class PNS_OPTIMIZER ...@@ -129,36 +130,38 @@ class PNS_OPTIMIZER
bool isStatic; bool isStatic;
}; };
bool mergeObtuse (PNS_LINE *aLine); bool mergeObtuse( PNS_LINE* aLine );
bool mergeFull (PNS_LINE *aLine); bool mergeFull( PNS_LINE* aLine );
bool removeUglyCorners (PNS_LINE *aLine); bool removeUglyCorners( PNS_LINE* aLine );
bool runSmartPads(PNS_LINE *aLine); bool runSmartPads( PNS_LINE* aLine );
bool mergeStep ( PNS_LINE *aLine, SHAPE_LINE_CHAIN& aCurrentLine, int step ); bool mergeStep( PNS_LINE* aLine, SHAPE_LINE_CHAIN& aCurrentLine, int step );
bool checkColliding( PNS_ITEM *aItem, bool aUpdateCache = true ); bool checkColliding( PNS_ITEM* aItem, bool aUpdateCache = true );
bool checkColliding( PNS_LINE *aLine, const SHAPE_LINE_CHAIN& aOptPath ); bool checkColliding( PNS_LINE* aLine, const SHAPE_LINE_CHAIN& aOptPath );
void cacheAdd( PNS_ITEM *aItem, bool aIsStatic ); void cacheAdd( PNS_ITEM* aItem, bool aIsStatic );
void removeCachedSegments (PNS_LINE *aLine, int aStartVertex = 0, int aEndVertex = -1); void removeCachedSegments( PNS_LINE* aLine, int aStartVertex = 0, int aEndVertex = -1 );
BreakoutList circleBreakouts( int aWidth, const SHAPE *aShape, bool aPermitDiagonal ) const; BreakoutList circleBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const;
BreakoutList rectBreakouts( 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 ovalBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const;
BreakoutList computeBreakouts( int aWidth, const PNS_ITEM *aItem, 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<PNS_ITEM *> m_cache; SHAPE_INDEX_LIST<PNS_ITEM*> m_cache;
typedef boost::unordered_map<PNS_ITEM*, CachedItem> CachedItemTags; typedef boost::unordered_map<PNS_ITEM*, CachedItem> CachedItemTags;
CachedItemTags m_cacheTags; CachedItemTags m_cacheTags;
PNS_NODE *m_world; PNS_NODE* m_world;
int m_collisionKindMask; int m_collisionKindMask;
int m_effortLevel; int m_effortLevel;
bool m_keepPostures; bool m_keepPostures;
}; };
#endif #endif
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License along * You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>. * with this program. If not, see <http://www.gnu.or/licenses/>.
*/ */
#include <cstdio> #include <cstdio>
#include <vector> #include <vector>
...@@ -52,216 +53,227 @@ ...@@ -52,216 +53,227 @@
using namespace std; using namespace std;
// an ugly singleton for drawing debug items within the router context. To be fixed sometime in the future. // an ugly singleton for drawing debug items within the router context.
static PNS_ROUTER *theRouter; // 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: public:
PCBNEW_CLEARANCE_FUNC( BOARD *aBoard ) PCBNEW_CLEARANCE_FUNC( BOARD* aBoard )
{ {
m_clearanceCache.resize(aBoard->GetNetCount()); m_clearanceCache.resize( aBoard->GetNetCount() );
for(unsigned int i = 0; i < aBoard->GetNetCount(); i++) for( unsigned int i = 0; i < aBoard->GetNetCount(); i++ )
{ {
NETINFO_ITEM *ni = aBoard->FindNet(i); NETINFO_ITEM* ni = aBoard->FindNet( i );
wxString netClassName = ni->GetClassName(); wxString netClassName = ni->GetClassName();
NETCLASS *nc = aBoard->m_NetClasses.Find(netClassName); NETCLASS* nc = aBoard->m_NetClasses.Find( netClassName );
int clearance = nc->GetClearance(); int clearance = nc->GetClearance();
m_clearanceCache[i] = clearance; m_clearanceCache[i] = clearance;
TRACE(1, "Add net %d netclass %s clearance %d", i % netClassName.mb_str() % 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 operator()( const PNS_ITEM* a, const PNS_ITEM* b )
{ {
int net_a = a->GetNet(); int net_a = a->GetNet();
int cl_a = (net_a >= 0 ? m_clearanceCache[net_a] : m_defaultClearance); int cl_a = (net_a >= 0 ? m_clearanceCache[net_a] : m_defaultClearance);
int net_b = b->GetNet(); int net_b = b->GetNet();
int cl_b = (net_b >= 0 ? m_clearanceCache[net_b] : m_defaultClearance); int cl_b = (net_b >= 0 ? m_clearanceCache[net_b] : m_defaultClearance);
return std::max(cl_a, cl_b);
}
private: return std::max( cl_a, cl_b );
}
private:
vector<int> m_clearanceCache; vector<int> m_clearanceCache;
int m_defaultClearance; 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()) switch( aPad->GetAttribute() )
{ {
case PAD_STANDARD: case PAD_STANDARD:
layers = PNS_LAYERSET(0, 15); layers = PNS_LAYERSET( 0, 15 );
break; break;
case PAD_SMD: case PAD_SMD:
case PAD_CONN: case PAD_CONN:
{ {
LAYER_MSK lmsk = aPad->GetLayerMask(); LAYER_MSK lmsk = aPad->GetLayerMask();
int i; int i;
for(i = FIRST_COPPER_LAYER; i <= LAST_COPPER_LAYER; i++) for( i = FIRST_COPPER_LAYER; i <= LAST_COPPER_LAYER; i++ )
if( lmsk & (1<<i)) if( lmsk & (1 << i) )
{ {
layers = PNS_LAYERSET( i ); layers = PNS_LAYERSET( i );
break; break;
} }
break; break;
} }
default: default:
TRACE(0, "unsupported pad type 0x%x", aPad->GetAttribute()); TRACE( 0, "unsupported pad type 0x%x", aPad->GetAttribute() );
return NULL; return NULL;
} }
PNS_SOLID *solid = new PNS_SOLID; PNS_SOLID* solid = new PNS_SOLID;
solid->SetLayers(layers); solid->SetLayers( layers );
solid->SetNet( aPad->GetNet() ); solid->SetNet( aPad->GetNet() );
wxPoint wx_c = aPad->GetPosition(); wxPoint wx_c = aPad->GetPosition();
wxSize wx_sz = aPad->GetSize(); wxSize wx_sz = aPad->GetSize();
VECTOR2I c(wx_c.x, wx_c.y); VECTOR2I c( wx_c.x, wx_c.y );
VECTOR2I sz(wx_sz.x, wx_sz.y); VECTOR2I sz( wx_sz.x, wx_sz.y );
solid->SetCenter( c ); solid->SetCenter( c );
double orient = aPad->GetOrientation() / 10.0; double orient = aPad->GetOrientation() / 10.0;
if(orient == 90.0 || orient == 270.0) if( orient == 90.0 || orient == 270.0 )
sz = VECTOR2I(sz.y, sz.x); sz = VECTOR2I( sz.y, sz.x );
else if (orient != 0.0 && orient != 180.0) else if( orient != 0.0 && orient != 180.0 )
{ {
TRACEn(0, "non-orthogonal pad rotations not supported yet"); TRACEn( 0, "non-orthogonal pad rotations not supported yet" );
delete solid; delete solid;
return NULL; return NULL;
} }
switch(aPad->GetShape()) switch( aPad->GetShape() )
{ {
case PAD_CIRCLE: case PAD_CIRCLE:
solid->SetShape ( new SHAPE_CIRCLE ( c, sz.x / 2) ); solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
break; break;
case PAD_OVAL: case PAD_OVAL:
if(sz.x == sz.y) if( sz.x == sz.y )
solid->SetShape ( new SHAPE_CIRCLE ( c, sz.x / 2) ); solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
else else
solid->SetShape ( new SHAPE_RECT ( c - sz / 2, sz.x, sz.y) ); solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
break; break;
case PAD_RECT: case PAD_RECT:
solid->SetShape ( new SHAPE_RECT ( c - sz / 2, sz.x, sz.y) ); solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
break; break;
default: default:
TRACEn(0, "unsupported pad shape"); TRACEn( 0, "unsupported pad shape" );
delete solid; delete solid;
return NULL; return NULL;
} }
solid->SetParent( aPad );
solid->SetParent(aPad);
return solid; return solid;
} }
PNS_ITEM *PNS_ROUTER::syncTrack( TRACK *aTrack )
{
PNS_SEGMENT *s = new PNS_SEGMENT( SEG (aTrack->GetStart(), aTrack->GetEnd() ), aTrack->GetNet() ); 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->SetWidth( aTrack->GetWidth() );
s->SetLayers (PNS_LAYERSET(aTrack->GetLayer())); s->SetLayers( PNS_LAYERSET( aTrack->GetLayer() ) );
s->SetParent(aTrack); s->SetParent( aTrack );
return s; return s;
} }
PNS_ITEM *PNS_ROUTER::syncVia( SEGVIA *aVia ) PNS_ITEM* PNS_ROUTER::syncVia( SEGVIA* aVia )
{ {
PNS_VIA *v = new PNS_VIA( PNS_VIA* v = new PNS_VIA(
aVia->GetPosition(), aVia->GetPosition(),
PNS_LAYERSET(0, 15), PNS_LAYERSET( 0, 15 ),
aVia->GetWidth(), aVia->GetWidth(),
aVia->GetNet()); aVia->GetNet() );
v->SetParent(aVia); v->SetParent( aVia );
return v; return v;
} }
void PNS_ROUTER::SetBoard( BOARD *aBoard )
void PNS_ROUTER::SetBoard( BOARD* aBoard )
{ {
m_board = aBoard; m_board = aBoard;
TRACE(1, "m_board = %p\n", m_board); TRACE( 1, "m_board = %p\n", m_board );
} }
int PNS_ROUTER::NextCopperLayer( bool aUp ) int PNS_ROUTER::NextCopperLayer( bool aUp )
{ {
LAYER_MSK mask = m_board->GetEnabledLayers() & m_board->GetVisibleLayers(); LAYER_MSK mask = m_board->GetEnabledLayers() & m_board->GetVisibleLayers();
LAYER_NUM l = m_currentLayer; LAYER_NUM l = m_currentLayer;
do { do {
l += (aUp ? 1 : -1); l += ( aUp ? 1 : -1 );
if(l > LAST_COPPER_LAYER)
if( l > LAST_COPPER_LAYER )
l = FIRST_COPPER_LAYER; l = FIRST_COPPER_LAYER;
if(l < FIRST_COPPER_LAYER) if( l < FIRST_COPPER_LAYER )
l = LAST_COPPER_LAYER; l = LAST_COPPER_LAYER;
if(mask & GetLayerMask(l)) if( mask & GetLayerMask( l ) )
return l; return l;
} while( l != m_currentLayer );
} while (l != m_currentLayer);
return l; return l;
} }
void PNS_ROUTER::SyncWorld() void PNS_ROUTER::SyncWorld()
{ {
vector<D_PAD *> pads; vector<D_PAD*> pads;
if(!m_board) if( !m_board )
{ {
TRACEn(0,"No board attached, aborting sync."); TRACEn( 0, "No board attached, aborting sync." );
return; return;
} }
ClearWorld(); ClearWorld();
m_clearanceFunc = new PCBNEW_CLEARANCE_FUNC(m_board); m_clearanceFunc = new PCBNEW_CLEARANCE_FUNC( m_board );
m_world = new PNS_NODE(); m_world = new PNS_NODE();
m_world->SetClearanceFunctor ( m_clearanceFunc ); m_world->SetClearanceFunctor( m_clearanceFunc );
m_world->SetMaxClearance ( 1000000 ); //m_board->GetBiggestClearanceValue()); m_world->SetMaxClearance( 1000000 ); // m_board->GetBiggestClearanceValue());
pads = m_board->GetPads(); pads = m_board->GetPads();
BOOST_FOREACH( D_PAD *pad, pads ) BOOST_FOREACH( D_PAD * pad, pads ) {
{ PNS_ITEM* solid = syncPad( pad );
PNS_ITEM *solid = syncPad(pad);
if(solid) if( solid )
m_world->Add(solid); m_world->Add( solid );
} }
for(TRACK *t = m_board->m_Track; t; t = t->Next()) for( TRACK* t = m_board->m_Track; t; t = t->Next() )
{ {
KICAD_T type = t->Type(); KICAD_T type = t->Type();
PNS_ITEM *item = NULL; PNS_ITEM* item = NULL;
if(type == PCB_TRACE_T)
item = syncTrack ( t ); if( type == PCB_TRACE_T )
item = syncTrack( t );
else if( type == PCB_VIA_T ) else if( type == PCB_VIA_T )
item = syncVia (static_cast <SEGVIA *>(t)); item = syncVia( static_cast <SEGVIA*>(t) );
if(item) if( item )
m_world->Add(item); m_world->Add( item );
} }
m_placer = new PNS_LINE_PLACER ( m_world ); m_placer = new PNS_LINE_PLACER( m_world );
} }
PNS_ROUTER::PNS_ROUTER() PNS_ROUTER::PNS_ROUTER()
{ {
theRouter = this; theRouter = this;
...@@ -278,44 +290,48 @@ PNS_ROUTER::PNS_ROUTER() ...@@ -278,44 +290,48 @@ PNS_ROUTER::PNS_ROUTER()
m_start_diagonal = false; m_start_diagonal = false;
m_board = NULL; 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) if( m_previewItems )
{ {
m_previewItems->FreeItems(); m_previewItems->FreeItems();
delete m_previewItems; delete m_previewItems;
} }
m_view = aView; m_view = aView;
m_previewItems = new KiGfx::VIEW_GROUP(m_view); m_previewItems = new KiGfx::VIEW_GROUP( m_view );
m_previewItems->SetLayer(ITEM_GAL_LAYER( GP_OVERLAY )); m_previewItems->SetLayer( ITEM_GAL_LAYER( GP_OVERLAY ) );
m_view -> Add (m_previewItems); m_view->Add( m_previewItems );
m_previewItems->ViewSetVisible(true); m_previewItems->ViewSetVisible( true );
} }
PNS_ROUTER *PNS_ROUTER::GetInstance()
PNS_ROUTER* PNS_ROUTER::GetInstance()
{ {
return theRouter; return theRouter;
} }
PNS_ROUTER::~PNS_ROUTER() PNS_ROUTER::~PNS_ROUTER()
{ {
ClearWorld(); ClearWorld();
theRouter = NULL; theRouter = NULL;
} }
void PNS_ROUTER::ClearWorld() void PNS_ROUTER::ClearWorld()
{ {
if(m_world) if( m_world )
delete m_world; delete m_world;
if(m_clearanceFunc)
if( m_clearanceFunc )
delete m_clearanceFunc; delete m_clearanceFunc;
if(m_placer)
if( m_placer )
delete m_placer; delete m_placer;
m_clearanceFunc = NULL; m_clearanceFunc = NULL;
...@@ -323,77 +339,85 @@ void PNS_ROUTER::ClearWorld() ...@@ -323,77 +339,85 @@ void PNS_ROUTER::ClearWorld()
m_placer = NULL; m_placer = NULL;
} }
void PNS_ROUTER::SetCurrentWidth (int w )
void PNS_ROUTER::SetCurrentWidth( int w )
{ {
// fixme: change width while routing // fixme: change width while routing
m_currentWidth = w; m_currentWidth = w;
} }
bool PNS_ROUTER::RoutingInProgress() const 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) if( m_state == IDLE )
return m_world->HitTest( aP ); return m_world->HitTest( aP );
else else
return m_placer->GetCurrentNode() -> HitTest(aP); 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) if( !item )
{ {
aSplitsSegment = false; aSplitsSegment = false;
return aP; return aP;
} }
switch(item->GetKind()) switch( item->GetKind() )
{ {
case PNS_ITEM::SOLID: case PNS_ITEM::SOLID:
anchor = static_cast<PNS_SOLID *>(item)->GetCenter(); anchor = static_cast<PNS_SOLID*>(item)->GetCenter();
aSplitsSegment = false; aSplitsSegment = false;
break; break;
case PNS_ITEM::VIA: case PNS_ITEM::VIA:
anchor = static_cast<PNS_VIA *>(item)->GetPos(); anchor = static_cast<PNS_VIA*>(item)->GetPos();
aSplitsSegment = false; aSplitsSegment = false;
break; break;
case PNS_ITEM::SEGMENT: case PNS_ITEM::SEGMENT:
{ {
PNS_SEGMENT *seg = static_cast<PNS_SEGMENT *>(item); PNS_SEGMENT* seg = static_cast<PNS_SEGMENT*>(item);
const SEG& s = seg->GetSeg(); const SEG& s = seg->GetSeg();
int w = seg->GetWidth(); int w = seg->GetWidth();
aSplitsSegment = false; aSplitsSegment = false;
if ((aP - s.a).EuclideanNorm() < w / 2) if( (aP - s.a).EuclideanNorm() < w / 2 )
anchor = s.a; anchor = s.a;
else if ((aP - s.b).EuclideanNorm() < w / 2) else if( (aP - s.b).EuclideanNorm() < w / 2 )
anchor = s.b; anchor = s.b;
else { else
anchor = s.NearestPoint(aP); {
anchor = s.NearestPoint( aP );
aSplitsSegment = true; aSplitsSegment = true;
} }
break; break;
} }
default: default:
break; break;
} }
return anchor; return anchor;
} }
void PNS_ROUTER::StartRouting(const VECTOR2I& aP, PNS_ITEM *aStartItem) void PNS_ROUTER::StartRouting( const VECTOR2I& aP, PNS_ITEM* aStartItem )
{ {
VECTOR2I p; VECTOR2I p;
static int unknowNetIdx = 0;//-10000; static int unknowNetIdx = 0; // -10000;
m_placingVia = false; m_placingVia = false;
m_startsOnVia = false; m_startsOnVia = false;
...@@ -403,7 +427,7 @@ void PNS_ROUTER::StartRouting(const VECTOR2I& aP, PNS_ITEM *aStartItem) ...@@ -403,7 +427,7 @@ void PNS_ROUTER::StartRouting(const VECTOR2I& aP, PNS_ITEM *aStartItem)
p = SnapToItem( aStartItem, aP, splitSeg ); p = SnapToItem( aStartItem, aP, splitSeg );
if(!aStartItem || aStartItem->GetNet() < 0) if( !aStartItem || aStartItem->GetNet() < 0 )
m_currentNet = unknowNetIdx--; m_currentNet = unknowNetIdx--;
else else
m_currentNet = aStartItem->GetNet(); m_currentNet = aStartItem->GetNet();
...@@ -412,178 +436,183 @@ void PNS_ROUTER::StartRouting(const VECTOR2I& aP, PNS_ITEM *aStartItem) ...@@ -412,178 +436,183 @@ void PNS_ROUTER::StartRouting(const VECTOR2I& aP, PNS_ITEM *aStartItem)
m_originalStart = p; m_originalStart = p;
m_currentEnd = p; m_currentEnd = p;
m_placer->SetInitialDirection(m_start_diagonal ? DIRECTION_45(DIRECTION_45::NE) : DIRECTION_45(DIRECTION_45::N)); m_placer->SetInitialDirection( m_start_diagonal ? DIRECTION_45(
m_placer->StartPlacement(m_originalStart, m_currentNet, m_currentWidth, m_currentLayer); DIRECTION_45::NE ) : DIRECTION_45( DIRECTION_45::N ) );
m_placer->StartPlacement( m_originalStart, m_currentNet, m_currentWidth, m_currentLayer );
m_state = ROUTE_TRACK; m_state = ROUTE_TRACK;
if(splitSeg) if( splitSeg )
splitAdjacentSegments(m_placer->GetCurrentNode(), aStartItem, p); 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() void PNS_ROUTER::EraseView()
{ {
BOOST_FOREACH(BOARD_ITEM *item, m_hiddenItems) BOOST_FOREACH( BOARD_ITEM* item, m_hiddenItems )
{ {
item->ViewSetVisible(true); item->ViewSetVisible( true );
} }
if(m_previewItems) if( m_previewItems )
m_previewItems->FreeItems(); m_previewItems->FreeItems();
m_previewItems->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY ); 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 );
m_previewItems->Add (pitem); if( aIsHead )
if(aIsHead)
pitem->MarkAsHead(); pitem->MarkAsHead();
pitem->ViewSetVisible(true); pitem->ViewSetVisible( true );
m_previewItems->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY | KiGfx::VIEW_ITEM::APPEARANCE ); 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); ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( NULL, m_previewItems );
pitem->DebugLine (aLine, aWidth, aType ); pitem->DebugLine( aLine, aWidth, aType );
m_previewItems->Add (pitem); m_previewItems->Add( pitem );
pitem->ViewSetVisible(true); pitem->ViewSetVisible( true );
m_previewItems->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY | KiGfx::VIEW_ITEM::APPEARANCE ); 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; PNS_NODE::ItemVector removed, added;
VECTOR2I p = aP; VECTOR2I p = aP;
if(m_state == IDLE) if( m_state == IDLE )
return; return;
if(m_state == START_ROUTING) // TODO is something missing here?
if( m_state == START_ROUTING )
{ {
} }
EraseView(); EraseView();
m_currentEnd = p; m_currentEnd = p;
m_placer->Route(p); m_placer->Route( p );
PNS_LINE current = m_placer->GetTrace(); PNS_LINE current = m_placer->GetTrace();
DisplayItem (&current, true); DisplayItem( &current, true );
if(current.EndsWithVia()) if( current.EndsWithVia() )
DisplayItem( &current.GetVia(), true ); DisplayItem( &current.GetVia(), true );
m_placer->GetCurrentNode()->GetUpdatedItems(removed, added); m_placer->GetCurrentNode()->GetUpdatedItems( removed, added );
BOOST_FOREACH(PNS_ITEM *item, added) BOOST_FOREACH( PNS_ITEM* item, added ) {
{ DisplayItem( item );
DisplayItem(item);
} }
BOOST_FOREACH(PNS_ITEM *item, removed) BOOST_FOREACH( PNS_ITEM* item, removed )
{ {
BOARD_ITEM *parent = item->GetParent(); BOARD_ITEM* parent = item->GetParent();
if(parent) if( parent )
{ {
if(parent->ViewIsVisible()) if( parent->ViewIsVisible() )
m_hiddenItems.insert(parent); m_hiddenItems.insert( parent );
parent->ViewSetVisible(false); parent->ViewSetVisible( false );
parent->ViewUpdate (KiGfx::VIEW_ITEM::APPEARANCE); 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 )) if( aSeg && aSeg->OfKind( PNS_ITEM::SEGMENT ) )
{ {
PNS_NODE::OptJoint jt = aNode->FindJoint ( aP, aSeg->GetLayers().Start(), aSeg->GetNet()); PNS_NODE::OptJoint jt = aNode->FindJoint( aP, aSeg->GetLayers().Start(), aSeg->GetNet() );
if(jt && jt->LinkCount() >= 1) if( jt && jt->LinkCount() >= 1 )
return; return;
PNS_SEGMENT *s_old = static_cast<PNS_SEGMENT*>(aSeg); PNS_SEGMENT* s_old = static_cast<PNS_SEGMENT*>(aSeg);
PNS_SEGMENT *s_new [2]; PNS_SEGMENT* s_new[2];
s_new[0] = s_old->Clone(); s_new[0] = s_old->Clone();
s_new[1] = s_old->Clone(); s_new[1] = s_old->Clone();
s_new[0]->SetEnds (s_old->GetSeg().a, aP); s_new[0]->SetEnds( s_old->GetSeg().a, aP );
s_new[1]->SetEnds (aP, s_old->GetSeg().b); s_new[1]->SetEnds( aP, s_old->GetSeg().b );
aNode->Remove( s_old ); aNode->Remove( s_old );
aNode->Add( s_new [0] ); aNode->Add( s_new[0] );
aNode->Add( s_new [1] ); 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++) for( unsigned int i = 0; i < removed.size(); i++ )
{ {
BOARD_ITEM *parent = removed[i]->GetParent(); BOARD_ITEM* parent = removed[i]->GetParent();
if(parent) if( parent )
{ {
m_view->Remove(parent); m_view->Remove( parent );
m_board->Remove(parent); m_board->Remove( parent );
} }
} }
BOOST_FOREACH(PNS_ITEM *item, added) BOOST_FOREACH( PNS_ITEM* item, added )
{ {
BOARD_ITEM *newBI = NULL; BOARD_ITEM* newBI = NULL;
switch(item->GetKind())
switch( item->GetKind() )
{ {
case PNS_ITEM::SEGMENT: case PNS_ITEM::SEGMENT:
{ {
PNS_SEGMENT *seg = static_cast<PNS_SEGMENT*>(item); PNS_SEGMENT* seg = static_cast<PNS_SEGMENT*>( item );
TRACK *track = new TRACK(m_board); TRACK* track = new TRACK( m_board );
const SEG& s = seg->GetSeg(); const SEG& s = seg->GetSeg();
track->SetStart( wxPoint(s.a.x, s.a.y)); track->SetStart( wxPoint( s.a.x, s.a.y ) );
track->SetEnd( wxPoint(s.b.x, s.b.y )); track->SetEnd( wxPoint( s.b.x, s.b.y ) );
track->SetWidth(seg->GetWidth()); track->SetWidth( seg->GetWidth() );
track->SetLayer(seg->GetLayers().Start()); track->SetLayer( seg->GetLayers().Start() );
track->SetNet(seg->GetNet()); track->SetNet( seg->GetNet() );
newBI = track; newBI = track;
break; break;
} }
case PNS_ITEM::VIA: case PNS_ITEM::VIA:
{ {
SEGVIA *via_board = new SEGVIA(m_board); SEGVIA* via_board = new SEGVIA( m_board );
PNS_VIA *via = static_cast<PNS_VIA *>(item); PNS_VIA* via = static_cast<PNS_VIA*>( item );
via_board->SetPosition ( wxPoint(via->GetPos().x, via->GetPos().y )); via_board->SetPosition( wxPoint( via->GetPos().x, via->GetPos().y ) );
via_board->SetWidth ( via->GetDiameter() ); via_board->SetWidth( via->GetDiameter() );
via_board->SetNet ( via->GetNet() ); via_board->SetNet( via->GetNet() );
newBI = via_board; newBI = via_board;
break; break;
} }
...@@ -592,12 +621,12 @@ void PNS_ROUTER::commitRouting( PNS_NODE *aNode ) ...@@ -592,12 +621,12 @@ void PNS_ROUTER::commitRouting( PNS_NODE *aNode )
break; break;
} }
if(newBI) if( newBI )
{ {
item->SetParent(newBI); item->SetParent( newBI );
newBI->ClearFlags(); newBI->ClearFlags();
m_view->Add(newBI); m_view->Add( newBI );
m_board->Add(newBI); m_board->Add( newBI );
newBI->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY ); newBI->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY );
} }
} }
...@@ -605,41 +634,43 @@ void PNS_ROUTER::commitRouting( PNS_NODE *aNode ) ...@@ -605,41 +634,43 @@ void PNS_ROUTER::commitRouting( PNS_NODE *aNode )
m_world->Commit( aNode ); 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_VIA* theVia = NULL;
PNS_LAYERSET l; PNS_LAYERSET l;
BOOST_FOREACH(PNS_ITEM *item, aJoint->GetLinkList()) BOOST_FOREACH( PNS_ITEM* item, aJoint->GetLinkList() )
{ {
if(item->GetKind() == PNS_ITEM::VIA) if( item->GetKind() == PNS_ITEM::VIA )
theVia = static_cast<PNS_VIA *>(item); theVia = static_cast<PNS_VIA*>( item );
l.Merge (item->GetLayers()); l.Merge( item->GetLayers() );
} }
if(l.Start() == l.End()) if( l.Start() == l.End() )
return theVia; return theVia;
return NULL; 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_LINE* ourLine = aNode->AssembleLine( aLatestSeg );
PNS_NODE *cleaned = aNode->Branch(); PNS_NODE* cleaned = aNode->Branch();
PNS_JOINT a, b; PNS_JOINT a, b;
vector<PNS_LINE *> lines;
vector<PNS_LINE*> lines;
cleaned->FindLineEnds (ourLine, a, b); cleaned->FindLineEnds( ourLine, a, b );
cleaned->FindLinesBetweenJoints( a, b, lines); cleaned->FindLinesBetweenJoints( a, b, lines );
BOOST_FOREACH(PNS_LINE *line, lines) BOOST_FOREACH( PNS_LINE* line, lines )
{ {
if(! (line->ContainsSegment (aLatestSeg) ) ) if( !( line->ContainsSegment( aLatestSeg ) ) )
{ {
cleaned->Remove(line); cleaned->Remove( line );
} }
} }
...@@ -647,85 +678,85 @@ PNS_NODE *PNS_ROUTER::removeLoops ( PNS_NODE *aNode, PNS_SEGMENT *aLatestSeg ) ...@@ -647,85 +678,85 @@ PNS_NODE *PNS_ROUTER::removeLoops ( PNS_NODE *aNode, PNS_SEGMENT *aLatestSeg )
} }
bool PNS_ROUTER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem )
bool PNS_ROUTER::FixRoute(const VECTOR2I& aP, PNS_ITEM *aEndItem) {
{
bool real_end = false; bool real_end = false;
PNS_LINE pl = m_placer->GetTrace(); PNS_LINE pl = m_placer->GetTrace();
const SHAPE_LINE_CHAIN& l = pl.GetCLine(); const SHAPE_LINE_CHAIN& l = pl.GetCLine();
if(!l.SegmentCount()) if( !l.SegmentCount() )
return true; return true;
VECTOR2I p_pre_last = l.CPoint(-1); VECTOR2I p_pre_last = l.CPoint( -1 );
const VECTOR2I p_last = l.CPoint(-1); const VECTOR2I p_last = l.CPoint( -1 );
DIRECTION_45 d_last (l.CSegment(-1)); DIRECTION_45 d_last( l.CSegment( -1 ) );
if(l.PointCount() > 2) if( l.PointCount() > 2 )
p_pre_last = l.CPoint(-2); p_pre_last = l.CPoint( -2 );
if(aEndItem && m_currentNet >= 0 && m_currentNet == aEndItem->GetNet()) if( aEndItem && m_currentNet >= 0 && m_currentNet == aEndItem->GetNet() )
real_end = true; real_end = true;
int last = (real_end || m_placingVia) ? l.SegmentCount() : max(1, l.SegmentCount() - 1); int last = ( real_end || m_placingVia ) ? l.SegmentCount() : max( 1, l.SegmentCount() - 1 );
PNS_NODE *latest = m_placer->GetCurrentNode(); PNS_NODE* latest = m_placer->GetCurrentNode();
if(real_end) if( real_end )
splitAdjacentSegments(latest, aEndItem, aP); splitAdjacentSegments( latest, aEndItem, aP );
PNS_SEGMENT *lastSeg = NULL; PNS_SEGMENT* lastSeg = NULL;
for (int i = 0; i < last; i++)
for( int i = 0; i < last; i++ )
{ {
const SEG& s = pl.GetCLine().CSegment(i); const SEG& s = pl.GetCLine().CSegment( i );
PNS_SEGMENT *seg = new PNS_SEGMENT( s, m_currentNet ); PNS_SEGMENT* seg = new PNS_SEGMENT( s, m_currentNet );
seg->SetWidth(pl.GetWidth()); seg->SetWidth( pl.GetWidth() );
seg->SetLayer(m_currentLayer); seg->SetLayer( m_currentLayer );
latest->Add(seg); latest->Add( seg );
lastSeg = seg; lastSeg = seg;
} }
if( pl.EndsWithVia() ) if( pl.EndsWithVia() )
latest->Add(pl.GetVia().Clone()); latest->Add( pl.GetVia().Clone() );
if(real_end) if( real_end )
latest = removeLoops( latest, lastSeg ); latest = removeLoops( latest, lastSeg );
commitRouting(latest); commitRouting( latest );
EraseView(); EraseView();
if(real_end) if( real_end )
{ {
m_state = IDLE; m_state = IDLE;
//m_world->KillChildren(); // m_world->KillChildren();
} else { }
else
{
m_state = ROUTE_TRACK; m_state = ROUTE_TRACK;
m_placer->SetInitialDirection(d_last); m_placer->SetInitialDirection( d_last );
m_currentStart = m_placingVia ? p_last : p_pre_last; m_currentStart = m_placingVia ? p_last : p_pre_last;
if(m_placingVia) if( m_placingVia )
m_currentLayer = NextCopperLayer(true); m_currentLayer = NextCopperLayer( true );
m_placer->StartPlacement(m_currentStart, m_currentNet, m_currentWidth, m_currentLayer); m_placer->StartPlacement( m_currentStart, m_currentNet, m_currentWidth, m_currentLayer );
m_startsOnVia = m_placingVia; m_startsOnVia = m_placingVia;
m_placingVia = false; m_placingVia = false;
} }
return real_end; return real_end;
} }
void PNS_ROUTER::StopRouting() void PNS_ROUTER::StopRouting()
{ {
if(!RoutingInProgress()) if( !RoutingInProgress() )
return; return;
//highlightCurrent(false); // highlightCurrent(false);
EraseView(); EraseView();
...@@ -733,42 +764,50 @@ void PNS_ROUTER::StopRouting() ...@@ -733,42 +764,50 @@ void PNS_ROUTER::StopRouting()
m_world->KillChildren(); m_world->KillChildren();
} }
void PNS_ROUTER::FlipPosture() void PNS_ROUTER::FlipPosture()
{ {
if(m_placer->GetTail().GetCLine().SegmentCount() == 0) if( m_placer->GetTail().GetCLine().SegmentCount() == 0 )
{ {
m_start_diagonal = !m_start_diagonal; m_start_diagonal = !m_start_diagonal;
m_placer->SetInitialDirection(m_start_diagonal ? DIRECTION_45(DIRECTION_45::NE) : DIRECTION_45(DIRECTION_45::N)); m_placer->SetInitialDirection( m_start_diagonal ? DIRECTION_45(
} else DIRECTION_45::NE ) : DIRECTION_45( DIRECTION_45::N ) );
}
else
m_placer->FlipPosture(); m_placer->FlipPosture();
Move(m_currentEnd, NULL); Move( m_currentEnd, NULL );
} }
void PNS_ROUTER::SwitchLayer(int layer)
void PNS_ROUTER::SwitchLayer( int layer )
{ {
switch(m_state) switch( m_state )
{ {
case IDLE: case IDLE:
m_currentLayer = layer; m_currentLayer = layer;
break; break;
case ROUTE_TRACK: case ROUTE_TRACK:
if(m_startsOnVia) if( m_startsOnVia )
{ {
m_currentLayer = layer; m_currentLayer = layer;
m_placer->StartPlacement(m_currentStart, m_currentNet, m_currentWidth, m_currentLayer); m_placer->StartPlacement( m_currentStart, m_currentNet, m_currentWidth,
m_currentLayer );
} }
default: default:
break; break;
} }
} }
void PNS_ROUTER::ToggleViaPlacement ()
void PNS_ROUTER::ToggleViaPlacement()
{ {
if(m_state == ROUTE_TRACK) if( m_state == ROUTE_TRACK )
{ {
m_placingVia = !m_placingVia; m_placingVia = !m_placingVia;
m_placer->AddVia(m_placingVia, m_currentViaDiameter, m_currentViaDrill); m_placer->AddVia( m_placingVia, m_currentViaDiameter, m_currentViaDrill );
} }
} }
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License along * You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>. * with this program. If not, see <http://www.gnu.or/licenses/>.
*/ */
#ifndef __PNS_ROUTER_H #ifndef __PNS_ROUTER_H
#define __PNS_ROUTER_H #define __PNS_ROUTER_H
...@@ -48,8 +49,8 @@ class PNS_CLEARANCE_FUNC; ...@@ -48,8 +49,8 @@ class PNS_CLEARANCE_FUNC;
class VIEW_GROUP; class VIEW_GROUP;
namespace KiGfx { namespace KiGfx {
class VIEW; class VIEW;
class VIEW_GROUP; class VIEW_GROUP;
}; };
...@@ -59,10 +60,11 @@ namespace KiGfx { ...@@ -59,10 +60,11 @@ namespace KiGfx {
* Main router class. * Main router class.
*/ */
class PNS_ROUTER { class PNS_ROUTER
{
private: private:
enum RouterState { enum RouterState
{
IDLE, IDLE,
START_ROUTING, START_ROUTING,
ROUTE_TRACK, ROUTE_TRACK,
...@@ -70,28 +72,27 @@ private: ...@@ -70,28 +72,27 @@ private:
}; };
public: public:
PNS_ROUTER();
~PNS_ROUTER();
PNS_ROUTER (); static PNS_ROUTER* GetInstance();
~PNS_ROUTER ();
static PNS_ROUTER *GetInstance();
void ClearWorld(); void ClearWorld();
void SetBoard( BOARD *aBoard ); void SetBoard( BOARD* aBoard );
void SyncWorld(); void SyncWorld();
void SetView(KiGfx::VIEW *aView); void SetView( KiGfx::VIEW* aView );
bool RoutingInProgress() const; bool RoutingInProgress() const;
void StartRouting(const VECTOR2I& aP, PNS_ITEM *aItem); void StartRouting( const VECTOR2I& aP, PNS_ITEM* aItem );
void Move(const VECTOR2I& aP, PNS_ITEM *aItem); void Move( const VECTOR2I& aP, PNS_ITEM* aItem );
bool FixRoute(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 PNS_NODE* GetWorld() const
{ {
...@@ -100,24 +101,26 @@ public: ...@@ -100,24 +101,26 @@ public:
void FlipPosture(); void FlipPosture();
void DisplayItem ( const PNS_ITEM *aItem, bool aIsHead = false ); void DisplayItem( const PNS_ITEM* aItem, bool aIsHead = false );
void DisplayDebugLine ( const SHAPE_LINE_CHAIN &aLine, int aType = 0, int aWidth = 0); 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 DisplayDebugBox( const BOX2I& aBox, int aType = 0, int aWidth = 0 );
void EraseView();
void SwitchLayer( int layer );
void EraseView ( );
void SwitchLayer (int layer );
int GetCurrentLayer() const { return m_currentLayer; } int GetCurrentLayer() const { return m_currentLayer; }
void ToggleViaPlacement (); void ToggleViaPlacement();
void SetCurrentWidth(int w); void SetCurrentWidth( int w );
void SetCurrentViaDiameter(int d) { m_currentViaDiameter = d;}
void SetCurrentViaDrill(int d) { m_currentViaDrill = d;} void SetCurrentViaDiameter( int d ) { m_currentViaDiameter = d; }
void SetCurrentViaDrill( int d ) { m_currentViaDrill = d; }
int GetCurrentWidth() const { return m_currentWidth; } int GetCurrentWidth() const { return m_currentWidth; }
int GetCurrentViaDiameter() const { return m_currentViaDiameter; } int GetCurrentViaDiameter() const { return m_currentViaDiameter; }
int GetCurrentViaDrill() const { return m_currentViaDrill; } int GetCurrentViaDrill() const { return m_currentViaDrill; }
int GetCurrentNet() const { return m_currentNet; } int GetCurrentNet() const { return m_currentNet; }
PNS_CLEARANCE_FUNC *GetClearanceFunc() const PNS_CLEARANCE_FUNC* GetClearanceFunc() const
{ {
return m_clearanceFunc; return m_clearanceFunc;
} }
...@@ -127,41 +130,35 @@ public: ...@@ -127,41 +130,35 @@ public:
return m_placingVia; return m_placingVia;
} }
int NextCopperLayer( bool aUp ); int NextCopperLayer( bool aUp );
//typedef boost::optional<hoverItem> optHoverItem; // typedef boost::optional<hoverItem> optHoverItem;
const PNS_ITEMSET QueryHoverItems(const VECTOR2I& aP);
const VECTOR2I SnapToItem( PNS_ITEM *item, VECTOR2I aP, bool& aSplitsSegment );
const PNS_ITEMSET QueryHoverItems( const VECTOR2I& aP );
const VECTOR2I SnapToItem( PNS_ITEM* item, VECTOR2I aP, bool& aSplitsSegment );
private: private:
void clearViewFlags(); void clearViewFlags();
//optHoverItem queryHoverItemEx(const VECTOR2I& aP); // optHoverItem queryHoverItemEx(const VECTOR2I& aP);
PNS_ITEM *pickSingleItem ( PNS_ITEMSET &aItems ) const; //std::vector<PNS_ITEM*> aItems) const; PNS_ITEM* pickSingleItem( PNS_ITEMSET& aItems ) const; // std::vector<PNS_ITEM*> aItems) const;
void splitAdjacentSegments(PNS_NODE *aNode, PNS_ITEM *aSeg, const VECTOR2I& aP ); //optHoverItem& aItem); void splitAdjacentSegments( PNS_NODE* aNode, PNS_ITEM* aSeg, const VECTOR2I& aP ); // optHoverItem& aItem);
void commitRouting ( PNS_NODE *aNode ); void commitRouting( PNS_NODE* aNode );
PNS_NODE *removeLoops ( PNS_NODE *aNode, PNS_SEGMENT *aLatestSeg ); PNS_NODE* removeLoops( PNS_NODE* aNode, PNS_SEGMENT* aLatestSeg );
PNS_NODE *removeLoops ( PNS_NODE *aNode, PNS_LINE *aNewLine ); PNS_NODE* removeLoops( PNS_NODE* aNode, PNS_LINE* aNewLine );
PNS_VIA *checkLoneVia ( PNS_JOINT* aJoint ) const; PNS_VIA* checkLoneVia( PNS_JOINT* aJoint ) const;
PNS_ITEM *syncPad( D_PAD *aPad ); PNS_ITEM* syncPad( D_PAD* aPad );
PNS_ITEM *syncTrack( TRACK *aTrack ); PNS_ITEM* syncTrack( TRACK* aTrack );
PNS_ITEM *syncVia( SEGVIA *aVia ); PNS_ITEM* syncVia( SEGVIA* aVia );
void commitPad( PNS_SOLID *aPad ); void commitPad( PNS_SOLID* aPad );
void commitSegment( PNS_SEGMENT *aTrack ); void commitSegment( PNS_SEGMENT* aTrack );
void commitVia( PNS_VIA *aVia ); void commitVia( PNS_VIA* aVia );
void highlightCurrent( bool enabled ); void highlightCurrent( bool enabled );
int m_currentLayer; int m_currentLayer;
int m_currentNet; int m_currentNet;
int m_currentWidth; int m_currentWidth;
...@@ -172,12 +169,12 @@ private: ...@@ -172,12 +169,12 @@ private:
RouterState m_state; RouterState m_state;
BOARD *m_board; BOARD* m_board;
PNS_NODE *m_world; PNS_NODE* m_world;
PNS_LINE_PLACER *m_placer; PNS_LINE_PLACER* m_placer;
KiGfx::VIEW *m_view; KiGfx::VIEW* m_view;
KiGfx::VIEW_GROUP *m_previewItems; KiGfx::VIEW_GROUP* m_previewItems;
VECTOR2I m_currentEnd; VECTOR2I m_currentEnd;
VECTOR2I m_currentStart; VECTOR2I m_currentStart;
...@@ -188,10 +185,10 @@ private: ...@@ -188,10 +185,10 @@ private:
// optHoverItem m_startItem, m_endItem; // optHoverItem m_startItem, m_endItem;
PNS_ROUTING_SETTINGS m_settings; PNS_ROUTING_SETTINGS m_settings;
PNS_CLEARANCE_FUNC *m_clearanceFunc; PNS_CLEARANCE_FUNC* m_clearanceFunc;
boost::unordered_set<BOARD_ITEM *> m_hiddenItems;
boost::unordered_set<BOARD_ITEM*> m_hiddenItems;
}; };
#endif #endif
...@@ -22,7 +22,8 @@ ...@@ -22,7 +22,8 @@
#define __PNS_ROUTER_SETTINGS #define __PNS_ROUTER_SETTINGS
///> Routing modes ///> Routing modes
enum PNS_MODE { enum PNS_MODE
{
RM_Ignore = 0, ///> Ignore collisions RM_Ignore = 0, ///> Ignore collisions
RM_Shove, ///> Only shove RM_Shove, ///> Only shove
RM_Walkaround, ///> Only walkaround RM_Walkaround, ///> Only walkaround
...@@ -31,7 +32,7 @@ enum PNS_MODE { ...@@ -31,7 +32,7 @@ enum PNS_MODE {
class PNS_ROUTING_SETTINGS class PNS_ROUTING_SETTINGS
{ {
public: public:
PNS_MODE m_routingMode; PNS_MODE m_routingMode;
bool m_removeLoops; bool m_removeLoops;
......
...@@ -32,42 +32,44 @@ ...@@ -32,42 +32,44 @@
class PNS_NODE; class PNS_NODE;
class PNS_SEGMENT : public PNS_ITEM { class PNS_SEGMENT : public PNS_ITEM
{
public: public:
PNS_SEGMENT (): PNS_SEGMENT() :
PNS_ITEM(SEGMENT) PNS_ITEM( SEGMENT )
{}; {};
PNS_SEGMENT (const SEG& aSeg, int aNet): PNS_SEGMENT( const SEG& aSeg, int aNet ) :
PNS_ITEM(SEGMENT) PNS_ITEM( SEGMENT )
{ {
m_net = aNet; m_net = aNet;
m_shape.Clear(); m_shape.Clear();
m_shape.Append(aSeg.a); m_shape.Append( aSeg.a );
m_shape.Append(aSeg.b); m_shape.Append( aSeg.b );
}; };
PNS_SEGMENT (const PNS_LINE &aParentLine, const SEG& aSeg): PNS_SEGMENT( const PNS_LINE& aParentLine, const SEG& aSeg ) :
PNS_ITEM(SEGMENT) PNS_ITEM( SEGMENT )
{ {
m_net = aParentLine.GetNet(); m_net = aParentLine.GetNet();
m_layers = aParentLine.GetLayers(); m_layers = aParentLine.GetLayers();
m_width = aParentLine.GetWidth(); m_width = aParentLine.GetWidth();
m_shape.Clear(); m_shape.Clear();
m_shape.Append(aSeg.a); m_shape.Append( aSeg.a );
m_shape.Append(aSeg.b); m_shape.Append( aSeg.b );
}; };
PNS_SEGMENT *Clone() const; PNS_SEGMENT* Clone() const;
const SHAPE* GetShape() const { const SHAPE* GetShape() const
return static_cast<const SHAPE *>(&m_shape); {
return static_cast<const SHAPE*>( &m_shape );
} }
void SetLayer (int aLayer) void SetLayer( int aLayer )
{ {
SetLayers (PNS_LAYERSET ( aLayer )); SetLayers( PNS_LAYERSET( aLayer ) );
} }
int GetLayer() const int GetLayer() const
...@@ -85,22 +87,26 @@ public: ...@@ -85,22 +87,26 @@ public:
m_width = aWidth; m_width = aWidth;
} }
int GetWidth() const { int GetWidth() const
{
return m_width; return m_width;
} }
const SEG GetSeg() const { const SEG GetSeg() const
assert(m_shape.PointCount() >= 1); {
if(m_shape.PointCount() == 1) assert( m_shape.PointCount() >= 1 );
return SEG(m_shape.CPoint(0), m_shape.CPoint(0));
return SEG(m_shape.CPoint(0), m_shape.CPoint(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) void SetEnds( const VECTOR2I& a, const VECTOR2I& b )
{ {
m_shape.Clear(); m_shape.Clear();
m_shape.Append(a); m_shape.Append( a );
m_shape.Append(b); m_shape.Append( b );
} }
void SwapEnds() void SwapEnds()
...@@ -108,12 +114,12 @@ public: ...@@ -108,12 +114,12 @@ public:
m_shape = m_shape.Reverse(); m_shape = m_shape.Reverse();
} }
const SHAPE_LINE_CHAIN Hull(int aClearance, int aWalkaroundThickness) const; const SHAPE_LINE_CHAIN Hull( int aClearance, int aWalkaroundThickness ) const;
private: private:
SHAPE_LINE_CHAIN m_shape; SHAPE_LINE_CHAIN m_shape;
int m_width; int m_width;
}; };
#endif #endif
...@@ -37,30 +37,34 @@ ...@@ -37,30 +37,34 @@
using namespace std; using namespace std;
PNS_SHOVE::PNS_SHOVE( PNS_NODE *aWorld ) PNS_SHOVE::PNS_SHOVE( PNS_NODE* aWorld )
{ {
m_root = aWorld; m_root = aWorld;
m_iterLimit = 100; m_iterLimit = 100;
}; };
PNS_SHOVE::~PNS_SHOVE() PNS_SHOVE::~PNS_SHOVE()
{ {
} }
struct range {
struct range
{
range() range()
{ {
min_v = max_v = -1; min_v = max_v = -1;
} }
void add ( int x ) void add( int x )
{ {
if(min_v < 0) min_v = x; if( min_v < 0 ) min_v = x;
if(max_v < 0) max_v = x;
if(x < min_v) if( max_v < 0 ) max_v = x;
if( x < min_v )
min_v = x; min_v = x;
else if (x > max_v) else if( x > max_v )
max_v = x; max_v = x;
} }
...@@ -78,56 +82,58 @@ struct range { ...@@ -78,56 +82,58 @@ struct range {
}; };
// fixme: this is damn f***ing inefficient. And fails much too often due to broken direction finding algorithm. // 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(); const SHAPE_LINE_CHAIN& head = aHead->GetCLine();
bool cw = false; bool cw = false;
int i; int i;
if(aHead->EndsWithVia() && !aHead->GetLayers().Overlaps(aObstacle->GetLayers())) if( aHead->EndsWithVia() && !aHead->GetLayers().Overlaps( aObstacle->GetLayers() ) )
{ {
int clearance = aNode->GetClearance(aHead, aObstacle); int clearance = aNode->GetClearance( aHead, aObstacle );
SHAPE_LINE_CHAIN hull = aHead->GetVia().Hull( clearance - aObstacle->GetWidth() / 2 ); 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_cw, true );
aObstacle->NewWalkaround(hull, path_ccw, false); aObstacle->NewWalkaround( hull, path_ccw, false );
path = path_ccw.Length() < path_cw.Length() ? &path_ccw : &path_cw; path = path_ccw.Length() < path_cw.Length() ? &path_ccw : &path_cw;
aResult->SetShape(*path); aResult->SetShape( *path );
//PNSDisplayDebugLine (*path, 5); // PNSDisplayDebugLine (*path, 5);
if(!aResult->Is45Degree()) if( !aResult->Is45Degree() )
{ {
//printf("polyset non-45\npoly %s\nendpolyset\n", aResult->GetCLine().Format().c_str()); // printf("polyset non-45\npoly %s\nendpolyset\n", aResult->GetCLine().Format().c_str());
} }
/*... special case for vias? */ /*... special case for vias? */
return !aNode->CheckColliding(aResult, aHead); return !aNode->CheckColliding( aResult, aHead );
} }
int ns = head.SegmentCount(); int ns = head.SegmentCount();
if(aHead->EndsWithVia())
ns ++;
for(i = 0; i < head.SegmentCount(); i++) if( aHead->EndsWithVia() )
{ ns++;
const PNS_SEGMENT hs (*aHead, head.CSegment(i));
for( i = 0; i < head.SegmentCount(); i++ )
{
const PNS_SEGMENT hs( *aHead, head.CSegment( i ) );
if(aNode->CheckColliding(&hs, aObstacle)) if( aNode->CheckColliding( &hs, aObstacle ) )
{ {
VECTOR2I v1 = hs.GetSeg().b - hs.GetSeg().a; VECTOR2I v1 = hs.GetSeg().b - hs.GetSeg().a;
VECTOR2I v2 = aObstacleSeg.GetSeg().b - aObstacleSeg.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) if( det > 0 )
cw = true; cw = true;
else else
cw = false; cw = false;
...@@ -136,76 +142,79 @@ bool PNS_SHOVE::tryShove(PNS_NODE *aNode, PNS_LINE *aHead, PNS_LINE *aObstacle, ...@@ -136,76 +142,79 @@ bool PNS_SHOVE::tryShove(PNS_NODE *aNode, PNS_LINE *aHead, PNS_LINE *aObstacle,
} }
} }
if(aInvertWinding) if( aInvertWinding )
{ {
if(cw) if( cw )
cw = false; cw = false;
else else
cw = true; cw = true;
} }
PNS_LINE shoved (*aObstacle); PNS_LINE shoved( *aObstacle );
int clearance = aNode->GetClearance(aHead, aObstacle); int clearance = aNode->GetClearance( aHead, aObstacle );
range r; range r;
for(i = 0; i < ns; i++) for( i = 0; i < ns; i++ )
{ {
SHAPE_LINE_CHAIN hull; SHAPE_LINE_CHAIN hull;
if(i < head.SegmentCount()) if( i < head.SegmentCount() )
{ {
const PNS_SEGMENT hs (*aHead, head.CSegment(i)); const PNS_SEGMENT hs( *aHead, head.CSegment( i ) );
hull = hs.Hull( clearance, 0 ); hull = hs.Hull( clearance, 0 );
} else }
hull = aHead->GetVia().Hull( clearance - aObstacle->GetWidth() / 2); else
hull = aHead->GetVia().Hull( clearance - aObstacle->GetWidth() / 2 );
SHAPE_LINE_CHAIN path_pre, path_walk, path_post, tmp; SHAPE_LINE_CHAIN path_pre, path_walk, path_post, tmp;
SHAPE_LINE_CHAIN path_pre2, path_walk2, path_post2; SHAPE_LINE_CHAIN path_pre2, path_walk2, path_post2;
//shoved.NewWalkaround(hull, path_pre, path_walk, path_post, cw); // shoved.NewWalkaround(hull, path_pre, path_walk, path_post, cw);
shoved.NewWalkaround(hull, path_pre, path_walk, path_post, cw); shoved.NewWalkaround( hull, path_pre, path_walk, path_post, cw );
/*if(path_pre != path_pre2 || path_post != path_post2 || path_walk != path_walk2 ) /*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 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()); * 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());
}*/ * }*/
tmp = shoved.GetCLine(); tmp = shoved.GetCLine();
if(path_walk.SegmentCount())
r.add(i);
path_pre.Append(path_walk); if( path_walk.SegmentCount() )
path_pre.Append(path_post); r.add( i );
path_pre.Append( path_walk );
path_pre.Append( path_post );
path_pre.Simplify(); path_pre.Simplify();
shoved.SetShape(path_pre); shoved.SetShape( path_pre );
// shoved.SetAffectedRange ( start, end ); // shoved.SetAffectedRange ( start, end );
*aResult = shoved; *aResult = shoved;
if(!aResult->Is45Degree()) 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(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); TRACE( 2, "CW %d affectedRange %d-%d [total %d]", (cw ? 1 : 0) % r.start() % r.end() % ns );
return !aNode->CheckColliding(aResult, aHead); 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 ) if( !rv )
rv = tryShove(aNode, aCurrent, aObstacle, aObstacleSeg, aResult, true); rv = tryShove( aNode, aCurrent, aObstacle, aObstacleSeg, aResult, true );
if( !rv ) if( !rv )
{ {
TRACEn(2, "Shove failed" ); TRACEn( 2, "Shove failed" );
return SH_INCOMPLETE; return SH_INCOMPLETE;
} }
...@@ -214,105 +223,111 @@ PNS_SHOVE::ShoveStatus PNS_SHOVE::shoveSingleLine(PNS_NODE *aNode, PNS_LINE *aCu ...@@ -214,105 +223,111 @@ PNS_SHOVE::ShoveStatus PNS_SHOVE::shoveSingleLine(PNS_NODE *aNode, PNS_LINE *aCu
const SHAPE_LINE_CHAIN& sh_shoved = aResult->GetCLine(); const SHAPE_LINE_CHAIN& sh_shoved = aResult->GetCLine();
const SHAPE_LINE_CHAIN& sh_orig = aObstacle->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) ) if( sh_shoved.SegmentCount() > 1 && sh_shoved.CPoint( 0 ) == sh_orig.CPoint( 0 )
&& sh_shoved.CPoint( -1 ) == sh_orig.CPoint( -1 ) )
return SH_OK; return SH_OK;
else if (!sh_shoved.SegmentCount()) else if( !sh_shoved.SegmentCount() )
return SH_NULL; return SH_NULL;
else else
return SH_INCOMPLETE; return SH_INCOMPLETE;
} }
bool PNS_SHOVE::reduceSpringback( PNS_LINE *aHead )
bool PNS_SHOVE::reduceSpringback( PNS_LINE* aHead )
{ {
bool rv = false; bool rv = false;
while(!m_nodeStack.empty()) while( !m_nodeStack.empty() )
{ {
SpringbackTag st_stack = m_nodeStack.back(); SpringbackTag st_stack = m_nodeStack.back();
bool tail_ok = true; bool tail_ok = true;
if(!st_stack.node->CheckColliding(aHead) && tail_ok) if( !st_stack.node->CheckColliding( aHead ) && tail_ok )
{ {
rv = true; rv = true;
delete st_stack.node; delete st_stack.node;
m_nodeStack.pop_back(); m_nodeStack.pop_back();
} else }
else
break; break;
} }
return rv; 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(); BOX2I headBB = aHead->GetCLine().BBox();
SpringbackTag st; SpringbackTag st;
st.node = aNode; st.node = aNode;
st.cost = aCost; st.cost = aCost;
st.length = std::max(headBB.GetWidth(), headBB.GetHeight());; st.length = std::max( headBB.GetWidth(), headBB.GetHeight() );;
m_nodeStack.push_back(st); m_nodeStack.push_back( st );
return true; return true;
} }
const PNS_COST_ESTIMATOR PNS_SHOVE::TotalCost() const const PNS_COST_ESTIMATOR PNS_SHOVE::TotalCost() const
{ {
if(m_nodeStack.empty()) if( m_nodeStack.empty() )
return PNS_COST_ESTIMATOR(); return PNS_COST_ESTIMATOR();
else else
return m_nodeStack.back().cost; return m_nodeStack.back().cost;
} }
PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines(PNS_LINE* aCurrentHead)
PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines( PNS_LINE* aCurrentHead )
{ {
stack <PNS_LINE *> lineStack; stack <PNS_LINE*> lineStack;
PNS_NODE *node, *parent; PNS_NODE* node, * parent;
PNS_VIA *headVia = NULL; PNS_VIA* headVia = NULL;
bool fail = false; bool fail = false;
int iter = 0; 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; parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().node;
node = parent->Branch(); node = parent->Branch();
lineStack.push(head); lineStack.push( head );
//node->Add(tail); // node->Add(tail);
node->Add(head); node->Add( head );
if(head->EndsWithVia()) if( head->EndsWithVia() )
{ {
headVia = head->GetVia().Clone(); headVia = head->GetVia().Clone();
node->Add( headVia ); node->Add( headVia );
} }
PNS_OPTIMIZER optimizer (node); PNS_OPTIMIZER optimizer( node );
optimizer.SetEffortLevel (PNS_OPTIMIZER::MERGE_SEGMENTS | PNS_OPTIMIZER::SMART_PADS); optimizer.SetEffortLevel( PNS_OPTIMIZER::MERGE_SEGMENTS | PNS_OPTIMIZER::SMART_PADS );
optimizer.SetCollisionMask( -1 ); optimizer.SetCollisionMask( -1 );
PNS_NODE::OptObstacle nearest; PNS_NODE::OptObstacle nearest;
optimizer.CacheStaticItem(head); optimizer.CacheStaticItem( head );
if(headVia)
optimizer.CacheStaticItem(headVia);
TRACE(1, "ShoveStart [root: %d jts, node: %d jts]", m_root->JointCount() % node->JointCount()); if( headVia )
optimizer.CacheStaticItem( headVia );
//PNS_ITEM *lastWalkSolid = NULL; TRACE( 1, "ShoveStart [root: %d jts, node: %d jts]", m_root->JointCount() %
prof_counter totalRealTime; node->JointCount() );
// PNS_ITEM *lastWalkSolid = NULL;
prof_counter totalRealTime;
wxLongLong t_start = wxGetLocalTimeMillis(); wxLongLong t_start = wxGetLocalTimeMillis();
while(!lineStack.empty()) while( !lineStack.empty() )
{ {
wxLongLong t_cur = wxGetLocalTimeMillis(); wxLongLong t_cur = wxGetLocalTimeMillis();
if ((t_cur - t_start).ToLong() > ShoveTimeLimit) if( (t_cur - t_start).ToLong() > ShoveTimeLimit )
{ {
fail = true; fail = true;
break; break;
...@@ -320,80 +335,85 @@ PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines(PNS_LINE* aCurrentHead) ...@@ -320,80 +335,85 @@ PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines(PNS_LINE* aCurrentHead)
iter++; iter++;
if(iter > m_iterLimit) if( iter > m_iterLimit )
{ {
fail = true; fail = true;
break; break;
} }
PNS_LINE *currentLine = lineStack.top(); PNS_LINE* currentLine = lineStack.top();
prof_start( &totalRealTime, false ); prof_start( &totalRealTime, false );
nearest = node->NearestObstacle(currentLine, PNS_ITEM::ANY); nearest = node->NearestObstacle( currentLine, PNS_ITEM::ANY );
prof_end( &totalRealTime ); prof_end( &totalRealTime );
TRACE(2,"t-nearestObstacle %lld us", (totalRealTime.value )); TRACE( 2, "t-nearestObstacle %lld us", (totalRealTime.value ) );
if(!nearest) if( !nearest )
{ {
if(lineStack.size() > 1) if( lineStack.size() > 1 )
{ {
PNS_LINE *original = lineStack.top(); PNS_LINE* original = lineStack.top();
PNS_LINE optimized; PNS_LINE optimized;
int r_start, r_end; int r_start, r_end;
original->GetAffectedRange(r_start, r_end); original->GetAffectedRange( r_start, r_end );
TRACE(1, "Iter %d optimize-line [range %d-%d, total %d]", iter % r_start % r_end % original->GetCLine().PointCount() ); TRACE( 1, "Iter %d optimize-line [range %d-%d, total %d]",
//lastWalkSolid = NULL; iter % r_start % r_end % original->GetCLine().PointCount() );
// lastWalkSolid = NULL;
prof_start( &totalRealTime, false ); prof_start( &totalRealTime, false );
if( optimizer.Optimize(original, &optimized) ) if( optimizer.Optimize( original, &optimized ) )
{ {
node->Remove(original); node->Remove( original );
optimizer.CacheRemove(original); optimizer.CacheRemove( original );
node->Add(&optimized); node->Add( &optimized );
if(original->BelongsTo(node)) if( original->BelongsTo( node ) )
delete original; delete original;
} }
prof_end( &totalRealTime );
TRACE(2,"t-optimizeObstacle %lld us", (totalRealTime.value )); prof_end( &totalRealTime );
TRACE( 2, "t-optimizeObstacle %lld us", (totalRealTime.value ) );
} }
lineStack.pop();
} else {
switch(nearest->item->GetKind()) lineStack.pop();
}
else
{
switch( nearest->item->GetKind() )
{ {
case PNS_ITEM::SEGMENT: case PNS_ITEM::SEGMENT:
{ {
TRACE(1, "Iter %d shove-line", iter ); TRACE( 1, "Iter %d shove-line", iter );
PNS_SEGMENT *pseg = static_cast<PNS_SEGMENT*>(nearest->item); PNS_SEGMENT* pseg = static_cast<PNS_SEGMENT*>(nearest->item);
PNS_LINE *collidingLine = node->AssembleLine(pseg); PNS_LINE* collidingLine = node->AssembleLine( pseg );
PNS_LINE *shovedLine = collidingLine->CloneProperties(); PNS_LINE* shovedLine = collidingLine->CloneProperties();
prof_start( &totalRealTime, false ); prof_start( &totalRealTime, false );
ShoveStatus st = shoveSingleLine(node, currentLine, collidingLine, *pseg, shovedLine); ShoveStatus st = shoveSingleLine( node, currentLine, collidingLine,
*pseg, shovedLine );
prof_end( &totalRealTime ); prof_end( &totalRealTime );
TRACE(2,"t-shoveSingle %lld us", (totalRealTime.value )); TRACE( 2, "t-shoveSingle %lld us", (totalRealTime.value ) );
if(st == SH_OK) if( st == SH_OK )
{ {
node->Replace(collidingLine, shovedLine); node->Replace( collidingLine, shovedLine );
if(collidingLine->BelongsTo( node )) if( collidingLine->BelongsTo( node ) )
delete collidingLine; delete collidingLine;
optimizer.CacheRemove(collidingLine); optimizer.CacheRemove( collidingLine );
lineStack.push( shovedLine ); lineStack.push( shovedLine );
} else }
else
fail = true; fail = true;
//lastWalkSolid = NULL; // lastWalkSolid = NULL;
break; break;
} // case SEGMENT } // case SEGMENT
...@@ -401,67 +421,72 @@ PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines(PNS_LINE* aCurrentHead) ...@@ -401,67 +421,72 @@ PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines(PNS_LINE* aCurrentHead)
case PNS_ITEM::SOLID: case PNS_ITEM::SOLID:
case PNS_ITEM::VIA: case PNS_ITEM::VIA:
{ {
TRACE(1, "Iter %d walkaround-solid [%p]", iter % nearest->item ); TRACE( 1, "Iter %d walkaround-solid [%p]", iter % nearest->item );
if(lineStack.size() == 1) if( lineStack.size() == 1 )
{ {
fail = true; fail = true;
break; break;
} }
/* if(lastWalkSolid == nearest->item) /* if(lastWalkSolid == nearest->item)
{ * {
fail = true; * fail = true;
break; * break;
}*/ * }*/
PNS_WALKAROUND walkaround (node); PNS_WALKAROUND walkaround( node );
PNS_LINE *walkaroundLine = currentLine->CloneProperties(); PNS_LINE* walkaroundLine = currentLine->CloneProperties();
walkaround.SetSolidsOnly(true); walkaround.SetSolidsOnly( true );
walkaround.SetSingleDirection(true); walkaround.SetSingleDirection( true );
prof_start( &totalRealTime, false ); prof_start( &totalRealTime, false );
walkaround.Route(*currentLine, *walkaroundLine, false); walkaround.Route( *currentLine, *walkaroundLine, false );
prof_end( &totalRealTime ); prof_end( &totalRealTime );
TRACE(2,"t-walkSolid %lld us", (totalRealTime.value )); TRACE( 2, "t-walkSolid %lld us", (totalRealTime.value ) );
node->Replace(currentLine, walkaroundLine); node->Replace( currentLine, walkaroundLine );
if(currentLine->BelongsTo( node )) if( currentLine->BelongsTo( node ) )
delete currentLine; delete currentLine;
optimizer.CacheRemove(currentLine); optimizer.CacheRemove( currentLine );
lineStack.top() = walkaroundLine; lineStack.top() = walkaroundLine;
//lastWalkSolid = nearest->item; // lastWalkSolid = nearest->item;
break; break;
} }
default: default:
break; break;
} // switch } // switch
if(fail)
if( fail )
break; break;
} }
} }
node->Remove(head); node->Remove( head );
delete head; delete head;
if(headVia) if( headVia )
{ {
node->Remove(headVia); node->Remove( headVia );
delete headVia; delete headVia;
} }
TRACE(1, "Shove status : %s after %d iterations" , (fail ? "FAILED" : "OK") % iter ); TRACE( 1, "Shove status : %s after %d iterations", (fail ? "FAILED" : "OK") % iter );
if(!fail)
if( !fail )
{ {
pushSpringback(node, aCurrentHead, PNS_COST_ESTIMATOR()); pushSpringback( node, aCurrentHead, PNS_COST_ESTIMATOR() );
return SH_OK; return SH_OK;
} else { }
else
{
delete node; delete node;
return SH_INCOMPLETE; return SH_INCOMPLETE;
} }
......
...@@ -30,21 +30,22 @@ class PNS_LINE; ...@@ -30,21 +30,22 @@ class PNS_LINE;
class PNS_NODE; class PNS_NODE;
class PNS_ROUTER; class PNS_ROUTER;
class PNS_SHOVE { class PNS_SHOVE
{
public: public:
PNS_SHOVE(PNS_NODE *aWorld); PNS_SHOVE( PNS_NODE* aWorld );
~PNS_SHOVE(); ~PNS_SHOVE();
enum ShoveStatus { enum ShoveStatus
{
SH_OK = 0, SH_OK = 0,
SH_NULL, SH_NULL,
SH_INCOMPLETE SH_INCOMPLETE
}; };
ShoveStatus ShoveLines(PNS_LINE* aCurrentHead); ShoveStatus ShoveLines( PNS_LINE* aCurrentHead );
PNS_NODE *GetCurrentNode() PNS_NODE* GetCurrentNode()
{ {
return m_nodeStack.empty() ? m_root : m_nodeStack.back().node; return m_nodeStack.empty() ? m_root : m_nodeStack.back().node;
} }
...@@ -54,29 +55,32 @@ class PNS_SHOVE { ...@@ -54,29 +55,32 @@ class PNS_SHOVE {
void Reset(); void Reset();
void KillChildNodes(); void KillChildNodes();
private: private:
static const int ShoveTimeLimit = 3000; static const int ShoveTimeLimit = 3000;
bool tryShove(PNS_NODE *aWorld, PNS_LINE *aTrack, PNS_LINE * aObstacle, PNS_SEGMENT& aObstacleSeg, PNS_LINE *aResult, bool aInvertWinding ); bool tryShove( PNS_NODE* aWorld, PNS_LINE* aTrack, PNS_LINE* aObstacle,
PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult, bool aInvertWinding );
ShoveStatus shoveSingleLine(PNS_NODE *aNode, PNS_LINE *aCurrent, PNS_LINE *aObstacle, PNS_SEGMENT& aObstacleSeg, PNS_LINE *aResult ); ShoveStatus shoveSingleLine( PNS_NODE* aNode, PNS_LINE* aCurrent, PNS_LINE* aObstacle,
PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult );
bool reduceSpringback( PNS_LINE *aHead ); bool reduceSpringback( PNS_LINE* aHead );
bool pushSpringback( PNS_NODE *aNode, PNS_LINE *aHead, const PNS_COST_ESTIMATOR& aCost ); bool pushSpringback( PNS_NODE* aNode, PNS_LINE* aHead, const PNS_COST_ESTIMATOR& aCost );
struct SpringbackTag { struct SpringbackTag
{
int64_t length; int64_t length;
int segments; int segments;
VECTOR2I p; VECTOR2I p;
PNS_NODE *node; PNS_NODE* node;
PNS_COST_ESTIMATOR cost; PNS_COST_ESTIMATOR cost;
}; };
std::vector<SpringbackTag> m_nodeStack; std::vector<SpringbackTag> m_nodeStack;
PNS_NODE *m_root; PNS_NODE* m_root;
PNS_NODE *m_currentNode; PNS_NODE* m_currentNode;
int m_iterLimit; int m_iterLimit;
}; };
#endif #endif
...@@ -28,28 +28,25 @@ ...@@ -28,28 +28,25 @@
#include "pns_solid.h" #include "pns_solid.h"
#include "pns_utils.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()) switch( m_shape->Type() )
{ {
case SH_RECT: case SH_RECT:
{ {
SHAPE_RECT *rect = static_cast<SHAPE_RECT*> (m_shape); SHAPE_RECT* rect = static_cast<SHAPE_RECT*>( m_shape );
return OctagonalHull( rect->GetPosition(), return OctagonalHull( rect->GetPosition(), rect->GetSize(),
rect->GetSize(), aClearance + 1, 0.2 * aClearance );
aClearance + 1,
0.2 * aClearance );
} }
case SH_CIRCLE: case SH_CIRCLE:
{ {
SHAPE_CIRCLE *circle = static_cast<SHAPE_CIRCLE*> (m_shape); SHAPE_CIRCLE* circle = static_cast<SHAPE_CIRCLE*>( m_shape );
int r = circle->GetRadius(); int r = circle->GetRadius();
return OctagonalHull( circle->GetCenter() - VECTOR2I(r, r), return OctagonalHull( circle->GetCenter() - VECTOR2I( r, r ), VECTOR2I( 2 * r, 2 * r ),
VECTOR2I(2 * r, 2 * r), aClearance + 1, 0.52 * (r + aClearance) );
aClearance + 1,
0.52 * (r + aClearance) );
} }
default: default:
break; break;
} }
...@@ -57,8 +54,10 @@ const SHAPE_LINE_CHAIN PNS_SOLID::Hull(int aClearance, int aWalkaroundThickness) ...@@ -57,8 +54,10 @@ const SHAPE_LINE_CHAIN PNS_SOLID::Hull(int aClearance, int aWalkaroundThickness)
return SHAPE_LINE_CHAIN(); 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 // solids are never cloned as the shove algorithm never moves them
assert(false); assert( false );
} }
...@@ -29,24 +29,26 @@ ...@@ -29,24 +29,26 @@
#include "pns_item.h" #include "pns_item.h"
class PNS_SOLID : public PNS_ITEM { class PNS_SOLID : public PNS_ITEM
{
public: public:
PNS_SOLID() : PNS_ITEM(SOLID) PNS_SOLID() : PNS_ITEM( SOLID )
{ {
m_movable = false; m_movable = false;
m_shape = NULL; m_shape = NULL;
} }
PNS_ITEM *Clone() const; PNS_ITEM* Clone() const;
const SHAPE* GetShape() const { return m_shape; } const SHAPE* GetShape() const { return m_shape; }
const SHAPE_LINE_CHAIN Hull(int aClearance = 0, int aWalkaroundThickness = 0) const; const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0 ) const;
void SetShape( SHAPE* shape) void SetShape( SHAPE* shape )
{ {
if(m_shape) if( m_shape )
delete m_shape; delete m_shape;
m_shape = shape; m_shape = shape;
} }
...@@ -61,7 +63,6 @@ public: ...@@ -61,7 +63,6 @@ public:
} }
private: private:
VECTOR2I m_center; VECTOR2I m_center;
SHAPE* m_shape; SHAPE* m_shape;
}; };
......
...@@ -22,20 +22,23 @@ ...@@ -22,20 +22,23 @@
#include "pns_line.h" #include "pns_line.h"
#include "pns_router.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.SetClosed( true );
s.Append(aP0.x - aClearance , aP0.y - aClearance + aChamfer); s.Append( aP0.x - aClearance, aP0.y - aClearance + aChamfer );
s.Append(aP0.x - aClearance + aChamfer, aP0.y - aClearance); 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 - aChamfer, aP0.y - aClearance );
s.Append(aP0.x + aSize.x + aClearance, aP0.y - aClearance + aChamfer); 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, aP0.y + aSize.y + aClearance - aChamfer );
s.Append(aP0.x + aSize.x + aClearance - aChamfer, aP0.y + aSize.y + aClearance); 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 + aChamfer, aP0.y + aSize.y + aClearance );
s.Append(aP0.x - aClearance, aP0.y + aSize.y + aClearance - aChamfer); s.Append( aP0.x - aClearance, aP0.y + aSize.y + aClearance - aChamfer );
return s; return s;
} }
......
...@@ -24,10 +24,10 @@ ...@@ -24,10 +24,10 @@
#include <math/vector2d.h> #include <math/vector2d.h>
#include <geometry/shape_line_chain.h> #include <geometry/shape_line_chain.h>
/** Various utility functions */ /** 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
...@@ -26,36 +26,39 @@ ...@@ -26,36 +26,39 @@
static bool Circle2Circle( VECTOR2I p1, VECTOR2I p2, int r1, int r2, VECTOR2I& force ) static bool Circle2Circle( VECTOR2I p1, VECTOR2I p2, int r1, int r2, VECTOR2I& force )
{ {
int mindist = r1 + r2; int mindist = r1 + r2;
VECTOR2I delta = p2 - p1; VECTOR2I delta = p2 - p1;
int dist = delta.EuclideanNorm(); int dist = delta.EuclideanNorm();
if(dist >= mindist) if( dist >= mindist )
return false; return false;
force = delta.Resize(abs(mindist - dist) + 1); force = delta.Resize( abs( mindist - dist ) + 1 );
return true; return true;
}; };
static bool Rect2Circle( VECTOR2I rp0, VECTOR2I rsize, VECTOR2I cc, int cr, VECTOR2I& force ) static bool Rect2Circle( VECTOR2I rp0, VECTOR2I rsize, VECTOR2I cc, int cr, VECTOR2I& force )
{ {
VECTOR2I vts[] = { VECTOR2I(rp0.x, rp0.y), VECTOR2I vts[] =
VECTOR2I(rp0.x, rp0.y + rsize.y), {
VECTOR2I(rp0.x + rsize.x, rp0.y + rsize.y), VECTOR2I( rp0.x, rp0.y ),
VECTOR2I(rp0.x + rsize.x, rp0.y), VECTOR2I( rp0.x, rp0.y + rsize.y ),
VECTOR2I(rp0.x, rp0.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; int dist = INT_MAX;
VECTOR2I nearest; VECTOR2I nearest;
for (int i = 0; i < 4; i++) for( int i = 0; i < 4; i++ )
{ {
SEG s(vts[i], vts[i+1]); SEG s( vts[i], vts[i + 1] );
VECTOR2I pn = s.NearestPoint( cc ); VECTOR2I pn = s.NearestPoint( cc );
int d = (pn - cc).EuclideanNorm(); int d = (pn - cc).EuclideanNorm();
if( d < dist ) if( d < dist )
{ {
nearest = pn; nearest = pn;
...@@ -68,81 +71,91 @@ static bool Rect2Circle( VECTOR2I rp0, VECTOR2I rsize, VECTOR2I cc, int cr, VECT ...@@ -68,81 +71,91 @@ static bool Rect2Circle( VECTOR2I rp0, VECTOR2I rsize, VECTOR2I cc, int cr, VECT
VECTOR2I delta = cc - nearest; VECTOR2I delta = cc - nearest;
if(dist >= cr && !inside) if( dist >= cr && !inside )
return false; return false;
if(inside) if( inside )
force = -delta.Resize(abs(cr + dist) + 1); force = -delta.Resize( abs( cr + dist ) + 1 );
else else
force = delta.Resize(abs(cr - dist) + 1); force = delta.Resize( abs( cr - dist ) + 1 );
return true; 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()) switch( shape->Type() )
{ {
case SH_CIRCLE: case SH_CIRCLE:
{ {
const SHAPE_CIRCLE *cir = static_cast<const SHAPE_CIRCLE*>(shape); const SHAPE_CIRCLE* cir = static_cast<const SHAPE_CIRCLE*>(shape);
return Circle2Circle( cir->GetCenter(), p, cir->GetRadius(), r + clearance + 1, force ); return Circle2Circle( cir->GetCenter(), p, cir->GetRadius(), r + clearance + 1, force );
} }
case SH_RECT: case SH_RECT:
{ {
const SHAPE_RECT *rect = static_cast<const SHAPE_RECT*>(shape); const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>(shape);
return Rect2Circle( rect->GetPosition(), rect->GetSize(), p, r + clearance + 1, force ); return Rect2Circle( rect->GetPosition(), rect->GetSize(), p, r + clearance + 1, force );
} }
default: default:
return false; return false;
} }
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; int iter = 0;
PNS_VIA mv ( *this); PNS_VIA mv( *this );
VECTOR2I force, totalForce; VECTOR2I force, totalForce;
while(iter < aMaxIterations) while( iter < aMaxIterations )
{ {
PNS_NODE::OptObstacle obs = aNode->CheckColliding( &mv, aSolidsOnly ? PNS_ITEM::SOLID : PNS_ITEM::ANY); PNS_NODE::OptObstacle obs = aNode->CheckColliding( &mv,
aSolidsOnly ? PNS_ITEM::SOLID : PNS_ITEM::ANY );
if(!obs) if( !obs )
break; break;
int clearance = aNode->GetClearance(obs->item, &mv); int clearance = aNode->GetClearance( obs->item, &mv );
if(iter > 10) if( iter > 10 )
{ {
VECTOR2I l = - aDirection.Resize(m_diameter / 4); VECTOR2I l = -aDirection.Resize( m_diameter / 4 );
totalForce += l; totalForce += l;
mv.SetPos(mv.GetPos() + l); mv.SetPos( mv.GetPos() + l );
} }
if( ShPushoutForce(obs->item->GetShape(), mv.GetPos(), mv.GetDiameter() / 2, force, clearance) ) if( ShPushoutForce( obs->item->GetShape(), mv.GetPos(), mv.GetDiameter() / 2, force,
clearance ) )
{ {
totalForce += force; totalForce += force;
mv.SetPos(mv.GetPos() + force); mv.SetPos( mv.GetPos() + force );
} }
iter++; iter++;
} }
if(iter == aMaxIterations) if( iter == aMaxIterations )
return false; return false;
aForce = totalForce; aForce = totalForce;
return true; 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
...@@ -30,27 +30,28 @@ class PNS_NODE; ...@@ -30,27 +30,28 @@ class PNS_NODE;
class PNS_VIA : public PNS_ITEM class PNS_VIA : public PNS_ITEM
{ {
public: public:
PNS_VIA( ): PNS_VIA() :
PNS_ITEM (VIA) {}; PNS_ITEM( VIA ) {};
PNS_VIA( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aDiameter, int aNet = -1) : PNS_VIA( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers, int aDiameter, int aNet = -1 ) :
PNS_ITEM (VIA) { PNS_ITEM( VIA )
SetNet(aNet); {
SetLayers(aLayers); SetNet( aNet );
SetLayers( aLayers );
m_pos = aPos; m_pos = aPos;
m_diameter = aDiameter; m_diameter = aDiameter;
m_shape = SHAPE_CIRCLE(aPos, aDiameter/2); m_shape = SHAPE_CIRCLE( aPos, aDiameter / 2 );
}; };
PNS_VIA(const PNS_VIA& b) : PNS_ITEM(VIA) PNS_VIA( const PNS_VIA& b ) : PNS_ITEM( VIA )
{ {
SetNet(b.GetNet()); SetNet( b.GetNet() );
SetLayers(b.GetLayers()); SetLayers( b.GetLayers() );
m_pos = b.m_pos; m_pos = b.m_pos;
m_diameter = b.m_diameter; m_diameter = b.m_diameter;
m_shape = SHAPE_CIRCLE(m_pos, m_diameter/2); m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 );
} }
const VECTOR2I& GetPos() const const VECTOR2I& GetPos() const
...@@ -61,7 +62,7 @@ class PNS_VIA : public PNS_ITEM ...@@ -61,7 +62,7 @@ class PNS_VIA : public PNS_ITEM
void SetPos( const VECTOR2I& aPos ) void SetPos( const VECTOR2I& aPos )
{ {
m_pos = aPos; m_pos = aPos;
m_shape.SetCenter(aPos); m_shape.SetCenter( aPos );
} }
int GetDiameter() const int GetDiameter() const
...@@ -69,10 +70,10 @@ class PNS_VIA : public PNS_ITEM ...@@ -69,10 +70,10 @@ class PNS_VIA : public PNS_ITEM
return m_diameter; return m_diameter;
} }
void SetDiameter(int aDiameter) void SetDiameter( int aDiameter )
{ {
m_diameter = aDiameter; m_diameter = aDiameter;
m_shape.SetRadius(m_diameter/2); m_shape.SetRadius( m_diameter / 2 );
} }
int GetDrill() const int GetDrill() const
...@@ -80,34 +81,38 @@ class PNS_VIA : public PNS_ITEM ...@@ -80,34 +81,38 @@ class PNS_VIA : public PNS_ITEM
return m_drill; return m_drill;
} }
void SetDrill(int aDrill) void SetDrill( int aDrill )
{ {
m_drill = 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 const SHAPE* GetShape() const
{ {
return &m_shape; return &m_shape;
} }
PNS_VIA *Clone() const PNS_VIA* Clone() const
{ {
PNS_VIA *v = new PNS_VIA(); PNS_VIA* v = new PNS_VIA();
v->SetNet(GetNet()); v->SetNet( GetNet() );
v->SetLayers(GetLayers()); v->SetLayers( GetLayers() );
v->m_pos = m_pos; v->m_pos = m_pos;
v->m_diameter = m_diameter; v->m_diameter = m_diameter;
v->m_shape = SHAPE_CIRCLE(m_pos, m_diameter/2); v->m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 );
return v; return v;
} }
const SHAPE_LINE_CHAIN Hull(int aClearance = 0, int aWalkaroundThickness = 0) const; const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0 ) const;
private: private:
int m_diameter; int m_diameter;
int m_drill; int m_drill;
......
...@@ -40,182 +40,192 @@ void PNS_WALKAROUND::start( const PNS_LINE& aInitialPath ) ...@@ -40,182 +40,192 @@ void PNS_WALKAROUND::start( const PNS_LINE& aInitialPath )
} }
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<PNS_OBSTACLE>& current_obs = aWindingDirection ? m_currentObstacle[0] : m_currentObstacle[1]; optional<PNS_OBSTACLE>& current_obs =
aWindingDirection ? m_currentObstacle[0] : m_currentObstacle[1];
bool& prev_recursive = aWindingDirection ? m_recursiveCollision[0] : m_recursiveCollision[1]; bool& prev_recursive = aWindingDirection ? m_recursiveCollision[0] : m_recursiveCollision[1];
if(!current_obs) if( !current_obs )
return DONE; return DONE;
SHAPE_LINE_CHAIN path_pre[2], path_walk[2], path_post[2]; SHAPE_LINE_CHAIN path_pre[2], path_walk[2], path_post[2];
VECTOR2I last = aPath.GetCLine().CPoint(-1); VECTOR2I last = aPath.GetCLine().CPoint( -1 );
if((current_obs->hull).PointInside(last)) if( ( current_obs->hull ).PointInside( last ) )
{ {
m_recursiveBlockageCount ++; m_recursiveBlockageCount++;
if(m_recursiveBlockageCount < 3) if( m_recursiveBlockageCount < 3 )
aPath.GetLine().Append( current_obs->hull.NearestPoint(last) ); aPath.GetLine().Append( current_obs->hull.NearestPoint( last ) );
else { else
aPath = aPath.ClipToNearestObstacle(m_world); {
aPath = aPath.ClipToNearestObstacle( m_world );
return STUCK; return STUCK;
} }
} }
aPath.NewWalkaround(current_obs->hull, path_pre[0], path_walk[0], path_post[0], aWindingDirection); aPath.NewWalkaround( current_obs->hull, path_pre[0], path_walk[0],
aPath.NewWalkaround(current_obs->hull, path_pre[1], path_walk[1], path_post[1], !aWindingDirection); 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_pre = path_walk[0].Length();
int len_alt = path_walk[1].Length(); int len_alt = path_walk[1].Length();
PNS_LINE walk_path (aPath, path_walk[1]); 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); bool alt_collides = m_world->CheckColliding( &walk_path,
m_solids_only ? PNS_ITEM::SOLID : PNS_ITEM::ANY );
SHAPE_LINE_CHAIN pnew; SHAPE_LINE_CHAIN pnew;
if(!m_forceSingleDirection && len_alt < len_pre && !alt_collides && !prev_recursive) if( !m_forceSingleDirection && len_alt < len_pre && !alt_collides && !prev_recursive )
{ {
pnew = path_pre[1]; pnew = path_pre[1];
pnew.Append(path_walk[1]); pnew.Append( path_walk[1] );
pnew.Append(path_post[1]); pnew.Append( path_post[1] );
current_obs = nearestObstacle(PNS_LINE(aPath, path_post[1])); current_obs = nearestObstacle( PNS_LINE( aPath, path_post[1] ) );
prev_recursive = false; prev_recursive = false;
} else { }
else
{
pnew = path_pre[0]; pnew = path_pre[0];
pnew.Append(path_walk[0]); pnew.Append( path_walk[0] );
pnew.Append(path_post[0]); pnew.Append( path_post[0] );
current_obs = nearestObstacle(PNS_LINE(aPath, path_walk[0])); current_obs = nearestObstacle( PNS_LINE( aPath, path_walk[0] ) );
if(!current_obs) if( !current_obs )
{ {
prev_recursive = false; prev_recursive = false;
current_obs = nearestObstacle(PNS_LINE(aPath, path_post[0])); current_obs = nearestObstacle( PNS_LINE( aPath, path_post[0] ) );
} else }
else
prev_recursive = true; prev_recursive = true;
} }
pnew.Simplify(); pnew.Simplify();
aPath.SetShape(pnew); aPath.SetShape( pnew );
return IN_PROGRESS; 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); PNS_LINE path_cw( aInitialPath ), path_ccw( aInitialPath );
WalkaroundStatus s_cw = IN_PROGRESS, s_ccw = IN_PROGRESS; WalkaroundStatus s_cw = IN_PROGRESS, s_ccw = IN_PROGRESS;
SHAPE_LINE_CHAIN best_path; SHAPE_LINE_CHAIN best_path;
start(aInitialPath); start( aInitialPath );
m_currentObstacle[0] = m_currentObstacle[1] = nearestObstacle(aInitialPath); m_currentObstacle[0] = m_currentObstacle[1] = nearestObstacle( aInitialPath );
m_recursiveBlockageCount = 0; m_recursiveBlockageCount = 0;
aWalkPath = aInitialPath; aWalkPath = aInitialPath;
while(m_iteration < m_iteration_limit) while( m_iteration < m_iteration_limit )
{ {
if(s_cw != STUCK) if( s_cw != STUCK )
s_cw = singleStep(path_cw, true); s_cw = singleStep( path_cw, true );
if(s_ccw != STUCK) if( s_ccw != STUCK )
s_ccw = singleStep(path_ccw, false); s_ccw = singleStep( path_ccw, false );
if((s_cw == DONE && s_ccw == DONE) || (s_cw == STUCK && s_ccw == STUCK)) if( ( s_cw == DONE && s_ccw == DONE ) || ( s_cw == STUCK && s_ccw == STUCK ) )
{ {
int len_cw = path_cw.GetCLine().Length(); int len_cw = path_cw.GetCLine().Length();
int len_ccw = path_ccw.GetCLine().Length(); int len_ccw = path_ccw.GetCLine().Length();
if( m_forceLongerPath )
if(m_forceLongerPath)
aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw); aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw);
else else
aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw); aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw);
break; break;
} else if(s_cw == DONE && !m_forceLongerPath) { }
else if( s_cw == DONE && !m_forceLongerPath )
{
aWalkPath = path_cw; aWalkPath = path_cw;
break; break;
} else if (s_ccw == DONE && !m_forceLongerPath) { }
else if( s_ccw == DONE && !m_forceLongerPath )
{
aWalkPath = path_ccw; aWalkPath = path_ccw;
break; break;
} }
m_iteration++; m_iteration++;
} }
if(m_iteration == m_iteration_limit) if( m_iteration == m_iteration_limit )
{ {
int len_cw = path_cw.GetCLine().Length(); int len_cw = path_cw.GetCLine().Length();
int len_ccw = path_ccw.GetCLine().Length(); int len_ccw = path_ccw.GetCLine().Length();
if(m_forceLongerPath) if( m_forceLongerPath )
aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw); aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw);
else else
aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw); aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw);
} }
if(m_cursorApproachMode) if( m_cursorApproachMode )
{ {
//int len_cw = path_cw.GetCLine().Length(); // int len_cw = path_cw.GetCLine().Length();
//int len_ccw = path_ccw.GetCLine().Length(); // int len_ccw = path_ccw.GetCLine().Length();
bool found = false; bool found = false;
SHAPE_LINE_CHAIN l = aWalkPath.GetCLine(); SHAPE_LINE_CHAIN l = aWalkPath.GetCLine();
for( int i = 0; i < l.SegmentCount(); i++ )
for(int i = 0; i < l.SegmentCount(); i++)
{ {
const SEG s = l.Segment(i); const SEG s = l.Segment( i );
VECTOR2I nearest = s.NearestPoint(m_cursorPos); VECTOR2I nearest = s.NearestPoint( m_cursorPos );
VECTOR2I::extended_type dist_a = (s.a - m_cursorPos).SquaredEuclideanNorm(); VECTOR2I::extended_type dist_a = (s.a - m_cursorPos).SquaredEuclideanNorm();
VECTOR2I::extended_type dist_b = (s.b - m_cursorPos).SquaredEuclideanNorm(); VECTOR2I::extended_type dist_b = (s.b - m_cursorPos).SquaredEuclideanNorm();
VECTOR2I::extended_type dist_n = (nearest - m_cursorPos).SquaredEuclideanNorm(); VECTOR2I::extended_type dist_n = (nearest - m_cursorPos).SquaredEuclideanNorm();
if( dist_n <= dist_a && dist_n < dist_b )
if(dist_n <= dist_a && dist_n < dist_b)
{ {
//PNSDisplayDebugLine(l, 3); // PNSDisplayDebugLine(l, 3);
l.Remove(i + 1, -1); l.Remove( i + 1, -1 );
l.Append( nearest ); l.Append( nearest );
l.Simplify(); l.Simplify();
found = true; found = true;
break; break;
} }
} }
if(found)
if( found )
{ {
aWalkPath = aInitialPath; aWalkPath = aInitialPath;
aWalkPath.SetShape(l); aWalkPath.SetShape( l );
} }
} }
aWalkPath.SetWorld( m_world );
aWalkPath.SetWorld(m_world);
aWalkPath.GetLine().Simplify(); aWalkPath.GetLine().Simplify();
WalkaroundStatus st = s_ccw == DONE || s_cw == DONE ? DONE : STUCK; WalkaroundStatus st = s_ccw == DONE || s_cw == DONE ? DONE : STUCK;
if(aOptimize && st == DONE) if( aOptimize && st == DONE )
PNS_OPTIMIZER::Optimize(&aWalkPath, PNS_OPTIMIZER::MERGE_OBTUSE, m_world); PNS_OPTIMIZER::Optimize( &aWalkPath, PNS_OPTIMIZER::MERGE_OBTUSE, m_world );
return st; return st;
} }
...@@ -24,28 +24,28 @@ ...@@ -24,28 +24,28 @@
#include "pns_line.h" #include "pns_line.h"
#include "pns_node.h" #include "pns_node.h"
class PNS_WALKAROUND { class PNS_WALKAROUND
{
static const int DefaultIterationLimit = 50; static const int DefaultIterationLimit = 50;
public:
PNS_WALKAROUND( PNS_NODE* aWorld ) :
public: m_world( aWorld ), m_iteration_limit( DefaultIterationLimit )
PNS_WALKAROUND( PNS_NODE *aWorld ): {
m_world(aWorld), m_iteration_limit(DefaultIterationLimit) {
m_forceSingleDirection = false; m_forceSingleDirection = false;
m_forceLongerPath = false; m_forceLongerPath = false;
m_cursorApproachMode = false; m_cursorApproachMode = false;
}; };
~PNS_WALKAROUND() {}; ~PNS_WALKAROUND() {};
enum WalkaroundStatus { enum WalkaroundStatus
{
IN_PROGRESS = 0, IN_PROGRESS = 0,
DONE, DONE,
STUCK STUCK
}; };
void SetWorld ( PNS_NODE *aNode ) void SetWorld( PNS_NODE* aNode )
{ {
m_world = aNode; m_world = aNode;
} }
...@@ -55,34 +55,33 @@ class PNS_WALKAROUND { ...@@ -55,34 +55,33 @@ class PNS_WALKAROUND {
m_iteration_limit = aIterLimit; m_iteration_limit = aIterLimit;
} }
void SetSolidsOnly ( bool aSolidsOnly ) void SetSolidsOnly( bool aSolidsOnly )
{ {
m_solids_only = aSolidsOnly; m_solids_only = aSolidsOnly;
} }
void SetSingleDirection( bool aForceSingleDirection )
void SetSingleDirection (bool aForceSingleDirection )
{ {
m_forceSingleDirection = aForceSingleDirection; m_forceSingleDirection = aForceSingleDirection;
m_forceLongerPath = true; m_forceLongerPath = true;
} }
void SetApproachCursor ( bool aEnabled, const VECTOR2I& aPos ) void SetApproachCursor( bool aEnabled, const VECTOR2I& aPos )
{ {
m_cursorPos = aPos; m_cursorPos = aPos;
m_cursorApproachMode = aEnabled; m_cursorApproachMode = aEnabled;
} }
WalkaroundStatus Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath,
bool aOptimize = true );
WalkaroundStatus Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath, bool aOptimize = true); private:
private:
void start( const PNS_LINE& aInitialPath ); void start( const PNS_LINE& aInitialPath );
WalkaroundStatus singleStep(PNS_LINE& aPath, bool aWindingDirection); WalkaroundStatus singleStep( PNS_LINE& aPath, bool aWindingDirection );
PNS_NODE::OptObstacle nearestObstacle(const PNS_LINE& aPath); PNS_NODE::OptObstacle nearestObstacle( const PNS_LINE& aPath );
PNS_NODE *m_world; PNS_NODE* m_world;
int m_recursiveBlockageCount; int m_recursiveBlockageCount;
int m_iteration; int m_iteration;
......
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
...@@ -31,167 +31,200 @@ ...@@ -31,167 +31,200 @@
using namespace KiGfx; using namespace KiGfx;
ROUTER_PREVIEW_ITEM::ROUTER_PREVIEW_ITEM( const PNS_ITEM *aItem, VIEW_GROUP *aParent ) ROUTER_PREVIEW_ITEM::ROUTER_PREVIEW_ITEM( const PNS_ITEM* aItem, VIEW_GROUP* aParent ) :
: EDA_ITEM( NOT_USED ) EDA_ITEM( NOT_USED )
{ {
m_Flags = 0; m_Flags = 0;
m_parent = aParent; m_parent = aParent;
if(aItem)
Update(aItem); if( aItem )
} Update( aItem );
}
ROUTER_PREVIEW_ITEM::~ROUTER_PREVIEW_ITEM() 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 = getLayerColor( m_layer );
m_color.a = 0.8; m_color.a = 0.8;
switch(aItem->GetKind()) switch( aItem->GetKind() )
{ {
case PNS_ITEM::LINE: case PNS_ITEM::LINE:
m_type = PR_LINE; m_type = PR_LINE;
m_width = static_cast<const PNS_LINE *>(aItem)->GetWidth(); m_width = static_cast<const PNS_LINE*>(aItem)->GetWidth();
m_line = * static_cast<const SHAPE_LINE_CHAIN *>(aItem->GetShape()); m_line = *static_cast<const SHAPE_LINE_CHAIN*>( aItem->GetShape() );
break; break;
case PNS_ITEM::SEGMENT: case PNS_ITEM::SEGMENT:
m_type = PR_LINE; m_type = PR_LINE;
m_width = static_cast<const PNS_SEGMENT *>(aItem)->GetWidth(); m_width = static_cast<const PNS_SEGMENT*>(aItem)->GetWidth();
m_line = * static_cast<const SHAPE_LINE_CHAIN *>(aItem->GetShape()); m_line = *static_cast<const SHAPE_LINE_CHAIN*>( aItem->GetShape() );
break; break;
case PNS_ITEM::VIA: case PNS_ITEM::VIA:
m_type = PR_VIA; m_type = PR_VIA;
m_color = COLOR4D(0.7, 0.7, 0.7, 0.8); m_color = COLOR4D( 0.7, 0.7, 0.7, 0.8 );
m_width = static_cast<const PNS_VIA *>(aItem)->GetDiameter(); m_width = static_cast<const PNS_VIA*>(aItem)->GetDiameter();
m_viaCenter = static_cast<const PNS_VIA *>(aItem)->GetPos(); m_viaCenter = static_cast<const PNS_VIA*>(aItem)->GetPos();
break; break;
default: default:
break; break;
} }
ViewSetVisible(true); ViewSetVisible( true );
ViewUpdate(GEOMETRY | APPEARANCE); ViewUpdate( GEOMETRY | APPEARANCE );
} }
void ROUTER_PREVIEW_ITEM::MarkAsHead( )
void ROUTER_PREVIEW_ITEM::MarkAsHead()
{ {
if(m_type != PR_VIA) if( m_type != PR_VIA )
m_color.Saturate(1.0); 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) switch( m_type )
{ {
case PR_LINE: case PR_LINE:
bbox = m_line.BBox(); bbox = m_line.BBox();
bbox.Inflate( m_width / 2); bbox.Inflate( m_width / 2 );
return bbox; return bbox;
case PR_VIA: case PR_VIA:
bbox = BOX2I( m_viaCenter, VECTOR2I(0, 0)); bbox = BOX2I( m_viaCenter, VECTOR2I( 0, 0 ) );
bbox.Inflate( m_width / 2); bbox.Inflate( m_width / 2 );
return bbox; return bbox;
default: default:
break; break;
} }
return bbox; return bbox;
} }
void ROUTER_PREVIEW_ITEM::ViewDraw( int aLayer, KiGfx::GAL* aGal ) const void ROUTER_PREVIEW_ITEM::ViewDraw( int aLayer, KiGfx::GAL* aGal ) const
{ {
switch( m_type ) switch( m_type )
{ {
case PR_LINE: 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); for( int s = 0; s < m_line.SegmentCount(); s++ )
aGal->SetLineWidth(m_width); aGal->DrawLine( m_line.CSegment( s ).a, m_line.CSegment( s ).b );
aGal->SetStrokeColor(m_color);
aGal->SetIsStroke(true); if( m_line.IsClosed() )
aGal->SetIsFill(false); aGal->DrawLine( m_line.CSegment( -1 ).b, m_line.CSegment( 0 ).a );
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; break;
case PR_VIA:
aGal->SetLayerDepth(-101.0); case PR_VIA:
aGal->SetIsStroke(false); aGal->SetLayerDepth( -101.0 );
aGal->SetIsFill(true); aGal->SetIsStroke( false );
aGal->SetFillColor(m_color); aGal->SetIsFill( true );
aGal->DrawCircle(m_viaCenter, m_width / 2); aGal->SetFillColor( m_color );
aGal->DrawCircle( m_viaCenter, m_width / 2 );
break; break;
default: default:
break; 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 #if 0
m_line = aLine; m_line = aLine;
m_width = aWidth; m_width = aWidth;
m_color = assignColor(aStyle); m_color = assignColor( aStyle );
m_type = PR_LINE; m_type = PR_LINE;
ViewUpdate(GEOMETRY | APPEARANCE); ViewUpdate( GEOMETRY | APPEARANCE );
#endif #endif
} }
void ROUTER_PREVIEW_ITEM::DebugBox ( const BOX2I& aBox, int aStyle )
void ROUTER_PREVIEW_ITEM::DebugBox( const BOX2I& aBox, int aStyle )
{ {
#if 0 #if 0
assert(false); assert( false );
m_line.Clear(); m_line.Clear();
m_line.Append( aBox.GetX(), aBox.GetY() ); 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.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.Append( aBox.GetX(), aBox.GetY() + aBox.GetHeight() );
m_line.SetClosed(true); m_line.SetClosed( true );
m_width = 20000; m_width = 20000;
m_color = assignColor(aStyle); m_color = assignColor( aStyle );
m_type = PR_LINE; m_type = PR_LINE;
ViewUpdate(GEOMETRY | APPEARANCE); ViewUpdate( GEOMETRY | APPEARANCE );
#endif #endif
} }
const COLOR4D ROUTER_PREVIEW_ITEM::getLayerColor (int layer ) const
const COLOR4D ROUTER_PREVIEW_ITEM::getLayerColor( int aLayer ) const
{ {
//assert (m_view != NULL); // assert (m_view != NULL);
PCB_RENDER_SETTINGS* settings =
static_cast <PCB_RENDER_SETTINGS*> ( m_parent->GetView()->GetPainter()->GetSettings() );
PCB_RENDER_SETTINGS *settings = static_cast <PCB_RENDER_SETTINGS*> (m_parent -> GetView() -> GetPainter() -> GetSettings()); return settings->GetLayerColor( aLayer );
return settings->GetLayerColor(layer);
} }
const COLOR4D ROUTER_PREVIEW_ITEM::assignColor ( int style ) const const COLOR4D ROUTER_PREVIEW_ITEM::assignColor( int aStyle ) const
{ {
COLOR4D color; COLOR4D color;
switch(style)
switch( aStyle )
{ {
case 0: color =COLOR4D(0, 1, 0, 1);break; case 0:
case 1: color =COLOR4D(1, 0, 0, 0.3);break; color = COLOR4D( 0, 1, 0, 1 ); break;
case 2: color =COLOR4D(1, 0.5, 0.5, 1);break;
case 3: color =COLOR4D(0, 0, 1, 1);break; case 1:
case 4: color =COLOR4D(1, 1, 1, 1); break; color = COLOR4D( 1, 0, 0, 0.3 ); break;
case 5: color =COLOR4D(1, 1, 0, 1); break;
case 6: color =COLOR4D(0, 1, 1, 1); break; case 2:
case 32: color =COLOR4D(0, 0, 1, 0.5); break; color = COLOR4D( 1, 0.5, 0.5, 1 ); break;
default: 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; return color;
} }
...@@ -43,29 +43,31 @@ class PNS_ROUTER; ...@@ -43,29 +43,31 @@ class PNS_ROUTER;
class ROUTER_PREVIEW_ITEM : public EDA_ITEM class ROUTER_PREVIEW_ITEM : public EDA_ITEM
{ {
public: public:
enum ItemType { enum ItemType
{
PR_VIA, PR_VIA,
PR_LINE, PR_LINE,
PR_STUCK_MARKER PR_STUCK_MARKER
}; };
enum ItemFlags { enum ItemFlags
{
PR_SUGGESTION = 1 PR_SUGGESTION = 1
}; };
ROUTER_PREVIEW_ITEM( const PNS_ITEM *aItem = NULL, KiGfx::VIEW_GROUP *aParent = NULL ); ROUTER_PREVIEW_ITEM( const PNS_ITEM* aItem = NULL, KiGfx::VIEW_GROUP* aParent = NULL );
~ROUTER_PREVIEW_ITEM(); ~ROUTER_PREVIEW_ITEM();
void Update ( const PNS_ITEM *aItem); void Update( const PNS_ITEM* aItem );
void StuckMarker( VECTOR2I& aPosition ); void StuckMarker( VECTOR2I& aPosition );
void DebugLine ( const SHAPE_LINE_CHAIN& aLine, int aWidth = 0, int aStyle = 0 ); void DebugLine( const SHAPE_LINE_CHAIN& aLine, int aWidth = 0, int aStyle = 0 );
void DebugBox ( const BOX2I& aBox, int aStyle = 0); void DebugBox( const BOX2I& aBox, int aStyle = 0 );
void Show(int a, std::ostream& b) const {};
const BOX2I ViewBBox() const; void Show( int a, std::ostream& b ) const {};
const BOX2I ViewBBox() const;
virtual void ViewDraw( int aLayer, KiGfx::GAL* aGal ) const; virtual void ViewDraw( int aLayer, KiGfx::GAL* aGal ) const;
...@@ -75,16 +77,15 @@ class ROUTER_PREVIEW_ITEM : public EDA_ITEM ...@@ -75,16 +77,15 @@ class ROUTER_PREVIEW_ITEM : public EDA_ITEM
aCount = 1; aCount = 1;
} }
void MarkAsHead( ); void MarkAsHead();
private: private:
const KiGfx::COLOR4D assignColor( int aStyle ) const;
const KiGfx::COLOR4D getLayerColor( int aLayer ) const;
const KiGfx::COLOR4D assignColor ( int style ) const; KiGfx::VIEW_GROUP* m_parent;
const KiGfx::COLOR4D getLayerColor (int layer ) const;
KiGfx::VIEW_GROUP *m_parent; PNS_ROUTER* m_router;
PNS_ROUTER *m_router;
SHAPE_LINE_CHAIN m_line; SHAPE_LINE_CHAIN m_line;
ItemType m_type; ItemType m_type;
...@@ -96,8 +97,7 @@ class ROUTER_PREVIEW_ITEM : public EDA_ITEM ...@@ -96,8 +97,7 @@ class ROUTER_PREVIEW_ITEM : public EDA_ITEM
VECTOR2I m_stuckPosition; VECTOR2I m_stuckPosition;
VECTOR2I m_viaCenter; VECTOR2I m_viaCenter;
}; };
#endif #endif
...@@ -42,27 +42,27 @@ using namespace KiGfx; ...@@ -42,27 +42,27 @@ using namespace KiGfx;
using namespace std; using namespace std;
using boost::optional; using boost::optional;
static TOOL_ACTION ACT_AutoEndRoute ( "AutoEndRoute", AS_CONTEXT, 'F' ); static TOOL_ACTION ACT_AutoEndRoute( "AutoEndRoute", AS_CONTEXT, 'F' );
static TOOL_ACTION ACT_PlaceVia ( "PlaceVia", AS_CONTEXT, 'V' ); static TOOL_ACTION ACT_PlaceVia( "PlaceVia", AS_CONTEXT, 'V' );
static TOOL_ACTION ACT_OpenRouteOptions ( "OpenRouterOptions", AS_CONTEXT, 'E' ); static TOOL_ACTION ACT_OpenRouteOptions( "OpenRouterOptions", AS_CONTEXT, 'E' );
static TOOL_ACTION ACT_SwitchPosture ( "SwitchPosture", AS_CONTEXT, '/' ); static TOOL_ACTION ACT_SwitchPosture( "SwitchPosture", AS_CONTEXT, '/' );
static TOOL_ACTION ACT_EndTrack ( "SwitchPosture", AS_CONTEXT, WXK_END ); static TOOL_ACTION ACT_EndTrack( "SwitchPosture", AS_CONTEXT, WXK_END );
ROUTER_TOOL::ROUTER_TOOL() : ROUTER_TOOL::ROUTER_TOOL() :
TOOL_INTERACTIVE( "pcbnew.InteractiveRouter" ) TOOL_INTERACTIVE( "pcbnew.InteractiveRouter" )
{ {
m_router = NULL; m_router = NULL;
m_menu = new CONTEXT_MENU ; m_menu = new CONTEXT_MENU;
m_menu->SetTitle( wxT( "Interactive router") ); // fixme: not implemented yet. Sorry. m_menu->SetTitle( wxT( "Interactive router" ) ); // fixme: not implemented yet. Sorry.
m_menu->Add( wxT ("Cancel"), 0); m_menu->Add( wxT( "Cancel" ), 0 );
m_menu->Add( wxT ("New track"), 1); m_menu->Add( wxT( "New track" ), 1 );
m_menu->Add( wxT ("End track"), 2); m_menu->Add( wxT( "End track" ), 2 );
m_menu->Add( wxT ("Auto-end track"), 2); m_menu->Add( wxT( "Auto-end track" ), 2 );
m_menu->Add( wxT ("Place via"), 3); m_menu->Add( wxT( "Place via" ), 3 );
m_menu->Add( wxT ("Switch posture"), 4); m_menu->Add( wxT( "Switch posture" ), 4 );
m_menu->Add( wxT ("Routing options..."), 5); m_menu->Add( wxT( "Routing options..." ), 5 );
} }
...@@ -74,38 +74,41 @@ ROUTER_TOOL::~ROUTER_TOOL() ...@@ -74,38 +74,41 @@ ROUTER_TOOL::~ROUTER_TOOL()
void ROUTER_TOOL::Reset() void ROUTER_TOOL::Reset()
{ {
if( m_router )
if(m_router)
delete m_router; delete m_router;
m_router = new PNS_ROUTER; m_router = new PNS_ROUTER;
TRACEn(0,"Reset"); TRACEn( 0, "Reset" );
m_router->ClearWorld(); m_router->ClearWorld();
m_router->SetBoard( getModel <BOARD> (PCB_T) ); m_router->SetBoard( getModel<BOARD>( PCB_T ) );
m_router->SyncWorld(); m_router->SyncWorld();
if(getView()) if( getView() )
m_router->SetView( getView() ); m_router->SetView( getView() );
Go( &ROUTER_TOOL::Main, TOOL_EVENT( TC_Command, TA_Action, GetName() ) ); Go( &ROUTER_TOOL::Main, TOOL_EVENT( TC_Command, TA_Action, GetName() ) );
} }
int ROUTER_TOOL::getDefaultWidth( int aNetCode ) int ROUTER_TOOL::getDefaultWidth( int aNetCode )
{ {
int w, d1, d2; int w, d1, d2;
getNetclassDimensions( aNetCode, w, d1, d2);
getNetclassDimensions( aNetCode, w, d1, d2 );
return w; 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 <BOARD> (PCB_T); BOARD* board = getModel<BOARD>( PCB_T );
NETCLASS* netClass = NULL; NETCLASS* netClass = NULL;
NETINFO_ITEM *ni = board->FindNet(aNetCode); NETINFO_ITEM* ni = board->FindNet( aNetCode );
if(ni) if( ni )
{ {
wxString netClassName = ni->GetClassName(); wxString netClassName = ni->GetClassName();
netClass = board->m_NetClasses.Find( netClassName ); netClass = board->m_NetClasses.Find( netClassName );
...@@ -120,19 +123,20 @@ void ROUTER_TOOL::getNetclassDimensions ( int aNetCode, int& aWidth, int& aViaDi ...@@ -120,19 +123,20 @@ void ROUTER_TOOL::getNetclassDimensions ( int aNetCode, int& aWidth, int& aViaDi
} }
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(); int tl = getView()->GetTopLayer();
if(aLayer > 0) if( aLayer > 0 )
tl = aLayer; tl = aLayer;
PNS_ITEM *picked_seg = NULL, *picked_via = NULL; PNS_ITEM* picked_seg = NULL;
PNS_ITEMSET candidates = m_router->QueryHoverItems(aWhere); 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; continue;
if( item->GetParent() && !item->GetParent()->ViewIsVisible() ) if( item->GetParent() && !item->GetParent()->ViewIsVisible() )
...@@ -140,12 +144,14 @@ PNS_ITEM *ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLa ...@@ -140,12 +144,14 @@ PNS_ITEM *ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLa
if( aNet < 0 || item->GetNet() == aNet ) 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) if( item->GetLayers().Overlaps( tl ) || !picked_via )
picked_via = item; picked_via = item;
} else { }
if(item->GetLayers().Overlaps(tl) || !picked_seg) else
{
if( item->GetLayers().Overlaps( tl ) || !picked_seg )
picked_seg = item; picked_seg = item;
} }
} }
...@@ -153,95 +159,101 @@ PNS_ITEM *ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLa ...@@ -153,95 +159,101 @@ PNS_ITEM *ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLa
if( DisplayOpt.ContrastModeDisplay ) if( DisplayOpt.ContrastModeDisplay )
{ {
if( picked_seg && !picked_seg->GetLayers().Overlaps(tl)) if( picked_seg && !picked_seg->GetLayers().Overlaps( tl ) )
picked_seg = NULL; picked_seg = NULL;
} }
PNS_ITEM *rv = picked_via ? picked_via : picked_seg; PNS_ITEM* rv = picked_via ? picked_via : picked_seg;
if( rv && aLayer >= 0 && !rv-> GetLayers().Overlaps(aLayer) ) if( rv && aLayer >= 0 && !rv->GetLayers().Overlaps( aLayer ) )
rv = NULL; rv = NULL;
if(rv) if( rv )
TRACE(0, "%s, layer : %d, tl: %d", rv->GetKindStr().c_str() % rv->GetLayers().Start() % tl); TRACE( 0, "%s, layer : %d, tl: %d", rv->GetKindStr().c_str() % rv->GetLayers().Start() %
tl );
return rv; return rv;
} }
void ROUTER_TOOL::setMsgPanel( bool aEnabled, int aEntry,
void ROUTER_TOOL::setMsgPanel ( bool enabled, int entry, const wxString& aUpperMessage, const wxString& aLowerMessage ) const wxString& aUpperMessage, const wxString& aLowerMessage )
{ {
PCB_EDIT_FRAME *frame = getEditFrame<PCB_EDIT_FRAME> (); PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME> ();
if(m_panelItems.size() <= (unsigned int) entry) if( m_panelItems.size() <= (unsigned int) aEntry )
m_panelItems.resize(entry + 1); m_panelItems.resize( aEntry + 1 );
m_panelItems[entry] = MSG_PANEL_ITEM( aUpperMessage, aLowerMessage, BLACK ); m_panelItems[aEntry] = MSG_PANEL_ITEM( aUpperMessage, aLowerMessage, BLACK );
frame->SetMsgPanel(m_panelItems); frame->SetMsgPanel( m_panelItems );
} }
void ROUTER_TOOL::clearMsgPanel() void ROUTER_TOOL::clearMsgPanel()
{ {
PCB_EDIT_FRAME *frame = getEditFrame<PCB_EDIT_FRAME> (); PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME> ();
frame->ClearMsgPanel(); frame->ClearMsgPanel();
} }
void ROUTER_TOOL::highlightNet(bool enabled, int netcode)
void ROUTER_TOOL::highlightNet( bool aEnabled, int aNetcode )
{ {
RENDER_SETTINGS *rs = getView()->GetPainter()->GetSettings(); RENDER_SETTINGS* rs = getView()->GetPainter()->GetSettings();
if(netcode >= 0 && enabled) if( aNetcode >= 0 && aEnabled )
rs->SetHighlight(true, netcode); rs->SetHighlight( true, aNetcode );
else else
rs->SetHighlight(false); rs->SetHighlight( false );
getView()->UpdateAllLayersColor(); getView()->UpdateAllLayersColor();
} }
void ROUTER_TOOL::updateStartItem( TOOL_EVENT& aEvent ) void ROUTER_TOOL::updateStartItem( TOOL_EVENT& aEvent )
{ {
VIEW_CONTROLS *ctls = getViewControls(); VIEW_CONTROLS* ctls = getViewControls();
int tl = getView()->GetTopLayer(); int tl = getView()->GetTopLayer();
PNS_ITEM *startItem = NULL; PNS_ITEM* startItem = NULL;
if( aEvent.IsMotion() || aEvent.IsClick() ) if( aEvent.IsMotion() || aEvent.IsClick() )
{ {
VECTOR2I p = aEvent.Position(); VECTOR2I p = aEvent.Position();
startItem = pickSingleItem(p); startItem = pickSingleItem( p );
if( startItem && startItem->GetNet() >= 0 )
if(startItem && startItem->GetNet() >= 0)
{ {
bool dummy; bool dummy;
VECTOR2I cursorPos = m_router->SnapToItem (startItem, p, dummy); VECTOR2I cursorPos = m_router->SnapToItem( startItem, p, dummy );
ctls->ForceCursorPosition(true, cursorPos); ctls->ForceCursorPosition( true, cursorPos );
m_startSnapPoint = cursorPos; m_startSnapPoint = cursorPos;
if(startItem->GetLayers().IsMultilayer())
if( startItem->GetLayers().IsMultilayer() )
m_startLayer = tl; m_startLayer = tl;
else else
m_startLayer = startItem->GetLayers().Start(); m_startLayer = startItem->GetLayers().Start();
m_startItem = startItem; m_startItem = startItem;
} else { }
else
{
m_startItem = NULL; m_startItem = NULL;
m_startSnapPoint = p; m_startSnapPoint = p;
m_startLayer = tl; m_startLayer = tl;
ctls->ForceCursorPosition(false); ctls->ForceCursorPosition( false );
} }
} }
} }
void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent )
{ {
VIEW_CONTROLS *ctls = getViewControls(); VIEW_CONTROLS* ctls = getViewControls();
VECTOR2I p = aEvent.Position(); VECTOR2I p = aEvent.Position();
int layer; int layer;
if(m_router->GetCurrentNet() < 0 || !m_startItem) if( m_router->GetCurrentNet() < 0 || !m_startItem )
{ {
m_endItem = NULL; m_endItem = NULL;
m_endSnapPoint = p; m_endSnapPoint = p;
...@@ -250,47 +262,52 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) ...@@ -250,47 +262,52 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent )
bool dummy; bool dummy;
if(m_router->IsPlacingVia()) if( m_router->IsPlacingVia() )
layer = -1; layer = -1;
else else
layer = m_router->GetCurrentLayer(); layer = m_router->GetCurrentLayer();
PNS_ITEM *endItem = pickSingleItem(p, m_startItem->GetNet(), layer ); PNS_ITEM* endItem = pickSingleItem( p, m_startItem->GetNet(), layer );
if(endItem) if( endItem )
{ {
VECTOR2I cursorPos = m_router->SnapToItem (endItem, p, dummy); VECTOR2I cursorPos = m_router->SnapToItem( endItem, p, dummy );
ctls->ForceCursorPosition(true, cursorPos); ctls->ForceCursorPosition( true, cursorPos );
m_endItem = endItem; m_endItem = endItem;
m_endSnapPoint = cursorPos; m_endSnapPoint = cursorPos;
} else { }
else
{
m_endItem = NULL; m_endItem = NULL;
m_endSnapPoint = p; m_endSnapPoint = p;
ctls->ForceCursorPosition(false); ctls->ForceCursorPosition( false );
} }
if(m_endItem) if( m_endItem )
TRACE(0, "%s, layer : %d", m_endItem->GetKindStr().c_str() % m_endItem->GetLayers().Start() ); 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(); VIEW_CONTROLS* ctls = getViewControls();
int width = getDefaultWidth( m_startItem ? m_startItem->GetNet() : -1 );
int width = getDefaultWidth( m_startItem ? m_startItem->GetNet() : -1); if( m_startItem && m_startItem->OfKind( PNS_ITEM::SEGMENT ) )
if(m_startItem && m_startItem->OfKind(PNS_ITEM::SEGMENT)) width = static_cast<PNS_SEGMENT*>( m_startItem )->GetWidth();
width = static_cast<PNS_SEGMENT *>(m_startItem)->GetWidth();
m_router->SetCurrentWidth(width); m_router->SetCurrentWidth( width );
m_router->SwitchLayer(m_startLayer); m_router->SwitchLayer( m_startLayer );
getEditFrame<PCB_EDIT_FRAME>() -> SetTopLayer (m_startLayer); getEditFrame<PCB_EDIT_FRAME>()->SetTopLayer( m_startLayer );
if(m_startItem && m_startItem->GetNet() >= 0) if( m_startItem && m_startItem->GetNet() >= 0 )
highlightNet(true, m_startItem->GetNet() ); highlightNet( true, m_startItem->GetNet() );
ctls->ForceCursorPosition(false); ctls->ForceCursorPosition( false );
ctls->SetAutoPan(true); ctls->SetAutoPan( true );
m_router->StartRouting( m_startSnapPoint, m_startItem ); m_router->StartRouting( m_startSnapPoint, m_startItem );
...@@ -301,18 +318,21 @@ void ROUTER_TOOL::startRouting ( ) ...@@ -301,18 +318,21 @@ void ROUTER_TOOL::startRouting ( )
{ {
if( evt->IsCancel() ) if( evt->IsCancel() )
break; break;
else if (evt->IsMotion()) else if( evt->IsMotion() )
{ {
updateEndItem( *evt ); updateEndItem( *evt );
m_router->Move ( m_endSnapPoint, m_endItem ); m_router->Move( m_endSnapPoint, m_endItem );
} }
else if (evt->IsClick (MB_Left )) else if( evt->IsClick( MB_Left ) )
{ {
updateEndItem( *evt ); updateEndItem( *evt );
if(m_router->FixRoute(m_endSnapPoint, m_endItem))
if( m_router->FixRoute( m_endSnapPoint, m_endItem ) )
break; 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() ) switch( evt->KeyCode() )
{ {
...@@ -320,11 +340,11 @@ void ROUTER_TOOL::startRouting ( ) ...@@ -320,11 +340,11 @@ void ROUTER_TOOL::startRouting ( )
{ {
int w, diameter, drill; int w, diameter, drill;
getNetclassDimensions( m_router->GetCurrentNet(), w, diameter, drill ); getNetclassDimensions( m_router->GetCurrentNet(), w, diameter, drill );
m_router->SetCurrentViaDiameter(diameter); m_router->SetCurrentViaDiameter( diameter );
m_router->SetCurrentViaDrill(drill); m_router->SetCurrentViaDrill( drill );
m_router->ToggleViaPlacement(); m_router->ToggleViaPlacement();
getEditFrame<PCB_EDIT_FRAME>() -> SetTopLayer (m_router->GetCurrentLayer()); getEditFrame<PCB_EDIT_FRAME>()->SetTopLayer( m_router->GetCurrentLayer() );
m_router->Move ( m_endSnapPoint, m_endItem ); m_router->Move( m_endSnapPoint, m_endItem );
break; break;
} }
...@@ -334,58 +354,56 @@ void ROUTER_TOOL::startRouting ( ) ...@@ -334,58 +354,56 @@ void ROUTER_TOOL::startRouting ( )
case '+': case '+':
case '=': case '=':
m_router->SwitchLayer ( m_router->NextCopperLayer (true) ); m_router->SwitchLayer( m_router->NextCopperLayer( true ) );
updateEndItem( *evt ); updateEndItem( *evt );
getEditFrame<PCB_EDIT_FRAME>() -> SetTopLayer (m_router->GetCurrentLayer()); getEditFrame<PCB_EDIT_FRAME>()->SetTopLayer( m_router->GetCurrentLayer() );
m_router->Move ( m_endSnapPoint, m_endItem ); m_router->Move( m_endSnapPoint, m_endItem );
break; break;
case '-': case '-':
m_router->SwitchLayer ( m_router->NextCopperLayer (false) ); m_router->SwitchLayer( m_router->NextCopperLayer( false ) );
getEditFrame<PCB_EDIT_FRAME>() -> SetTopLayer (m_router->GetCurrentLayer()); getEditFrame<PCB_EDIT_FRAME>()->SetTopLayer( m_router->GetCurrentLayer() );
m_router->Move ( m_endSnapPoint, m_endItem ); m_router->Move( m_endSnapPoint, m_endItem );
break; break;
} }
} }
} }
if(m_router->RoutingInProgress()) if( m_router->RoutingInProgress() )
m_router->StopRouting(); m_router->StopRouting();
ctls->SetAutoPan(false); ctls->SetAutoPan( false );
ctls->ForceCursorPosition(false); ctls->ForceCursorPosition( false );
highlightNet(false); highlightNet( false );
} }
int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) int ROUTER_TOOL::Main( TOOL_EVENT& aEvent )
{ {
VIEW_CONTROLS *ctls = getViewControls(); VIEW_CONTROLS* ctls = getViewControls();
//SetContextMenu ( m_menu ); // SetContextMenu ( m_menu );
//setMsgPanel(true, 0, wxT("KiRouter"), wxT("Pick an item to start routing")); // setMsgPanel(true, 0, wxT("KiRouter"), wxT("Pick an item to start routing"));
ctls->SetSnapping ( true ); ctls->SetSnapping( true );
ctls->ShowCursor( true ); ctls->ShowCursor( true );
// Main loop: keep receiving events // Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() ) while( OPT_TOOL_EVENT evt = Wait() )
{ {
if( evt->IsCancel() ) if( evt->IsCancel() )
break; // Finish break; // Finish
else if( evt->IsMotion( ) ) else if( evt->IsMotion() )
updateStartItem( *evt ); updateStartItem( *evt );
else if( evt->IsClick ( MB_Left ) ) else if( evt->IsClick( MB_Left ) )
{ {
updateStartItem( *evt ); updateStartItem( *evt );
startRouting( ); startRouting();
} }
} }
// clearMsgPanel();
//clearMsgPanel();
// Restore the default settings // Restore the default settings
ctls->SetAutoPan( false ); ctls->SetAutoPan( false );
...@@ -394,4 +412,3 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -394,4 +412,3 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent )
return 0; return 0;
} }
...@@ -46,34 +46,35 @@ public: ...@@ -46,34 +46,35 @@ public:
private: private:
PNS_ITEM *pickSingleItem( const VECTOR2I& aWhere, int aNet = -1, int aLayer = -1 ); PNS_ITEM* pickSingleItem( const VECTOR2I& aWhere, int aNet = -1, int aLayer = -1 );
void setMsgPanel( bool enabled, int entry, const wxString& aUpperMessage = wxT(""),
void setMsgPanel ( bool enabled, int entry, const wxString& aUpperMessage = wxT(""), const wxString& aLowerMessage = wxT("") ); const wxString& aLowerMessage = wxT("") );
void clearMsgPanel(); void clearMsgPanel();
int getDefaultWidth( int aNetCode ); int getDefaultWidth( int aNetCode );
void startRouting ( ); void startRouting();
void highlightNet(bool enabled, int netcode = -1); void highlightNet( bool enabled, int netcode = -1 );
void updateStartItem( TOOL_EVENT& aEvent ); void updateStartItem( TOOL_EVENT& aEvent );
void updateEndItem( TOOL_EVENT& aEvent ); void updateEndItem( TOOL_EVENT& aEvent );
void getNetclassDimensions ( int aNetCode, int& aWidth, int& aViaDiameter, int& aViaDrill); void getNetclassDimensions( int aNetCode, int& aWidth, int& aViaDiameter, int& aViaDrill );
MSG_PANEL_ITEMS m_panelItems; MSG_PANEL_ITEMS m_panelItems;
PNS_ROUTER *m_router; PNS_ROUTER* m_router;
PNS_ITEM *m_startItem; PNS_ITEM* m_startItem;
int m_startLayer; int m_startLayer;
VECTOR2I m_startSnapPoint; VECTOR2I m_startSnapPoint;
PNS_ITEM *m_endItem; PNS_ITEM* m_endItem;
VECTOR2I m_endSnapPoint; VECTOR2I m_endSnapPoint;
/*boost::shared_ptr<CONTEXT_MENU> m_menu;*/ /*boost::shared_ptr<CONTEXT_MENU> m_menu;*/
CONTEXT_MENU * m_menu; CONTEXT_MENU* m_menu;
}; };
#endif #endif
...@@ -21,30 +21,27 @@ ...@@ -21,30 +21,27 @@
#ifndef __TRACE_H #ifndef __TRACE_H
#define __TRACE_H #define __TRACE_H
#ifdef DEBUG #ifdef DEBUG
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <boost/format.hpp> #include <boost/format.hpp>
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 TRACEn( level, msg ) \
#define TRACE(level, fmt, ...) \ _trace_print( __FUNCTION__, level, std::string( msg ) );
_trace_print(__FUNCTION__, level, (boost::format(fmt) % __VA_ARGS__).str() );
#define TRACEn(level, msg) \
_trace_print(__FUNCTION__, level, std::string(msg));
#else #else
#define TRACE(level, fmt, ...) #define TRACE( level, fmt, ... )
#define TRACEn(level, msg) #define TRACEn( level, msg )
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment