Pcbnew: improved track scripting support.
This commit is contained in:
parent
e10242a0a9
commit
7434e68876
|
@ -33,7 +33,7 @@
|
|||
#include <wx/wx.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <memory> // std::shared_ptr
|
||||
|
||||
/**
|
||||
* 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
|
||||
#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_SPTR_FOR_SWIG(TypeName, MemberType) namespace std { %template(TypeName) std::shared_ptr<MemberType>; } typedef std::shared_ptr<MemberType> TypeName;
|
||||
#else
|
||||
/// Declare a std::vector but no swig %template
|
||||
#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_SPTR_FOR_SWIG(TypeName, MemberType) typedef std::shared_ptr<MemberType> TypeName;
|
||||
#endif
|
||||
|
||||
|
||||
#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 )
|
||||
{
|
||||
LSET layer_set = aLayerSet;
|
||||
|
|
|
@ -1328,11 +1328,39 @@ public:
|
|||
* set (the user is responsible of flag clearing). False
|
||||
* for no reorder : useful when we want just calculate the
|
||||
* 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,
|
||||
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
|
||||
* get a footprint by its bounding rectangle at \a aPosition on \a aLayer.
|
||||
|
|
|
@ -31,15 +31,11 @@
|
|||
#ifndef CLASS_NETCLASS_H
|
||||
#define CLASS_NETCLASS_H
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include <macros.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include <richio.h>
|
||||
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <richio.h>
|
||||
|
||||
|
||||
class LINE_READER;
|
||||
|
@ -209,11 +205,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
typedef std::shared_ptr<NETCLASS> NETCLASSPTR;
|
||||
#ifdef SWIG
|
||||
%shared_ptr( NETCLASSPTR );
|
||||
#endif
|
||||
|
||||
DECL_SPTR_FOR_SWIG( NETCLASSPTR, NETCLASS )
|
||||
DECL_MAP_FOR_SWIG( NETCLASS_MAP, wxString, NETCLASSPTR );
|
||||
|
||||
|
||||
|
|
|
@ -142,6 +142,15 @@ private:
|
|||
|
||||
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
|
||||
|
||||
unsigned m_RatsnestStartIdx; /* Starting point of ratsnests of this
|
||||
|
@ -302,12 +311,6 @@ public:
|
|||
|
||||
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
|
||||
* @return const wxString&, a reference to the full netname
|
||||
|
@ -552,7 +555,10 @@ public:
|
|||
const D_PADS& GetPads() const { return m_PadsFullList; }
|
||||
|
||||
/// 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
|
||||
|
|
Loading…
Reference in New Issue