Pcbnew: improved track scripting support.

This commit is contained in:
Dick Hollenbeck 2016-07-19 16:34:09 -04:00 committed by Wayne Stambaugh
parent e10242a0a9
commit 7434e68876
5 changed files with 254 additions and 21 deletions

View File

@ -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

View File

@ -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;

View File

@ -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.

View File

@ -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 );

View File

@ -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