Removed legacy connectivity/ratsnest algorithm, replaced with the new one. No legacy autorouting for the moment
This commit is contained in:
parent
9ad886344b
commit
3cba1007eb
|
@ -481,7 +481,7 @@ public:
|
|||
* It shows the connections from a pad to the nearest connected pad
|
||||
* @param aModule = module to consider.
|
||||
*/
|
||||
void build_ratsnest_module( MODULE* aModule );
|
||||
void build_ratsnest_module( MODULE *mod, wxPoint aMoveVector );
|
||||
|
||||
/**
|
||||
* Function TraceModuleRatsNest
|
||||
|
@ -526,7 +526,8 @@ public:
|
|||
* When aInit = false, aItemRef is not used (can be NULL)
|
||||
*/
|
||||
void BuildAirWiresTargetsList( BOARD_CONNECTED_ITEM* aItemRef,
|
||||
const wxPoint& aPosition, bool aInit );
|
||||
const wxPoint& aPosition,
|
||||
int aNet );
|
||||
|
||||
/**
|
||||
* Function TestForActiveLinksInRatsnest
|
||||
|
|
|
@ -184,25 +184,13 @@ set( PCBNEW_EXPORTERS
|
|||
exporters/gendrill_gerber_writer.cpp
|
||||
)
|
||||
|
||||
set( PCBNEW_AUTOROUTER_SRCS
|
||||
autorouter/rect_placement/rect_placement.cpp
|
||||
autorouter/move_and_route_event_functions.cpp
|
||||
autorouter/auto_place_footprints.cpp
|
||||
autorouter/autorout.cpp
|
||||
autorouter/routing_matrix.cpp
|
||||
autorouter/dist.cpp
|
||||
autorouter/queue.cpp
|
||||
autorouter/spread_footprints.cpp
|
||||
autorouter/solve.cpp
|
||||
autorouter/graphpcb.cpp
|
||||
autorouter/work.cpp
|
||||
)
|
||||
|
||||
set( PCBNEW_MICROWAVE_SRCS
|
||||
microwave/microwave_inductor.cpp
|
||||
)
|
||||
|
||||
set( PCBNEW_CLASS_SRCS
|
||||
autorouter/rect_placement/rect_placement.cpp
|
||||
autorouter/spread_footprints.cpp
|
||||
board_commit.cpp
|
||||
tool_modview.cpp
|
||||
modview_frame.cpp
|
||||
|
@ -299,7 +287,6 @@ set( PCBNEW_CLASS_SRCS
|
|||
zone_filling_algorithm.cpp
|
||||
zones_functions_for_undo_redo.cpp
|
||||
zones_polygons_insulated_copper_islands.cpp
|
||||
zones_polygons_test_connections.cpp
|
||||
zones_test_and_combine_areas.cpp
|
||||
class_footprint_wizard.cpp
|
||||
class_action_plugin.cpp
|
||||
|
@ -334,7 +321,6 @@ set( PCBNEW_CLASS_SRCS
|
|||
)
|
||||
|
||||
set( PCBNEW_SRCS
|
||||
${PCBNEW_AUTOROUTER_SRCS}
|
||||
${PCBNEW_MICROWAVE_SRCS}
|
||||
${PCBNEW_CLASS_SRCS}
|
||||
${PCBNEW_DIALOGS}
|
||||
|
@ -622,7 +608,6 @@ add_library( pcbnew_kiface MODULE
|
|||
${PCBNEW_COMMON_SRCS}
|
||||
${PCBNEW_SCRIPTING_SRCS}
|
||||
)
|
||||
|
||||
set_target_properties( pcbnew_kiface PROPERTIES
|
||||
# Decorate OUTPUT_NAME with PREFIX and SUFFIX, creating something like
|
||||
# _pcbnew.so, _pcbnew.dll, or _pcbnew.kiface
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#include <pcbnew.h>
|
||||
#include <protos.h>
|
||||
|
||||
#include <connectivity.h>
|
||||
|
||||
#define BLOCK_OUTLINE_COLOR YELLOW
|
||||
|
||||
/**
|
||||
|
@ -536,6 +538,7 @@ void PCB_EDIT_FRAME::Block_Delete()
|
|||
{
|
||||
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
||||
itemsList->SetPickedItemStatus( UR_DELETED, ii );
|
||||
GetBoard()->GetConnectivity()->Remove( item );
|
||||
|
||||
switch( item->Type() )
|
||||
{
|
||||
|
@ -599,6 +602,7 @@ void PCB_EDIT_FRAME::Block_Rotate()
|
|||
{
|
||||
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
||||
wxASSERT( item );
|
||||
|
||||
itemsList->SetPickedItemStatus( UR_CHANGED, ii );
|
||||
|
||||
switch( item->Type() )
|
||||
|
@ -642,6 +646,7 @@ void PCB_EDIT_FRAME::Block_Rotate()
|
|||
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
||||
wxASSERT( item );
|
||||
item->Rotate( centre, rotAngle );
|
||||
GetBoard()->GetConnectivity()->Update( item );
|
||||
}
|
||||
|
||||
Compile_Ratsnest( NULL, true );
|
||||
|
@ -667,6 +672,7 @@ void PCB_EDIT_FRAME::Block_Flip()
|
|||
wxASSERT( item );
|
||||
itemsList->SetPickedItemStatus( UR_FLIPPED, ii );
|
||||
item->Flip( center );
|
||||
GetBoard()->GetConnectivity()->Update( item );
|
||||
|
||||
// If a connected item is flipped, the ratsnest is no more OK
|
||||
switch( item->Type() )
|
||||
|
@ -721,6 +727,7 @@ void PCB_EDIT_FRAME::Block_Move()
|
|||
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
||||
itemsList->SetPickedItemStatus( UR_MOVED, ii );
|
||||
item->Move( MoveVector );
|
||||
GetBoard()->GetConnectivity()->Update( item );
|
||||
item->ClearFlags( IS_MOVED );
|
||||
|
||||
switch( item->Type() )
|
||||
|
|
|
@ -596,7 +596,7 @@ bool BOARD_NETLIST_UPDATER::testConnectivity( NETLIST& aNetlist )
|
|||
if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() )
|
||||
continue;
|
||||
|
||||
int nc = zone->GetNet()->GetNodesCount();
|
||||
int nc = m_board->GetConnectivity()->GetPadCount( zone->GetNetCode() );
|
||||
|
||||
if( nc == 0 )
|
||||
{
|
||||
|
@ -668,7 +668,6 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
|
|||
if( !m_isDryRun )
|
||||
{
|
||||
m_commit.Push( _( "Update netlist" ) );
|
||||
m_frame->Compile_Ratsnest( NULL, false );
|
||||
m_board->GetConnectivity()->Build( m_board );
|
||||
testConnectivity( aNetlist );
|
||||
}
|
||||
|
|
|
@ -120,9 +120,6 @@ BOARD::~BOARD()
|
|||
Delete( area_to_remove );
|
||||
}
|
||||
|
||||
m_FullRatsnest.clear();
|
||||
m_LocalRatsnest.clear();
|
||||
|
||||
DeleteMARKERs();
|
||||
DeleteZONEOutlines();
|
||||
|
||||
|
@ -1157,20 +1154,8 @@ void BOARD::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList )
|
|||
txt.Printf( wxT( "%d" ), m_NetInfo.GetNetCount() );
|
||||
aList.push_back( MSG_PANEL_ITEM( _( "Nets" ), txt, RED ) );
|
||||
|
||||
/* These parameters are known only if the full ratsnest is available,
|
||||
* so, display them only if this is the case
|
||||
*/
|
||||
if( (m_Status_Pcb & NET_CODES_OK) )
|
||||
{
|
||||
txt.Printf( wxT( "%d" ), GetRatsnestsCount() );
|
||||
aList.push_back( MSG_PANEL_ITEM( _( "Links" ), txt, DARKGREEN ) );
|
||||
|
||||
txt.Printf( wxT( "%d" ), GetRatsnestsCount() - GetUnconnectedNetCount() );
|
||||
aList.push_back( MSG_PANEL_ITEM( _( "Connections" ), txt, DARKGREEN ) );
|
||||
|
||||
txt.Printf( wxT( "%d" ), GetUnconnectedNetCount() );
|
||||
aList.push_back( MSG_PANEL_ITEM( _( "Unconnected" ), txt, BLUE ) );
|
||||
}
|
||||
txt.Printf( wxT( "%d" ), GetConnectivity()->GetUnconnectedCount() );
|
||||
aList.push_back( MSG_PANEL_ITEM( _( "Unconnected" ), txt, BLUE ) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1428,10 +1413,14 @@ MODULE* BOARD::FindModule( const wxString& aRefOrTimeStamp, bool aSearchByTimeSt
|
|||
// Sort nets by decreasing pad count. For same pad count, sort by alphabetic names
|
||||
static bool sortNetsByNodes( const NETINFO_ITEM* a, const NETINFO_ITEM* b )
|
||||
{
|
||||
if( b->GetNodesCount() == a->GetNodesCount() )
|
||||
return a->GetNetname() < b->GetNetname();
|
||||
auto connectivity = a->GetParent()->GetConnectivity();
|
||||
int countA = connectivity->GetPadCount( a->GetNet() );
|
||||
int countB = connectivity->GetPadCount( b->GetNet() );
|
||||
|
||||
return b->GetNodesCount() < a->GetNodesCount();
|
||||
if( countA == countB )
|
||||
return a->GetNetname() < b->GetNetname();
|
||||
else
|
||||
return countB < countA;
|
||||
}
|
||||
|
||||
// Sort nets by alphabetic names
|
||||
|
@ -1619,10 +1608,10 @@ D_PAD* BOARD::GetPad( TRACK* aTrace, ENDPOINT_T aEndPoint )
|
|||
|
||||
D_PAD* BOARD::GetPadFast( const wxPoint& aPosition, LSET aLayerSet )
|
||||
{
|
||||
for( unsigned i=0; i<GetPadCount(); ++i )
|
||||
for( auto mod : Modules() )
|
||||
{
|
||||
D_PAD* pad = m_NetInfo.GetPad(i);
|
||||
|
||||
for ( auto pad : mod->PadsIter() )
|
||||
{
|
||||
if( pad->GetPosition() != aPosition )
|
||||
continue;
|
||||
|
||||
|
@ -1630,8 +1619,9 @@ D_PAD* BOARD::GetPadFast( const wxPoint& aPosition, LSET aLayerSet )
|
|||
if( ( pad->GetLayerSet() & aLayerSet ).any() )
|
||||
return pad;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1744,29 +1734,23 @@ bool sortPadsByXthenYCoord( D_PAD* const & ref, D_PAD* const & comp )
|
|||
|
||||
void BOARD::GetSortedPadListByXthenYCoord( std::vector<D_PAD*>& aVector, int aNetCode )
|
||||
{
|
||||
if( aNetCode < 0 )
|
||||
for ( auto mod : Modules() )
|
||||
{
|
||||
aVector.insert( aVector.end(), m_NetInfo.m_PadsFullList.begin(),
|
||||
m_NetInfo.m_PadsFullList.end() );
|
||||
}
|
||||
else
|
||||
{
|
||||
const NETINFO_ITEM* net = m_NetInfo.GetNetItem( aNetCode );
|
||||
if( net )
|
||||
for ( auto pad : mod->PadsIter( ) )
|
||||
{
|
||||
aVector.insert( aVector.end(), net->m_PadInNetList.begin(),
|
||||
net->m_PadInNetList.end() );
|
||||
if( aNetCode < 0 || pad->GetNetCode() == aNetCode )
|
||||
{
|
||||
aVector.push_back( pad );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort( aVector.begin(), aVector.end(), sortPadsByXthenYCoord );
|
||||
std::sort( aVector.begin(), aVector.end(), sortPadsByXthenYCoord );
|
||||
}
|
||||
|
||||
|
||||
void BOARD::PadDelete( D_PAD* aPad )
|
||||
{
|
||||
m_NetInfo.DeletePad( aPad );
|
||||
|
||||
aPad->DeleteStructure();
|
||||
}
|
||||
|
||||
|
@ -2830,7 +2814,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets,
|
|||
if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() )
|
||||
continue;
|
||||
|
||||
if( zone->GetNet()->GetNodesCount() == 0 )
|
||||
if( GetConnectivity()->GetPadCount( zone->GetNetCode() ) == 0 )
|
||||
{
|
||||
msg.Printf( _( "Copper zone (net name '%s'): net has no pads connected." ),
|
||||
GetChars( zone->GetNet()->GetNetname() ) );
|
||||
|
@ -2900,3 +2884,42 @@ bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
|
|||
{
|
||||
return m_connectivity->GetRatsnest();
|
||||
}*/
|
||||
|
||||
const std::vector<D_PAD*> BOARD::GetPads()
|
||||
{
|
||||
std::vector<D_PAD*> rv;
|
||||
for ( auto mod: Modules() )
|
||||
{
|
||||
for ( auto pad: mod->PadsIter() )
|
||||
rv.push_back ( pad );
|
||||
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
unsigned BOARD::GetPadCount() const
|
||||
{
|
||||
return m_connectivity->GetPadCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function GetPad
|
||||
* @return D_PAD* - at the \a aIndex
|
||||
*/
|
||||
D_PAD* BOARD::GetPad( unsigned aIndex ) const
|
||||
{
|
||||
unsigned count = 0;
|
||||
for ( MODULE *mod = m_Modules; mod ; mod = mod->Next() ) // FIXME: const DLIST_ITERATOR
|
||||
{
|
||||
for ( D_PAD *pad = mod->Pads(); pad; pad = pad->Next() )
|
||||
{
|
||||
if ( count == aIndex )
|
||||
return pad;
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -257,15 +257,11 @@ public:
|
|||
DLIST_ITERATOR_WRAPPER<MODULE> Modules() { return DLIST_ITERATOR_WRAPPER<MODULE>(m_Modules); }
|
||||
DLIST_ITERATOR_WRAPPER<BOARD_ITEM> Drawings() { return DLIST_ITERATOR_WRAPPER<BOARD_ITEM>(m_Drawings); }
|
||||
|
||||
|
||||
|
||||
// will be deprecated as soon as append board functionality is fixed
|
||||
DLIST<BOARD_ITEM>& DrawingsList() { return m_Drawings; }
|
||||
|
||||
/// Ratsnest list for the BOARD
|
||||
std::vector<RATSNEST_ITEM> m_FullRatsnest;
|
||||
|
||||
/// Ratsnest list relative to a given footprint (used while moving a footprint).
|
||||
std::vector<RATSNEST_ITEM> m_LocalRatsnest;
|
||||
|
||||
/// zone contour currently in progress
|
||||
ZONE_CONTAINER* m_CurrentZoneContour;
|
||||
|
||||
|
@ -712,15 +708,6 @@ public:
|
|||
/** Calculate the zone segment count */
|
||||
int GetNumSegmZone() const;
|
||||
|
||||
/**
|
||||
* Function GetNumRatsnests
|
||||
* @return int - The number of rats
|
||||
*/
|
||||
unsigned GetRatsnestsCount() const
|
||||
{
|
||||
return m_FullRatsnest.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function GetNodesCount
|
||||
* @return the number of pads members of nets (i.e. with netcode > 0)
|
||||
|
@ -753,19 +740,13 @@ public:
|
|||
* Function GetPadCount
|
||||
* @return the number of pads in board
|
||||
*/
|
||||
unsigned GetPadCount() const
|
||||
{
|
||||
return m_NetInfo.GetPadCount();
|
||||
}
|
||||
unsigned GetPadCount() const;
|
||||
|
||||
/**
|
||||
* Function GetPad
|
||||
* @return D_PAD* - at the \a aIndex from m_NetInfo
|
||||
* @return D_PAD* - at the \a aIndex
|
||||
*/
|
||||
D_PAD* GetPad( unsigned aIndex ) const
|
||||
{
|
||||
return m_NetInfo.GetPad( aIndex );
|
||||
}
|
||||
D_PAD* GetPad( unsigned aIndex ) const;
|
||||
|
||||
/**
|
||||
* Function GetPads
|
||||
|
@ -774,7 +755,7 @@ public:
|
|||
* ownership of the respective PADs.
|
||||
* @return D_PADS - a full list of pads
|
||||
*/
|
||||
const D_PADS& GetPads() { return m_NetInfo.m_PadsFullList; }
|
||||
const std::vector<D_PAD*> GetPads();
|
||||
|
||||
void BuildListOfNets()
|
||||
{
|
||||
|
@ -1192,14 +1173,6 @@ public:
|
|||
int Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_Examine,
|
||||
bool aCreate_Markers );
|
||||
|
||||
/****** function relative to ratsnest calculations: */
|
||||
|
||||
/**
|
||||
* Function Test_Connection_To_Copper_Areas
|
||||
* init .m_ZoneSubnet parameter in tracks and pads according to the connections to areas found
|
||||
* @param aNetcode = netcode to analyze. if -1, analyze all nets
|
||||
*/
|
||||
void Test_Connections_To_Copper_Areas( int aNetcode = -1 );
|
||||
|
||||
/**
|
||||
* Function GetViaByPosition
|
||||
|
|
|
@ -48,15 +48,7 @@ class CN_BOARD_ITEM_DATA;
|
|||
*/
|
||||
class BOARD_CONNECTED_ITEM : public BOARD_ITEM
|
||||
{
|
||||
friend class CONNECTIONS;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
// These 2 members are used for temporary storage during connections calculations:
|
||||
std::vector<TRACK*> m_TracksConnected; // list of other tracks connected to me
|
||||
std::vector<D_PAD*> m_PadsConnected; // list of other pads connected to me
|
||||
|
||||
BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype );
|
||||
|
||||
// Do not create a copy constructor & operator=.
|
||||
|
|
|
@ -60,61 +60,6 @@ class MSG_PANEL_ITEM;
|
|||
#define CH_ACTIF 8 /* Not routed. */
|
||||
#define LOCAL_RATSNEST_ITEM 0x8000 /* Line between two pads of a single module. */
|
||||
|
||||
|
||||
/**
|
||||
* Class RATSNEST_ITEM
|
||||
* describes a ratsnest line: a straight line connecting 2 pads
|
||||
*/
|
||||
class RATSNEST_ITEM
|
||||
{
|
||||
private:
|
||||
int m_NetCode; // netcode ( = 1.. n , 0 is the value used for not connected items)
|
||||
|
||||
public:
|
||||
int m_Status; // State: see previous defines (CH_ ...)
|
||||
D_PAD* m_PadStart; // pointer to the starting pad
|
||||
D_PAD* m_PadEnd; // pointer to ending pad
|
||||
int m_Length; // length of the line (used in some calculations)
|
||||
|
||||
RATSNEST_ITEM();
|
||||
|
||||
/**
|
||||
* Function GetNet
|
||||
* @return int - the net code.
|
||||
*/
|
||||
int GetNet() const
|
||||
{
|
||||
return m_NetCode;
|
||||
}
|
||||
|
||||
void SetNet( int aNetCode )
|
||||
{
|
||||
m_NetCode = aNetCode;
|
||||
}
|
||||
|
||||
bool IsVisible()
|
||||
{
|
||||
return (m_Status & CH_VISIBLE) != 0;
|
||||
}
|
||||
|
||||
bool IsActive()
|
||||
{
|
||||
return (m_Status & CH_ACTIF) != 0;
|
||||
}
|
||||
|
||||
bool IsLocal()
|
||||
{
|
||||
return (m_Status & LOCAL_RATSNEST_ITEM) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function Draw
|
||||
*/
|
||||
void Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMode,
|
||||
const wxPoint& offset );
|
||||
};
|
||||
|
||||
|
||||
DECL_VEC_FOR_SWIG( D_PADS, D_PAD* )
|
||||
|
||||
/**
|
||||
|
@ -142,25 +87,6 @@ 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
|
||||
* net (included) in a general buffer of
|
||||
* ratsnest (a vector<RATSNEST_ITEM*>
|
||||
* buffer) */
|
||||
|
||||
unsigned m_RatsnestEndIdx; // Ending point of ratsnests of this net
|
||||
// (excluded) in this buffer
|
||||
|
||||
NETINFO_ITEM( BOARD* aParent, const wxString& aNetName = wxEmptyString, int aNetCode = -1 );
|
||||
~NETINFO_ITEM();
|
||||
|
||||
|
@ -340,12 +266,6 @@ public:
|
|||
*/
|
||||
void Clear()
|
||||
{
|
||||
m_PadInNetList.clear();
|
||||
|
||||
m_RatsnestStartIdx = 0; // Starting point of ratsnests of this net in a
|
||||
// general buffer of ratsnest
|
||||
m_RatsnestEndIdx = 0; // Ending point of ratsnests of this net
|
||||
|
||||
SetClass( NETCLASSPTR() );
|
||||
}
|
||||
|
||||
|
@ -540,15 +460,6 @@ public:
|
|||
* Function GetPadCount
|
||||
* @return the number of pads in board
|
||||
*/
|
||||
unsigned GetPadCount() const { return m_PadsFullList.size(); }
|
||||
|
||||
/**
|
||||
* Function GetPads
|
||||
* returns a list of all the pads (so long as buildPadsFullList() has
|
||||
* been recently called). Returned list contains non-owning pointers.
|
||||
* @return D_PADS& - a full list of pads
|
||||
*/
|
||||
const D_PADS& GetPads() const { return m_PadsFullList; }
|
||||
|
||||
/// Return the name map, at least for python.
|
||||
const NETNAMES_MAP& NetsByName() const { return m_netNames; }
|
||||
|
@ -556,14 +467,6 @@ public:
|
|||
/// Return the netcode map, at least for python.
|
||||
const NETCODES_MAP& NetsByNetcode() const { return m_netCodes; }
|
||||
|
||||
/**
|
||||
* Function GetPad
|
||||
* @return D_PAD* - the pad from m_PadsFullList or nullptr if bad @a aIdx
|
||||
*/
|
||||
D_PAD* GetPad( unsigned aIdx ) const;
|
||||
|
||||
bool DeletePad( D_PAD* aPad );
|
||||
|
||||
///> Constant that holds the "unconnected net" number (typically 0)
|
||||
///> all items "connected" to this net are actually not connected items
|
||||
static const int UNCONNECTED;
|
||||
|
@ -680,9 +583,6 @@ private:
|
|||
NETNAMES_MAP m_netNames; ///< map of <wxString, NETINFO_ITEM*>, is NETINFO_ITEM owner
|
||||
NETCODES_MAP m_netCodes; ///< map of <int, NETINFO_ITEM*> is NOT owner
|
||||
|
||||
D_PADS m_PadsFullList; ///< contains all pads, sorted by pad's netname.
|
||||
///< can be used in ratsnest calculations.
|
||||
|
||||
int m_newNetCode; ///< possible value for new net code assignment
|
||||
};
|
||||
|
||||
|
@ -695,17 +595,13 @@ private:
|
|||
#define START_ON_TRACK 0x40
|
||||
#define END_ON_TRACK 0x80
|
||||
|
||||
|
||||
/* Status bit (OR'ed bits) for class BOARD member .m_Status_Pcb */
|
||||
enum StatusPcbFlags {
|
||||
LISTE_PAD_OK = 1, /* Pad list is Ok */
|
||||
LISTE_RATSNEST_ITEM_OK = 2, /* General Ratsnest is Ok */
|
||||
|
||||
RATSNEST_ITEM_LOCAL_OK = 4, /* current MODULE ratsnest is Ok */
|
||||
CONNEXION_OK = 8, /* List of connections exists. */
|
||||
NET_CODES_OK = 0x10, /* Bit indicating that Netcode is OK,
|
||||
* do not change net name. */
|
||||
DO_NOT_SHOW_GENERAL_RASTNEST = 0x20 /* Do not display the general
|
||||
* ratsnest (used in module moves) */
|
||||
};
|
||||
|
||||
|
||||
#endif // CLASS_NETINFO_
|
||||
|
|
|
@ -54,10 +54,6 @@ NETINFO_ITEM::NETINFO_ITEM( BOARD* aParent, const wxString& aNetName, int aNetCo
|
|||
m_NetCode( aNetCode ), m_Netname( aNetName ), m_ShortNetname( m_Netname.AfterLast( '/' ) )
|
||||
{
|
||||
m_parent = aParent;
|
||||
m_RatsnestStartIdx = 0; // Starting point of ratsnests of this net in a
|
||||
// general buffer of ratsnest
|
||||
m_RatsnestEndIdx = 0; // Ending point of ratsnests of this net
|
||||
|
||||
m_NetClassName = NETCLASS::Default;
|
||||
}
|
||||
|
||||
|
@ -144,39 +140,4 @@ void NETINFO_ITEM::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList )
|
|||
// Displays the net length of internal ICs connections (wires inside ICs):
|
||||
txt = ::LengthDoubleToString( lengthPadToDie );
|
||||
aList.push_back( MSG_PANEL_ITEM( _( "In Package" ), txt, RED ) );
|
||||
}
|
||||
|
||||
|
||||
/***********************/
|
||||
/* class RATSNEST_ITEM */
|
||||
/***********************/
|
||||
|
||||
RATSNEST_ITEM::RATSNEST_ITEM()
|
||||
{
|
||||
m_NetCode = 0; // netcode ( = 1.. n , 0 is the value used for not
|
||||
// connected items)
|
||||
m_Status = 0; // state
|
||||
m_PadStart = NULL; // pointer to the starting pad
|
||||
m_PadEnd = NULL; // pointer to ending pad
|
||||
m_Length = 0; // length of the line (temporary used in some
|
||||
// calculations)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function Draw
|
||||
* Draws a line (a ratsnest) from the starting pad to the ending pad
|
||||
*/
|
||||
void RATSNEST_ITEM::Draw( EDA_DRAW_PANEL* panel,
|
||||
wxDC* DC,
|
||||
GR_DRAWMODE aDrawMode,
|
||||
const wxPoint& aOffset )
|
||||
{
|
||||
GRSetDrawMode( DC, aDrawMode );
|
||||
|
||||
COLOR4D color = g_ColorsSettings.GetItemColor( LAYER_RATSNEST );
|
||||
|
||||
GRLine( panel->GetClipBox(), DC,
|
||||
m_PadStart->GetPosition() - aOffset,
|
||||
m_PadEnd->GetPosition() - aOffset, 0, color );
|
||||
}
|
||||
}
|
|
@ -62,7 +62,6 @@ void NETINFO_LIST::clear()
|
|||
for( it = m_netNames.begin(), itEnd = m_netNames.end(); it != itEnd; ++it )
|
||||
delete it->second;
|
||||
|
||||
m_PadsFullList.clear();
|
||||
m_netNames.clear();
|
||||
m_netCodes.clear();
|
||||
m_newNetCode = 0;
|
||||
|
@ -143,32 +142,6 @@ void NETINFO_LIST::AppendNet( NETINFO_ITEM* aNewElement )
|
|||
}
|
||||
|
||||
|
||||
D_PAD* NETINFO_LIST::GetPad( unsigned aIdx ) const
|
||||
{
|
||||
if( aIdx < m_PadsFullList.size() )
|
||||
return m_PadsFullList[aIdx];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool NETINFO_LIST::DeletePad( D_PAD* aPad )
|
||||
{
|
||||
std::vector<D_PAD*>::iterator it = m_PadsFullList.begin();
|
||||
std::vector<D_PAD*>::iterator end = m_PadsFullList.end();
|
||||
|
||||
for( ; it != end; ++it )
|
||||
{
|
||||
if( *it == aPad )
|
||||
{
|
||||
m_PadsFullList.erase( it );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* sort function, to sort pad list by netnames
|
||||
* this is a case sensitive sort.
|
||||
* DO NOT change it because NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname )
|
||||
|
@ -199,47 +172,15 @@ void NETINFO_LIST::buildListOfNets()
|
|||
D_PAD* pad;
|
||||
int nodes_count = 0;
|
||||
|
||||
// Build the PAD list, sorted by net
|
||||
buildPadsFullList();
|
||||
|
||||
// Restore the initial state of NETINFO_ITEMs
|
||||
for( NETINFO_LIST::iterator net( begin() ), netEnd( end() ); net != netEnd; ++net )
|
||||
net->Clear();
|
||||
|
||||
// Assign pads to appropriate NETINFO_ITEMs
|
||||
for( unsigned ii = 0; ii < m_PadsFullList.size(); ii++ )
|
||||
{
|
||||
pad = m_PadsFullList[ii];
|
||||
|
||||
if( pad->GetNetCode() == NETINFO_LIST::UNCONNECTED ) // pad not connected
|
||||
continue;
|
||||
|
||||
if( !( pad->GetLayerSet() & LSET::AllCuMask() ).any() )
|
||||
// pad not a copper layer (happens when building complex shapes)
|
||||
continue;
|
||||
|
||||
// Add pad to the appropriate list of pads
|
||||
NETINFO_ITEM* net = pad->GetNet();
|
||||
|
||||
// it should not be possible for BOARD_CONNECTED_ITEM to return NULL as a result of GetNet()
|
||||
wxASSERT( net );
|
||||
|
||||
if( net )
|
||||
net->m_PadInNetList.push_back( pad );
|
||||
|
||||
++nodes_count;
|
||||
}
|
||||
|
||||
m_Parent->SetNodeCount( nodes_count );
|
||||
|
||||
m_Parent->SynchronizeNetsAndNetClasses( );
|
||||
|
||||
m_Parent->m_Status_Pcb |= NET_CODES_OK;
|
||||
|
||||
m_Parent->SetAreasNetCodesFromNetNames();
|
||||
}
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
void NETINFO_LIST::Show() const
|
||||
{
|
||||
|
@ -255,46 +196,6 @@ void NETINFO_LIST::Show() const
|
|||
#endif
|
||||
|
||||
|
||||
void NETINFO_LIST::buildPadsFullList()
|
||||
{
|
||||
/*
|
||||
* initialize:
|
||||
* m_Pads (list of pads)
|
||||
* set m_Status_Pcb = LISTE_PAD_OK;
|
||||
* also clear m_Pcb->m_FullRatsnest that could have bad data
|
||||
* (m_Pcb->m_FullRatsnest uses pointer to pads)
|
||||
* Be aware NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname )
|
||||
* when search a net by its net name does a binary search
|
||||
* and expects to have a nets list sorted by an alphabetic case sensitive sort
|
||||
* So do not change the sort function used here
|
||||
*/
|
||||
|
||||
if( m_Parent->m_Status_Pcb & LISTE_PAD_OK )
|
||||
return;
|
||||
|
||||
// empty the old list
|
||||
m_PadsFullList.clear();
|
||||
m_Parent->m_FullRatsnest.clear();
|
||||
|
||||
// Clear variables used in ratsnest computation
|
||||
for( MODULE* module = m_Parent->m_Modules; module; module = module->Next() )
|
||||
{
|
||||
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
|
||||
{
|
||||
m_PadsFullList.push_back( pad );
|
||||
|
||||
pad->SetSubRatsnest( 0 );
|
||||
pad->SetParent( module );
|
||||
}
|
||||
}
|
||||
|
||||
// Sort pad list per net
|
||||
sort( m_PadsFullList.begin(), m_PadsFullList.end(), padlistSortByNetnames );
|
||||
|
||||
m_Parent->m_Status_Pcb = LISTE_PAD_OK;
|
||||
}
|
||||
|
||||
|
||||
int NETINFO_LIST::getFreeNetCode()
|
||||
{
|
||||
do {
|
||||
|
@ -373,4 +274,4 @@ NETINFO_ITEM* NETINFO_MAPPING::iterator::operator->() const
|
|||
const int NETINFO_LIST::UNCONNECTED = 0;
|
||||
const int NETINFO_LIST::ORPHANED = -1;
|
||||
|
||||
NETINFO_ITEM NETINFO_LIST::ORPHANED_ITEM = NETINFO_ITEM( NULL, wxEmptyString, NETINFO_LIST::UNCONNECTED );
|
||||
NETINFO_ITEM NETINFO_LIST::ORPHANED_ITEM = NETINFO_ITEM( NULL, wxEmptyString, NETINFO_LIST::UNCONNECTED );
|
||||
|
|
120
pcbnew/clean.cpp
120
pcbnew/clean.cpp
|
@ -35,14 +35,12 @@
|
|||
#include <pcbnew.h>
|
||||
#include <class_board.h>
|
||||
#include <class_track.h>
|
||||
#include <connect.h>
|
||||
#include <dialog_cleaning_options.h>
|
||||
#include <board_commit.h>
|
||||
|
||||
#include <tuple>
|
||||
#include <connectivity.h>
|
||||
|
||||
// Helper class used to clean tracks and vias
|
||||
class TRACKS_CLEANER: CONNECTIONS
|
||||
class TRACKS_CLEANER
|
||||
{
|
||||
public:
|
||||
TRACKS_CLEANER( BOARD* aPcb, BOARD_COMMIT& aCommit );
|
||||
|
@ -69,7 +67,7 @@ private:
|
|||
* Removes redundant vias like vias at same location
|
||||
* or on pad through
|
||||
*/
|
||||
bool clean_vias();
|
||||
bool cleanupVias();
|
||||
|
||||
/**
|
||||
* Removes all the following THT vias on the same position of the
|
||||
|
@ -98,12 +96,6 @@ private:
|
|||
*/
|
||||
bool clean_segments();
|
||||
|
||||
/**
|
||||
* helper function
|
||||
* Rebuild list of tracks, and connected tracks
|
||||
* this info must be rebuilt when tracks are erased
|
||||
*/
|
||||
void buildTrackConnectionInfo();
|
||||
|
||||
/**
|
||||
* helper function
|
||||
|
@ -147,7 +139,6 @@ void PCB_EDIT_FRAME::Clean_Pcb()
|
|||
// Clear undo and redo lists to avoid inconsistencies between lists
|
||||
SetCurItem( NULL );
|
||||
commit.Push( _( "Board cleanup" ) );
|
||||
Compile_Ratsnest( NULL, true );
|
||||
}
|
||||
|
||||
m_canvas->Refresh( true );
|
||||
|
@ -165,13 +156,12 @@ bool TRACKS_CLEANER::CleanupBoard( bool aRemoveMisConnected,
|
|||
bool aMergeSegments,
|
||||
bool aDeleteUnconnected )
|
||||
{
|
||||
buildTrackConnectionInfo();
|
||||
|
||||
bool modified = false;
|
||||
|
||||
// delete redundant vias
|
||||
if( aCleanVias )
|
||||
modified |= clean_vias();
|
||||
modified |= cleanupVias();
|
||||
|
||||
// Remove null segments and intermediate points on aligned segments
|
||||
// If not asked, remove null segments only if remove misconnected is asked
|
||||
|
@ -187,7 +177,7 @@ bool TRACKS_CLEANER::CleanupBoard( bool aRemoveMisConnected,
|
|||
modified = true;
|
||||
|
||||
// Refresh track connection info
|
||||
buildTrackConnectionInfo();
|
||||
//buildTrackConnectionInfo(); FIXME: update connectivity
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,7 +185,9 @@ bool TRACKS_CLEANER::CleanupBoard( bool aRemoveMisConnected,
|
|||
if( aDeleteUnconnected )
|
||||
{
|
||||
if( modified ) // Refresh track connection info
|
||||
buildTrackConnectionInfo();
|
||||
{
|
||||
//buildTrackConnectionInfo(); FIXME: update connectivity
|
||||
}
|
||||
|
||||
if( deleteDanglingTracks() )
|
||||
{
|
||||
|
@ -214,101 +206,37 @@ bool TRACKS_CLEANER::CleanupBoard( bool aRemoveMisConnected,
|
|||
|
||||
|
||||
TRACKS_CLEANER::TRACKS_CLEANER( BOARD* aPcb, BOARD_COMMIT& aCommit )
|
||||
: CONNECTIONS( aPcb ), m_brd( aPcb ), m_commit( aCommit )
|
||||
: m_brd( aPcb ), m_commit( aCommit )
|
||||
{
|
||||
// Be sure pad list is up to date
|
||||
BuildPadsList();
|
||||
}
|
||||
|
||||
|
||||
void TRACKS_CLEANER::buildTrackConnectionInfo()
|
||||
{
|
||||
BuildTracksCandidatesList( m_brd->m_Track, NULL );
|
||||
|
||||
// clear flags and variables used in cleanup
|
||||
for( TRACK* track = m_brd->m_Track; track != NULL; track = track->Next() )
|
||||
{
|
||||
track->start = NULL;
|
||||
track->end = NULL;
|
||||
track->m_PadsConnected.clear();
|
||||
track->SetState( START_ON_PAD | END_ON_PAD | BUSY, false );
|
||||
}
|
||||
|
||||
// Build connections info tracks to pads
|
||||
SearchTracksConnectedToPads();
|
||||
|
||||
for( TRACK* track = m_brd->m_Track; track != NULL; track = track->Next() )
|
||||
{
|
||||
// Mark track if connected to pads
|
||||
for( unsigned jj = 0; jj < track->m_PadsConnected.size(); jj++ )
|
||||
{
|
||||
D_PAD * pad = track->m_PadsConnected[jj];
|
||||
|
||||
if( pad->HitTest( track->GetStart() ) )
|
||||
{
|
||||
track->start = pad;
|
||||
track->SetState( START_ON_PAD, true );
|
||||
}
|
||||
|
||||
if( pad->HitTest( track->GetEnd() ) )
|
||||
{
|
||||
track->end = pad;
|
||||
track->SetState( END_ON_PAD, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool TRACKS_CLEANER::removeBadTrackSegments()
|
||||
{
|
||||
// The rastsnet is expected to be up to date (Compile_Ratsnest was called)
|
||||
|
||||
// Rebuild physical connections.
|
||||
// the list of physical connected items to a given item is in
|
||||
// m_PadsConnected and m_TracksConnected members of each item
|
||||
BuildTracksCandidatesList( m_brd->m_Track );
|
||||
|
||||
// build connections between track segments and pads.
|
||||
SearchTracksConnectedToPads();
|
||||
|
||||
TRACK* segment;
|
||||
|
||||
// build connections between track ends
|
||||
for( segment = m_brd->m_Track; segment; segment = segment->Next() )
|
||||
{
|
||||
SearchConnectedTracks( segment );
|
||||
GetConnectedTracks( segment );
|
||||
}
|
||||
|
||||
bool isModified = false;
|
||||
auto connectivity = m_brd->GetConnectivity();
|
||||
|
||||
for( segment = m_brd->m_Track; segment; segment = segment->Next() )
|
||||
for( auto segment : m_brd->Tracks() )
|
||||
{
|
||||
segment->SetState( FLAG0, false );
|
||||
|
||||
for( unsigned ii = 0; ii < segment->m_PadsConnected.size(); ++ii )
|
||||
for( auto testedPad : connectivity->GetConnectedPads( segment ) )
|
||||
{
|
||||
if( segment->GetNetCode() != segment->m_PadsConnected[ii]->GetNetCode() )
|
||||
if( segment->GetNetCode() != testedPad->GetNetCode() )
|
||||
segment->SetState( FLAG0, true );
|
||||
}
|
||||
|
||||
for( unsigned ii = 0; ii < segment->m_TracksConnected.size(); ++ii )
|
||||
for( auto testedTrack : connectivity->GetConnectedTracks( segment ) )
|
||||
{
|
||||
TRACK* tested = segment->m_TracksConnected[ii];
|
||||
|
||||
if( segment->GetNetCode() != tested->GetNetCode() && !tested->GetState( FLAG0 ) )
|
||||
if( segment->GetNetCode() != testedTrack->GetNetCode() && !testedTrack->GetState( FLAG0 ) )
|
||||
segment->SetState( FLAG0, true );
|
||||
}
|
||||
}
|
||||
|
||||
// Remove tracks having a flagged segment
|
||||
TRACK* next;
|
||||
|
||||
for( segment = m_brd->m_Track; segment; segment = next )
|
||||
for( auto segment : m_brd->Tracks() )
|
||||
{
|
||||
next = segment->Next();
|
||||
|
||||
if( segment->GetState( FLAG0 ) ) // Segment is flagged to be removed
|
||||
{
|
||||
isModified = true;
|
||||
|
@ -317,15 +245,6 @@ bool TRACKS_CLEANER::removeBadTrackSegments()
|
|||
}
|
||||
}
|
||||
|
||||
if( isModified )
|
||||
{ // some pointers are invalid. Clear the m_TracksConnected list,
|
||||
// to avoid any issue
|
||||
for( segment = m_brd->m_Track; segment; segment = segment->Next() )
|
||||
segment->m_TracksConnected.clear();
|
||||
|
||||
m_brd->m_Status_Pcb = 0;
|
||||
}
|
||||
|
||||
return isModified;
|
||||
}
|
||||
|
||||
|
@ -353,7 +272,7 @@ bool TRACKS_CLEANER::remove_duplicates_of_via( const VIA *aVia )
|
|||
}
|
||||
|
||||
|
||||
bool TRACKS_CLEANER::clean_vias()
|
||||
bool TRACKS_CLEANER::cleanupVias()
|
||||
{
|
||||
bool modified = false;
|
||||
|
||||
|
@ -376,9 +295,10 @@ bool TRACKS_CLEANER::clean_vias()
|
|||
/* To delete through Via on THT pads at same location
|
||||
* Examine the list of connected pads:
|
||||
* if one through pad is found, the via can be removed */
|
||||
for( unsigned ii = 0; ii < via->m_PadsConnected.size(); ++ii )
|
||||
|
||||
const auto pads = m_brd->GetConnectivity()->GetConnectedPads( via );
|
||||
for( const auto pad : pads )
|
||||
{
|
||||
const D_PAD* pad = via->m_PadsConnected[ii];
|
||||
const LSET all_cu = LSET::AllCuMask();
|
||||
|
||||
if( ( pad->GetLayerSet() & all_cu ) == all_cu )
|
||||
|
|
|
@ -39,756 +39,63 @@
|
|||
// Helper classes to handle connection points
|
||||
#include <connect.h>
|
||||
|
||||
const bool g_UseLegacyConnectionAlgo = false;
|
||||
|
||||
extern void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb );
|
||||
extern void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb, int aNetcode );
|
||||
|
||||
|
||||
|
||||
// Local functions
|
||||
static void RebuildTrackChain( BOARD* pcb );
|
||||
|
||||
|
||||
CONNECTIONS::CONNECTIONS( BOARD * aBrd )
|
||||
{
|
||||
m_brd = aBrd;
|
||||
m_firstTrack = NULL;
|
||||
m_lastTrack = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Fills m_sortedPads with all pads that be connected to tracks
|
||||
* pads are sorted by X coordinate ( and Y coordinates for same X value )
|
||||
* aNetcode = net code to filter pads or < 0 to put all pads in list
|
||||
/*
|
||||
* Function SortTracksByNetCode used in RebuildTrackChain()
|
||||
* to sort track segments by net code.
|
||||
*/
|
||||
void CONNECTIONS::BuildPadsList( int aNetcode )
|
||||
static bool SortTracksByNetCode( const TRACK* const & ref, const TRACK* const & compare )
|
||||
{
|
||||
// Creates sorted pad list if not exists
|
||||
m_sortedPads.clear();
|
||||
m_brd->GetSortedPadListByXthenYCoord( m_sortedPads, aNetcode < 0 ? -1 : aNetcode );
|
||||
// For items having the same Net, keep the order in list
|
||||
if( ref->GetNetCode() == compare->GetNetCode())
|
||||
return ref->m_Param < compare->m_Param;
|
||||
|
||||
return ref->GetNetCode() < compare->GetNetCode();
|
||||
}
|
||||
|
||||
/* Explores the list of pads and adds to m_PadsConnected member
|
||||
* of each pad pads connected to
|
||||
* Here, connections are due to intersecting pads, not tracks
|
||||
*/
|
||||
void CONNECTIONS::SearchConnectionsPadsToIntersectingPads()
|
||||
{
|
||||
std::vector<CONNECTED_POINT*> candidates;
|
||||
|
||||
BuildPadsCandidatesList();
|
||||
|
||||
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
||||
{
|
||||
D_PAD* pad = m_sortedPads[ii];
|
||||
|
||||
pad->m_PadsConnected.clear();
|
||||
candidates.clear();
|
||||
|
||||
CollectItemsNearTo( candidates, pad->ShapePos(), pad->GetBoundingRadius() );
|
||||
|
||||
// add pads to pad.m_PadsConnected, if they are connected
|
||||
for( unsigned jj = 0; jj < candidates.size(); jj++ )
|
||||
{
|
||||
CONNECTED_POINT* item = candidates[jj];
|
||||
|
||||
D_PAD* candidate_pad = item->GetPad();
|
||||
|
||||
if( pad == candidate_pad )
|
||||
continue;
|
||||
|
||||
if( !( pad->GetLayerSet() & candidate_pad->GetLayerSet() ).any() )
|
||||
continue;
|
||||
|
||||
if( pad->HitTest( item->GetPoint() ) )
|
||||
{
|
||||
pad->m_PadsConnected.push_back( candidate_pad );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Explores the list of pads
|
||||
* Adds to m_PadsConnected member of each track the pad(s) connected to
|
||||
* Adds to m_TracksConnected member of each pad the track(s) connected to
|
||||
* D_PAD::m_TracksConnected is cleared before adding items
|
||||
* TRACK::m_PadsConnected is not cleared
|
||||
*/
|
||||
void CONNECTIONS::SearchTracksConnectedToPads( bool add_to_padlist, bool add_to_tracklist)
|
||||
{
|
||||
std::vector<CONNECTED_POINT*> candidates;
|
||||
|
||||
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
||||
{
|
||||
D_PAD * pad = m_sortedPads[ii];
|
||||
pad->m_TracksConnected.clear();
|
||||
candidates.clear();
|
||||
|
||||
CollectItemsNearTo( candidates, pad->GetPosition(), pad->GetBoundingRadius() );
|
||||
|
||||
// add this pad to track.m_PadsConnected, if it is connected
|
||||
for( unsigned jj = 0; jj < candidates.size(); jj++ )
|
||||
{
|
||||
CONNECTED_POINT* cp_item = candidates[jj];
|
||||
|
||||
if( !( pad->GetLayerSet() & cp_item->GetTrack()->GetLayerSet() ).any() )
|
||||
continue;
|
||||
|
||||
if( pad->HitTest( cp_item->GetPoint() ) )
|
||||
{
|
||||
if( add_to_padlist )
|
||||
cp_item->GetTrack()->m_PadsConnected.push_back( pad );
|
||||
|
||||
if( add_to_tracklist )
|
||||
pad->m_TracksConnected.push_back( cp_item->GetTrack() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CONNECTIONS::CollectItemsNearTo( std::vector<CONNECTED_POINT*>& aList,
|
||||
const wxPoint& aPosition, int aDistMax )
|
||||
{
|
||||
/* Search items in m_Candidates that position is <= aDistMax from aPosition
|
||||
* (Rectilinear distance)
|
||||
* m_Candidates is sorted by X then Y values, so a fast binary search is used
|
||||
* to locate the "best" entry point in list
|
||||
* The best entry is a pad having its m_Pos.x == (or near) aPosition.x
|
||||
* All candidates are near this candidate in list
|
||||
* So from this entry point, a linear search is made to find all candidates
|
||||
*/
|
||||
int idxmax = m_candidates.size()-1;
|
||||
|
||||
int delta = m_candidates.size();
|
||||
|
||||
int idx = 0; // Starting index is the beginning of list
|
||||
while( delta )
|
||||
{
|
||||
// Calculate half size of remaining interval to test.
|
||||
// Ensure the computed value is not truncated (too small)
|
||||
if( (delta & 1) && ( delta > 1 ) )
|
||||
delta++;
|
||||
delta /= 2;
|
||||
|
||||
CONNECTED_POINT& item = m_candidates[idx];
|
||||
|
||||
int dist = item.GetPoint().x - aPosition.x;
|
||||
if( abs(dist) <= aDistMax )
|
||||
{
|
||||
break; // A good entry point is found. The list can be scanned from this point.
|
||||
}
|
||||
|
||||
else if( item.GetPoint().x < aPosition.x ) // We should search after this item
|
||||
{
|
||||
idx += delta;
|
||||
if( idx > idxmax )
|
||||
idx = idxmax;
|
||||
}
|
||||
else // We should search before this item
|
||||
{
|
||||
idx -= delta;
|
||||
if( idx < 0 )
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now explore the candidate list from the "best" entry point found
|
||||
* (candidate "near" aPosition.x)
|
||||
* We explore the list until abs(candidate->m_Point.x - aPosition.x) > aDistMax
|
||||
* because the list is sorted by X position (and for a given X pos, by Y pos)
|
||||
* Currently a linear search is made because the number of candidates
|
||||
* having the right X position is usually small
|
||||
*/
|
||||
// search next candidates in list
|
||||
wxPoint diff;
|
||||
for( int ii = idx; ii <= idxmax; ii++ )
|
||||
{
|
||||
CONNECTED_POINT* item = &m_candidates[ii];
|
||||
diff = item->GetPoint() - aPosition;
|
||||
if( abs(diff.x) > aDistMax )
|
||||
break; // Exit: the distance is to long, we cannot find other candidates
|
||||
if( abs(diff.y) > aDistMax )
|
||||
continue; // the y distance is to long, but we can find other candidates
|
||||
// We have here a good candidate: add it
|
||||
aList.push_back( item );
|
||||
}
|
||||
// search previous candidates in list
|
||||
for( int ii = idx-1; ii >=0; ii-- )
|
||||
{
|
||||
CONNECTED_POINT * item = &m_candidates[ii];
|
||||
diff = item->GetPoint() - aPosition;
|
||||
if( abs(diff.x) > aDistMax )
|
||||
break;
|
||||
if( abs(diff.y) > aDistMax )
|
||||
continue;
|
||||
// We have here a good candidate:add it
|
||||
aList.push_back( item );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CONNECTIONS::BuildPadsCandidatesList()
|
||||
{
|
||||
m_candidates.clear();
|
||||
m_candidates.reserve( m_sortedPads.size() );
|
||||
|
||||
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
||||
{
|
||||
D_PAD * pad = m_sortedPads[ii];
|
||||
CONNECTED_POINT candidate( pad, pad->GetPosition() );
|
||||
m_candidates.push_back( candidate );
|
||||
}
|
||||
}
|
||||
|
||||
/* sort function used to sort .m_Connected by X the Y values
|
||||
* items are sorted by X coordinate value,
|
||||
* and for same X value, by Y coordinate value.
|
||||
*/
|
||||
static bool sortConnectedPointByXthenYCoordinates( const CONNECTED_POINT & aRef,
|
||||
const CONNECTED_POINT & aTst )
|
||||
{
|
||||
if( aRef.GetPoint().x == aTst.GetPoint().x )
|
||||
return aRef.GetPoint().y < aTst.GetPoint().y;
|
||||
return aRef.GetPoint().x < aTst.GetPoint().x;
|
||||
}
|
||||
|
||||
void CONNECTIONS::BuildTracksCandidatesList( TRACK* aBegin, TRACK* aEnd)
|
||||
{
|
||||
m_candidates.clear();
|
||||
m_firstTrack = m_lastTrack = aBegin;
|
||||
|
||||
unsigned ii = 0;
|
||||
|
||||
// Count candidates ( i.e. end points )
|
||||
for( const TRACK* track = aBegin; track; track = track->Next() )
|
||||
{
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
ii++;
|
||||
else
|
||||
ii += 2;
|
||||
|
||||
m_lastTrack = track;
|
||||
|
||||
if( track == aEnd )
|
||||
break;
|
||||
}
|
||||
|
||||
// Build candidate list
|
||||
m_candidates.reserve( ii );
|
||||
for( TRACK* track = aBegin; track; track = track->Next() )
|
||||
{
|
||||
CONNECTED_POINT candidate( track, track->GetStart() );
|
||||
|
||||
m_candidates.push_back( candidate );
|
||||
if( track->Type() != PCB_VIA_T )
|
||||
{
|
||||
CONNECTED_POINT candidate2( track, track->GetEnd());
|
||||
m_candidates.push_back( candidate2 );
|
||||
}
|
||||
|
||||
if( track == aEnd )
|
||||
break;
|
||||
}
|
||||
|
||||
// Sort list by increasing X coordinate,
|
||||
// and for increasing Y coordinate when items have the same X coordinate
|
||||
// So candidates to the same location are consecutive in list.
|
||||
sort( m_candidates.begin(), m_candidates.end(), sortConnectedPointByXthenYCoordinates );
|
||||
}
|
||||
|
||||
|
||||
/* Populates .m_connected with tracks/vias connected to aTrack
|
||||
* param aTrack = track or via to use as reference
|
||||
* For calculation time reason, an exhaustive search cannot be made
|
||||
* and a proximity search is made:
|
||||
* Only tracks with one end near one end of aTrack are collected.
|
||||
* near means dist <= aTrack width / 2
|
||||
* because with this constraint we can make a fast search in track list
|
||||
* m_candidates is expected to be populated by the track candidates ends list
|
||||
*/
|
||||
int CONNECTIONS::SearchConnectedTracks( const TRACK* aTrack )
|
||||
{
|
||||
int count = 0;
|
||||
m_connected.clear();
|
||||
|
||||
LSET layerMask = aTrack->GetLayerSet();
|
||||
|
||||
// Search for connections to starting point:
|
||||
#define USE_EXTENDED_SEARCH
|
||||
|
||||
#ifdef USE_EXTENDED_SEARCH
|
||||
int dist_max = aTrack->GetWidth() / 2;
|
||||
static std::vector<CONNECTED_POINT*> tracks_candidates;
|
||||
#endif
|
||||
|
||||
wxPoint position = aTrack->GetStart();
|
||||
|
||||
for( int kk = 0; kk < 2; kk++ )
|
||||
{
|
||||
#ifndef USE_EXTENDED_SEARCH
|
||||
int idx = searchEntryPointInCandidatesList( position );
|
||||
|
||||
if( idx >= 0 )
|
||||
{
|
||||
// search after:
|
||||
for( unsigned ii = idx; ii < m_candidates.size(); ii ++ )
|
||||
{
|
||||
if( m_candidates[ii].GetTrack() == aTrack )
|
||||
continue;
|
||||
|
||||
if( m_candidates[ii].GetPoint() != position )
|
||||
break;
|
||||
|
||||
if( ( m_candidates[ii].GetTrack()->GetLayerSet() & layerMask ).any() )
|
||||
m_connected.push_back( m_candidates[ii].GetTrack() );
|
||||
}
|
||||
|
||||
// search before:
|
||||
for( int ii = idx-1; ii >= 0; ii -- )
|
||||
{
|
||||
if( m_candidates[ii].GetTrack() == aTrack )
|
||||
continue;
|
||||
|
||||
if( m_candidates[ii].GetPoint() != position )
|
||||
break;
|
||||
|
||||
if( ( m_candidates[ii].GetTrack()->GetLayerSet() & layerMask ).any() )
|
||||
m_connected.push_back( m_candidates[ii].GetTrack() );
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
tracks_candidates.clear();
|
||||
|
||||
CollectItemsNearTo( tracks_candidates, position, dist_max );
|
||||
|
||||
for( unsigned ii = 0; ii < tracks_candidates.size(); ii++ )
|
||||
{
|
||||
TRACK* ctrack = tracks_candidates[ii]->GetTrack();
|
||||
|
||||
if( !( ctrack->GetLayerSet() & layerMask ).any() )
|
||||
continue;
|
||||
|
||||
if( ctrack == aTrack )
|
||||
continue;
|
||||
|
||||
// We have a good candidate: calculate the actual distance
|
||||
// between ends, which should be <= dist max.
|
||||
wxPoint delta = tracks_candidates[ii]->GetPoint() - position;
|
||||
|
||||
int dist = KiROUND( EuclideanNorm( delta ) );
|
||||
|
||||
if( dist > dist_max )
|
||||
continue;
|
||||
|
||||
m_connected.push_back( ctrack );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Search for connections to ending point:
|
||||
if( aTrack->Type() == PCB_VIA_T )
|
||||
break;
|
||||
|
||||
position = aTrack->GetEnd();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int CONNECTIONS::searchEntryPointInCandidatesList( const wxPoint& aPoint )
|
||||
{
|
||||
// Search the aPoint coordinates in m_Candidates
|
||||
// m_Candidates is sorted by X then Y values, and a fast binary search is used
|
||||
int idxmax = m_candidates.size()-1;
|
||||
|
||||
int delta = m_candidates.size();
|
||||
|
||||
int idx = 0; // Starting index is the beginning of list
|
||||
|
||||
while( delta )
|
||||
{
|
||||
// Calculate half size of remaining interval to test.
|
||||
// Ensure the computed value is not truncated (too small)
|
||||
if( ( delta & 1 ) && ( delta > 1 ) )
|
||||
delta++;
|
||||
|
||||
delta /= 2;
|
||||
|
||||
CONNECTED_POINT& candidate = m_candidates[idx];
|
||||
|
||||
if( candidate.GetPoint() == aPoint ) // candidate found
|
||||
{
|
||||
return idx;
|
||||
}
|
||||
|
||||
// Not found: test the middle of the remaining sub list
|
||||
if( candidate.GetPoint().x == aPoint.x ) // Must search considering Y coordinate
|
||||
{
|
||||
if(candidate.GetPoint().y < aPoint.y) // Must search after this item
|
||||
{
|
||||
idx += delta;
|
||||
if( idx > idxmax )
|
||||
idx = idxmax;
|
||||
}
|
||||
else // Must search before this item
|
||||
{
|
||||
idx -= delta;
|
||||
if( idx < 0 )
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
else if( candidate.GetPoint().x < aPoint.x ) // Must search after this item
|
||||
{
|
||||
idx += delta;
|
||||
if( idx > idxmax )
|
||||
idx = idxmax;
|
||||
}
|
||||
else // Must search before this item
|
||||
{
|
||||
idx -= delta;
|
||||
if( idx < 0 )
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Used after a track change (delete a track ou add a track)
|
||||
* Connections to pads are recalculated
|
||||
* Note also aFirstTrack (and aLastTrack ) can be NULL
|
||||
*/
|
||||
void CONNECTIONS::Build_CurrNet_SubNets_Connections( TRACK* aFirstTrack, TRACK* aLastTrack, int aNetcode )
|
||||
{
|
||||
m_firstTrack = aFirstTrack; // The first track used to build m_Candidates
|
||||
m_lastTrack = aLastTrack; // The last track used to build m_Candidates
|
||||
|
||||
// Pads subnets are expected already cleared, because this function
|
||||
// does not know the full list of pads
|
||||
BuildTracksCandidatesList( aFirstTrack, aLastTrack );
|
||||
TRACK* curr_track;
|
||||
for( curr_track = aFirstTrack; curr_track != NULL; curr_track = curr_track->Next() )
|
||||
{
|
||||
// Clear track subnet id (Pads subnets are cleared outside this function)
|
||||
curr_track->SetSubNet( 0 );
|
||||
curr_track->m_TracksConnected.clear();
|
||||
curr_track->m_PadsConnected.clear();
|
||||
|
||||
// Update connections between tracks:
|
||||
SearchConnectedTracks( curr_track );
|
||||
curr_track->m_TracksConnected = m_connected;
|
||||
|
||||
if( curr_track == aLastTrack )
|
||||
break;
|
||||
}
|
||||
|
||||
// Update connections between tracks and pads
|
||||
BuildPadsList( aNetcode );
|
||||
SearchTracksConnectedToPads();
|
||||
|
||||
// Update connections between intersecting pads (no tracks)
|
||||
SearchConnectionsPadsToIntersectingPads();
|
||||
|
||||
// Creates sub nets (clusters) for the current net:
|
||||
Propagate_SubNets();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change a subnet value to a new value, in m_sortedPads pad list
|
||||
* After that, 2 cluster (or subnets) are merged into only one.
|
||||
* Note: the resulting subnet value is the smallest between aOldSubNet et aNewSubNet
|
||||
* Helper function RebuildTrackChain
|
||||
* rebuilds the track segment linked list in order to have a chain
|
||||
* sorted by increasing netcodes.
|
||||
* We try to keep order of track segments in list, when possible
|
||||
* @param pcb = board to rebuild
|
||||
*/
|
||||
int CONNECTIONS::Merge_PadsSubNets( int aOldSubNet, int aNewSubNet )
|
||||
static void RebuildTrackChain( BOARD* pcb )
|
||||
{
|
||||
int change_count = 0;
|
||||
if( pcb->m_Track == NULL )
|
||||
return;
|
||||
|
||||
if( aOldSubNet == aNewSubNet )
|
||||
return 0;
|
||||
int item_count = pcb->m_Track.GetCount();
|
||||
|
||||
if( (aOldSubNet > 0) && (aOldSubNet < aNewSubNet) )
|
||||
std::swap( aOldSubNet, aNewSubNet );
|
||||
std::vector<TRACK*> trackList;
|
||||
trackList.reserve( item_count );
|
||||
|
||||
// Examine connections between intersecting pads
|
||||
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
||||
// Put track list in a temporary list to sort tracks by netcode
|
||||
// We try to keep the initial order of track segments in list, when possible
|
||||
// so we use m_Param (a member variable used for temporary storage)
|
||||
// to temporary keep trace of the order of segments
|
||||
// The sort function uses this variable to sort items that
|
||||
// have the same net code.
|
||||
// Without this, during sorting, the initial order is sometimes lost
|
||||
// by the sort algorithm
|
||||
for( int ii = 0; ii < item_count; ++ii )
|
||||
{
|
||||
D_PAD * curr_pad = m_sortedPads[ii];
|
||||
if( curr_pad->GetSubNet() != aOldSubNet )
|
||||
continue;
|
||||
|
||||
change_count++;
|
||||
curr_pad->SetSubNet( aNewSubNet );
|
||||
pcb->m_Track->m_Param = ii;
|
||||
trackList.push_back( pcb->m_Track.PopFront() );
|
||||
}
|
||||
|
||||
return change_count;
|
||||
// the list is empty now
|
||||
wxASSERT( pcb->m_Track == NULL && pcb->m_Track.GetCount()==0 );
|
||||
|
||||
sort( trackList.begin(), trackList.end(), SortTracksByNetCode );
|
||||
|
||||
// add them back to the list
|
||||
for( int i = 0; i < item_count; ++i )
|
||||
pcb->m_Track.PushBack( trackList[i] );
|
||||
}
|
||||
|
||||
/*
|
||||
* Change a subnet value to a new value, for tracks and pads which are connected to.
|
||||
* The result is merging 2 clusters (or subnets) into only one cluster.
|
||||
* Note: the resulting sub net value is the smallest between aOldSubNet et aNewSubNet
|
||||
*/
|
||||
int CONNECTIONS::Merge_SubNets( int aOldSubNet, int aNewSubNet )
|
||||
{
|
||||
TRACK* curr_track;
|
||||
int change_count = 0;
|
||||
|
||||
if( aOldSubNet == aNewSubNet )
|
||||
return 0;
|
||||
|
||||
if( (aOldSubNet > 0) && (aOldSubNet < aNewSubNet) )
|
||||
std::swap( aOldSubNet, aNewSubNet );
|
||||
|
||||
curr_track = (TRACK*)m_firstTrack;
|
||||
|
||||
for( ; curr_track != NULL; curr_track = curr_track->Next() )
|
||||
{
|
||||
if( curr_track->GetSubNet() != aOldSubNet )
|
||||
{
|
||||
if( curr_track == m_lastTrack )
|
||||
break;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
change_count++;
|
||||
curr_track->SetSubNet( aNewSubNet );
|
||||
|
||||
for( unsigned ii = 0; ii < curr_track->m_PadsConnected.size(); ii++ )
|
||||
{
|
||||
D_PAD * pad = curr_track->m_PadsConnected[ii];
|
||||
if( pad->GetSubNet() == aOldSubNet )
|
||||
{
|
||||
pad->SetSubNet( curr_track->GetSubNet() );
|
||||
}
|
||||
}
|
||||
|
||||
if( curr_track == m_lastTrack )
|
||||
break;
|
||||
}
|
||||
|
||||
return change_count;
|
||||
}
|
||||
|
||||
|
||||
/* Test a list of track segments, to create or propagate a sub netcode to pads and
|
||||
* segments connected together.
|
||||
* The track list must be sorted by nets, and all segments
|
||||
* from m_firstTrack to m_lastTrack have the same net
|
||||
* When 2 items are connected (a track to a pad, or a track to an other track),
|
||||
* they are grouped in a cluster.
|
||||
* The .m_Subnet member is the cluster identifier (subnet id)
|
||||
* For a given net, if all tracks are created, there is only one cluster.
|
||||
* but if not all tracks are created, there are more than one cluster,
|
||||
* and some ratsnests will be left active.
|
||||
* A ratsnest is active when it "connect" 2 items having different subnet id
|
||||
*/
|
||||
void CONNECTIONS::Propagate_SubNets()
|
||||
{
|
||||
int sub_netcode = 1;
|
||||
|
||||
TRACK* curr_track = (TRACK*)m_firstTrack;
|
||||
if( curr_track )
|
||||
curr_track->SetSubNet( sub_netcode );
|
||||
|
||||
// Examine connections between tracks and pads
|
||||
for( ; curr_track != NULL; curr_track = curr_track->Next() )
|
||||
{
|
||||
// First: handling connections to pads
|
||||
for( unsigned ii = 0; ii < curr_track->m_PadsConnected.size(); ii++ )
|
||||
{
|
||||
D_PAD * pad = curr_track->m_PadsConnected[ii];
|
||||
|
||||
if( curr_track->GetSubNet() ) // the track segment is already a cluster member
|
||||
{
|
||||
if( pad->GetSubNet() > 0 )
|
||||
{
|
||||
// The pad is already a cluster member, so we can merge the 2 clusters
|
||||
Merge_SubNets( pad->GetSubNet(), curr_track->GetSubNet() );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The pad is not yet attached to a cluster , so we can add this pad to
|
||||
* the cluster */
|
||||
pad->SetSubNet( curr_track->GetSubNet() );
|
||||
}
|
||||
}
|
||||
else // the track segment is not attached to a cluster
|
||||
{
|
||||
if( pad->GetSubNet() > 0 )
|
||||
{
|
||||
// it is connected to a pad in a cluster, merge this track
|
||||
curr_track->SetSubNet( pad->GetSubNet() );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* it is connected to a pad not in a cluster, so we must create a new
|
||||
* cluster (only with the 2 items: the track and the pad) */
|
||||
sub_netcode++;
|
||||
curr_track->SetSubNet( sub_netcode );
|
||||
pad->SetSubNet( curr_track->GetSubNet() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test connections between segments
|
||||
for( unsigned ii = 0; ii < curr_track->m_TracksConnected.size(); ii++ )
|
||||
{
|
||||
BOARD_CONNECTED_ITEM* track = curr_track->m_TracksConnected[ii];
|
||||
|
||||
if( curr_track->GetSubNet() ) // The current track is already a cluster member
|
||||
{
|
||||
// The other track is already a cluster member, so we can merge the 2 clusters
|
||||
if( track->GetSubNet() )
|
||||
{
|
||||
Merge_SubNets( track->GetSubNet(), curr_track->GetSubNet() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// The other track is not yet attached to a cluster , so we can add this
|
||||
// other track to the cluster
|
||||
track->SetSubNet( curr_track->GetSubNet() );
|
||||
}
|
||||
}
|
||||
else // the current track segment is not yet attached to a cluster
|
||||
{
|
||||
if( track->GetSubNet() )
|
||||
{
|
||||
// The other track is already a cluster member, so we can add
|
||||
// the current segment to the cluster
|
||||
curr_track->SetSubNet( track->GetSubNet() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// it is connected to an other segment not in a cluster, so we must
|
||||
// create a new cluster (only with the 2 track segments)
|
||||
sub_netcode++;
|
||||
curr_track->SetSubNet( sub_netcode );
|
||||
track->SetSubNet( curr_track->GetSubNet() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( curr_track == m_lastTrack )
|
||||
break;
|
||||
}
|
||||
|
||||
// Examine connections between intersecting pads, and propagate
|
||||
// sub_netcodes to intersecting pads
|
||||
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
||||
{
|
||||
D_PAD* curr_pad = m_sortedPads[ii];
|
||||
|
||||
for( unsigned jj = 0; jj < curr_pad->m_PadsConnected.size(); jj++ )
|
||||
{
|
||||
D_PAD* pad = curr_pad->m_PadsConnected[jj];
|
||||
|
||||
if( curr_pad->GetSubNet() ) // the current pad is already attached to a cluster
|
||||
{
|
||||
if( pad->GetSubNet() > 0 )
|
||||
{
|
||||
// The pad is already a cluster member, so we can merge the 2 clusters
|
||||
// Store the initial subnets, which will be modified by Merge_PadsSubNets
|
||||
int subnet1 = pad->GetSubNet();
|
||||
int subnet2 = curr_pad->GetSubNet();
|
||||
|
||||
// merge subnets of pads only, even those not connected by tracks
|
||||
Merge_PadsSubNets( subnet1, subnet2 );
|
||||
|
||||
// merge subnets of tracks (and pads, which are already merged)
|
||||
Merge_SubNets( subnet1, subnet2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// The pad is not yet attached to a cluster,
|
||||
// so we can add this pad to the cluster
|
||||
pad->SetSubNet( curr_pad->GetSubNet() );
|
||||
}
|
||||
}
|
||||
else // the current pad is not attached to a cluster
|
||||
{
|
||||
if( pad->GetSubNet() > 0 )
|
||||
{
|
||||
// the connected pad is in a cluster,
|
||||
// so we can add the current pad to the cluster
|
||||
curr_pad->SetSubNet( pad->GetSubNet() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// the connected pad is not in a cluster,
|
||||
// so we must create a new cluster, with the 2 pads.
|
||||
sub_netcode++;
|
||||
curr_pad->SetSubNet( sub_netcode );
|
||||
pad->SetSubNet( curr_pad->GetSubNet() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test all connections of the board,
|
||||
* and update subnet variable of pads and tracks
|
||||
* TestForActiveLinksInRatsnest must be called after this function
|
||||
* to update active/inactive ratsnest items status
|
||||
*/
|
||||
void PCB_BASE_FRAME::TestConnections()
|
||||
{
|
||||
// Clear the cluster identifier for all pads
|
||||
for( unsigned i = 0; i< m_Pcb->GetPadCount(); ++i )
|
||||
{
|
||||
D_PAD* pad = m_Pcb->GetPad(i);
|
||||
|
||||
pad->SetZoneSubNet( 0 );
|
||||
pad->SetSubNet( 0 );
|
||||
}
|
||||
|
||||
m_Pcb->Test_Connections_To_Copper_Areas();
|
||||
|
||||
// Test existing connections net by net
|
||||
// note some nets can have no tracks, and pads intersecting
|
||||
// so Build_CurrNet_SubNets_Connections must be called for each net
|
||||
CONNECTIONS connections( m_Pcb );
|
||||
|
||||
int last_net_tested = 0;
|
||||
int current_net_code = 0;
|
||||
|
||||
for( TRACK* track = m_Pcb->m_Track; track; )
|
||||
{
|
||||
// At this point, track is the first track of a given net
|
||||
current_net_code = track->GetNetCode();
|
||||
|
||||
// Get last track of the current net
|
||||
TRACK* lastTrack = track->GetEndNetCode( current_net_code );
|
||||
|
||||
if( current_net_code > 0 ) // do not spend time if net code = 0 ( dummy net )
|
||||
{
|
||||
// Test all previous nets having no tracks
|
||||
for( int net = last_net_tested+1; net < current_net_code; net++ )
|
||||
connections.Build_CurrNet_SubNets_Connections( NULL, NULL, net );
|
||||
|
||||
connections.Build_CurrNet_SubNets_Connections( track, lastTrack, current_net_code );
|
||||
last_net_tested = current_net_code;
|
||||
}
|
||||
|
||||
track = lastTrack->Next(); // this is now the first track of the next net
|
||||
}
|
||||
|
||||
// Test last nets without tracks, if any
|
||||
int netsCount = m_Pcb->GetNetCount();
|
||||
for( int net = last_net_tested+1; net < netsCount; net++ )
|
||||
connections.Build_CurrNet_SubNets_Connections( NULL, NULL, net );
|
||||
|
||||
Merge_SubNets_Connected_By_CopperAreas( m_Pcb );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void PCB_BASE_FRAME::TestNetConnection( wxDC* aDC, int aNetCode )
|
||||
{
|
||||
#if 0
|
||||
// Skip dummy net -1, and "not connected" net 0 (grouping all not connected pads)
|
||||
if( aNetCode <= 0 )
|
||||
return;
|
||||
|
@ -855,98 +162,5 @@ void PCB_BASE_FRAME::TestNetConnection( wxDC* aDC, int aNetCode )
|
|||
SetStatusText( msg );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void PCB_BASE_FRAME::ComputeLegacyConnections()
|
||||
{
|
||||
|
||||
// Build the net info list
|
||||
GetBoard()->BuildListOfNets();
|
||||
|
||||
// Reset variables and flags used in computation
|
||||
for( TRACK* t = m_Pcb->m_Track; t; t = t->Next() )
|
||||
{
|
||||
t->m_TracksConnected.clear();
|
||||
t->m_PadsConnected.clear();
|
||||
t->start = NULL;
|
||||
t->end = NULL;
|
||||
t->SetState( BUSY | IN_EDIT | BEGIN_ONPAD | END_ONPAD, false );
|
||||
t->SetZoneSubNet( 0 );
|
||||
}
|
||||
|
||||
// If no pad, reset pointers and netcode, and do nothing else
|
||||
if( m_Pcb->GetPadCount() == 0 )
|
||||
return;
|
||||
|
||||
CONNECTIONS connections( m_Pcb );
|
||||
connections.BuildPadsList();
|
||||
connections.BuildTracksCandidatesList(m_Pcb->m_Track);
|
||||
|
||||
// First pass: build connections between track segments and pads.
|
||||
connections.SearchTracksConnectedToPads();
|
||||
|
||||
for( TRACK* t = m_Pcb->m_Track; t; t = t->Next() )
|
||||
{
|
||||
connections.SearchConnectedTracks( t );
|
||||
connections.GetConnectedTracks( t );
|
||||
}
|
||||
|
||||
// Sort the track list by net codes:
|
||||
RebuildTrackChain( m_Pcb );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Function SortTracksByNetCode used in RebuildTrackChain()
|
||||
* to sort track segments by net code.
|
||||
*/
|
||||
static bool SortTracksByNetCode( const TRACK* const & ref, const TRACK* const & compare )
|
||||
{
|
||||
// For items having the same Net, keep the order in list
|
||||
if( ref->GetNetCode() == compare->GetNetCode())
|
||||
return ref->m_Param < compare->m_Param;
|
||||
|
||||
return ref->GetNetCode() < compare->GetNetCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function RebuildTrackChain
|
||||
* rebuilds the track segment linked list in order to have a chain
|
||||
* sorted by increasing netcodes.
|
||||
* We try to keep order of track segments in list, when possible
|
||||
* @param pcb = board to rebuild
|
||||
*/
|
||||
static void RebuildTrackChain( BOARD* pcb )
|
||||
{
|
||||
if( pcb->m_Track == NULL )
|
||||
return;
|
||||
|
||||
int item_count = pcb->m_Track.GetCount();
|
||||
|
||||
std::vector<TRACK*> trackList;
|
||||
trackList.reserve( item_count );
|
||||
|
||||
// Put track list in a temporary list to sort tracks by netcode
|
||||
// We try to keep the initial order of track segments in list, when possible
|
||||
// so we use m_Param (a member variable used for temporary storage)
|
||||
// to temporary keep trace of the order of segments
|
||||
// The sort function uses this variable to sort items that
|
||||
// have the same net code.
|
||||
// Without this, during sorting, the initial order is sometimes lost
|
||||
// by the sort algorithm
|
||||
for( int ii = 0; ii < item_count; ++ii )
|
||||
{
|
||||
pcb->m_Track->m_Param = ii;
|
||||
trackList.push_back( pcb->m_Track.PopFront() );
|
||||
}
|
||||
|
||||
// the list is empty now
|
||||
wxASSERT( pcb->m_Track == NULL && pcb->m_Track.GetCount()==0 );
|
||||
|
||||
sort( trackList.begin(), trackList.end(), SortTracksByNetCode );
|
||||
|
||||
// add them back to the list
|
||||
for( int i = 0; i < item_count; ++i )
|
||||
pcb->m_Track.PushBack( trackList[i] );
|
||||
#endif
|
||||
}
|
||||
|
|
225
pcbnew/connect.h
225
pcbnew/connect.h
|
@ -34,230 +34,5 @@
|
|||
#include <class_board.h>
|
||||
|
||||
|
||||
// Helper classes to handle connection points (i.e. candidates) for tracks
|
||||
|
||||
/* class CONNECTED_POINT describes a coordinate having a track or pad parent.
|
||||
* when a pad is the parent, the coordinate is (obviously) the connection point
|
||||
* when a track is the parent, the coordinate is the staring point
|
||||
* or the ending point.
|
||||
* therefore when building a list of CONNECTED_POINT, a pad or via generates one item,
|
||||
* and a track generates 2 items.
|
||||
*/
|
||||
class CONNECTED_POINT
|
||||
{
|
||||
private:
|
||||
BOARD_CONNECTED_ITEM * m_item; // a link to the parent item (track, via or pad)
|
||||
wxPoint m_point; // coordinates of this connected point
|
||||
|
||||
public:
|
||||
// ctor to build a CONNECTED_POINT instance, when the parent is a track or via
|
||||
CONNECTED_POINT( TRACK * aTrack, const wxPoint & aPoint)
|
||||
{
|
||||
m_item = aTrack;
|
||||
m_point = aPoint;
|
||||
}
|
||||
|
||||
// ctor to build a CONNECTED_POINT instance, when the parent is a pad
|
||||
CONNECTED_POINT( D_PAD * aPad, const wxPoint & aPoint)
|
||||
{
|
||||
m_item = aPad;
|
||||
m_point = aPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function GetTrack
|
||||
* @return the parent track or via of this connected point,
|
||||
* or null if the parent is a pad
|
||||
*/
|
||||
TRACK* GetTrack() const
|
||||
{
|
||||
return m_item->Type() != PCB_PAD_T ? (TRACK*) m_item : NULL ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function GetPad
|
||||
* @return the parent pad of this connected point,
|
||||
* or null if the parent is a track or via
|
||||
*/
|
||||
D_PAD * GetPad() const
|
||||
{
|
||||
return m_item->Type() == PCB_PAD_T ? (D_PAD*) m_item : NULL;
|
||||
}
|
||||
|
||||
const wxPoint & GetPoint() const { return m_point; }
|
||||
};
|
||||
|
||||
// A helper class to handle connections calculations:
|
||||
class CONNECTIONS
|
||||
{
|
||||
private:
|
||||
std::vector <TRACK*> m_connected; // List of connected tracks/vias
|
||||
// to a given track or via
|
||||
std::vector <CONNECTED_POINT> m_candidates; // List of points to test
|
||||
// (end points of tracks or vias location )
|
||||
BOARD * m_brd; // the master board.
|
||||
const TRACK * m_firstTrack; // The first track used to build m_Candidates
|
||||
const TRACK * m_lastTrack; // The last track used to build m_Candidates
|
||||
std::vector<D_PAD*> m_sortedPads; // list of sorted pads by X (then Y) coordinate
|
||||
|
||||
public:
|
||||
CONNECTIONS( BOARD * aBrd );
|
||||
~CONNECTIONS() {};
|
||||
|
||||
/**
|
||||
* Function BuildPadsList
|
||||
* Fills m_sortedPads with all pads that be connected to tracks
|
||||
* pads are sorted by X then Y coordinates to allow fast binary search in list
|
||||
* @param aNetcode = net code to use to filter pads
|
||||
* if aNetcode < 0, all pads will be put in list (default)
|
||||
*/
|
||||
void BuildPadsList( int aNetcode = -1 );
|
||||
|
||||
/**
|
||||
* Function GetPadsList
|
||||
* @return the pads list used in connections calculations
|
||||
*/
|
||||
std::vector<D_PAD*>& GetPadsList() { return m_sortedPads; }
|
||||
|
||||
/**
|
||||
* Function Build_CurrNet_SubNets_Connections
|
||||
* should be called after a track change (delete or add a track):
|
||||
* Connections to pads and to tracks are recalculated
|
||||
* If a track is deleted, the other pointers to pads do not change.
|
||||
* When a new track is added in track list, its pointers to pads are already initialized
|
||||
* Builds the subnets inside a net (tracks from aFirstTrack to aFirstTrack).
|
||||
* subnets are clusters of pads and tracks that are connected together.
|
||||
* When all tracks are created relative to the net, there is only a cluster
|
||||
* when not tracks there are a cluster per pad
|
||||
* @param aFirstTrack = first track of the given net
|
||||
* @param aLastTrack = last track of the given net
|
||||
* @param aNetcode = the netcode of the given net
|
||||
*/
|
||||
void Build_CurrNet_SubNets_Connections( TRACK* aFirstTrack, TRACK* aLastTrack, int aNetcode );
|
||||
|
||||
/**
|
||||
* Function BuildTracksCandidatesList
|
||||
* Fills m_Candidates with all connecting points (track ends or via location)
|
||||
* with tracks from aBegin to aEnd.
|
||||
* @param aBegin = first track to store in list (should not be NULL)
|
||||
* @param aEnd = last track to store in list
|
||||
* if aEnd == NULL, uses all tracks from aBegin
|
||||
*/
|
||||
void BuildTracksCandidatesList( TRACK * aBegin, TRACK * aEnd = NULL);
|
||||
|
||||
/**
|
||||
* Function BuildPadsCandidatesList
|
||||
* Populates m_candidates with all pads connecting points (pads position)
|
||||
* m_sortedPads is expected to be populated by the pad candidates list
|
||||
*/
|
||||
void BuildPadsCandidatesList();
|
||||
|
||||
/**
|
||||
* function SearchConnectedTracks
|
||||
* Populates .m_connected with tracks/vias connected to aTrack
|
||||
* m_candidates is expected to be populated by the track candidates ends list
|
||||
* @param aTrack = track or via to use as reference
|
||||
*/
|
||||
int SearchConnectedTracks( const TRACK * aTrack );
|
||||
|
||||
/**
|
||||
* Function GetConnectedTracks
|
||||
* Copy m_Connected that contains the list of tracks connected
|
||||
* calculated by SearchConnectedTracks
|
||||
* in aTrack->m_TracksConnected
|
||||
* @param aTrack = track or via to fill with connected tracks
|
||||
*/
|
||||
void GetConnectedTracks(TRACK * aTrack)
|
||||
{
|
||||
aTrack->m_TracksConnected = m_connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* function SearchConnectionsPadsToIntersectingPads
|
||||
* Explores the list of pads and adds to m_PadsConnected member
|
||||
* of each pad pads connected to
|
||||
* Here, connections are due to intersecting pads, not tracks
|
||||
* m_sortedPads must be initialized
|
||||
*/
|
||||
void SearchConnectionsPadsToIntersectingPads();
|
||||
|
||||
/**
|
||||
* function SearchTracksConnectedToPads
|
||||
* Explores the list of pads.
|
||||
* if( add_to_padlist )
|
||||
* adds to m_PadsConnected member of each track the pad(s) connected to
|
||||
* if add_to_tracklist
|
||||
* adds to m_TracksConnected member of each pad the track(s) connected to
|
||||
* D_PAD::m_TracksConnected is cleared before adding items
|
||||
* TRACK::m_PadsConnected is not cleared
|
||||
* @param add_to_padlist = true to fill m_PadsConnected member of each track
|
||||
* @param add_to_tracklist = true to fill m_TracksConnected member of each pad
|
||||
*/
|
||||
void SearchTracksConnectedToPads( bool add_to_padlist = true, bool add_to_tracklist = true);
|
||||
|
||||
/**
|
||||
* function CollectItemsNearTo
|
||||
* Used by SearchTracksConnectedToPads
|
||||
* Fills aList with pads near to aPosition
|
||||
* near means aPosition to pad position <= aDistMax
|
||||
* @param aList = list to fill
|
||||
* @param aPosition = aPosition to use as reference
|
||||
* @param aDistMax = dist max from aPosition to a candidate to select it
|
||||
*/
|
||||
void CollectItemsNearTo( std::vector<CONNECTED_POINT*>& aList,
|
||||
const wxPoint& aPosition, int aDistMax );
|
||||
|
||||
/**
|
||||
* Function Propagate_SubNets
|
||||
* Test a list of tracks, to create or propagate a sub netcode to pads and
|
||||
* segments connected together.
|
||||
* The track list must be sorted by nets, and all segments
|
||||
* from m_firstTrack to m_lastTrack have the same net.
|
||||
* When 2 items are connected (a track to a pad, or a track to an other track),
|
||||
* they are grouped in a cluster.
|
||||
* For pads, this is the .m_physical_connexion member which is a cluster identifier
|
||||
* For tracks, this is the .m_Subnet member which is a cluster identifier
|
||||
* For a given net, if all tracks are created, there is only one cluster.
|
||||
* but if not all tracks are created, there are more than one cluster,
|
||||
* and some ratsnests will be left active.
|
||||
*/
|
||||
void Propagate_SubNets();
|
||||
|
||||
private:
|
||||
/**
|
||||
* function searchEntryPointInCandidatesList
|
||||
* Search an item in m_Connected connected to aPoint
|
||||
* note m_Connected containts usually more than one candidate
|
||||
* and searchEntryPointInCandidatesList returns an index to one of these candidates
|
||||
* Others are neightbor of the indexed item.
|
||||
* @param aPoint is the reference coordinates
|
||||
* @return the index of item found or -1 if no candidate
|
||||
*/
|
||||
int searchEntryPointInCandidatesList( const wxPoint & aPoint);
|
||||
|
||||
/**
|
||||
* Function Merge_SubNets
|
||||
* Change a subnet old value to a new value, for tracks and pads which are connected to
|
||||
* tracks from m_firstTrack to m_lastTrack and their connected pads.
|
||||
* and modify the subnet parameter (change the old value to the new value).
|
||||
* After that, 2 cluster (or subnets) are merged into only one.
|
||||
* Note: the resulting sub net value is the smallest between aOldSubNet and aNewSubNet
|
||||
* @return modification count
|
||||
* @param aOldSubNet = subnet value to modify
|
||||
* @param aNewSubNet = new subnet value for each item which have old_val as subnet value
|
||||
*/
|
||||
int Merge_SubNets( int aOldSubNet, int aNewSubNet );
|
||||
|
||||
/**
|
||||
* Function Merge_PadsSubNets
|
||||
* Change a subnet value to a new value, in m_sortedPads pad list
|
||||
* After that, 2 cluster (or subnets) are merged into only one.
|
||||
* Note: the resulting subnet value is the smallest between aOldSubNet et aNewSubNet
|
||||
* @return modification count
|
||||
* @param aOldSubNet = subnet value to modify
|
||||
* @param aNewSubNet = new subnet value for each item which have old_val as subnet value
|
||||
*/
|
||||
int Merge_PadsSubNets( int aOldSubNet, int aNewSubNet );
|
||||
};
|
||||
|
||||
#endif // ifndef CONNECT_H
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#define PROFILE
|
||||
|
||||
#ifdef PROFILE
|
||||
#include <profile.h>
|
||||
#endif
|
||||
|
@ -127,7 +125,6 @@ void CONNECTIVITY_DATA::updateRatsnest()
|
|||
#ifdef PROFILE
|
||||
rnUpdate.Show();
|
||||
#endif /* PROFILE */
|
||||
printf( "Dirty: %d\n", nDirty );
|
||||
}
|
||||
|
||||
|
||||
|
@ -165,6 +162,7 @@ void CONNECTIVITY_DATA::RecalculateRatsnest()
|
|||
|
||||
|
||||
|
||||
|
||||
for( auto c : clusters )
|
||||
{
|
||||
int net = c->OriginNet();
|
||||
|
@ -181,7 +179,7 @@ void CONNECTIVITY_DATA::RecalculateRatsnest()
|
|||
}
|
||||
|
||||
|
||||
void CONNECTIVITY_DATA::blockRatsnestItems( const std::vector<BOARD_ITEM*>& aItems )
|
||||
void CONNECTIVITY_DATA::BlockRatsnestItems( const std::vector<BOARD_ITEM*>& aItems )
|
||||
{
|
||||
std::vector<BOARD_CONNECTED_ITEM*> citems;
|
||||
|
||||
|
@ -231,7 +229,7 @@ void CONNECTIVITY_DATA::ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>&
|
|||
|
||||
m_dynamicRatsnest.clear();
|
||||
|
||||
blockRatsnestItems( aItems );
|
||||
BlockRatsnestItems( aItems );
|
||||
|
||||
for( unsigned int nc = 1; nc < m_dynamicConnectivity->m_nets.size(); nc++ )
|
||||
{
|
||||
|
@ -333,45 +331,182 @@ const std::list<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetConnectedItems(
|
|||
const KICAD_T aTypes[] ) const
|
||||
{
|
||||
std::list<BOARD_CONNECTED_ITEM*> rv;
|
||||
const auto clusters = m_connAlgo->SearchClusters( CN_CONNECTIVITY_ALGO::CSM_CONNECTIVITY_CHECK, aTypes, aItem->GetNetCode() );
|
||||
const auto clusters = m_connAlgo->SearchClusters( CN_CONNECTIVITY_ALGO::CSM_CONNECTIVITY_CHECK,
|
||||
aTypes, aItem->GetNetCode() );
|
||||
|
||||
for ( auto cl : clusters )
|
||||
if ( cl->Contains (aItem ) )
|
||||
for( auto cl : clusters )
|
||||
if( cl->Contains( aItem ) )
|
||||
{
|
||||
for ( const auto item : *cl )
|
||||
for( const auto item : *cl )
|
||||
rv.push_back( item->Parent() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
const std::list<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetNetItems(
|
||||
int aNetCode,
|
||||
const std::list<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetNetItems( int aNetCode,
|
||||
const KICAD_T aTypes[] ) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool CONNECTIVITY_DATA::CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport )
|
||||
{
|
||||
RecalculateRatsnest();
|
||||
|
||||
for ( auto net : m_nets )
|
||||
for( auto net : m_nets )
|
||||
{
|
||||
if ( net )
|
||||
if( net )
|
||||
{
|
||||
for ( const auto& edge: net->GetEdges() )
|
||||
for( const auto& edge : net->GetEdges() )
|
||||
{
|
||||
CN_DISJOINT_NET_ENTRY ent;
|
||||
ent.net = edge.GetSourceNode()->Parent()->GetNetCode();
|
||||
ent.a = edge.GetSourceNode()->Parent();
|
||||
ent.b = edge.GetTargetNode()->Parent();
|
||||
ent.a = edge.GetSourceNode()->Parent();
|
||||
ent.b = edge.GetTargetNode()->Parent();
|
||||
ent.anchorA = edge.GetSourceNode()->Pos();
|
||||
ent.anchorB = edge.GetTargetNode()->Pos();
|
||||
aReport.push_back( ent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return aReport.empty();
|
||||
}
|
||||
|
||||
|
||||
const std::vector<TRACK*> CONNECTIVITY_DATA::GetConnectedTracks( const BOARD_CONNECTED_ITEM* aItem )
|
||||
const
|
||||
{
|
||||
auto& entry = m_connAlgo->ItemEntry( aItem );
|
||||
|
||||
std::set<TRACK*> tracks;
|
||||
std::vector<TRACK*> rv;
|
||||
|
||||
for( auto citem : entry.GetItems() )
|
||||
{
|
||||
for( auto connected : citem->ConnectedItems() )
|
||||
{
|
||||
if( connected->Parent()->Type() == PCB_TRACE_T )
|
||||
tracks.insert( static_cast<TRACK*> ( connected->Parent() ) );
|
||||
}
|
||||
}
|
||||
|
||||
std::copy( tracks.begin(), tracks.end(), std::back_inserter( rv ) );
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<D_PAD*> CONNECTIVITY_DATA::GetConnectedPads( const BOARD_CONNECTED_ITEM* aItem )
|
||||
const
|
||||
{
|
||||
auto& entry = m_connAlgo->ItemEntry( aItem );
|
||||
|
||||
std::set<D_PAD*> pads;
|
||||
std::vector<D_PAD*> rv;
|
||||
|
||||
for( auto citem : entry.GetItems() )
|
||||
{
|
||||
for( auto connected : citem->ConnectedItems() )
|
||||
{
|
||||
if( connected->Parent()->Type() == PCB_PAD_T )
|
||||
pads.insert( static_cast<D_PAD*> ( connected->Parent() ) );
|
||||
}
|
||||
}
|
||||
|
||||
std::copy( pads.begin(), pads.end(), std::back_inserter( rv ) );
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
unsigned int CONNECTIVITY_DATA::GetLinksCount() const
|
||||
{
|
||||
return 0;
|
||||
assert( false );
|
||||
}
|
||||
|
||||
|
||||
unsigned int CONNECTIVITY_DATA::GetConnectedCount() const
|
||||
{
|
||||
return 0;
|
||||
assert( false );
|
||||
}
|
||||
|
||||
|
||||
unsigned int CONNECTIVITY_DATA::GetNodeCount( int aNet ) const
|
||||
{
|
||||
return 0;
|
||||
assert( false );
|
||||
}
|
||||
|
||||
|
||||
unsigned int CONNECTIVITY_DATA::GetPadCount( int aNet ) const
|
||||
{
|
||||
return 0;
|
||||
assert( false );
|
||||
}
|
||||
|
||||
|
||||
const std::vector<VECTOR2I> CONNECTIVITY_DATA::NearestUnconnectedTargets(
|
||||
const BOARD_CONNECTED_ITEM* aRef,
|
||||
const VECTOR2I& aPos,
|
||||
int aNet )
|
||||
{
|
||||
CN_CLUSTER_PTR refCluster;
|
||||
int refNet = -1;
|
||||
|
||||
if( aRef )
|
||||
refNet = aRef->GetNetCode();
|
||||
|
||||
if( aNet >= 0 )
|
||||
refNet = aNet;
|
||||
|
||||
if( aRef )
|
||||
{
|
||||
for( auto cl : m_connAlgo->GetClusters() )
|
||||
{
|
||||
if( cl->Contains( aRef ) )
|
||||
{
|
||||
refCluster = cl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set <VECTOR2I> anchors;
|
||||
|
||||
for( auto cl : m_connAlgo->GetClusters() )
|
||||
{
|
||||
if( cl != refCluster )
|
||||
{
|
||||
for( auto item : *cl )
|
||||
{
|
||||
if( item->Parent()->GetNetCode() == refNet
|
||||
&& item->Parent()->Type() != PCB_ZONE_AREA_T )
|
||||
for( auto anchor : item->Anchors() )
|
||||
{
|
||||
anchors.insert( anchor->Pos() );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<VECTOR2I> rv;
|
||||
|
||||
std::copy( anchors.begin(), anchors.end(), std::back_inserter( rv ) );
|
||||
std::sort( rv.begin(), rv.end(), [aPos] ( const VECTOR2I& a, const VECTOR2I& b )
|
||||
{
|
||||
auto da = (a - aPos).EuclideanNorm();
|
||||
auto db = (b - aPos).EuclideanNorm();
|
||||
|
||||
return da < db;
|
||||
} );
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ class BOARD_ITEM;
|
|||
class ZONE_CONTAINER;
|
||||
class RN_DATA;
|
||||
class RN_NET;
|
||||
class TRACK;
|
||||
class D_PAD;
|
||||
|
||||
struct CN_DISJOINT_NET_ENTRY
|
||||
{
|
||||
|
@ -130,7 +132,7 @@ public:
|
|||
*/
|
||||
void PropagateNets();
|
||||
|
||||
bool CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport );
|
||||
bool CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport );
|
||||
|
||||
/**
|
||||
* Function FindIsolatedCopperIslands()
|
||||
|
@ -152,6 +154,18 @@ public:
|
|||
*/
|
||||
unsigned int GetUnconnectedCount() const;
|
||||
|
||||
unsigned int GetLinksCount() const;
|
||||
|
||||
unsigned int GetConnectedCount() const;
|
||||
|
||||
|
||||
unsigned int GetNodeCount( int aNet = -1 ) const;
|
||||
|
||||
unsigned int GetPadCount( int aNet = -1 ) const;
|
||||
|
||||
const std::vector<TRACK*> GetConnectedTracks( const BOARD_CONNECTED_ITEM* aItem ) const;
|
||||
|
||||
const std::vector<D_PAD*> GetConnectedPads( const BOARD_CONNECTED_ITEM* aItem ) const;
|
||||
|
||||
/**
|
||||
* Function ClearDynamicRatsnest()
|
||||
|
@ -188,11 +202,16 @@ public:
|
|||
const std::list<BOARD_CONNECTED_ITEM*> GetNetItems( int aNetCode,
|
||||
const KICAD_T aTypes[] ) const;
|
||||
|
||||
const std::vector<VECTOR2I> NearestUnconnectedTargets( const BOARD_CONNECTED_ITEM* aRef,
|
||||
const VECTOR2I& aPos,
|
||||
int aMaxCount = -1 );
|
||||
|
||||
void BlockRatsnestItems( const std::vector<BOARD_ITEM*>& aItems );
|
||||
|
||||
private:
|
||||
|
||||
void updateRatsnest();
|
||||
void addRatsnestCluster( std::shared_ptr<CN_CLUSTER> aCluster );
|
||||
void blockRatsnestItems( const std::vector<BOARD_ITEM*>& aItems );
|
||||
|
||||
std::unique_ptr<CONNECTIVITY_DATA> m_dynamicConnectivity;
|
||||
std::shared_ptr<CN_CONNECTIVITY_ALGO> m_connAlgo;
|
||||
|
|
|
@ -160,10 +160,31 @@ public:
|
|||
void SetTargetNode( const CN_ANCHOR_PTR& aNode ) { m_target = aNode; }
|
||||
void SetWeight( unsigned int weight ) { m_weight = weight; }
|
||||
|
||||
void SetVisible( bool aVisible )
|
||||
{
|
||||
m_visible = aVisible;
|
||||
}
|
||||
|
||||
bool IsVisible() const
|
||||
{
|
||||
return m_visible;
|
||||
}
|
||||
|
||||
const VECTOR2I GetSourcePos() const
|
||||
{
|
||||
return m_source->Pos();
|
||||
}
|
||||
|
||||
const VECTOR2I GetTargetPos() const
|
||||
{
|
||||
return m_target->Pos();
|
||||
}
|
||||
|
||||
private:
|
||||
CN_ANCHOR_PTR m_source;
|
||||
CN_ANCHOR_PTR m_target;
|
||||
unsigned int m_weight = 0;
|
||||
bool m_visible = true;
|
||||
};
|
||||
|
||||
class CN_CLUSTER
|
||||
|
|
|
@ -238,10 +238,6 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete()
|
|||
if( gen_rastnest )
|
||||
m_Parent->Compile_Ratsnest( NULL, true );
|
||||
|
||||
// There is a chance that some of tracks have changed their nets, so rebuild ratsnest from scratch
|
||||
if( m_Parent->IsGalCanvasActive() )
|
||||
pcb->GetRatsnest()->ProcessBoard();
|
||||
else
|
||||
m_Parent->GetCanvas()->Refresh();
|
||||
|
||||
// There is a chance that some of tracks have changed their nets, so rebuild ratsnest from scratch
|
||||
m_Parent->GetCanvas()->Refresh();
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include <view/view.h>
|
||||
#include <view/view_controls.h>
|
||||
#include <pcb_painter.h>
|
||||
#include <connectivity.h>
|
||||
|
||||
#define COL_NETNAME 0
|
||||
#define COL_NETINFO 1
|
||||
|
@ -141,7 +142,9 @@ void DIALOG_SELECT_NET_FROM_LIST::buildNetsList()
|
|||
continue;
|
||||
}
|
||||
|
||||
if( !m_cbShowZeroPad->IsChecked() && net->m_PadInNetList.size() == 0 )
|
||||
unsigned nPads = m_brd->GetConnectivity()->GetPadCount( netcode );
|
||||
|
||||
if( !m_cbShowZeroPad->IsChecked() && nPads == 0 )
|
||||
continue;
|
||||
|
||||
if( m_netsListGrid->GetNumberRows() <= row_idx )
|
||||
|
@ -154,7 +157,7 @@ void DIALOG_SELECT_NET_FROM_LIST::buildNetsList()
|
|||
|
||||
if( netcode )
|
||||
{
|
||||
txt.Printf( wxT( "%u" ), (unsigned) net->m_PadInNetList.size() );
|
||||
txt.Printf( wxT( "%u" ), nPads );
|
||||
m_netsListGrid->SetCellValue( row_idx, COL_NETINFO, txt );
|
||||
}
|
||||
else // For the net 0 (unconnected pads), the pad count is not known
|
||||
|
|
|
@ -150,7 +150,7 @@ private:
|
|||
/** Fills m_DragList with of track segments connected to pads in aConnections
|
||||
* For each selected track segment the EDIT flag is set
|
||||
*/
|
||||
void fillList( CONNECTIONS& aConnections );
|
||||
void fillList( std::vector<D_PAD*>& aList );
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -41,8 +41,7 @@
|
|||
|
||||
#include <class_module.h>
|
||||
#include <class_board.h>
|
||||
#include <connect.h>
|
||||
|
||||
#include <connectivity.h>
|
||||
|
||||
/* a list of DRAG_SEGM_PICKER items used to move or drag tracks */
|
||||
std::vector<DRAG_SEGM_PICKER> g_DragSegmentList;
|
||||
|
@ -61,7 +60,6 @@ DRAG_SEGM_PICKER::DRAG_SEGM_PICKER( TRACK* aTrack )
|
|||
m_Flipped = false;
|
||||
}
|
||||
|
||||
|
||||
void DRAG_SEGM_PICKER::SetAuxParameters()
|
||||
{
|
||||
MODULE* module = NULL;
|
||||
|
@ -155,16 +153,14 @@ void DRAG_LIST::BuildDragListe( MODULE* aModule )
|
|||
m_Pad = NULL;
|
||||
m_Module = aModule;
|
||||
|
||||
// Build connections info
|
||||
CONNECTIONS connections( m_Brd );
|
||||
std::vector<D_PAD*>&padList = connections.GetPadsList();
|
||||
std::vector<D_PAD*> padList;
|
||||
|
||||
for( D_PAD* pad = aModule->Pads(); pad; pad = pad->Next() )
|
||||
for ( auto pad : aModule->PadsIter() )
|
||||
padList.push_back( pad );
|
||||
|
||||
sort( padList.begin(), padList.end(), sortPadsByXthenYCoord );
|
||||
|
||||
fillList( connections );
|
||||
fillList( padList );
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,11 +170,10 @@ void DRAG_LIST::BuildDragListe( D_PAD* aPad )
|
|||
m_Module = NULL;
|
||||
|
||||
// Build connections info
|
||||
CONNECTIONS connections( m_Brd );
|
||||
std::vector<D_PAD*>&padList = connections.GetPadsList();
|
||||
std::vector<D_PAD*> padList;
|
||||
padList.push_back( aPad );
|
||||
|
||||
fillList( connections );
|
||||
fillList( padList );
|
||||
}
|
||||
|
||||
|
||||
|
@ -188,26 +183,18 @@ bool sort_tracklist( const DRAG_SEGM_PICKER& ref, const DRAG_SEGM_PICKER& tst )
|
|||
return ref.m_Track < tst.m_Track;
|
||||
}
|
||||
|
||||
|
||||
void DRAG_LIST::fillList( CONNECTIONS& aConnections )
|
||||
void DRAG_LIST::fillList( std::vector<D_PAD*>& aList )
|
||||
{
|
||||
aConnections.BuildTracksCandidatesList( m_Brd->m_Track, NULL);
|
||||
|
||||
// Build connections info tracks to pads
|
||||
// Rebuild pads to track info only)
|
||||
aConnections.SearchTracksConnectedToPads( false, true );
|
||||
|
||||
std::vector<D_PAD*>padList = aConnections.GetPadsList();
|
||||
|
||||
printf("FillList!\n");
|
||||
// clear flags and variables of selected tracks
|
||||
for( unsigned ii = 0; ii < padList.size(); ii++ )
|
||||
for( auto pad : aList )
|
||||
{
|
||||
D_PAD * pad = padList[ii];
|
||||
auto connectedTracks = m_Brd->GetConnectivity()->GetConnectedTracks( pad );
|
||||
|
||||
// store track connected to the pad
|
||||
for( unsigned jj = 0; jj < pad->m_TracksConnected.size(); jj++ )
|
||||
for ( auto track : connectedTracks )
|
||||
{
|
||||
TRACK * track = pad->m_TracksConnected[jj];
|
||||
track->start = NULL;
|
||||
track->end = NULL;
|
||||
track->SetState( START_ON_PAD|END_ON_PAD|BUSY, false );
|
||||
|
@ -215,14 +202,13 @@ void DRAG_LIST::fillList( CONNECTIONS& aConnections )
|
|||
}
|
||||
|
||||
// store tracks connected to pads
|
||||
for( unsigned ii = 0; ii < padList.size(); ii++ )
|
||||
for( auto pad : aList )
|
||||
{
|
||||
D_PAD * pad = padList[ii];
|
||||
auto connectedTracks = m_Brd->GetConnectivity()->GetConnectedTracks( pad );
|
||||
|
||||
// store track connected to the pad
|
||||
for( unsigned jj = 0; jj < pad->m_TracksConnected.size(); jj++ )
|
||||
for ( auto track : connectedTracks )
|
||||
{
|
||||
TRACK * track = pad->m_TracksConnected[jj];
|
||||
|
||||
if( pad->HitTest( track->GetStart() ) )
|
||||
{
|
||||
|
|
|
@ -196,19 +196,6 @@ void DRC::RunTests( wxTextCtrl* aMessages )
|
|||
// ( the board can be reloaded )
|
||||
m_pcb = m_pcbEditorFrame->GetBoard();
|
||||
|
||||
// Ensure ratsnest is up to date:
|
||||
if( (m_pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
|
||||
{
|
||||
if( aMessages )
|
||||
{
|
||||
aMessages->AppendText( _( "Compile ratsnest...\n" ) );
|
||||
wxSafeYield();
|
||||
}
|
||||
|
||||
m_pcbEditorFrame->Compile_Ratsnest( NULL, true );
|
||||
//m_pcb->GetRatsnest()->ProcessBoard();
|
||||
}
|
||||
|
||||
// someone should have cleared the two lists before calling this.
|
||||
|
||||
if( !testNetClasses() )
|
||||
|
@ -636,7 +623,7 @@ void DRC::testZones()
|
|||
// perhaps a "dead" net, which happens when all pads in this net were removed
|
||||
// Remark: a netcode < 0 should not happen (this is more a bug somewhere)
|
||||
int pads_in_net = (test_area->GetNetCode() > 0) ?
|
||||
test_area->GetNet()->GetNodesCount() : 1;
|
||||
m_pcb->GetConnectivity()->GetPadCount( test_area->GetNetCode() ) : 1;
|
||||
|
||||
if( ( netcode < 0 ) || pads_in_net == 0 )
|
||||
{
|
||||
|
|
|
@ -663,8 +663,6 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
|||
}
|
||||
|
||||
SetCurItem( NULL ); // CurItem might be deleted by this command, clear the pointer
|
||||
TestConnections();
|
||||
TestForActiveLinksInRatsnest( 0 ); // Recalculate the active ratsnest, i.e. the unconnected links
|
||||
OnModify();
|
||||
SetMsgPanel( GetBoard() );
|
||||
m_canvas->Refresh();
|
||||
|
@ -673,7 +671,6 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
|||
case ID_POPUP_PCB_FILL_ZONE:
|
||||
m_canvas->MoveCursorToCrossHair();
|
||||
Fill_Zone( (ZONE_CONTAINER*) GetCurItem() );
|
||||
TestNetConnection( NULL, ( (ZONE_CONTAINER*) GetCurItem() )->GetNetCode() );
|
||||
SetMsgPanel( GetBoard() );
|
||||
m_canvas->Refresh();
|
||||
break;
|
||||
|
@ -1449,11 +1446,7 @@ void PCB_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent )
|
|||
SetToolID( id, wxCURSOR_PENCIL, _( "Add tracks" ) );
|
||||
else
|
||||
SetToolID( id, wxCURSOR_QUESTION_ARROW, _( "Add tracks" ) );
|
||||
|
||||
if( (GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
|
||||
{
|
||||
Compile_Ratsnest( &dc, true );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
@ -1523,8 +1516,7 @@ void PCB_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent )
|
|||
case ID_PCB_SHOW_1_RATSNEST_BUTT:
|
||||
SetToolID( id, wxCURSOR_HAND, _( "Select rats nest" ) );
|
||||
|
||||
if( ( GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
|
||||
Compile_Ratsnest( &dc, true );
|
||||
Compile_Ratsnest( &dc, true );
|
||||
|
||||
break;
|
||||
|
||||
|
|
|
@ -227,9 +227,9 @@ void PCB_EDIT_FRAME::Show_1_Ratsnest( EDA_ITEM* item, wxDC* DC )
|
|||
if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) )
|
||||
return;
|
||||
|
||||
if( ( GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
|
||||
Compile_Ratsnest( DC, true );
|
||||
Compile_Ratsnest( DC, true );
|
||||
|
||||
#if 0
|
||||
if( item )
|
||||
{
|
||||
if( item->Type() == PCB_PAD_T )
|
||||
|
@ -311,4 +311,5 @@ void PCB_EDIT_FRAME::Show_1_Ratsnest( EDA_ITEM* item, wxDC* DC )
|
|||
for( unsigned ii = 0; ii < GetBoard()->GetRatsnestsCount(); ii++ )
|
||||
GetBoard()->m_FullRatsnest[ii].m_Status &= ~CH_VISIBLE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <class_board.h>
|
||||
#include <class_track.h>
|
||||
#include <class_zone.h>
|
||||
#include <connectivity.h>
|
||||
|
||||
|
||||
static void Abort_Create_Track( EDA_DRAW_PANEL* panel, wxDC* DC );
|
||||
|
@ -158,7 +159,11 @@ TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC )
|
|||
|
||||
DBG( g_CurrentTrackList.VerifyListIntegrity() );
|
||||
|
||||
BuildAirWiresTargetsList( lockPoint, wxPoint( 0, 0 ), true );
|
||||
int net = -1;
|
||||
if (lockPoint)
|
||||
net = lockPoint->GetNetCode();
|
||||
|
||||
BuildAirWiresTargetsList( lockPoint, wxPoint( 0, 0 ), net );
|
||||
|
||||
DBG( g_CurrentTrackList.VerifyListIntegrity() );
|
||||
|
||||
|
@ -183,7 +188,6 @@ TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC )
|
|||
|
||||
if( pad )
|
||||
{
|
||||
g_CurrentTrackSegment->m_PadsConnected.push_back( pad );
|
||||
// Useful to display track length, if the pad has a die length:
|
||||
g_CurrentTrackSegment->SetState( BEGIN_ONPAD, true );
|
||||
g_CurrentTrackSegment->start = pad;
|
||||
|
@ -268,12 +272,6 @@ TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC )
|
|||
|
||||
D_PAD* pad = GetBoard()->GetPad( previousTrack, ENDPOINT_END );
|
||||
|
||||
if( pad )
|
||||
{
|
||||
newTrack->m_PadsConnected.push_back( pad );
|
||||
previousTrack->m_PadsConnected.push_back( pad );
|
||||
}
|
||||
|
||||
newTrack->start = previousTrack->end;
|
||||
|
||||
DBG( g_CurrentTrackList.VerifyListIntegrity(); );
|
||||
|
@ -489,6 +487,7 @@ bool PCB_EDIT_FRAME::End_Route( TRACK* aTrack, wxDC* aDC )
|
|||
ITEM_PICKER picker( track, UR_NEW );
|
||||
s_ItemsListPicker.PushItem( picker );
|
||||
GetBoard()->m_Track.Insert( track, insertBeforeMe );
|
||||
GetBoard()->GetConnectivity()->Add( track );
|
||||
}
|
||||
|
||||
TraceAirWiresToTargets( aDC );
|
||||
|
@ -534,6 +533,8 @@ bool PCB_EDIT_FRAME::End_Route( TRACK* aTrack, wxDC* aDC )
|
|||
m_canvas->SetMouseCapture( NULL, NULL );
|
||||
SetCurItem( NULL );
|
||||
|
||||
GetBoard()->GetConnectivity()->RecalculateRatsnest();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -825,7 +826,7 @@ void ShowNewTrackWhenMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPo
|
|||
displ_opts->m_ShowTrackClearanceMode = showTrackClearanceMode;
|
||||
displ_opts->m_DisplayPcbTrackFill = tmp;
|
||||
|
||||
frame->BuildAirWiresTargetsList( NULL, g_CurrentTrackSegment->GetEnd(), false );
|
||||
frame->BuildAirWiresTargetsList( NULL, g_CurrentTrackSegment->GetEnd(), g_CurrentTrackSegment->GetNetCode() );
|
||||
frame->TraceAirWiresToTargets( aDC );
|
||||
}
|
||||
|
||||
|
|
|
@ -701,8 +701,6 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF
|
|||
backupFileName = create_backup_file( aFileName );
|
||||
}
|
||||
|
||||
GetBoard()->m_Status_Pcb &= ~CONNEXION_OK;
|
||||
|
||||
GetBoard()->SynchronizeNetsAndNetClasses();
|
||||
|
||||
// Select default Netclass before writing file.
|
||||
|
@ -787,7 +785,6 @@ bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName )
|
|||
return false;
|
||||
}
|
||||
|
||||
GetBoard()->m_Status_Pcb &= ~CONNEXION_OK;
|
||||
GetBoard()->SynchronizeNetsAndNetClasses();
|
||||
|
||||
// Select default Netclass before writing file.
|
||||
|
|
|
@ -238,8 +238,6 @@ void PCB_BASE_FRAME::GlobalChange_PadSettings( D_PAD* aPad,
|
|||
{
|
||||
if( pad->GetLayerSet() != aPad->GetLayerSet() )
|
||||
continue;
|
||||
else
|
||||
m_Pcb->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK);
|
||||
}
|
||||
|
||||
// Change characteristics:
|
||||
|
|
|
@ -107,17 +107,3 @@ void PCB_EDIT_FRAME::HighLight( wxDC* DC )
|
|||
|
||||
GetBoard()->DrawHighLight( m_canvas, DC, GetBoard()->GetHighLightNetCode() );
|
||||
}
|
||||
|
||||
void PCB_EDIT_FRAME::HighlightUnconnectedPads( wxDC* DC )
|
||||
{
|
||||
for( unsigned ii = 0; ii < GetBoard()->GetRatsnestsCount(); ii++ )
|
||||
{
|
||||
RATSNEST_ITEM* net = &GetBoard()->m_FullRatsnest[ii];
|
||||
|
||||
if( (net->m_Status & CH_ACTIF) == 0 )
|
||||
continue;
|
||||
|
||||
net->m_PadStart->Draw( m_canvas, DC, GR_OR | GR_HIGHLIGHT );
|
||||
net->m_PadEnd->Draw( m_canvas, DC, GR_OR | GR_HIGHLIGHT );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include <wx/wfstream.h>
|
||||
#include <boost/ptr_container/ptr_map.hpp>
|
||||
#include <memory.h>
|
||||
#include <connectivity.h>
|
||||
|
||||
using namespace PCB_KEYS_T;
|
||||
|
||||
|
@ -63,15 +64,17 @@ static const wxString traceFootprintLibrary( wxT( "KicadFootprintLib" ) );
|
|||
///> Removes empty nets (i.e. with node count equal zero) from net classes
|
||||
void filterNetClass( const BOARD& aBoard, NETCLASS& aNetClass )
|
||||
{
|
||||
auto connectivity = aBoard.GetConnectivity();
|
||||
for( NETCLASS::iterator it = aNetClass.begin(); it != aNetClass.end(); )
|
||||
{
|
||||
NETINFO_ITEM* netinfo = aBoard.FindNet( *it );
|
||||
|
||||
if( netinfo && netinfo->GetNodesCount() <= 0 ) // hopefully there are no nets with negative
|
||||
if( netinfo && connectivity->GetNodeCount( netinfo->GetNet() ) <= 0 ) // hopefully there are no nets with negative
|
||||
aNetClass.Remove( it++ ); // node count, but you never know..
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -531,8 +534,8 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const
|
|||
m_out->Print( 0, "\n" );
|
||||
|
||||
m_out->Print( aNestLevel, "(general\n" );
|
||||
m_out->Print( aNestLevel+1, "(links %d)\n", aBoard->GetRatsnestsCount() );
|
||||
m_out->Print( aNestLevel+1, "(no_connects %d)\n", aBoard->GetUnconnectedNetCount() );
|
||||
m_out->Print( aNestLevel+1, "(links %d)\n", aBoard->GetConnectivity()->GetLinksCount() );
|
||||
m_out->Print( aNestLevel+1, "(no_connects %d)\n", aBoard->GetConnectivity()->GetUnconnectedCount() );
|
||||
|
||||
// Write Bounding box info
|
||||
EDA_RECT bbox = aBoard->GetBoundingBox();
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
#include <drag.h>
|
||||
#include <dialog_get_footprint_by_name.h>
|
||||
|
||||
#include <connectivity.h>
|
||||
|
||||
static void MoveFootprint( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
|
||||
const wxPoint& aPosition, bool aErase );
|
||||
static void Abort_MoveOrCopyModule( EDA_DRAW_PANEL* Panel, wxDC* DC );
|
||||
|
@ -265,7 +267,7 @@ bool PCB_EDIT_FRAME::Delete_Module( MODULE* aModule, wxDC* aDC )
|
|||
SetMsgPanel( aModule );
|
||||
|
||||
/* Remove module from list, and put it in undo command list */
|
||||
m_Pcb->m_Modules.Remove( aModule );
|
||||
m_Pcb->Remove( aModule );
|
||||
aModule->SetState( IS_DELETED, true );
|
||||
SaveCopyInUndoList( aModule, UR_DELETED );
|
||||
|
||||
|
@ -322,7 +324,7 @@ void PCB_EDIT_FRAME::Change_Side_Module( MODULE* Module, wxDC* DC )
|
|||
|
||||
/* Flip the module */
|
||||
Module->Flip( Module->GetPosition() );
|
||||
|
||||
m_Pcb->GetConnectivity()->Update( Module );
|
||||
SetMsgPanel( Module );
|
||||
|
||||
if( !Module->IsMoving() ) /* Inversion simple */
|
||||
|
@ -343,8 +345,8 @@ void PCB_EDIT_FRAME::Change_Side_Module( MODULE* Module, wxDC* DC )
|
|||
DrawSegmentWhileMovingFootprint( m_canvas, DC );
|
||||
}
|
||||
|
||||
GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
|
||||
}
|
||||
m_Pcb->GetConnectivity()->Update( Module );
|
||||
}
|
||||
|
||||
|
||||
|
@ -356,7 +358,7 @@ void PCB_BASE_FRAME::PlaceModule( MODULE* aModule, wxDC* aDC, bool aDoNotRecreat
|
|||
return;
|
||||
|
||||
OnModify();
|
||||
GetBoard()->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK);
|
||||
|
||||
|
||||
if( aModule->IsNew() )
|
||||
{
|
||||
|
@ -381,7 +383,7 @@ void PCB_BASE_FRAME::PlaceModule( MODULE* aModule, wxDC* aDC, bool aDoNotRecreat
|
|||
|
||||
DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)GetDisplayOptions();
|
||||
|
||||
if( displ_opts->m_Show_Module_Ratsnest && ( GetBoard()->m_Status_Pcb & LISTE_PAD_OK ) && aDC )
|
||||
if( displ_opts->m_Show_Module_Ratsnest && aDC )
|
||||
TraceModuleRatsNest( aDC );
|
||||
|
||||
newpos = GetCrossHairPosition();
|
||||
|
@ -410,6 +412,8 @@ void PCB_BASE_FRAME::PlaceModule( MODULE* aModule, wxDC* aDC, bool aDoNotRecreat
|
|||
|
||||
m_canvas->SetMouseCapture( NULL, NULL );
|
||||
|
||||
m_Pcb->GetConnectivity()->Update( aModule );
|
||||
|
||||
if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) && !aDoNotRecreateRatsnest )
|
||||
Compile_Ratsnest( aDC, true );
|
||||
|
||||
|
@ -456,7 +460,6 @@ void PCB_BASE_FRAME::Rotate_Module( wxDC* DC, MODULE* module, double angle, bool
|
|||
}
|
||||
}
|
||||
|
||||
GetBoard()->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK );
|
||||
|
||||
if( incremental )
|
||||
module->SetOrientation( module->GetOrientation() + angle );
|
||||
|
@ -464,6 +467,7 @@ void PCB_BASE_FRAME::Rotate_Module( wxDC* DC, MODULE* module, double angle, bool
|
|||
module->SetOrientation( angle );
|
||||
|
||||
SetMsgPanel( module );
|
||||
m_Pcb->GetConnectivity()->Update( module );
|
||||
|
||||
if( DC )
|
||||
{
|
||||
|
@ -485,34 +489,4 @@ void PCB_BASE_FRAME::Rotate_Module( wxDC* DC, MODULE* module, double angle, bool
|
|||
if( module->GetFlags() == 0 ) // module not in edit: redraw full screen
|
||||
m_canvas->Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Redraw in XOR mode the outlines of the module.
|
||||
void MODULE::DrawOutlinesWhenMoving( EDA_DRAW_PANEL* panel, wxDC* DC,
|
||||
const wxPoint& aMoveVector )
|
||||
{
|
||||
int pad_fill_tmp;
|
||||
D_PAD* pt_pad;
|
||||
|
||||
DrawEdgesOnly( panel, DC, aMoveVector, GR_XOR );
|
||||
DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
|
||||
|
||||
// Show pads in sketch mode to speedu up drawings
|
||||
pad_fill_tmp = displ_opts->m_DisplayPadFill;
|
||||
displ_opts->m_DisplayPadFill = true;
|
||||
|
||||
pt_pad = Pads();
|
||||
|
||||
for( ; pt_pad != NULL; pt_pad = pt_pad->Next() )
|
||||
pt_pad->Draw( panel, DC, GR_XOR, aMoveVector );
|
||||
|
||||
displ_opts->m_DisplayPadFill = pad_fill_tmp;
|
||||
|
||||
if( displ_opts->m_Show_Module_Ratsnest )
|
||||
{
|
||||
PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) panel->GetParent();
|
||||
frame->build_ratsnest_module( this );
|
||||
frame->TraceModuleRatsNest( DC );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -206,5 +206,4 @@ void PCB_BASE_FRAME::PlacePad( D_PAD* aPad, wxDC* DC )
|
|||
|
||||
OnModify();
|
||||
m_canvas->SetMouseCapture( NULL, NULL );
|
||||
m_Pcb->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK );
|
||||
}
|
||||
|
|
|
@ -265,9 +265,6 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME )
|
|||
EVT_TOOL_RANGE( ID_PCB_MUWAVE_START_CMD, ID_PCB_MUWAVE_END_CMD,
|
||||
PCB_EDIT_FRAME::ProcessMuWaveFunctions )
|
||||
|
||||
EVT_MENU_RANGE( ID_POPUP_PCB_AUTOPLACE_START_RANGE, ID_POPUP_PCB_AUTOPLACE_END_RANGE,
|
||||
PCB_EDIT_FRAME::OnPlaceOrRouteFootprints )
|
||||
|
||||
EVT_MENU_RANGE( ID_POPUP_PCB_START_RANGE, ID_POPUP_PCB_END_RANGE,
|
||||
PCB_EDIT_FRAME::Process_Special_Functions )
|
||||
|
||||
|
|
|
@ -41,118 +41,8 @@
|
|||
|
||||
#include <pcbnew.h>
|
||||
|
||||
#include <minimun_spanning_tree.h>
|
||||
|
||||
/**
|
||||
* @brief class MIN_SPAN_TREE_PADS (derived from MIN_SPAN_TREE) specializes
|
||||
* the base class to calculate a minimum spanning tree from a list of pads,
|
||||
* and to add this tree as ratsnest to the main ratsnest list.
|
||||
*/
|
||||
class MIN_SPAN_TREE_PADS: public MIN_SPAN_TREE
|
||||
{
|
||||
friend class MIN_SPAN_TREE;
|
||||
public:
|
||||
std::vector <D_PAD*>* m_PadsList; // list of pads:
|
||||
/* these pads are the parents of nodes of the tree.
|
||||
* Each node position is the corresponding pad position.
|
||||
* This pad list is used to evaluate the weight of an edge in tree.
|
||||
* -> edge = link between 2 nodes = links between 2 pads.
|
||||
* -> weight of a link = rectilinear distance between the 2 pads
|
||||
*/
|
||||
|
||||
public:
|
||||
MIN_SPAN_TREE_PADS(): MIN_SPAN_TREE()
|
||||
{
|
||||
m_PadsList = NULL;
|
||||
}
|
||||
|
||||
void MSP_Init( std::vector <D_PAD*>* aPadsList )
|
||||
{
|
||||
m_PadsList = aPadsList;
|
||||
MIN_SPAN_TREE::MSP_Init( (int) m_PadsList->size() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function AddTreeToRatsnest
|
||||
* Adds the current minimum spanning tree as ratsnest items
|
||||
* to the main ratsnest list
|
||||
* @param aRatsnestList = a ratsnest list to add to
|
||||
*/
|
||||
void AddTreeToRatsnest( std::vector<RATSNEST_ITEM>* aRatsnestList );
|
||||
|
||||
/**
|
||||
* Function GetWeight
|
||||
* calculates the weight between 2 items
|
||||
* NOTE: The weight between a node and itself should be 0
|
||||
* @param aItem1 = first item
|
||||
* @param aItem2 = other item
|
||||
* @return the weight between items ( the rectilinear distance )
|
||||
*/
|
||||
int GetWeight( int aItem1, int aItem2 ) override;
|
||||
};
|
||||
|
||||
|
||||
void MIN_SPAN_TREE_PADS::AddTreeToRatsnest( std::vector<RATSNEST_ITEM>* aRatsnestList )
|
||||
{
|
||||
std::vector<D_PAD*>& padsBuffer = *m_PadsList;
|
||||
|
||||
if( padsBuffer.empty() )
|
||||
return;
|
||||
|
||||
int netcode = padsBuffer[0]->GetNetCode();
|
||||
|
||||
// Note: to get edges in minimum spanning tree,
|
||||
// the index value 0 is not used: it is just
|
||||
// the entry point of the minimum spanning tree.
|
||||
// The first edge (i.e. rastnest) starts at index 1
|
||||
for( int ii = 1; ii < m_Size; ii++ )
|
||||
{
|
||||
// Create the new ratsnest
|
||||
RATSNEST_ITEM net;
|
||||
|
||||
net.SetNet( netcode );
|
||||
net.m_Status = CH_ACTIF | CH_VISIBLE;
|
||||
net.m_Length = GetDist(ii);
|
||||
net.m_PadStart = padsBuffer[ii];
|
||||
net.m_PadEnd = padsBuffer[ GetWhoTo(ii) ];
|
||||
|
||||
aRatsnestList->push_back( net );
|
||||
}
|
||||
}
|
||||
|
||||
/* Function GetWeight
|
||||
* calculates the weight between 2 items
|
||||
* Here it calculate the rectilinear distance between 2 pads (2 items)
|
||||
* NOTE: The weight between a node and itself should be <=0
|
||||
* aItem1 and aItem2 are the 2 items
|
||||
* return the rectilinear distance
|
||||
*/
|
||||
int MIN_SPAN_TREE_PADS::GetWeight( int aItem1, int aItem2 )
|
||||
{
|
||||
// NOTE: The distance (weight) between a node and itself should be 0
|
||||
// so we add 1 to other distances to be sure we never have 0
|
||||
// in cases other than a node and itself
|
||||
|
||||
D_PAD* pad1 = (*m_PadsList)[aItem1];
|
||||
D_PAD* pad2 = (*m_PadsList)[aItem2];
|
||||
|
||||
if( pad1 == pad2 )
|
||||
return 0;
|
||||
|
||||
int weight = abs( pad2->GetPosition().x - pad1->GetPosition().x ) +
|
||||
abs( pad2->GetPosition().y - pad1->GetPosition().y );
|
||||
return weight + 1;
|
||||
}
|
||||
|
||||
|
||||
/* Note about the ratsnest computation:
|
||||
* Building the general ratsnest:
|
||||
* For each net, the ratsnest is the set of lines connecting pads,
|
||||
* using the shorter distance
|
||||
* Therefore this problem is well known in graph therory, and sloved
|
||||
* using the "minimum spanning tree".
|
||||
* We use here an algorithm to build the minimum spanning tree known as Prim's algorithm
|
||||
*/
|
||||
#include <connectivity.h>
|
||||
#include <ratsnest_data.h>
|
||||
|
||||
/**
|
||||
* Function Compile_Ratsnest
|
||||
|
@ -164,128 +54,24 @@ int MIN_SPAN_TREE_PADS::GetWeight( int aItem1, int aItem2 )
|
|||
*/
|
||||
void PCB_BASE_FRAME::Compile_Ratsnest( wxDC* aDC, bool aDisplayStatus )
|
||||
{
|
||||
wxString msg;
|
||||
GetBoard()->GetConnectivity()->RecalculateRatsnest();
|
||||
|
||||
GetBoard()->m_Status_Pcb = 0; // we want a full ratsnest computation, from the scratch
|
||||
ClearMsgPanel();
|
||||
|
||||
// Rebuild the full pads and net info list
|
||||
ComputeLegacyConnections();
|
||||
|
||||
if( aDisplayStatus )
|
||||
{
|
||||
msg.Printf( wxT( " %d" ), m_Pcb->GetPadCount() );
|
||||
AppendMsgPanel( wxT( "Pads" ), msg, RED );
|
||||
msg.Printf( wxT( " %d" ), m_Pcb->GetNetCount() );
|
||||
AppendMsgPanel( wxT( "Nets" ), msg, CYAN );
|
||||
}
|
||||
|
||||
/* Compute the full ratsnest
|
||||
* which can be see like all the possible links or logical connections.
|
||||
* some of them are active (no track connected) and others are inactive
|
||||
* (when tracks connect pads)
|
||||
* This full ratsnest is not modified by track editing.
|
||||
* It changes only when a netlist is read, or footprints are modified
|
||||
*/
|
||||
Build_Board_Ratsnest();
|
||||
|
||||
// Compute the pad connections due to the existing tracks (physical connections)
|
||||
TestConnections();
|
||||
|
||||
/* Compute the active ratsnest, i.e. the unconnected links
|
||||
*/
|
||||
TestForActiveLinksInRatsnest( 0 );
|
||||
|
||||
// Redraw the active ratsnest ( if enabled )
|
||||
if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) && aDC )
|
||||
if( GetBoard()->IsElementVisible(LAYER_RATSNEST) && aDC )
|
||||
DrawGeneralRatsnest( aDC, 0 );
|
||||
|
||||
wxString msg;
|
||||
|
||||
ClearMsgPanel();
|
||||
|
||||
if( aDisplayStatus )
|
||||
{
|
||||
msg.Printf( wxT( " %d" ), m_Pcb->GetConnectivity()->GetPadCount() );
|
||||
AppendMsgPanel( wxT( "Pads" ), msg, RED );
|
||||
msg.Printf( wxT( " %d" ), m_Pcb->GetConnectivity()->GetNetCount() );
|
||||
AppendMsgPanel( wxT( "Nets" ), msg, CYAN );
|
||||
SetMsgPanel( m_Pcb );
|
||||
}
|
||||
|
||||
|
||||
/* Sort function used by QSORT
|
||||
* Sort pads by net code
|
||||
*/
|
||||
static bool sortByNetcode( const D_PAD* const & ref, const D_PAD* const & item )
|
||||
{
|
||||
return ref->GetNetCode() < item->GetNetCode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to compute the full ratsnest
|
||||
* This is the "basic" ratsnest depending only on pads.
|
||||
*
|
||||
* Create the sorted pad list (if necessary)
|
||||
* The active pads (i.e included in a net ) are called nodes
|
||||
* This pad list is sorted by net codes
|
||||
* A ratsnest can be seen as a logical connection.
|
||||
*
|
||||
* Update :
|
||||
* nb_nodes = Active pads count for the board
|
||||
* nb_links = link count for the board (logical connection count)
|
||||
* (there are n-1 links in a net which counting n active pads) .
|
||||
*/
|
||||
void PCB_BASE_FRAME::Build_Board_Ratsnest()
|
||||
{
|
||||
D_PAD* pad;
|
||||
int noconn;
|
||||
|
||||
m_Pcb->SetUnconnectedNetCount( 0 );
|
||||
|
||||
m_Pcb->m_FullRatsnest.clear();
|
||||
|
||||
if( m_Pcb->GetPadCount() == 0 )
|
||||
return;
|
||||
|
||||
// Created pad list and the net_codes if needed
|
||||
if( (m_Pcb->m_Status_Pcb & NET_CODES_OK) == 0 )
|
||||
m_Pcb->BuildListOfNets();
|
||||
|
||||
for( unsigned ii = 0; ii<m_Pcb->GetPadCount(); ++ii )
|
||||
{
|
||||
pad = m_Pcb->GetPad( ii );
|
||||
pad->SetSubRatsnest( 0 );
|
||||
}
|
||||
|
||||
if( m_Pcb->GetNodesCount() == 0 )
|
||||
return; // No useful connections.
|
||||
|
||||
// Ratsnest computation
|
||||
unsigned current_net_code = 1; // First net code is analyzed.
|
||||
// (net_code = 0 -> no connect)
|
||||
noconn = 0;
|
||||
MIN_SPAN_TREE_PADS min_spanning_tree;
|
||||
|
||||
for( ; current_net_code < m_Pcb->GetNetCount(); current_net_code++ )
|
||||
{
|
||||
NETINFO_ITEM* net = m_Pcb->FindNet( current_net_code );
|
||||
|
||||
if( !net ) // Should not occur
|
||||
{
|
||||
UTF8 msg = StrPrintf( "%s: error, net %d not found", __func__, current_net_code );
|
||||
wxMessageBox( msg ); // BTW, it does happen.
|
||||
return;
|
||||
}
|
||||
|
||||
net->m_RatsnestStartIdx = m_Pcb->GetRatsnestsCount();
|
||||
|
||||
min_spanning_tree.MSP_Init( &net->m_PadInNetList );
|
||||
min_spanning_tree.BuildTree();
|
||||
min_spanning_tree.AddTreeToRatsnest( &m_Pcb->m_FullRatsnest );
|
||||
net->m_RatsnestEndIdx = m_Pcb->GetRatsnestsCount();
|
||||
}
|
||||
|
||||
m_Pcb->SetUnconnectedNetCount( noconn );
|
||||
m_Pcb->m_Status_Pcb |= LISTE_RATSNEST_ITEM_OK;
|
||||
|
||||
// Update the ratsnest display option (visible/invisible) flag
|
||||
for( unsigned ii = 0; ii < m_Pcb->GetRatsnestsCount(); ii++ )
|
||||
{
|
||||
if( !GetBoard()->IsElementVisible( LAYER_RATSNEST ) ) // Clear VISIBLE flag
|
||||
m_Pcb->m_FullRatsnest[ii].m_Status &= ~CH_VISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,452 +85,33 @@ void PCB_BASE_FRAME::Build_Board_Ratsnest()
|
|||
*/
|
||||
void PCB_BASE_FRAME::DrawGeneralRatsnest( wxDC* aDC, int aNetcode )
|
||||
{
|
||||
if( ( m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
|
||||
return;
|
||||
|
||||
if( ( m_Pcb->m_Status_Pcb & DO_NOT_SHOW_GENERAL_RASTNEST ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( aDC == NULL )
|
||||
return;
|
||||
|
||||
const int state = CH_VISIBLE | CH_ACTIF;
|
||||
auto connectivity = m_Pcb->GetConnectivity();
|
||||
|
||||
for( unsigned ii = 0; ii < m_Pcb->GetRatsnestsCount(); ii++ )
|
||||
COLOR4D color = g_ColorsSettings.GetItemColor(LAYER_RATSNEST);
|
||||
|
||||
for( int i = 1; i < connectivity->GetNetCount(); ++i )
|
||||
{
|
||||
RATSNEST_ITEM& item = m_Pcb->m_FullRatsnest[ii];
|
||||
RN_NET* net = connectivity->GetRatsnestForNet( i );
|
||||
|
||||
if( ( item.m_Status & state ) != state )
|
||||
continue;
|
||||
|
||||
if( ( aNetcode <= 0 ) || ( aNetcode == item.GetNet() ) )
|
||||
{
|
||||
item.Draw( m_canvas, aDC, GR_XOR, wxPoint( 0, 0 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function used by TestForActiveLinksInRatsnest
|
||||
* Function testing the ratsnest between 2 blocks ( of the same net )
|
||||
* The search is made between pads in block 1 and the others blocks
|
||||
* The block n ( n > 1 ) is merged with block 1 and linked by the smallest ratsnest
|
||||
* between block 1 and the block n (activate the logical connection)
|
||||
* @param aRatsnestBuffer = the buffer to store NETINFO_ITEM* items
|
||||
* @param aNetinfo = the current NETINFO_ITEM for the current net
|
||||
* output: .state member, bit CH_ACTIF of the ratsnest item
|
||||
* @return last subratsnest id in use
|
||||
*/
|
||||
static int tst_links_between_blocks( NETINFO_ITEM* aNetinfo,
|
||||
std::vector<RATSNEST_ITEM>& aRatsnestBuffer )
|
||||
{
|
||||
int subratsnest_id, min_id;
|
||||
RATSNEST_ITEM* link, * best_link;
|
||||
|
||||
// Search a link from a block to an other block
|
||||
best_link = NULL;
|
||||
|
||||
for( unsigned ii = aNetinfo->m_RatsnestStartIdx; ii < aNetinfo->m_RatsnestEndIdx; ii++ )
|
||||
{
|
||||
link = &aRatsnestBuffer[ii];
|
||||
|
||||
// If this link joints 2 pads inside the same block, do nothing
|
||||
// (these pads are already connected)
|
||||
if( link->m_PadStart->GetSubRatsnest() == link->m_PadEnd->GetSubRatsnest() )
|
||||
continue;
|
||||
|
||||
// This link joints 2 pads of different blocks: this is a candidate,
|
||||
// but we want to select the shorter link, so use it only if it is shorter
|
||||
// than the previous candidate:
|
||||
if( best_link == NULL ) // no candidate
|
||||
best_link = link;
|
||||
else if( best_link->m_Length > link->m_Length ) // It is a better candidate.
|
||||
best_link = link;
|
||||
}
|
||||
|
||||
if( best_link == NULL )
|
||||
return 1;
|
||||
|
||||
/* At this point we have found a link between 2 different blocks (subratsnest)
|
||||
* we must set its status to ACTIVE and merge the 2 blocks
|
||||
*/
|
||||
best_link->m_Status |= CH_ACTIF;
|
||||
subratsnest_id = best_link->m_PadStart->GetSubRatsnest();
|
||||
min_id = best_link->m_PadEnd->GetSubRatsnest();
|
||||
|
||||
if( min_id > subratsnest_id )
|
||||
std::swap( min_id, subratsnest_id );
|
||||
|
||||
// Merge the 2 blocks in one sub ratsnest:
|
||||
for( unsigned ii = 0; ii < aNetinfo->m_PadInNetList.size(); ii++ )
|
||||
{
|
||||
if( aNetinfo->m_PadInNetList[ii]->GetSubRatsnest() == subratsnest_id )
|
||||
{
|
||||
aNetinfo->m_PadInNetList[ii]->SetSubRatsnest( min_id );
|
||||
}
|
||||
}
|
||||
|
||||
return subratsnest_id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function used by TestForActiveLinksInRatsnest_general
|
||||
* The general ratsnest list must exists because this function explores this ratsnest
|
||||
* Activates (i.e. set the CH_ACTIF flag) the ratsnest links between 2 pads when
|
||||
* at least one pad not already connected (SubRatsnest = 0)
|
||||
* and actives the corresponding link
|
||||
*
|
||||
* @param aFirstItem = starting address for the ratsnest list
|
||||
* @param aLastItem = ending address for the ratsnest list
|
||||
* @param aCurrSubRatsnestId = last sub ratsnest id in use (computed from the track
|
||||
* analysis)
|
||||
*
|
||||
* output:
|
||||
* ratsnest list (status member bit CH_ACTIF set)
|
||||
* and pads linked (m_SubRatsnest value set)
|
||||
*
|
||||
* @return new block number
|
||||
*/
|
||||
static void tst_links_between_pads( int & aCurrSubRatsnestId,
|
||||
RATSNEST_ITEM* aFirstItem,
|
||||
RATSNEST_ITEM* aLastItem )
|
||||
{
|
||||
for( RATSNEST_ITEM* item = aFirstItem; item < aLastItem; item++ )
|
||||
{
|
||||
D_PAD* pad_start = item->m_PadStart;
|
||||
D_PAD* pad_end = item->m_PadEnd;
|
||||
|
||||
/* Update the current SubRatsnest if the 2 pads are not connected :
|
||||
* a new cluster is created and the link activated
|
||||
*/
|
||||
if( (pad_start->GetSubRatsnest() == 0) && (pad_end->GetSubRatsnest() == 0) )
|
||||
{
|
||||
aCurrSubRatsnestId++;
|
||||
pad_start->SetSubRatsnest( aCurrSubRatsnestId );
|
||||
pad_end->SetSubRatsnest( aCurrSubRatsnestId );
|
||||
item->m_Status |= CH_ACTIF;
|
||||
}
|
||||
|
||||
/* If a pad is already connected to a subratsnest: activate the link
|
||||
* the pad other is merged in the existing subratsnest
|
||||
*/
|
||||
else if( pad_start->GetSubRatsnest() == 0 )
|
||||
{
|
||||
pad_start->SetSubRatsnest( pad_end->GetSubRatsnest() );
|
||||
item->m_Status |= CH_ACTIF;
|
||||
}
|
||||
else if( pad_end->GetSubRatsnest() == 0 )
|
||||
{
|
||||
pad_end->SetSubRatsnest( pad_start->GetSubRatsnest() );
|
||||
item->m_Status |= CH_ACTIF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* function TestForActiveLinksInRatsnest
|
||||
* determine the active links inside the full ratsnest
|
||||
*
|
||||
* I used an algorithm inspired by the "Lee algorithm".
|
||||
* The idea is all pads must be connected by a physical track or a logical track
|
||||
* a physical track is the existing track on copper layers.
|
||||
* a logical track is the link that must be activated (visible) if
|
||||
* no track found between 2 pads.
|
||||
* The algorithm explore the existing full ratnest
|
||||
* This is a 2 steps algorithm (executed for each net).
|
||||
* - First:
|
||||
* Initialise for each pad the subratsnest id to its subnet value
|
||||
* explore the full ratnest (relative to the net) and active a link each time at least one pad of
|
||||
* the given link is not connected to an other pad by a track ( subratsnest = 0)
|
||||
* If the 2 pads linked have both the subratsnest id = 0, a new subratsnest value is created
|
||||
* - Second:
|
||||
* explore the full ratnest (relative to the net) and find a link that links
|
||||
* 2 pads having different subratsnest values
|
||||
* Active the link and merge the 2 subratsnest value.
|
||||
*
|
||||
* This is usually fast because the ratsnest is not built here: it is just explored
|
||||
* to see what link must be activated
|
||||
*/
|
||||
void PCB_BASE_FRAME::TestForActiveLinksInRatsnest( int aNetCode )
|
||||
{
|
||||
RATSNEST_ITEM* rats;
|
||||
D_PAD* pad;
|
||||
NETINFO_ITEM* net;
|
||||
|
||||
if( m_Pcb->GetPadCount() == 0 )
|
||||
return;
|
||||
|
||||
if( (m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
|
||||
Build_Board_Ratsnest();
|
||||
|
||||
for( int net_code = 1; net_code < (int) m_Pcb->GetNetCount(); net_code++ )
|
||||
{
|
||||
net = m_Pcb->FindNet( net_code );
|
||||
|
||||
wxCHECK_RET( net != NULL,
|
||||
wxString::Format( wxT( "Net code %d not found!" ), net_code ) );
|
||||
|
||||
if( aNetCode && (net_code != aNetCode) )
|
||||
continue;
|
||||
|
||||
// Create subratsnests id from subnets created by existing tracks:
|
||||
int subratsnest = 0;
|
||||
for( unsigned ip = 0; ip < net->m_PadInNetList.size(); ip++ )
|
||||
{
|
||||
pad = net->m_PadInNetList[ip];
|
||||
int subnet = pad->GetSubNet();
|
||||
pad->SetSubRatsnest( subnet );
|
||||
subratsnest = std::max( subratsnest, subnet );
|
||||
}
|
||||
|
||||
for( unsigned ii = net->m_RatsnestStartIdx; ii < net->m_RatsnestEndIdx; ii++ )
|
||||
{
|
||||
m_Pcb->m_FullRatsnest[ii].m_Status &= ~CH_ACTIF;
|
||||
}
|
||||
|
||||
// First pass - activate links for not connected pads
|
||||
rats = &m_Pcb->m_FullRatsnest[0];
|
||||
tst_links_between_pads( subratsnest,
|
||||
rats + net->m_RatsnestStartIdx,
|
||||
rats + net->m_RatsnestEndIdx );
|
||||
|
||||
// Second pass activate links between blocks (Iteration)
|
||||
while( subratsnest > 1 )
|
||||
{
|
||||
subratsnest = tst_links_between_blocks( net, m_Pcb->m_FullRatsnest );
|
||||
}
|
||||
}
|
||||
|
||||
m_Pcb->SetUnconnectedNetCount( 0 );
|
||||
|
||||
unsigned cnt = 0;
|
||||
|
||||
for( unsigned ii = 0; ii < m_Pcb->GetRatsnestsCount(); ii++ )
|
||||
{
|
||||
if( m_Pcb->m_FullRatsnest[ii].IsActive() )
|
||||
cnt++;
|
||||
}
|
||||
|
||||
m_Pcb->SetUnconnectedNetCount( cnt );
|
||||
}
|
||||
|
||||
|
||||
void PCB_BASE_FRAME::build_ratsnest_module( MODULE* aModule )
|
||||
{
|
||||
// for local ratsnest calculation when moving a footprint:
|
||||
// list of pads to use for this local ratsnets:
|
||||
// this is the list of connected pads of the current module,
|
||||
// and all pads connected to these pads:
|
||||
static std::vector <D_PAD*> localPadList;
|
||||
static unsigned pads_module_count; // node count (node = pad with a net
|
||||
// code) for the footprint being moved
|
||||
static unsigned internalRatsCount; // number of internal links (links
|
||||
// between pads of the module)
|
||||
D_PAD* pad_ref;
|
||||
D_PAD* pad_externe;
|
||||
int current_net_code;
|
||||
int distance;
|
||||
wxPoint pad_pos; // True pad position according to the
|
||||
// current footprint position
|
||||
|
||||
if( (GetBoard()->m_Status_Pcb & LISTE_PAD_OK) == 0 )
|
||||
{
|
||||
GetBoard()->m_Status_Pcb = 0;
|
||||
GetBoard()->BuildListOfNets();
|
||||
}
|
||||
|
||||
/* Compute the "local" ratsnest if needed (when this footprint starts move)
|
||||
* and the list of external pads to consider, i.e pads in others
|
||||
* footprints which are "connected" to
|
||||
* a pad in the current footprint
|
||||
*/
|
||||
if( (m_Pcb->m_Status_Pcb & RATSNEST_ITEM_LOCAL_OK) == 0 )
|
||||
{
|
||||
// Compute the "internal" ratsnest, i.e the links between the current
|
||||
// footprint pads
|
||||
localPadList.clear();
|
||||
m_Pcb->m_LocalRatsnest.clear();
|
||||
|
||||
// collect active pads of the module:
|
||||
for( pad_ref = aModule->Pads(); pad_ref; pad_ref = pad_ref->Next() )
|
||||
{
|
||||
if( pad_ref->GetNetCode() == NETINFO_LIST::UNCONNECTED )
|
||||
continue;
|
||||
|
||||
if( !( pad_ref->GetLayerSet() & LSET::AllCuMask() ).any() )
|
||||
// pad not a copper layer (happens when building complex shapes)
|
||||
continue;
|
||||
|
||||
localPadList.push_back( pad_ref );
|
||||
pad_ref->SetSubRatsnest( 0 );
|
||||
pad_ref->SetSubNet( 0 );
|
||||
}
|
||||
|
||||
pads_module_count = localPadList.size();
|
||||
|
||||
if( pads_module_count == 0 )
|
||||
return; // no connection!
|
||||
|
||||
sort( localPadList.begin(), localPadList.end(), sortByNetcode );
|
||||
|
||||
// Build the list of pads linked to the current footprint pads
|
||||
current_net_code = 0;
|
||||
|
||||
for( unsigned ii = 0; ii < pads_module_count; ii++ )
|
||||
{
|
||||
pad_ref = localPadList[ii];
|
||||
|
||||
if( pad_ref->GetNetCode() == current_net_code )
|
||||
continue;
|
||||
|
||||
// A new net was found, load all pads of others modules members of this net:
|
||||
NETINFO_ITEM* net = pad_ref->GetNet();
|
||||
|
||||
if( net == NULL ) //Should not occur
|
||||
if( ( aNetcode <= 0 ) || ( aNetcode == i ) )
|
||||
{
|
||||
wxMessageBox( wxT( "build_ratsnest_module() error: net not found" ) );
|
||||
return;
|
||||
for ( const auto& edge : net->GetEdges() )
|
||||
{
|
||||
auto s = edge.GetSourcePos();
|
||||
auto d = edge.GetTargetPos();
|
||||
GRLine( m_canvas->GetClipBox(), aDC, wxPoint(s.x, s.y), wxPoint(d.x, d.y), 0, color );
|
||||
}
|
||||
}
|
||||
|
||||
for( unsigned jj = 0; jj < net->m_PadInNetList.size(); jj++ )
|
||||
{
|
||||
pad_externe = net->m_PadInNetList[jj];
|
||||
|
||||
if( pad_externe->GetParent() == aModule )
|
||||
continue;
|
||||
|
||||
pad_externe->SetSubRatsnest( 0 );
|
||||
pad_externe->SetSubNet( 0 );
|
||||
|
||||
localPadList.push_back( pad_externe );
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the pad list by net_code
|
||||
sort( localPadList.begin() + pads_module_count, localPadList.end(),
|
||||
sortByNetcode );
|
||||
|
||||
/* Compute the internal rats nest:
|
||||
* this is the same as general ratsnest, but considers only the current
|
||||
* footprint pads it is therefore not time consuming, and it is made only
|
||||
* once
|
||||
*/
|
||||
current_net_code = localPadList[0]->GetNetCode();
|
||||
|
||||
MIN_SPAN_TREE_PADS min_spanning_tree;
|
||||
std::vector<D_PAD*> padsBuffer; // contains pads of only one net
|
||||
|
||||
for( unsigned ii = 0; ii < pads_module_count; ii++ )
|
||||
{
|
||||
// Search the end of pad list relative to the current net
|
||||
unsigned jj = ii + 1;
|
||||
|
||||
for( ; jj <= pads_module_count; jj++ )
|
||||
{
|
||||
if( jj >= pads_module_count )
|
||||
break;
|
||||
|
||||
if( localPadList[jj]->GetNetCode() != current_net_code )
|
||||
break;
|
||||
}
|
||||
|
||||
for( unsigned kk = ii; kk < jj; kk++ )
|
||||
padsBuffer.push_back( localPadList[kk] );
|
||||
|
||||
min_spanning_tree.MSP_Init( &padsBuffer );
|
||||
min_spanning_tree.BuildTree();
|
||||
min_spanning_tree.AddTreeToRatsnest( &m_Pcb->m_LocalRatsnest );
|
||||
padsBuffer.clear();
|
||||
|
||||
ii = jj;
|
||||
|
||||
if( ii < localPadList.size() )
|
||||
current_net_code = localPadList[ii]->GetNetCode();
|
||||
}
|
||||
|
||||
internalRatsCount = m_Pcb->m_LocalRatsnest.size();
|
||||
|
||||
// set the flag LOCAL_RATSNEST_ITEM of the ratsnest status:
|
||||
for( unsigned ii = 0; ii < m_Pcb->m_LocalRatsnest.size(); ii++ )
|
||||
m_Pcb->m_LocalRatsnest[ii].m_Status = LOCAL_RATSNEST_ITEM;
|
||||
|
||||
m_Pcb->m_Status_Pcb |= RATSNEST_ITEM_LOCAL_OK;
|
||||
} // End of internal ratsnest build
|
||||
|
||||
/* This section computes the "external" ratsnest: it is done when the
|
||||
* footprint position changes
|
||||
*
|
||||
* This section search:
|
||||
* for each current module pad the nearest neighbor external pad (of
|
||||
* course for the same net code).
|
||||
* For each current footprint cluster of pad (pads having the same net
|
||||
* code),
|
||||
* we search the smaller rats nest.
|
||||
* so, for each net, only one rats nest item is created
|
||||
*/
|
||||
RATSNEST_ITEM local_rats;
|
||||
|
||||
local_rats.m_Length = INT_MAX;
|
||||
local_rats.m_Status = 0;
|
||||
bool addRats = false;
|
||||
|
||||
// Erase external ratsnest items:
|
||||
if( internalRatsCount < m_Pcb->m_LocalRatsnest.size() )
|
||||
m_Pcb->m_LocalRatsnest.erase( m_Pcb->m_LocalRatsnest.begin() + internalRatsCount,
|
||||
m_Pcb->m_LocalRatsnest.end() );
|
||||
|
||||
current_net_code = localPadList[0]->GetNetCode();
|
||||
|
||||
for( unsigned ii = 0; ii < pads_module_count; ii++ )
|
||||
{
|
||||
pad_ref = localPadList[ii];
|
||||
|
||||
if( pad_ref->GetNetCode() != current_net_code )
|
||||
{
|
||||
// if needed, creates a new ratsnest for the old net
|
||||
if( addRats )
|
||||
{
|
||||
m_Pcb->m_LocalRatsnest.push_back( local_rats );
|
||||
}
|
||||
|
||||
addRats = false;
|
||||
current_net_code = pad_ref->GetNetCode();
|
||||
local_rats.m_Length = INT_MAX;
|
||||
}
|
||||
|
||||
pad_pos = pad_ref->GetPosition() - g_Offset_Module;
|
||||
|
||||
// Search the nearest external pad of this current pad
|
||||
for( unsigned jj = pads_module_count; jj < localPadList.size(); jj++ )
|
||||
{
|
||||
pad_externe = localPadList[jj];
|
||||
|
||||
// we search pads having the same net code
|
||||
if( pad_externe->GetNetCode() < pad_ref->GetNetCode() )
|
||||
continue;
|
||||
|
||||
if( pad_externe->GetNetCode() > pad_ref->GetNetCode() ) // pads are sorted by net code
|
||||
break;
|
||||
|
||||
distance = abs( pad_externe->GetPosition().x - pad_pos.x ) +
|
||||
abs( pad_externe->GetPosition().y - pad_pos.y );
|
||||
|
||||
if( distance < local_rats.m_Length )
|
||||
{
|
||||
local_rats.m_PadStart = pad_ref;
|
||||
local_rats.m_PadEnd = pad_externe;
|
||||
local_rats.SetNet( pad_ref->GetNetCode() );
|
||||
local_rats.m_Length = distance;
|
||||
local_rats.m_Status = 0;
|
||||
|
||||
addRats = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( addRats ) // Ensure the last created rats nest item is stored in buffer
|
||||
m_Pcb->m_LocalRatsnest.push_back( local_rats );
|
||||
}
|
||||
|
||||
|
||||
|
@ -753,34 +120,12 @@ void PCB_BASE_FRAME::TraceModuleRatsNest( wxDC* DC )
|
|||
if( DC == NULL )
|
||||
return;
|
||||
|
||||
if( ( m_Pcb->m_Status_Pcb & RATSNEST_ITEM_LOCAL_OK ) == 0 )
|
||||
return;
|
||||
|
||||
COLOR4D tmpcolor = g_ColorsSettings.GetItemColor( LAYER_RATSNEST );
|
||||
|
||||
for( unsigned ii = 0; ii < m_Pcb->m_LocalRatsnest.size(); ii++ )
|
||||
for( const auto& l : GetBoard()->GetConnectivity()->GetDynamicRatsnest() )
|
||||
{
|
||||
RATSNEST_ITEM* rats = &m_Pcb->m_LocalRatsnest[ii];
|
||||
|
||||
if( rats->m_Status & LOCAL_RATSNEST_ITEM )
|
||||
{
|
||||
g_ColorsSettings.SetItemColor( LAYER_RATSNEST, YELLOW );
|
||||
rats->Draw( m_canvas, DC, GR_XOR, g_Offset_Module );
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ColorsSettings.SetItemColor( LAYER_RATSNEST, tmpcolor );
|
||||
|
||||
wxPoint tmp = rats->m_PadStart->GetPosition();
|
||||
|
||||
rats->m_PadStart->SetPosition( tmp - g_Offset_Module );
|
||||
rats->Draw( m_canvas, DC, GR_XOR, wxPoint( 0, 0 ) );
|
||||
|
||||
rats->m_PadStart->SetPosition( tmp );
|
||||
}
|
||||
GRLine( m_canvas->GetClipBox(), DC, wxPoint(l.a.x, l.a.y), wxPoint(l.b.x, l.b.y), 0, tmpcolor );
|
||||
}
|
||||
|
||||
g_ColorsSettings.SetItemColor( LAYER_RATSNEST, tmpcolor );
|
||||
}
|
||||
|
||||
|
||||
|
@ -798,34 +143,9 @@ void PCB_BASE_FRAME::TraceModuleRatsNest( wxDC* DC )
|
|||
* and when the mouse is moved, the g_MaxLinksShowed links to neighbors are
|
||||
* drawn
|
||||
*/
|
||||
static std::vector <wxPoint> s_TargetsLocations;
|
||||
static wxPoint s_CursorPos; // Coordinate of the moving point (mouse cursor and
|
||||
// end of current track segment)
|
||||
|
||||
/* Used by BuildAirWiresTargetsList(): sort function by link length
|
||||
* (rectilinear distance between s_CursorPos and item pos)
|
||||
*/
|
||||
static bool sort_by_distance( const wxPoint& ref, const wxPoint& compare )
|
||||
{
|
||||
wxPoint deltaref = ref - s_CursorPos; // relative coordinate of ref
|
||||
wxPoint deltacmp = compare - s_CursorPos; // relative coordinate of compare
|
||||
|
||||
// rectilinear distance between ref and s_CursorPos:
|
||||
int lengthref = abs( deltaref.x ) + abs( deltaref.y );
|
||||
|
||||
// rectilinear distance between compare and s_CursorPos:
|
||||
int lengthcmp = abs( deltacmp.x ) + abs( deltacmp.y );
|
||||
|
||||
return lengthref < lengthcmp;
|
||||
}
|
||||
|
||||
static bool sort_by_point( const wxPoint& ref, const wxPoint& compare )
|
||||
{
|
||||
if( ref.x == compare.x )
|
||||
return ref.y < compare.y;
|
||||
|
||||
return ref.x < compare.x;
|
||||
}
|
||||
static wxPoint s_CursorPos; // Coordinate of the moving point (mouse cursor and
|
||||
// end of current track segment)
|
||||
|
||||
/* Function BuildAirWiresTargetsList
|
||||
* Build a list of candidates that can be a coonection point
|
||||
|
@ -833,101 +153,79 @@ static bool sort_by_point( const wxPoint& ref, const wxPoint& compare )
|
|||
* This functions prepares data to show airwires to nearest connecting points (pads)
|
||||
* from the current new track to candidates during track creation
|
||||
*/
|
||||
|
||||
static BOARD_CONNECTED_ITEM *s_ref = nullptr;
|
||||
static int s_refNet = -1;
|
||||
|
||||
void PCB_BASE_FRAME::BuildAirWiresTargetsList( BOARD_CONNECTED_ITEM* aItemRef,
|
||||
const wxPoint& aPosition, bool aInit )
|
||||
const wxPoint& aPosition, int aNet )
|
||||
{
|
||||
if( ( ( m_Pcb->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK ) == 0 )
|
||||
|| ( ( m_Pcb->m_Status_Pcb & LISTE_PAD_OK ) == 0 )
|
||||
|| ( ( m_Pcb->m_Status_Pcb & NET_CODES_OK ) == 0 ) )
|
||||
{
|
||||
s_TargetsLocations.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
s_CursorPos = aPosition; // needed for sort_by_distance
|
||||
s_ref = aItemRef;
|
||||
s_refNet = aNet;
|
||||
}
|
||||
|
||||
if( aInit )
|
||||
{
|
||||
s_TargetsLocations.clear();
|
||||
|
||||
if( aItemRef == NULL )
|
||||
return;
|
||||
|
||||
int net_code = aItemRef->GetNetCode();
|
||||
int subnet = aItemRef->GetSubNet();
|
||||
|
||||
if( net_code <= 0 )
|
||||
return;
|
||||
static MODULE movedModule(nullptr);
|
||||
|
||||
NETINFO_ITEM* net = m_Pcb->FindNet( net_code );
|
||||
|
||||
if( net == NULL ) // Should not occur
|
||||
{
|
||||
wxMessageBox( wxT( "BuildAirWiresTargetsList() error: net not found" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a list of pads candidates ( pads not already connected to the
|
||||
// current track ):
|
||||
for( unsigned ii = 0; ii < net->m_PadInNetList.size(); ii++ )
|
||||
{
|
||||
D_PAD* pad = net->m_PadInNetList[ii];
|
||||
|
||||
if( pad == aItemRef )
|
||||
continue;
|
||||
|
||||
if( !pad->GetSubNet() || (pad->GetSubNet() != subnet) )
|
||||
s_TargetsLocations.push_back( pad->GetPosition() );
|
||||
}
|
||||
|
||||
// Create a list of tracks ends candidates, not already connected to the
|
||||
// current track:
|
||||
for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() )
|
||||
{
|
||||
if( track->GetNetCode() < net_code )
|
||||
continue;
|
||||
if( track->GetNetCode() > net_code )
|
||||
break;
|
||||
|
||||
if( !track->GetSubNet() || (track->GetSubNet() != subnet) )
|
||||
{
|
||||
if( aPosition != track->GetStart() )
|
||||
s_TargetsLocations.push_back( track->GetStart() );
|
||||
if( aPosition != track->GetEnd() && track->GetStart() != track->GetEnd() )
|
||||
s_TargetsLocations.push_back( track->GetEnd() );
|
||||
}
|
||||
}
|
||||
|
||||
// Remove duplicate targets, using the C++ unique algorithm
|
||||
sort( s_TargetsLocations.begin(), s_TargetsLocations.end(), sort_by_point );
|
||||
std::vector< wxPoint >::iterator it = unique( s_TargetsLocations.begin(), s_TargetsLocations.end() );
|
||||
|
||||
// Using the C++ unique algorithm only moves the duplicate entries to the end of
|
||||
// of the array. This removes the duplicate entries from the array.
|
||||
s_TargetsLocations.resize( it - s_TargetsLocations.begin() );
|
||||
} // end if Init
|
||||
|
||||
// in all cases, sort by distances:
|
||||
sort( s_TargetsLocations.begin(), s_TargetsLocations.end(), sort_by_distance );
|
||||
void PCB_BASE_FRAME::build_ratsnest_module( MODULE *mod, wxPoint aMoveVector )
|
||||
{
|
||||
auto connectivity = GetBoard()->GetConnectivity();
|
||||
movedModule = *mod;
|
||||
movedModule.Move( -aMoveVector );
|
||||
connectivity->ClearDynamicRatsnest();
|
||||
connectivity->BlockRatsnestItems( {mod} );
|
||||
connectivity->ComputeDynamicRatsnest( {&movedModule} );
|
||||
}
|
||||
|
||||
|
||||
void PCB_BASE_FRAME::TraceAirWiresToTargets( wxDC* aDC )
|
||||
{
|
||||
auto connectivity = GetBoard()->GetConnectivity();
|
||||
DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)GetDisplayOptions();
|
||||
|
||||
auto targets = connectivity->NearestUnconnectedTargets( s_ref, s_CursorPos, s_refNet );
|
||||
|
||||
if( aDC == NULL )
|
||||
return;
|
||||
|
||||
if( s_TargetsLocations.size() == 0 )
|
||||
return;
|
||||
|
||||
GRSetDrawMode( aDC, GR_XOR );
|
||||
DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)GetDisplayOptions();
|
||||
|
||||
for( int ii = 0; ii < (int) s_TargetsLocations.size(); ii++ )
|
||||
for (int i = 0; i < std::min( (int)displ_opts->m_MaxLinksShowed, (int)targets.size() ); i++)
|
||||
{
|
||||
if( ii >= displ_opts->m_MaxLinksShowed )
|
||||
break;
|
||||
auto p = targets[i];
|
||||
GRLine( m_canvas->GetClipBox(), aDC, s_CursorPos, wxPoint(p.x, p.y), 0, YELLOW );
|
||||
}
|
||||
|
||||
GRLine( m_canvas->GetClipBox(), aDC, s_CursorPos, s_TargetsLocations[ii], 0, YELLOW );
|
||||
}
|
||||
|
||||
// Redraw in XOR mode the outlines of the module.
|
||||
void MODULE::DrawOutlinesWhenMoving( EDA_DRAW_PANEL* panel, wxDC* DC,
|
||||
const wxPoint& aMoveVector )
|
||||
{
|
||||
int pad_fill_tmp;
|
||||
D_PAD* pt_pad;
|
||||
|
||||
DrawEdgesOnly( panel, DC, aMoveVector, GR_XOR );
|
||||
DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
|
||||
|
||||
// Show pads in sketch mode to speedu up drawings
|
||||
pad_fill_tmp = displ_opts->m_DisplayPadFill;
|
||||
displ_opts->m_DisplayPadFill = true;
|
||||
|
||||
pt_pad = Pads();
|
||||
|
||||
for( ; pt_pad != NULL; pt_pad = pt_pad->Next() )
|
||||
pt_pad->Draw( panel, DC, GR_XOR, aMoveVector );
|
||||
|
||||
displ_opts->m_DisplayPadFill = pad_fill_tmp;
|
||||
|
||||
if( displ_opts->m_Show_Module_Ratsnest )
|
||||
{
|
||||
PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) panel->GetParent();
|
||||
frame->build_ratsnest_module( this, aMoveVector );
|
||||
frame->TraceModuleRatsNest( DC );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -299,7 +299,7 @@ public:
|
|||
|
||||
#include <profile.h>
|
||||
|
||||
RN_NET::RN_NET() : m_dirty( true ), m_visible( true )
|
||||
RN_NET::RN_NET() : m_dirty( true )
|
||||
{
|
||||
m_triangulator.reset( new TRIANGULATOR_STATE );
|
||||
}
|
||||
|
@ -709,3 +709,9 @@ unsigned int RN_NET::GetNodeCount() const
|
|||
{
|
||||
return m_nodes.size();
|
||||
}
|
||||
|
||||
void RN_NET::SetVisible( bool aEnabled )
|
||||
{
|
||||
for ( auto& edge : m_rnEdges )
|
||||
edge.SetVisible ( aEnabled );
|
||||
}
|
||||
|
|
|
@ -178,21 +178,8 @@ public:
|
|||
* @param aEnabled is new state. True if ratsnest for a given net is meant to be displayed,
|
||||
* false otherwise.
|
||||
*/
|
||||
void SetVisible( bool aEnabled )
|
||||
{
|
||||
m_visible = aEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function IsVisible()
|
||||
* Returns the visibility flag state.
|
||||
* @return True if ratsnest for given net is set as visible, false otherwise,
|
||||
*/
|
||||
bool IsVisible() const
|
||||
{
|
||||
return m_visible;
|
||||
}
|
||||
|
||||
void SetVisible( bool aEnabled );
|
||||
|
||||
/**
|
||||
* Function MarkDirty()
|
||||
* Marks ratsnest for given net as 'dirty', i.e. requiring recomputation.
|
||||
|
@ -314,9 +301,6 @@ protected:
|
|||
///> Flag indicating necessity of recalculation of ratsnest for a net.
|
||||
bool m_dirty;
|
||||
|
||||
///> Visibility flag.
|
||||
bool m_visible;
|
||||
|
||||
class TRIANGULATOR_STATE;
|
||||
|
||||
std::shared_ptr<TRIANGULATOR_STATE> m_triangulator;
|
||||
|
|
|
@ -97,15 +97,15 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
|
|||
{
|
||||
RN_NET* net = m_data->GetRatsnestForNet( i );
|
||||
|
||||
if( !net->IsVisible() )
|
||||
continue;
|
||||
|
||||
// Draw the "static" ratsnest
|
||||
if( i != highlightedNet )
|
||||
gal->SetStrokeColor( color ); // using the default ratsnest color for not highlighted
|
||||
|
||||
for( const auto& edge : net->GetUnconnected() )
|
||||
{
|
||||
if ( !edge.IsVisible() )
|
||||
continue;
|
||||
|
||||
const auto& sourceNode = edge.GetSourceNode();
|
||||
const auto& targetNode = edge.GetTargetNode();
|
||||
const VECTOR2I source( sourceNode->Pos() );
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <class_module.h>
|
||||
#include <class_track.h>
|
||||
#include <board_commit.h>
|
||||
#include <ratsnest_data.h>
|
||||
#include <layers_id_colors_and_visibility.h>
|
||||
#include <geometry/convex_hull.h>
|
||||
#include <wxPcbStruct.h>
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <geometry/shape_line_chain.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/shape_circle.h>
|
||||
#include <geometry/convex_hull.h>
|
||||
|
||||
#include "pns_node.h"
|
||||
#include "pns_line_placer.h"
|
||||
|
@ -51,14 +52,6 @@
|
|||
|
||||
#include <router/router_preview_item.h>
|
||||
|
||||
#include <class_board.h>
|
||||
#include <class_board_connected_item.h>
|
||||
#include <class_module.h>
|
||||
#include <class_track.h>
|
||||
#include <ratsnest_data.h>
|
||||
#include <layers_id_colors_and_visibility.h>
|
||||
#include <geometry/convex_hull.h>
|
||||
|
||||
namespace PNS {
|
||||
|
||||
// an ugly singleton for drawing debug items within the router context.
|
||||
|
|
|
@ -44,8 +44,6 @@ using namespace std::placeholders;
|
|||
#include <tools/pcb_actions.h>
|
||||
#include <tools/grid_helper.h>
|
||||
|
||||
#include <ratsnest_data.h>
|
||||
|
||||
#include "pns_kicad_iface.h"
|
||||
#include "pns_tool_base.h"
|
||||
#include "pns_segment.h"
|
||||
|
|
|
@ -55,8 +55,6 @@ using namespace std::placeholders;
|
|||
#include <tools/edit_tool.h>
|
||||
#include <tools/tool_event_utils.h>
|
||||
|
||||
#include <ratsnest_data.h>
|
||||
|
||||
#include "router_tool.h"
|
||||
#include "pns_segment.h"
|
||||
#include "pns_router.h"
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
#include <class_track.h>
|
||||
#include <class_zone.h>
|
||||
#include <class_drawsegment.h>
|
||||
#include <ratsnest_data.h>
|
||||
#include <connectivity.h>
|
||||
#include <view/view.h>
|
||||
|
||||
#include <specctra.h>
|
||||
|
@ -117,8 +117,8 @@ void PCB_EDIT_FRAME::ImportSpecctraSession( wxCommandEvent& event )
|
|||
OnModify();
|
||||
GetBoard()->m_Status_Pcb = 0;
|
||||
|
||||
Compile_Ratsnest( NULL, true );
|
||||
GetBoard()->GetRatsnest()->ProcessBoard();
|
||||
GetBoard()->GetConnectivity()->Clear();
|
||||
GetBoard()->GetConnectivity()->Build( GetBoard() );
|
||||
|
||||
if( GetGalCanvas() ) // Update view:
|
||||
{
|
||||
|
|
|
@ -747,9 +747,7 @@ void PCB_EDIT_FRAME::OnSelectOptionToolbar( wxCommandEvent& event )
|
|||
case ID_TB_OPTIONS_SHOW_RATSNEST:
|
||||
SetElementVisibility( LAYER_RATSNEST, state );
|
||||
OnModify();
|
||||
|
||||
if( state && (GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
|
||||
Compile_Ratsnest( NULL, true );
|
||||
Compile_Ratsnest( NULL, true );
|
||||
|
||||
m_canvas->Refresh();
|
||||
break;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <pcbnew.h>
|
||||
#include <protos.h>
|
||||
|
||||
#include <connectivity.h>
|
||||
|
||||
static void ListSetState( EDA_ITEM* Start, int NbItem, STATUS_FLAGS State,
|
||||
bool onoff );
|
||||
|
@ -267,11 +268,13 @@ int PCB_EDIT_FRAME::EraseRedundantTrack( wxDC* aDC,
|
|||
pt_del->UnLink();
|
||||
pt_del->SetStatus( 0 );
|
||||
pt_del->ClearFlags();
|
||||
GetBoard()->GetConnectivity()->Remove ( pt_del );
|
||||
ITEM_PICKER picker( pt_del, UR_DELETED );
|
||||
aItemsListPicker->PushItem( picker );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetBoard()->GetConnectivity()->Remove ( pt_del );
|
||||
pt_del->DeleteStructure();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,10 +185,10 @@ int PCB_EDIT_FRAME::Fill_All_Zones( wxWindow * aActiveWindow, bool aVerbose )
|
|||
aActiveWindow->Raise();
|
||||
#endif
|
||||
}
|
||||
TestConnections();
|
||||
//TestConnections();
|
||||
|
||||
// Recalculate the active ratsnest, i.e. the unconnected links
|
||||
TestForActiveLinksInRatsnest( 0 );
|
||||
//TestForActiveLinksInRatsnest( 0 );
|
||||
if( progressDialog )
|
||||
progressDialog->Destroy();
|
||||
return errorLevel;
|
||||
|
|
Loading…
Reference in New Issue