Pcbnew: improved track scripting support.
This commit is contained in:
parent
e10242a0a9
commit
7434e68876
|
@ -33,7 +33,7 @@
|
||||||
#include <wx/wx.h>
|
#include <wx/wx.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory> // std::shared_ptr
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Macro TO_UTF8
|
* Macro TO_UTF8
|
||||||
|
@ -123,11 +123,12 @@ template <typename T> inline const T& Clamp( const T& lower, const T& value, con
|
||||||
/// Declare a std::vector and also the swig %template in unison
|
/// Declare a std::vector and also the swig %template in unison
|
||||||
#define DECL_VEC_FOR_SWIG(TypeName, MemberType) namespace std { %template(TypeName) vector<MemberType>; } typedef std::vector<MemberType> TypeName;
|
#define DECL_VEC_FOR_SWIG(TypeName, MemberType) namespace std { %template(TypeName) vector<MemberType>; } typedef std::vector<MemberType> TypeName;
|
||||||
#define DECL_MAP_FOR_SWIG(TypeName, KeyType, ValueType) namespace std { %template(TypeName) map<KeyType, ValueType>; } typedef std::map<KeyType, ValueType> TypeName;
|
#define DECL_MAP_FOR_SWIG(TypeName, KeyType, ValueType) namespace std { %template(TypeName) map<KeyType, ValueType>; } typedef std::map<KeyType, ValueType> TypeName;
|
||||||
|
#define DECL_SPTR_FOR_SWIG(TypeName, MemberType) namespace std { %template(TypeName) std::shared_ptr<MemberType>; } typedef std::shared_ptr<MemberType> TypeName;
|
||||||
#else
|
#else
|
||||||
/// Declare a std::vector but no swig %template
|
/// Declare a std::vector but no swig %template
|
||||||
#define DECL_VEC_FOR_SWIG(TypeName, MemberType) typedef std::vector<MemberType> TypeName;
|
#define DECL_VEC_FOR_SWIG(TypeName, MemberType) typedef std::vector<MemberType> TypeName;
|
||||||
#define DECL_MAP_FOR_SWIG(TypeName, KeyType, ValueType) typedef std::map<KeyType, ValueType> TypeName;
|
#define DECL_MAP_FOR_SWIG(TypeName, KeyType, ValueType) typedef std::map<KeyType, ValueType> TypeName;
|
||||||
|
#define DECL_SPTR_FOR_SWIG(TypeName, MemberType) typedef std::shared_ptr<MemberType> TypeName;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif // MACROS_H
|
#endif // MACROS_H
|
||||||
|
|
|
@ -176,6 +176,212 @@ void BOARD::Move( const wxPoint& aMoveVector ) // overload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TRACKS BOARD::TracksInNet( int aNetCode )
|
||||||
|
{
|
||||||
|
TRACKS ret;
|
||||||
|
|
||||||
|
INSPECTOR_FUNC inspector = [aNetCode,&ret] ( EDA_ITEM* item, void* testData )
|
||||||
|
{
|
||||||
|
TRACK* t = (TRACK*) item;
|
||||||
|
|
||||||
|
if( t->GetNetCode() == aNetCode )
|
||||||
|
ret.push_back( t );
|
||||||
|
|
||||||
|
return SEARCH_CONTINUE;
|
||||||
|
};
|
||||||
|
|
||||||
|
// visit this BOARD's TRACKs and VIAs with above TRACK INSPECTOR which
|
||||||
|
// appends all in aNetCode to ret.
|
||||||
|
Visit( inspector, NULL, GENERAL_COLLECTOR::Tracks );
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function removeTrack
|
||||||
|
* removes aOneToRemove from aList, which is a non-owning std::vector
|
||||||
|
*/
|
||||||
|
static void removeTrack( TRACKS* aList, TRACK* aOneToRemove )
|
||||||
|
{
|
||||||
|
aList->erase( std::remove( aList->begin(), aList->end(), aOneToRemove ), aList->end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void otherEnd( const TRACK& aTrack, const wxPoint& aNotThisEnd, wxPoint* aOtherEnd )
|
||||||
|
{
|
||||||
|
if( aTrack.GetStart() == aNotThisEnd )
|
||||||
|
{
|
||||||
|
*aOtherEnd = aTrack.GetEnd();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wxASSERT( aTrack.GetEnd() == aNotThisEnd );
|
||||||
|
*aOtherEnd = aTrack.GetStart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function find_vias_and_tracks_at
|
||||||
|
* collects TRACKs and VIAs at aPos and returns true if any were VIAs.
|
||||||
|
*/
|
||||||
|
static int find_vias_and_tracks_at( TRACKS& at_next, TRACKS& in_net, LSET& lset, const wxPoint& next )
|
||||||
|
{
|
||||||
|
// first find all vias (in this net) at 'next' location, and expand LSET with each
|
||||||
|
for( TRACKS::iterator it = in_net.begin(); it != in_net.end(); )
|
||||||
|
{
|
||||||
|
TRACK* t = *it;
|
||||||
|
|
||||||
|
if( t->Type() == PCB_VIA_T && (t->GetLayerSet() & lset).any() &&
|
||||||
|
( t->GetStart() == next || t->GetEnd() == next ) )
|
||||||
|
{
|
||||||
|
lset |= t->GetLayerSet();
|
||||||
|
at_next.push_back( t );
|
||||||
|
in_net.erase( it );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
int track_count = 0;
|
||||||
|
|
||||||
|
// with expanded lset, find all tracks with an end on any of the layers in lset
|
||||||
|
for( TRACKS::iterator it = in_net.begin(); it != in_net.end(); )
|
||||||
|
{
|
||||||
|
TRACK* t = *it;
|
||||||
|
|
||||||
|
if( (t->GetLayerSet() & lset).any() &&
|
||||||
|
( t->GetStart() == next || t->GetEnd() == next ) )
|
||||||
|
{
|
||||||
|
at_next.push_back( t );
|
||||||
|
in_net.erase( it );
|
||||||
|
++track_count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return track_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function checkConnectedTo
|
||||||
|
* returns if aTracksInNet contains a copper pathway to aGoal when starting with
|
||||||
|
* aFirstTrack. aFirstTrack should have one end situated on aStart, and the
|
||||||
|
* traversal testing begins from the other end of aFirstTrack.
|
||||||
|
* <p>
|
||||||
|
* The function throws an exception instead of returning bool so that detailed
|
||||||
|
* information can be provided about a possible failure in the track layout.
|
||||||
|
*
|
||||||
|
* @throw IO_ERROR - if points are not connected, with text saying why.
|
||||||
|
*/
|
||||||
|
static void checkConnectedTo( BOARD* aBoard, TRACKS* aList, const TRACKS& aTracksInNet,
|
||||||
|
const wxPoint& aGoal, const wxPoint& aStart, TRACK* aFirstTrack )
|
||||||
|
{
|
||||||
|
TRACKS in_net = aTracksInNet; // copy source list so the copy can be modified
|
||||||
|
wxPoint next;
|
||||||
|
|
||||||
|
otherEnd( *aFirstTrack, aStart, &next );
|
||||||
|
|
||||||
|
aList->push_back( aFirstTrack );
|
||||||
|
removeTrack( &in_net, aFirstTrack );
|
||||||
|
|
||||||
|
LSET lset( aFirstTrack->GetLayer() );
|
||||||
|
|
||||||
|
while( in_net.size() )
|
||||||
|
{
|
||||||
|
if( next == aGoal )
|
||||||
|
return; // success
|
||||||
|
|
||||||
|
if( aBoard->GetPad( next, lset ) )
|
||||||
|
{
|
||||||
|
std::string m = StrPrintf(
|
||||||
|
"there is an intervening pad at:(xy %s) between start:(xy %s) and goal:(xy %s)",
|
||||||
|
BOARD_ITEM::FormatInternalUnits( next ).c_str(),
|
||||||
|
BOARD_ITEM::FormatInternalUnits( aStart ).c_str(),
|
||||||
|
BOARD_ITEM::FormatInternalUnits( aGoal ).c_str()
|
||||||
|
);
|
||||||
|
THROW_IO_ERROR( m );
|
||||||
|
}
|
||||||
|
|
||||||
|
int track_count = find_vias_and_tracks_at( *aList, in_net, lset, next );
|
||||||
|
|
||||||
|
if( track_count != 1 )
|
||||||
|
{
|
||||||
|
std::string m = StrPrintf(
|
||||||
|
"found %d tracks intersecting at (xy %s), exactly 2 would be acceptable.",
|
||||||
|
track_count,
|
||||||
|
BOARD_ITEM::FormatInternalUnits( next ).c_str()
|
||||||
|
);
|
||||||
|
THROW_IO_ERROR( m );
|
||||||
|
}
|
||||||
|
|
||||||
|
// reduce lset down to the layer that the only track at 'next' is on.
|
||||||
|
lset = aList->back()->GetLayerSet();
|
||||||
|
|
||||||
|
otherEnd( *aList->back(), next, &next );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string m = StrPrintf(
|
||||||
|
"not enough tracks connecting start:(xy %s) and goal:(xy %s).",
|
||||||
|
BOARD_ITEM::FormatInternalUnits( aStart ).c_str(),
|
||||||
|
BOARD_ITEM::FormatInternalUnits( aGoal ).c_str()
|
||||||
|
);
|
||||||
|
THROW_IO_ERROR( m );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TRACKS BOARD::TracksInNetBetweenPoints( const wxPoint& aStartPos, const wxPoint& aEndPos, int aNetCode )
|
||||||
|
{
|
||||||
|
TRACKS in_between_pts;
|
||||||
|
TRACKS on_start_pad;
|
||||||
|
TRACKS in_net = TracksInNet( aNetCode ); // a small subset of TRACKs and VIAs
|
||||||
|
|
||||||
|
for( auto t : in_net )
|
||||||
|
{
|
||||||
|
if( t->Type() == PCB_TRACE_T && ( t->GetStart() == aStartPos || t->GetEnd() == aStartPos ) )
|
||||||
|
on_start_pad.push_back( t );
|
||||||
|
}
|
||||||
|
|
||||||
|
IO_ERROR last_error;
|
||||||
|
|
||||||
|
for( auto t : on_start_pad )
|
||||||
|
{
|
||||||
|
// checkConnectedTo() fills in_between_pts on every attempt. For failures
|
||||||
|
// this set needs to be cleared.
|
||||||
|
in_between_pts.clear();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
checkConnectedTo( this, &in_between_pts, in_net, aEndPos, aStartPos, t );
|
||||||
|
}
|
||||||
|
catch( const IO_ERROR& ioe ) // means not connected
|
||||||
|
{
|
||||||
|
last_error = ioe;
|
||||||
|
continue; // keep trying, there may be other paths leaving from aStartPos
|
||||||
|
}
|
||||||
|
|
||||||
|
// success, no exception means a valid connection,
|
||||||
|
// return this set of TRACKS without throwing.
|
||||||
|
return in_between_pts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( on_start_pad.size() == 1 )
|
||||||
|
throw last_error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string m = StrPrintf(
|
||||||
|
"no path connecting start:(xy %s) with end:(xy %s)",
|
||||||
|
BOARD_ITEM::FormatInternalUnits( aStartPos ).c_str(),
|
||||||
|
BOARD_ITEM::FormatInternalUnits( aEndPos ).c_str()
|
||||||
|
);
|
||||||
|
THROW_IO_ERROR( m );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void BOARD::chainMarkedSegments( wxPoint aPosition, const LSET& aLayerSet, TRACKS* aList )
|
void BOARD::chainMarkedSegments( wxPoint aPosition, const LSET& aLayerSet, TRACKS* aList )
|
||||||
{
|
{
|
||||||
LSET layer_set = aLayerSet;
|
LSET layer_set = aLayerSet;
|
||||||
|
|
|
@ -1328,11 +1328,39 @@ public:
|
||||||
* set (the user is responsible of flag clearing). False
|
* set (the user is responsible of flag clearing). False
|
||||||
* for no reorder : useful when we want just calculate the
|
* for no reorder : useful when we want just calculate the
|
||||||
* track length in this case, flags are reset
|
* track length in this case, flags are reset
|
||||||
* @return TRACK* The first in the chain of interesting segments.
|
* @return TRACK* - The first in the chain of interesting segments.
|
||||||
*/
|
*/
|
||||||
TRACK* MarkTrace( TRACK* aTrace, int* aCount, double* aTraceLength,
|
TRACK* MarkTrace( TRACK* aTrace, int* aCount, double* aTraceLength,
|
||||||
double* aInPackageLength, bool aReorder );
|
double* aInPackageLength, bool aReorder );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function TrackInNet
|
||||||
|
* collects all the TRACKs and VIAs that are members of a net given by aNetCode.
|
||||||
|
* Used from python.
|
||||||
|
* @param aList is a non-owning container that is appended to with the TRACKs and VIAs,
|
||||||
|
* and is not initiallly cleared.
|
||||||
|
* @param aNetCode gives the id of the net.
|
||||||
|
* @return TRACKS - which are in the net identified by @a aNetCode.
|
||||||
|
*/
|
||||||
|
TRACKS TracksInNet( int aNetCode );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function TrackInNetBetweenPoints
|
||||||
|
* collects all the TRACKs and VIAs that are members of a net given by aNetCode and that
|
||||||
|
* make up a path between two end points. The end points must be carefully chosen,
|
||||||
|
* and are typically the locations of two neighboring pads. The function fails if there
|
||||||
|
* is an intervening pad or a 3 way intersection at a track or via.
|
||||||
|
* Used from python.
|
||||||
|
* @param aStartPos must correspond to a point on the BOARD which has a TRACK end or start,
|
||||||
|
* typically the location of either a via or pad.
|
||||||
|
* @param aEndPos must correspond to a point on the BOARD which has a TRACK end or start,
|
||||||
|
* typically the location of either a via or pad.
|
||||||
|
* @param aNetCode gives the id of the net.
|
||||||
|
* @return TRACKS - non empty if success, empty if your aStartPos or aEndPos are bad or
|
||||||
|
* the net is interrupted along the way by an intervening D_PAD or a 3 way path.
|
||||||
|
*/
|
||||||
|
TRACKS TracksInNetBetweenPoints( const wxPoint& aStartPos, const wxPoint& aEndPos, int aNetCode );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetFootprint
|
* Function GetFootprint
|
||||||
* get a footprint by its bounding rectangle at \a aPosition on \a aLayer.
|
* get a footprint by its bounding rectangle at \a aPosition on \a aLayer.
|
||||||
|
|
|
@ -31,15 +31,11 @@
|
||||||
#ifndef CLASS_NETCLASS_H
|
#ifndef CLASS_NETCLASS_H
|
||||||
#define CLASS_NETCLASS_H
|
#define CLASS_NETCLASS_H
|
||||||
|
|
||||||
#include <set>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
#include <wx/string.h>
|
#include <set>
|
||||||
|
|
||||||
#include <richio.h>
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <richio.h>
|
||||||
|
|
||||||
|
|
||||||
class LINE_READER;
|
class LINE_READER;
|
||||||
|
@ -209,11 +205,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef std::shared_ptr<NETCLASS> NETCLASSPTR;
|
DECL_SPTR_FOR_SWIG( NETCLASSPTR, NETCLASS )
|
||||||
#ifdef SWIG
|
|
||||||
%shared_ptr( NETCLASSPTR );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DECL_MAP_FOR_SWIG( NETCLASS_MAP, wxString, NETCLASSPTR );
|
DECL_MAP_FOR_SWIG( NETCLASS_MAP, wxString, NETCLASSPTR );
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,15 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
D_PADS& Pads() { return m_PadInNetList; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetNodesCount
|
||||||
|
* @return int - number of pad nodes in the net
|
||||||
|
*/
|
||||||
|
int GetNodesCount() const { return m_PadInNetList.size(); }
|
||||||
|
|
||||||
|
|
||||||
D_PADS m_PadInNetList; ///< List of pads connected to this net
|
D_PADS m_PadInNetList; ///< List of pads connected to this net
|
||||||
|
|
||||||
unsigned m_RatsnestStartIdx; /* Starting point of ratsnests of this
|
unsigned m_RatsnestStartIdx; /* Starting point of ratsnests of this
|
||||||
|
@ -302,12 +311,6 @@ public:
|
||||||
|
|
||||||
void SetNetCode( int aNetCode ) { m_NetCode = aNetCode; }
|
void SetNetCode( int aNetCode ) { m_NetCode = aNetCode; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Function GetNodesCount
|
|
||||||
* @return int - number of nodes in the net
|
|
||||||
*/
|
|
||||||
int GetNodesCount() const { return m_PadInNetList.size(); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetNetname
|
* Function GetNetname
|
||||||
* @return const wxString&, a reference to the full netname
|
* @return const wxString&, a reference to the full netname
|
||||||
|
@ -552,7 +555,10 @@ public:
|
||||||
const D_PADS& GetPads() const { return m_PadsFullList; }
|
const D_PADS& GetPads() const { return m_PadsFullList; }
|
||||||
|
|
||||||
/// Return the name map, at least for python.
|
/// Return the name map, at least for python.
|
||||||
const NETNAMES_MAP& GetNets() const { return m_netNames; }
|
const NETNAMES_MAP& NetsByName() const { return m_netNames; }
|
||||||
|
|
||||||
|
/// Return the netcode map, at least for python.
|
||||||
|
const NETCODES_MAP& NetsByNetcode() const { return m_netCodes; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetPad
|
* Function GetPad
|
||||||
|
|
Loading…
Reference in New Issue