Removed legacy connectivity/ratsnest algorithm, replaced with the new one. No legacy autorouting for the moment

This commit is contained in:
Tomasz Włostowski 2017-03-22 14:51:07 +01:00
parent 9ad886344b
commit 3cba1007eb
43 changed files with 500 additions and 2481 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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() ) )
{

View File

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

View File

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

View File

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

View File

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

View File

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

View 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:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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