Uncrustifying push&shove router
This commit is contained in:
parent
9bef4cb797
commit
85d1048762
|
@ -1,15 +1,15 @@
|
||||||
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
|
||||||
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 @@
|
||||||
|
|
||||||
class DIRECTION_45
|
class DIRECTION_45
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
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:
|
||||||
* 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:
|
||||||
*/
|
*/
|
||||||
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:
|
||||||
*/
|
*/
|
||||||
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:
|
||||||
* 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:
|
||||||
* 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:
|
||||||
*/
|
*/
|
||||||
bool IsDiagonal() const
|
bool IsDiagonal() const
|
||||||
{
|
{
|
||||||
return (m_dir % 2) == 1;
|
return ( m_dir % 2 ) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
mp0 = VECTOR2I( (w - h) * sw, 0 ); // direction: E
|
||||||
mp1 = VECTOR2I(h * sw, h * sh); // direction: NE
|
mp1 = VECTOR2I( h * sw, h * sh ); // direction: NE
|
||||||
} else {
|
}
|
||||||
mp0 = VECTOR2I(0, sh * (h - w)); // direction: N
|
else
|
||||||
mp1 = VECTOR2I(sw * w, sh * w); // direction: NE
|
{
|
||||||
|
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);
|
|
||||||
else
|
|
||||||
pl.Append(aP0 + mp0);
|
|
||||||
|
|
||||||
pl.Append(aP1);
|
if( start_diagonal )
|
||||||
|
pl.Append( aP0 + mp1 );
|
||||||
|
else
|
||||||
|
pl.Append( aP0 + mp0 );
|
||||||
|
|
||||||
|
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:
|
||||||
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:
|
||||||
* 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)
|
if( m_dir >= 8 )
|
||||||
m_dir = (Directions) (m_dir - 8);
|
m_dir = (Directions)( m_dir - 8 );
|
||||||
if(m_dir < 0)
|
|
||||||
m_dir = (Directions) (m_dir + 8);
|
|
||||||
|
|
||||||
return ;
|
if( m_dir < 0 )
|
||||||
if(aVec.y < 0)
|
m_dir = (Directions)( m_dir + 8 );
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
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:
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __DIRECTION_H
|
#endif // __DIRECTION_H
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
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 )
|
|
||||||
|
void PNS_INDEX::Add( PNS_ITEM* aItem )
|
||||||
{
|
{
|
||||||
ItemShapeIndex *idx = getSubindex(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 )
|
||||||
for(int i = layers.Start(); i <= layers.End(); ++i )
|
total += querySingle( SI_Traces + 2 * i + SI_SegStraight, shape, aMinDistance, v );
|
||||||
total += querySingle( SI_Traces + 2 * i + SI_SegStraight, shape, aMinDistance, v);
|
}
|
||||||
|
else
|
||||||
} 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 @@
|
||||||
#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
|
||||||
// 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;
|
||||||
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:
|
||||||
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:
|
||||||
|
|
||||||
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 @@
|
||||||
|
|
||||||
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 @@
|
||||||
/**
|
/**
|
||||||
* 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 @@
|
||||||
/**
|
/**
|
||||||
* 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:
|
||||||
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:
|
||||||
|
|
||||||
|
|
||||||
// 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 @@
|
||||||
*
|
*
|
||||||
* 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 @@
|
||||||
|
|
||||||
#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 @@
|
||||||
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
|
||||||
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
|
||||||
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( )
|
||||||
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( )
|
||||||
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();
|
|
||||||
found_anything = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (DIRECTION_45(s1).IsObtuse(DIRECTION_45(s2)))
|
|
||||||
{
|
|
||||||
VECTOR2I ip = *s1.IntersectLines(s2);
|
|
||||||
|
|
||||||
if(s1.Distance(ip) <= 1 || s2.Distance(ip) <= 1)
|
|
||||||
{
|
|
||||||
s1opt = SEG(s1.a, ip);
|
|
||||||
s2opt = SEG(ip, s2.b);
|
|
||||||
} else {
|
|
||||||
s1opt = SEG(s1.a, ip);
|
|
||||||
s2opt = SEG(ip, s2.b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (DIRECTION_45(s1opt).IsObtuse(DIRECTION_45(s2opt)))
|
|
||||||
{
|
|
||||||
SHAPE_LINE_CHAIN opt_path;
|
|
||||||
opt_path.Append(s1opt.a);
|
|
||||||
opt_path.Append(s1opt.b);
|
|
||||||
opt_path.Append(s2opt.b);
|
|
||||||
|
|
||||||
PNS_LINE opt_track (*this, opt_path);
|
|
||||||
|
|
||||||
if(!m_world->CheckColliding(&opt_track, PNS_ITEM::ANY))
|
|
||||||
{
|
|
||||||
current_path.Replace(s1.Index() + 1, s2.Index(), ip);
|
|
||||||
n_segs = current_path.SegmentCount();
|
n_segs = current_path.SegmentCount();
|
||||||
found_anything = true;
|
found_anything = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if( DIRECTION_45( s1 ).IsObtuse( DIRECTION_45( s2 ) ) )
|
||||||
|
{
|
||||||
|
VECTOR2I ip = *s1.IntersectLines( s2 );
|
||||||
|
|
||||||
|
if( s1.Distance( ip ) <= 1 || s2.Distance( ip ) <= 1 )
|
||||||
|
{
|
||||||
|
s1opt = SEG( s1.a, ip );
|
||||||
|
s2opt = SEG( ip, s2.b );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s1opt = SEG( s1.a, ip );
|
||||||
|
s2opt = SEG( ip, s2.b );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if( DIRECTION_45( s1opt ).IsObtuse( DIRECTION_45( s2opt ) ) )
|
||||||
|
{
|
||||||
|
SHAPE_LINE_CHAIN opt_path;
|
||||||
|
opt_path.Append( s1opt.a );
|
||||||
|
opt_path.Append( s1opt.b );
|
||||||
|
opt_path.Append( s2opt.b );
|
||||||
|
|
||||||
|
PNS_LINE opt_track( *this, opt_path );
|
||||||
|
|
||||||
|
if( !m_world->CheckColliding( &opt_track, PNS_ITEM::ANY ) )
|
||||||
|
{
|
||||||
|
current_path.Replace( s1.Index() + 1, s2.Index(), ip );
|
||||||
|
n_segs = current_path.SegmentCount();
|
||||||
|
found_anything = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
n++;
|
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 dir1( seg1 );
|
||||||
const DIRECTION_45 dir2(seg2);
|
const DIRECTION_45 dir2( seg2 );
|
||||||
|
|
||||||
DIRECTION_45::AngleType a = dir1.Angle(dir2);
|
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,
|
||||||
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,
|
||||||
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,
|
||||||
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(); j != vi2; j = (j + 1) % l_hull.PointCount())
|
|
||||||
|
for( int j = (vi2 + 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
|
|
||||||
{
|
|
||||||
int vtx = obstacle.Find(p);
|
|
||||||
|
|
||||||
if(vtx >= 0)
|
bool PNS_LINE::onEdge( const SHAPE_LINE_CHAIN& obstacle, VECTOR2I p, int& ei,
|
||||||
|
bool& is_vertex ) const
|
||||||
|
{
|
||||||
|
int vtx = obstacle.Find( p );
|
||||||
|
|
||||||
|
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
|
||||||
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++)
|
|
||||||
{
|
|
||||||
|
|
||||||
printf("check-seg rev %d %d/%d %d\n",reverse, i, sc, sc - 1 - i);
|
for( int i = 0; i < line.SegmentCount(); 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
|
||||||
|
|
||||||
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,
|
||||||
|
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)
|
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 {
|
}
|
||||||
int is = index_o_start;
|
else
|
||||||
int ie = (is_vertex_end ? index_o_end : index_o_end) % obstacle.PointCount();
|
|
||||||
|
|
||||||
while(1)
|
|
||||||
{
|
{
|
||||||
printf("is %d\n", is);
|
int is = index_o_start;
|
||||||
walk.Append(obstacle.CPoint(is));
|
int ie = ( is_vertex_end ? index_o_end : index_o_end ) % obstacle.PointCount();
|
||||||
if(is == ie)
|
|
||||||
|
while( 1 )
|
||||||
|
{
|
||||||
|
printf( "is %d\n", is );
|
||||||
|
walk.Append( obstacle.CPoint( is ) );
|
||||||
|
|
||||||
|
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;
|
||||||
/**
|
/**
|
||||||
* 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:
|
||||||
* 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:
|
||||||
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
|
||||||
///> Calculates a line thightly wrapping a convex hull of an obstacle object (aObstacle).
|
///> 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:
|
||||||
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:
|
||||||
|
|
||||||
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:
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
||||||
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:
|
||||||
int m_affectedRangeEnd;
|
int m_affectedRangeEnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // __PNS_LINE_H
|
#endif // __PNS_LINE_H
|
||||||
|
|
||||||
|
|
|
@ -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 )
|
||||||
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 )
|
||||||
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()
|
||||||
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()
|
||||||
|
|
||||||
// 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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()
|
||||||
|
|
||||||
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()
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
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()
|
||||||
|
|
||||||
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 );
|
||||||
|
|
||||||
head.Remove(0, n_head - 2);
|
TRACE( 0, "Placer: merge %d, new direction: %s", n_head % m_direction.Format().c_str() );
|
||||||
|
|
||||||
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()
|
||||||
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()
|
||||||
|
|
||||||
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()
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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;
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
}
|
}
|
||||||
|
|
||||||
///> 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 );
|
||||||
|
|
||||||
bool 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 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
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 {
|
||||||
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
|
||||||
/**
|
/**
|
||||||
* 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:
|
||||||
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:
|
||||||
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 addSegment( PNS_SEGMENT* aSeg );
|
||||||
|
void addLine( PNS_LINE* aLine );
|
||||||
|
void addVia( PNS_VIA* aVia );
|
||||||
|
void removeSolid( PNS_SOLID* aSeg );
|
||||||
|
void removeLine( PNS_LINE* aLine );
|
||||||
|
void removeSegment( PNS_SEGMENT* aSeg );
|
||||||
|
void removeVia( PNS_VIA* aVia );
|
||||||
|
|
||||||
void addSolid( PNS_SOLID *aSeg );
|
void doRemove( PNS_ITEM* aItem );
|
||||||
void addSegment( PNS_SEGMENT *aSeg );
|
void unlinkParent();
|
||||||
void addLine( PNS_LINE *aLine );
|
void releaseChildren();
|
||||||
void addVia( PNS_VIA *aVia );
|
|
||||||
void removeSolid( PNS_SOLID *aSeg );
|
|
||||||
void removeLine( PNS_LINE *aLine );
|
|
||||||
void removeSegment (PNS_SEGMENT *aSeg );
|
|
||||||
void removeVia (PNS_VIA *aVia );
|
|
||||||
|
|
||||||
void doRemove( PNS_ITEM *aItem );
|
|
||||||
void unlinkParent ( );
|
|
||||||
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 @@
|
||||||
* 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 @@
|
||||||
#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
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
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*>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PNS_OPTIMIZER::~PNS_OPTIMIZER ( )
|
|
||||||
{
|
{
|
||||||
//delete m_cache;
|
// m_cache = new SHAPE_INDEX_LIST<PNS_ITEM*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PNS_OPTIMIZER::~PNS_OPTIMIZER()
|
||||||
|
{
|
||||||
|
// 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)
|
|
||||||
{
|
|
||||||
std::vector<PNS_SEGMENT *> *segs = aLine->GetLinkedSegments();
|
|
||||||
|
|
||||||
if(!segs)
|
void PNS_OPTIMIZER::removeCachedSegments( PNS_LINE* aLine, int aStartVertex, int aEndVertex )
|
||||||
|
{
|
||||||
|
std::vector<PNS_SEGMENT*>* segs = aLine->GetLinkedSegments();
|
||||||
|
|
||||||
|
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 )
|
|
||||||
{
|
|
||||||
CacheVisitor v(aItem, m_world, m_collisionKindMask);
|
|
||||||
|
|
||||||
return m_world->CheckColliding(aItem);
|
bool PNS_OPTIMIZER::checkColliding( PNS_ITEM* aItem, bool aUpdateCache )
|
||||||
|
{
|
||||||
|
CacheVisitor v( aItem, m_world, m_collisionKindMask );
|
||||||
|
|
||||||
|
return m_world->CheckColliding( aItem );
|
||||||
|
|
||||||
// something is wrong with the cache, need to investigate.
|
// 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 )
|
||||||
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)
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
BOOST_FOREACH( SHAPE_LINE_CHAIN & l, breakouts ) {
|
||||||
{
|
// PNSDisplayDebugLine (l, 0);
|
||||||
//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,
|
||||||
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,
|
||||||
// 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 @@
|
||||||
* 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;
|
||||||
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;
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
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
|
||||||
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 @@
|
||||||
* 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 @@
|
||||||
|
|
||||||
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);
|
|
||||||
|
return std::max( cl_a, cl_b );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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 );
|
|
||||||
else if( type == PCB_VIA_T )
|
|
||||||
item = syncVia (static_cast <SEGVIA *>(t));
|
|
||||||
|
|
||||||
if(item)
|
if( type == PCB_TRACE_T )
|
||||||
m_world->Add(item);
|
item = syncTrack( t );
|
||||||
|
else if( type == PCB_VIA_T )
|
||||||
|
item = syncVia( static_cast <SEGVIA*>(t) );
|
||||||
|
|
||||||
|
if( 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()
|
||||||
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()
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
|
||||||
{
|
|
||||||
ROUTER_PREVIEW_ITEM * pitem = new ROUTER_PREVIEW_ITEM (NULL, m_previewItems);
|
|
||||||
|
|
||||||
pitem->DebugLine (aLine, aWidth, aType );
|
void PNS_ROUTER::DisplayDebugLine( const SHAPE_LINE_CHAIN& aLine, int aType, int aWidth )
|
||||||
m_previewItems->Add (pitem);
|
{
|
||||||
pitem->ViewSetVisible(true);
|
ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( NULL, m_previewItems );
|
||||||
|
|
||||||
|
pitem->DebugLine( aLine, aWidth, aType );
|
||||||
|
m_previewItems->Add( pitem );
|
||||||
|
pitem->ViewSetVisible( true );
|
||||||
m_previewItems->ViewUpdate( KiGfx::VIEW_ITEM::GEOMETRY | KiGfx::VIEW_ITEM::APPEARANCE );
|
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 (¤t, true);
|
DisplayItem( ¤t, true );
|
||||||
|
|
||||||
if(current.EndsWithVia())
|
if( current.EndsWithVia() )
|
||||||
DisplayItem( ¤t.GetVia(), true );
|
DisplayItem( ¤t.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 )
|
|
||||||
{
|
|
||||||
if(aSeg && aSeg->OfKind( PNS_ITEM::SEGMENT ))
|
|
||||||
{
|
|
||||||
PNS_NODE::OptJoint jt = aNode->FindJoint ( aP, aSeg->GetLayers().Start(), aSeg->GetNet());
|
|
||||||
|
|
||||||
if(jt && jt->LinkCount() >= 1)
|
void PNS_ROUTER::splitAdjacentSegments( PNS_NODE* aNode, PNS_ITEM* aSeg, const VECTOR2I& aP )
|
||||||
|
{
|
||||||
|
if( aSeg && aSeg->OfKind( PNS_ITEM::SEGMENT ) )
|
||||||
|
{
|
||||||
|
PNS_NODE::OptJoint jt = aNode->FindJoint( aP, aSeg->GetLayers().Start(), aSeg->GetNet() );
|
||||||
|
|
||||||
|
if( 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 )
|
||||||
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 )
|
||||||
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 )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
||||||
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 @@
|
||||||
* 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;
|
||||||
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 {
|
||||||
* 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:
|
||||||
};
|
};
|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
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:
|
||||||
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:
|
||||||
|
|
||||||
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:
|
||||||
// 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 @@
|
||||||
#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 {
|
||||||
|
|
||||||
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 @@
|
||||||
|
|
||||||
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:
|
||||||
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:
|
||||||
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 @@
|
||||||
|
|
||||||
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 {
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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++;
|
||||||
|
|
||||||
|
for( i = 0; i < head.SegmentCount(); i++ )
|
||||||
{
|
{
|
||||||
const PNS_SEGMENT hs (*aHead, head.CSegment(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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
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() %
|
||||||
|
node->JointCount() );
|
||||||
|
|
||||||
|
// PNS_ITEM *lastWalkSolid = NULL;
|
||||||
prof_counter totalRealTime;
|
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)
|
||||||
|
|
||||||
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 );
|
prof_end( &totalRealTime );
|
||||||
|
|
||||||
TRACE(2,"t-optimizeObstacle %lld us", (totalRealTime.value ));
|
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)
|
||||||
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;
|
||||||
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 {
|
||||||
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 @@
|
||||||
#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)
|
||||||
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 @@
|
||||||
|
|
||||||
#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:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
VECTOR2I m_center;
|
VECTOR2I m_center;
|
||||||
SHAPE* m_shape;
|
SHAPE* m_shape;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 @@
|
||||||
#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 @@
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
return OctagonalHull( m_pos - VECTOR2I(m_diameter/2, m_diameter/2), VECTOR2I(m_diameter, m_diameter), aClearance + 1, (2*aClearance + m_diameter) * 0.26);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
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
|
||||||
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
|
||||||
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 )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 @@
|
||||||
#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 {
|
||||||
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;
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
You'll see the P&S router sources here, but just not right now.
|
|
||||||
We are still dealing with some non-technical issues that should be solved by the next week.
|
|
||||||
|
|
||||||
Tom
|
|
|
@ -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:
|
case PR_VIA:
|
||||||
|
aGal->SetLayerDepth( -101.0 );
|
||||||
aGal->SetLayerDepth(-101.0);
|
aGal->SetIsStroke( false );
|
||||||
aGal->SetIsStroke(false);
|
aGal->SetIsFill( true );
|
||||||
aGal->SetIsFill(true);
|
aGal->SetFillColor( m_color );
|
||||||
aGal->SetFillColor(m_color);
|
aGal->DrawCircle( m_viaCenter, m_width / 2 );
|
||||||
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
|
|
||||||
{
|
|
||||||
//assert (m_view != NULL);
|
|
||||||
|
|
||||||
PCB_RENDER_SETTINGS *settings = static_cast <PCB_RENDER_SETTINGS*> (m_parent -> GetView() -> GetPainter() -> GetSettings());
|
const COLOR4D ROUTER_PREVIEW_ITEM::getLayerColor( int aLayer ) const
|
||||||
return settings->GetLayerColor(layer);
|
{
|
||||||
|
// assert (m_view != NULL);
|
||||||
|
|
||||||
|
PCB_RENDER_SETTINGS* settings =
|
||||||
|
static_cast <PCB_RENDER_SETTINGS*> ( m_parent->GetView()->GetPainter()->GetSettings() );
|
||||||
|
|
||||||
|
return settings->GetLayerColor( aLayer );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const COLOR4D ROUTER_PREVIEW_ITEM::assignColor ( int style ) const
|
const COLOR4D ROUTER_PREVIEW_ITEM::assignColor( int aStyle ) const
|
||||||
{
|
{
|
||||||
COLOR4D color;
|
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,30 +43,32 @@ 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 {};
|
|
||||||
|
void Show( int a, std::ostream& b ) const {};
|
||||||
|
|
||||||
const BOX2I ViewBBox() const;
|
const BOX2I ViewBBox() const;
|
||||||
|
|
||||||
|
|
||||||
virtual void ViewDraw( int aLayer, KiGfx::GAL* aGal ) const;
|
virtual void ViewDraw( int aLayer, KiGfx::GAL* aGal ) const;
|
||||||
|
|
||||||
virtual void ViewGetLayers( int aLayers[], int& aCount ) const
|
virtual void ViewGetLayers( int aLayers[], int& aCount ) const
|
||||||
|
@ -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
|
||||||
|
|
||||||
VECTOR2I m_stuckPosition;
|
VECTOR2I m_stuckPosition;
|
||||||
VECTOR2I m_viaCenter;
|
VECTOR2I m_viaCenter;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
RENDER_SETTINGS *rs = getView()->GetPainter()->GetSettings();
|
|
||||||
|
|
||||||
if(netcode >= 0 && enabled)
|
void ROUTER_TOOL::highlightNet( bool aEnabled, int aNetcode )
|
||||||
rs->SetHighlight(true, netcode);
|
{
|
||||||
|
RENDER_SETTINGS* rs = getView()->GetPainter()->GetSettings();
|
||||||
|
|
||||||
|
if( aNetcode >= 0 && aEnabled )
|
||||||
|
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 )
|
||||||
|
|
||||||
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))
|
|
||||||
width = static_cast<PNS_SEGMENT *>(m_startItem)->GetWidth();
|
|
||||||
|
|
||||||
m_router->SetCurrentWidth(width);
|
if( m_startItem && m_startItem->OfKind( PNS_ITEM::SEGMENT ) )
|
||||||
m_router->SwitchLayer(m_startLayer);
|
width = static_cast<PNS_SEGMENT*>( m_startItem )->GetWidth();
|
||||||
|
|
||||||
getEditFrame<PCB_EDIT_FRAME>() -> SetTopLayer (m_startLayer);
|
m_router->SetCurrentWidth( width );
|
||||||
|
m_router->SwitchLayer( m_startLayer );
|
||||||
|
|
||||||
if(m_startItem && m_startItem->GetNet() >= 0)
|
getEditFrame<PCB_EDIT_FRAME>()->SetTopLayer( m_startLayer );
|
||||||
highlightNet(true, m_startItem->GetNet() );
|
|
||||||
|
|
||||||
ctls->ForceCursorPosition(false);
|
if( m_startItem && m_startItem->GetNet() >= 0 )
|
||||||
ctls->SetAutoPan(true);
|
highlightNet( true, m_startItem->GetNet() );
|
||||||
|
|
||||||
|
ctls->ForceCursorPosition( false );
|
||||||
|
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 ( )
|
||||||
{
|
{
|
||||||
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 ( )
|
||||||
{
|
{
|
||||||
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 ( )
|
||||||
|
|
||||||
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 )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 @@
|
||||||
#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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue