Removed legacy connectivity/ratsnest algorithm, replaced with the new one. No legacy autorouting for the moment
This commit is contained in:
parent
9ad886344b
commit
3cba1007eb
|
@ -481,7 +481,7 @@ public:
|
||||||
* It shows the connections from a pad to the nearest connected pad
|
* It shows the connections from a pad to the nearest connected pad
|
||||||
* @param aModule = module to consider.
|
* @param aModule = module to consider.
|
||||||
*/
|
*/
|
||||||
void build_ratsnest_module( MODULE* aModule );
|
void build_ratsnest_module( MODULE *mod, wxPoint aMoveVector );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function TraceModuleRatsNest
|
* Function TraceModuleRatsNest
|
||||||
|
@ -526,7 +526,8 @@ public:
|
||||||
* When aInit = false, aItemRef is not used (can be NULL)
|
* When aInit = false, aItemRef is not used (can be NULL)
|
||||||
*/
|
*/
|
||||||
void BuildAirWiresTargetsList( BOARD_CONNECTED_ITEM* aItemRef,
|
void BuildAirWiresTargetsList( BOARD_CONNECTED_ITEM* aItemRef,
|
||||||
const wxPoint& aPosition, bool aInit );
|
const wxPoint& aPosition,
|
||||||
|
int aNet );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function TestForActiveLinksInRatsnest
|
* Function TestForActiveLinksInRatsnest
|
||||||
|
|
|
@ -184,25 +184,13 @@ set( PCBNEW_EXPORTERS
|
||||||
exporters/gendrill_gerber_writer.cpp
|
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
|
set( PCBNEW_MICROWAVE_SRCS
|
||||||
microwave/microwave_inductor.cpp
|
microwave/microwave_inductor.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set( PCBNEW_CLASS_SRCS
|
set( PCBNEW_CLASS_SRCS
|
||||||
|
autorouter/rect_placement/rect_placement.cpp
|
||||||
|
autorouter/spread_footprints.cpp
|
||||||
board_commit.cpp
|
board_commit.cpp
|
||||||
tool_modview.cpp
|
tool_modview.cpp
|
||||||
modview_frame.cpp
|
modview_frame.cpp
|
||||||
|
@ -299,7 +287,6 @@ set( PCBNEW_CLASS_SRCS
|
||||||
zone_filling_algorithm.cpp
|
zone_filling_algorithm.cpp
|
||||||
zones_functions_for_undo_redo.cpp
|
zones_functions_for_undo_redo.cpp
|
||||||
zones_polygons_insulated_copper_islands.cpp
|
zones_polygons_insulated_copper_islands.cpp
|
||||||
zones_polygons_test_connections.cpp
|
|
||||||
zones_test_and_combine_areas.cpp
|
zones_test_and_combine_areas.cpp
|
||||||
class_footprint_wizard.cpp
|
class_footprint_wizard.cpp
|
||||||
class_action_plugin.cpp
|
class_action_plugin.cpp
|
||||||
|
@ -334,7 +321,6 @@ set( PCBNEW_CLASS_SRCS
|
||||||
)
|
)
|
||||||
|
|
||||||
set( PCBNEW_SRCS
|
set( PCBNEW_SRCS
|
||||||
${PCBNEW_AUTOROUTER_SRCS}
|
|
||||||
${PCBNEW_MICROWAVE_SRCS}
|
${PCBNEW_MICROWAVE_SRCS}
|
||||||
${PCBNEW_CLASS_SRCS}
|
${PCBNEW_CLASS_SRCS}
|
||||||
${PCBNEW_DIALOGS}
|
${PCBNEW_DIALOGS}
|
||||||
|
@ -622,7 +608,6 @@ add_library( pcbnew_kiface MODULE
|
||||||
${PCBNEW_COMMON_SRCS}
|
${PCBNEW_COMMON_SRCS}
|
||||||
${PCBNEW_SCRIPTING_SRCS}
|
${PCBNEW_SCRIPTING_SRCS}
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties( pcbnew_kiface PROPERTIES
|
set_target_properties( pcbnew_kiface PROPERTIES
|
||||||
# Decorate OUTPUT_NAME with PREFIX and SUFFIX, creating something like
|
# Decorate OUTPUT_NAME with PREFIX and SUFFIX, creating something like
|
||||||
# _pcbnew.so, _pcbnew.dll, or _pcbnew.kiface
|
# _pcbnew.so, _pcbnew.dll, or _pcbnew.kiface
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
#include <pcbnew.h>
|
#include <pcbnew.h>
|
||||||
#include <protos.h>
|
#include <protos.h>
|
||||||
|
|
||||||
|
#include <connectivity.h>
|
||||||
|
|
||||||
#define BLOCK_OUTLINE_COLOR YELLOW
|
#define BLOCK_OUTLINE_COLOR YELLOW
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -536,6 +538,7 @@ void PCB_EDIT_FRAME::Block_Delete()
|
||||||
{
|
{
|
||||||
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
||||||
itemsList->SetPickedItemStatus( UR_DELETED, ii );
|
itemsList->SetPickedItemStatus( UR_DELETED, ii );
|
||||||
|
GetBoard()->GetConnectivity()->Remove( item );
|
||||||
|
|
||||||
switch( item->Type() )
|
switch( item->Type() )
|
||||||
{
|
{
|
||||||
|
@ -599,6 +602,7 @@ void PCB_EDIT_FRAME::Block_Rotate()
|
||||||
{
|
{
|
||||||
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
||||||
wxASSERT( item );
|
wxASSERT( item );
|
||||||
|
|
||||||
itemsList->SetPickedItemStatus( UR_CHANGED, ii );
|
itemsList->SetPickedItemStatus( UR_CHANGED, ii );
|
||||||
|
|
||||||
switch( item->Type() )
|
switch( item->Type() )
|
||||||
|
@ -642,6 +646,7 @@ void PCB_EDIT_FRAME::Block_Rotate()
|
||||||
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
||||||
wxASSERT( item );
|
wxASSERT( item );
|
||||||
item->Rotate( centre, rotAngle );
|
item->Rotate( centre, rotAngle );
|
||||||
|
GetBoard()->GetConnectivity()->Update( item );
|
||||||
}
|
}
|
||||||
|
|
||||||
Compile_Ratsnest( NULL, true );
|
Compile_Ratsnest( NULL, true );
|
||||||
|
@ -667,6 +672,7 @@ void PCB_EDIT_FRAME::Block_Flip()
|
||||||
wxASSERT( item );
|
wxASSERT( item );
|
||||||
itemsList->SetPickedItemStatus( UR_FLIPPED, ii );
|
itemsList->SetPickedItemStatus( UR_FLIPPED, ii );
|
||||||
item->Flip( center );
|
item->Flip( center );
|
||||||
|
GetBoard()->GetConnectivity()->Update( item );
|
||||||
|
|
||||||
// If a connected item is flipped, the ratsnest is no more OK
|
// If a connected item is flipped, the ratsnest is no more OK
|
||||||
switch( item->Type() )
|
switch( item->Type() )
|
||||||
|
@ -721,6 +727,7 @@ void PCB_EDIT_FRAME::Block_Move()
|
||||||
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
|
||||||
itemsList->SetPickedItemStatus( UR_MOVED, ii );
|
itemsList->SetPickedItemStatus( UR_MOVED, ii );
|
||||||
item->Move( MoveVector );
|
item->Move( MoveVector );
|
||||||
|
GetBoard()->GetConnectivity()->Update( item );
|
||||||
item->ClearFlags( IS_MOVED );
|
item->ClearFlags( IS_MOVED );
|
||||||
|
|
||||||
switch( item->Type() )
|
switch( item->Type() )
|
||||||
|
|
|
@ -596,7 +596,7 @@ bool BOARD_NETLIST_UPDATER::testConnectivity( NETLIST& aNetlist )
|
||||||
if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() )
|
if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int nc = zone->GetNet()->GetNodesCount();
|
int nc = m_board->GetConnectivity()->GetPadCount( zone->GetNetCode() );
|
||||||
|
|
||||||
if( nc == 0 )
|
if( nc == 0 )
|
||||||
{
|
{
|
||||||
|
@ -668,7 +668,6 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
|
||||||
if( !m_isDryRun )
|
if( !m_isDryRun )
|
||||||
{
|
{
|
||||||
m_commit.Push( _( "Update netlist" ) );
|
m_commit.Push( _( "Update netlist" ) );
|
||||||
m_frame->Compile_Ratsnest( NULL, false );
|
|
||||||
m_board->GetConnectivity()->Build( m_board );
|
m_board->GetConnectivity()->Build( m_board );
|
||||||
testConnectivity( aNetlist );
|
testConnectivity( aNetlist );
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,9 +120,6 @@ BOARD::~BOARD()
|
||||||
Delete( area_to_remove );
|
Delete( area_to_remove );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_FullRatsnest.clear();
|
|
||||||
m_LocalRatsnest.clear();
|
|
||||||
|
|
||||||
DeleteMARKERs();
|
DeleteMARKERs();
|
||||||
DeleteZONEOutlines();
|
DeleteZONEOutlines();
|
||||||
|
|
||||||
|
@ -1157,20 +1154,8 @@ void BOARD::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList )
|
||||||
txt.Printf( wxT( "%d" ), m_NetInfo.GetNetCount() );
|
txt.Printf( wxT( "%d" ), m_NetInfo.GetNetCount() );
|
||||||
aList.push_back( MSG_PANEL_ITEM( _( "Nets" ), txt, RED ) );
|
aList.push_back( MSG_PANEL_ITEM( _( "Nets" ), txt, RED ) );
|
||||||
|
|
||||||
/* These parameters are known only if the full ratsnest is available,
|
txt.Printf( wxT( "%d" ), GetConnectivity()->GetUnconnectedCount() );
|
||||||
* so, display them only if this is the case
|
aList.push_back( MSG_PANEL_ITEM( _( "Unconnected" ), txt, BLUE ) );
|
||||||
*/
|
|
||||||
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 ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
// 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 )
|
static bool sortNetsByNodes( const NETINFO_ITEM* a, const NETINFO_ITEM* b )
|
||||||
{
|
{
|
||||||
if( b->GetNodesCount() == a->GetNodesCount() )
|
auto connectivity = a->GetParent()->GetConnectivity();
|
||||||
return a->GetNetname() < b->GetNetname();
|
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
|
// 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 )
|
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 )
|
if( pad->GetPosition() != aPosition )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1630,8 +1619,9 @@ D_PAD* BOARD::GetPadFast( const wxPoint& aPosition, LSET aLayerSet )
|
||||||
if( ( pad->GetLayerSet() & aLayerSet ).any() )
|
if( ( pad->GetLayerSet() & aLayerSet ).any() )
|
||||||
return pad;
|
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 )
|
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(),
|
for ( auto pad : mod->PadsIter( ) )
|
||||||
m_NetInfo.m_PadsFullList.end() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const NETINFO_ITEM* net = m_NetInfo.GetNetItem( aNetCode );
|
|
||||||
if( net )
|
|
||||||
{
|
{
|
||||||
aVector.insert( aVector.end(), net->m_PadInNetList.begin(),
|
if( aNetCode < 0 || pad->GetNetCode() == aNetCode )
|
||||||
net->m_PadInNetList.end() );
|
{
|
||||||
|
aVector.push_back( pad );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort( aVector.begin(), aVector.end(), sortPadsByXthenYCoord );
|
std::sort( aVector.begin(), aVector.end(), sortPadsByXthenYCoord );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BOARD::PadDelete( D_PAD* aPad )
|
void BOARD::PadDelete( D_PAD* aPad )
|
||||||
{
|
{
|
||||||
m_NetInfo.DeletePad( aPad );
|
|
||||||
|
|
||||||
aPad->DeleteStructure();
|
aPad->DeleteStructure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2830,7 +2814,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets,
|
||||||
if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() )
|
if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( zone->GetNet()->GetNodesCount() == 0 )
|
if( GetConnectivity()->GetPadCount( zone->GetNetCode() ) == 0 )
|
||||||
{
|
{
|
||||||
msg.Printf( _( "Copper zone (net name '%s'): net has no pads connected." ),
|
msg.Printf( _( "Copper zone (net name '%s'): net has no pads connected." ),
|
||||||
GetChars( zone->GetNet()->GetNetname() ) );
|
GetChars( zone->GetNet()->GetNetname() ) );
|
||||||
|
@ -2900,3 +2884,42 @@ bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
|
||||||
{
|
{
|
||||||
return m_connectivity->GetRatsnest();
|
return m_connectivity->GetRatsnest();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
const std::vector<D_PAD*> BOARD::GetPads()
|
||||||
|
{
|
||||||
|
std::vector<D_PAD*> rv;
|
||||||
|
for ( auto mod: Modules() )
|
||||||
|
{
|
||||||
|
for ( auto pad: mod->PadsIter() )
|
||||||
|
rv.push_back ( pad );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned BOARD::GetPadCount() const
|
||||||
|
{
|
||||||
|
return m_connectivity->GetPadCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetPad
|
||||||
|
* @return D_PAD* - at the \a aIndex
|
||||||
|
*/
|
||||||
|
D_PAD* BOARD::GetPad( unsigned aIndex ) const
|
||||||
|
{
|
||||||
|
unsigned count = 0;
|
||||||
|
for ( MODULE *mod = m_Modules; mod ; mod = mod->Next() ) // FIXME: const DLIST_ITERATOR
|
||||||
|
{
|
||||||
|
for ( D_PAD *pad = mod->Pads(); pad; pad = pad->Next() )
|
||||||
|
{
|
||||||
|
if ( count == aIndex )
|
||||||
|
return pad;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -257,15 +257,11 @@ public:
|
||||||
DLIST_ITERATOR_WRAPPER<MODULE> Modules() { return DLIST_ITERATOR_WRAPPER<MODULE>(m_Modules); }
|
DLIST_ITERATOR_WRAPPER<MODULE> Modules() { return DLIST_ITERATOR_WRAPPER<MODULE>(m_Modules); }
|
||||||
DLIST_ITERATOR_WRAPPER<BOARD_ITEM> Drawings() { return DLIST_ITERATOR_WRAPPER<BOARD_ITEM>(m_Drawings); }
|
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
|
// will be deprecated as soon as append board functionality is fixed
|
||||||
DLIST<BOARD_ITEM>& DrawingsList() { return m_Drawings; }
|
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 contour currently in progress
|
||||||
ZONE_CONTAINER* m_CurrentZoneContour;
|
ZONE_CONTAINER* m_CurrentZoneContour;
|
||||||
|
|
||||||
|
@ -712,15 +708,6 @@ public:
|
||||||
/** Calculate the zone segment count */
|
/** Calculate the zone segment count */
|
||||||
int GetNumSegmZone() const;
|
int GetNumSegmZone() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Function GetNumRatsnests
|
|
||||||
* @return int - The number of rats
|
|
||||||
*/
|
|
||||||
unsigned GetRatsnestsCount() const
|
|
||||||
{
|
|
||||||
return m_FullRatsnest.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetNodesCount
|
* Function GetNodesCount
|
||||||
* @return the number of pads members of nets (i.e. with netcode > 0)
|
* @return the number of pads members of nets (i.e. with netcode > 0)
|
||||||
|
@ -753,19 +740,13 @@ public:
|
||||||
* Function GetPadCount
|
* Function GetPadCount
|
||||||
* @return the number of pads in board
|
* @return the number of pads in board
|
||||||
*/
|
*/
|
||||||
unsigned GetPadCount() const
|
unsigned GetPadCount() const;
|
||||||
{
|
|
||||||
return m_NetInfo.GetPadCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetPad
|
* 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
|
D_PAD* GetPad( unsigned aIndex ) const;
|
||||||
{
|
|
||||||
return m_NetInfo.GetPad( aIndex );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetPads
|
* Function GetPads
|
||||||
|
@ -774,7 +755,7 @@ public:
|
||||||
* ownership of the respective PADs.
|
* ownership of the respective PADs.
|
||||||
* @return D_PADS - a full list of 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()
|
void BuildListOfNets()
|
||||||
{
|
{
|
||||||
|
@ -1192,14 +1173,6 @@ public:
|
||||||
int Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_Examine,
|
int Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_Examine,
|
||||||
bool aCreate_Markers );
|
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
|
* Function GetViaByPosition
|
||||||
|
|
|
@ -48,15 +48,7 @@ class CN_BOARD_ITEM_DATA;
|
||||||
*/
|
*/
|
||||||
class BOARD_CONNECTED_ITEM : public BOARD_ITEM
|
class BOARD_CONNECTED_ITEM : public BOARD_ITEM
|
||||||
{
|
{
|
||||||
friend class CONNECTIONS;
|
|
||||||
|
|
||||||
public:
|
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 );
|
BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype );
|
||||||
|
|
||||||
// Do not create a copy constructor & operator=.
|
// Do not create a copy constructor & operator=.
|
||||||
|
|
|
@ -60,61 +60,6 @@ class MSG_PANEL_ITEM;
|
||||||
#define CH_ACTIF 8 /* Not routed. */
|
#define CH_ACTIF 8 /* Not routed. */
|
||||||
#define LOCAL_RATSNEST_ITEM 0x8000 /* Line between two pads of a single module. */
|
#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* )
|
DECL_VEC_FOR_SWIG( D_PADS, D_PAD* )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -142,25 +87,6 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
D_PADS& Pads() { return m_PadInNetList; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function GetNodesCount
|
|
||||||
* @return int - number of pad nodes in the net
|
|
||||||
*/
|
|
||||||
int GetNodesCount() const { return m_PadInNetList.size(); }
|
|
||||||
|
|
||||||
|
|
||||||
D_PADS m_PadInNetList; ///< List of pads connected to this net
|
|
||||||
|
|
||||||
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( BOARD* aParent, const wxString& aNetName = wxEmptyString, int aNetCode = -1 );
|
||||||
~NETINFO_ITEM();
|
~NETINFO_ITEM();
|
||||||
|
|
||||||
|
@ -340,12 +266,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void Clear()
|
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() );
|
SetClass( NETCLASSPTR() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,15 +460,6 @@ public:
|
||||||
* Function GetPadCount
|
* Function GetPadCount
|
||||||
* @return the number of pads in board
|
* @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.
|
/// Return the name map, at least for python.
|
||||||
const NETNAMES_MAP& NetsByName() const { return m_netNames; }
|
const NETNAMES_MAP& NetsByName() const { return m_netNames; }
|
||||||
|
@ -556,14 +467,6 @@ public:
|
||||||
/// Return the netcode map, at least for python.
|
/// Return the netcode map, at least for python.
|
||||||
const NETCODES_MAP& NetsByNetcode() const { return m_netCodes; }
|
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)
|
///> Constant that holds the "unconnected net" number (typically 0)
|
||||||
///> all items "connected" to this net are actually not connected items
|
///> all items "connected" to this net are actually not connected items
|
||||||
static const int UNCONNECTED;
|
static const int UNCONNECTED;
|
||||||
|
@ -680,9 +583,6 @@ private:
|
||||||
NETNAMES_MAP m_netNames; ///< map of <wxString, NETINFO_ITEM*>, is NETINFO_ITEM owner
|
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
|
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
|
int m_newNetCode; ///< possible value for new net code assignment
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -695,17 +595,13 @@ private:
|
||||||
#define START_ON_TRACK 0x40
|
#define START_ON_TRACK 0x40
|
||||||
#define END_ON_TRACK 0x80
|
#define END_ON_TRACK 0x80
|
||||||
|
|
||||||
|
|
||||||
/* Status bit (OR'ed bits) for class BOARD member .m_Status_Pcb */
|
/* Status bit (OR'ed bits) for class BOARD member .m_Status_Pcb */
|
||||||
enum StatusPcbFlags {
|
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 */
|
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
|
DO_NOT_SHOW_GENERAL_RASTNEST = 0x20 /* Do not display the general
|
||||||
* ratsnest (used in module moves) */
|
* ratsnest (used in module moves) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // CLASS_NETINFO_
|
#endif // CLASS_NETINFO_
|
||||||
|
|
|
@ -54,10 +54,6 @@ NETINFO_ITEM::NETINFO_ITEM( BOARD* aParent, const wxString& aNetName, int aNetCo
|
||||||
m_NetCode( aNetCode ), m_Netname( aNetName ), m_ShortNetname( m_Netname.AfterLast( '/' ) )
|
m_NetCode( aNetCode ), m_Netname( aNetName ), m_ShortNetname( m_Netname.AfterLast( '/' ) )
|
||||||
{
|
{
|
||||||
m_parent = aParent;
|
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;
|
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):
|
// Displays the net length of internal ICs connections (wires inside ICs):
|
||||||
txt = ::LengthDoubleToString( lengthPadToDie );
|
txt = ::LengthDoubleToString( lengthPadToDie );
|
||||||
aList.push_back( MSG_PANEL_ITEM( _( "In Package" ), txt, RED ) );
|
aList.push_back( MSG_PANEL_ITEM( _( "In Package" ), txt, RED ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************/
|
|
||||||
/* class RATSNEST_ITEM */
|
|
||||||
/***********************/
|
|
||||||
|
|
||||||
RATSNEST_ITEM::RATSNEST_ITEM()
|
|
||||||
{
|
|
||||||
m_NetCode = 0; // netcode ( = 1.. n , 0 is the value used for not
|
|
||||||
// connected items)
|
|
||||||
m_Status = 0; // state
|
|
||||||
m_PadStart = NULL; // pointer to the starting pad
|
|
||||||
m_PadEnd = NULL; // pointer to ending pad
|
|
||||||
m_Length = 0; // length of the line (temporary used in some
|
|
||||||
// calculations)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Draw
|
|
||||||
* Draws a line (a ratsnest) from the starting pad to the ending pad
|
|
||||||
*/
|
|
||||||
void RATSNEST_ITEM::Draw( EDA_DRAW_PANEL* panel,
|
|
||||||
wxDC* DC,
|
|
||||||
GR_DRAWMODE aDrawMode,
|
|
||||||
const wxPoint& aOffset )
|
|
||||||
{
|
|
||||||
GRSetDrawMode( DC, aDrawMode );
|
|
||||||
|
|
||||||
COLOR4D color = g_ColorsSettings.GetItemColor( LAYER_RATSNEST );
|
|
||||||
|
|
||||||
GRLine( panel->GetClipBox(), DC,
|
|
||||||
m_PadStart->GetPosition() - aOffset,
|
|
||||||
m_PadEnd->GetPosition() - aOffset, 0, color );
|
|
||||||
}
|
|
|
@ -62,7 +62,6 @@ void NETINFO_LIST::clear()
|
||||||
for( it = m_netNames.begin(), itEnd = m_netNames.end(); it != itEnd; ++it )
|
for( it = m_netNames.begin(), itEnd = m_netNames.end(); it != itEnd; ++it )
|
||||||
delete it->second;
|
delete it->second;
|
||||||
|
|
||||||
m_PadsFullList.clear();
|
|
||||||
m_netNames.clear();
|
m_netNames.clear();
|
||||||
m_netCodes.clear();
|
m_netCodes.clear();
|
||||||
m_newNetCode = 0;
|
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
|
/* sort function, to sort pad list by netnames
|
||||||
* this is a case sensitive sort.
|
* this is a case sensitive sort.
|
||||||
* DO NOT change it because NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname )
|
* DO NOT change it because NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname )
|
||||||
|
@ -199,47 +172,15 @@ void NETINFO_LIST::buildListOfNets()
|
||||||
D_PAD* pad;
|
D_PAD* pad;
|
||||||
int nodes_count = 0;
|
int nodes_count = 0;
|
||||||
|
|
||||||
// Build the PAD list, sorted by net
|
|
||||||
buildPadsFullList();
|
|
||||||
|
|
||||||
// Restore the initial state of NETINFO_ITEMs
|
// Restore the initial state of NETINFO_ITEMs
|
||||||
for( NETINFO_LIST::iterator net( begin() ), netEnd( end() ); net != netEnd; ++net )
|
for( NETINFO_LIST::iterator net( begin() ), netEnd( end() ); net != netEnd; ++net )
|
||||||
net->Clear();
|
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->SynchronizeNetsAndNetClasses( );
|
||||||
|
|
||||||
m_Parent->m_Status_Pcb |= NET_CODES_OK;
|
|
||||||
|
|
||||||
m_Parent->SetAreasNetCodesFromNetNames();
|
m_Parent->SetAreasNetCodesFromNetNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
void NETINFO_LIST::Show() const
|
void NETINFO_LIST::Show() const
|
||||||
{
|
{
|
||||||
|
@ -255,46 +196,6 @@ void NETINFO_LIST::Show() const
|
||||||
#endif
|
#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()
|
int NETINFO_LIST::getFreeNetCode()
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
|
@ -373,4 +274,4 @@ NETINFO_ITEM* NETINFO_MAPPING::iterator::operator->() const
|
||||||
const int NETINFO_LIST::UNCONNECTED = 0;
|
const int NETINFO_LIST::UNCONNECTED = 0;
|
||||||
const int NETINFO_LIST::ORPHANED = -1;
|
const int NETINFO_LIST::ORPHANED = -1;
|
||||||
|
|
||||||
NETINFO_ITEM NETINFO_LIST::ORPHANED_ITEM = NETINFO_ITEM( NULL, wxEmptyString, NETINFO_LIST::UNCONNECTED );
|
NETINFO_ITEM NETINFO_LIST::ORPHANED_ITEM = NETINFO_ITEM( NULL, wxEmptyString, NETINFO_LIST::UNCONNECTED );
|
||||||
|
|
120
pcbnew/clean.cpp
120
pcbnew/clean.cpp
|
@ -35,14 +35,12 @@
|
||||||
#include <pcbnew.h>
|
#include <pcbnew.h>
|
||||||
#include <class_board.h>
|
#include <class_board.h>
|
||||||
#include <class_track.h>
|
#include <class_track.h>
|
||||||
#include <connect.h>
|
|
||||||
#include <dialog_cleaning_options.h>
|
#include <dialog_cleaning_options.h>
|
||||||
#include <board_commit.h>
|
#include <board_commit.h>
|
||||||
|
#include <connectivity.h>
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
// Helper class used to clean tracks and vias
|
// Helper class used to clean tracks and vias
|
||||||
class TRACKS_CLEANER: CONNECTIONS
|
class TRACKS_CLEANER
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TRACKS_CLEANER( BOARD* aPcb, BOARD_COMMIT& aCommit );
|
TRACKS_CLEANER( BOARD* aPcb, BOARD_COMMIT& aCommit );
|
||||||
|
@ -69,7 +67,7 @@ private:
|
||||||
* Removes redundant vias like vias at same location
|
* Removes redundant vias like vias at same location
|
||||||
* or on pad through
|
* or on pad through
|
||||||
*/
|
*/
|
||||||
bool clean_vias();
|
bool cleanupVias();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all the following THT vias on the same position of the
|
* Removes all the following THT vias on the same position of the
|
||||||
|
@ -98,12 +96,6 @@ private:
|
||||||
*/
|
*/
|
||||||
bool clean_segments();
|
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
|
* helper function
|
||||||
|
@ -147,7 +139,6 @@ void PCB_EDIT_FRAME::Clean_Pcb()
|
||||||
// Clear undo and redo lists to avoid inconsistencies between lists
|
// Clear undo and redo lists to avoid inconsistencies between lists
|
||||||
SetCurItem( NULL );
|
SetCurItem( NULL );
|
||||||
commit.Push( _( "Board cleanup" ) );
|
commit.Push( _( "Board cleanup" ) );
|
||||||
Compile_Ratsnest( NULL, true );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_canvas->Refresh( true );
|
m_canvas->Refresh( true );
|
||||||
|
@ -165,13 +156,12 @@ bool TRACKS_CLEANER::CleanupBoard( bool aRemoveMisConnected,
|
||||||
bool aMergeSegments,
|
bool aMergeSegments,
|
||||||
bool aDeleteUnconnected )
|
bool aDeleteUnconnected )
|
||||||
{
|
{
|
||||||
buildTrackConnectionInfo();
|
|
||||||
|
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
|
|
||||||
// delete redundant vias
|
// delete redundant vias
|
||||||
if( aCleanVias )
|
if( aCleanVias )
|
||||||
modified |= clean_vias();
|
modified |= cleanupVias();
|
||||||
|
|
||||||
// Remove null segments and intermediate points on aligned segments
|
// Remove null segments and intermediate points on aligned segments
|
||||||
// If not asked, remove null segments only if remove misconnected is asked
|
// If not asked, remove null segments only if remove misconnected is asked
|
||||||
|
@ -187,7 +177,7 @@ bool TRACKS_CLEANER::CleanupBoard( bool aRemoveMisConnected,
|
||||||
modified = true;
|
modified = true;
|
||||||
|
|
||||||
// Refresh track connection info
|
// Refresh track connection info
|
||||||
buildTrackConnectionInfo();
|
//buildTrackConnectionInfo(); FIXME: update connectivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +185,9 @@ bool TRACKS_CLEANER::CleanupBoard( bool aRemoveMisConnected,
|
||||||
if( aDeleteUnconnected )
|
if( aDeleteUnconnected )
|
||||||
{
|
{
|
||||||
if( modified ) // Refresh track connection info
|
if( modified ) // Refresh track connection info
|
||||||
buildTrackConnectionInfo();
|
{
|
||||||
|
//buildTrackConnectionInfo(); FIXME: update connectivity
|
||||||
|
}
|
||||||
|
|
||||||
if( deleteDanglingTracks() )
|
if( deleteDanglingTracks() )
|
||||||
{
|
{
|
||||||
|
@ -214,101 +206,37 @@ bool TRACKS_CLEANER::CleanupBoard( bool aRemoveMisConnected,
|
||||||
|
|
||||||
|
|
||||||
TRACKS_CLEANER::TRACKS_CLEANER( BOARD* aPcb, BOARD_COMMIT& aCommit )
|
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()
|
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;
|
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 );
|
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 );
|
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() != testedTrack->GetNetCode() && !testedTrack->GetState( FLAG0 ) )
|
||||||
|
|
||||||
if( segment->GetNetCode() != tested->GetNetCode() && !tested->GetState( FLAG0 ) )
|
|
||||||
segment->SetState( FLAG0, true );
|
segment->SetState( FLAG0, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove tracks having a flagged segment
|
// Remove tracks having a flagged segment
|
||||||
TRACK* next;
|
for( auto segment : m_brd->Tracks() )
|
||||||
|
|
||||||
for( segment = m_brd->m_Track; segment; segment = next )
|
|
||||||
{
|
{
|
||||||
next = segment->Next();
|
|
||||||
|
|
||||||
if( segment->GetState( FLAG0 ) ) // Segment is flagged to be removed
|
if( segment->GetState( FLAG0 ) ) // Segment is flagged to be removed
|
||||||
{
|
{
|
||||||
isModified = true;
|
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;
|
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;
|
bool modified = false;
|
||||||
|
|
||||||
|
@ -376,9 +295,10 @@ bool TRACKS_CLEANER::clean_vias()
|
||||||
/* To delete through Via on THT pads at same location
|
/* To delete through Via on THT pads at same location
|
||||||
* Examine the list of connected pads:
|
* Examine the list of connected pads:
|
||||||
* if one through pad is found, the via can be removed */
|
* 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();
|
const LSET all_cu = LSET::AllCuMask();
|
||||||
|
|
||||||
if( ( pad->GetLayerSet() & all_cu ) == all_cu )
|
if( ( pad->GetLayerSet() & all_cu ) == all_cu )
|
||||||
|
|
|
@ -39,756 +39,63 @@
|
||||||
// Helper classes to handle connection points
|
// Helper classes to handle connection points
|
||||||
#include <connect.h>
|
#include <connect.h>
|
||||||
|
|
||||||
const bool g_UseLegacyConnectionAlgo = false;
|
/*
|
||||||
|
* Function SortTracksByNetCode used in RebuildTrackChain()
|
||||||
extern void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb );
|
* to sort track segments by net code.
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
void CONNECTIONS::BuildPadsList( int aNetcode )
|
static bool SortTracksByNetCode( const TRACK* const & ref, const TRACK* const & compare )
|
||||||
{
|
{
|
||||||
// Creates sorted pad list if not exists
|
// For items having the same Net, keep the order in list
|
||||||
m_sortedPads.clear();
|
if( ref->GetNetCode() == compare->GetNetCode())
|
||||||
m_brd->GetSortedPadListByXthenYCoord( m_sortedPads, aNetcode < 0 ? -1 : aNetcode );
|
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
|
* Helper function RebuildTrackChain
|
||||||
* After that, 2 cluster (or subnets) are merged into only one.
|
* rebuilds the track segment linked list in order to have a chain
|
||||||
* Note: the resulting subnet value is the smallest between aOldSubNet et aNewSubNet
|
* 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 )
|
int item_count = pcb->m_Track.GetCount();
|
||||||
return 0;
|
|
||||||
|
|
||||||
if( (aOldSubNet > 0) && (aOldSubNet < aNewSubNet) )
|
std::vector<TRACK*> trackList;
|
||||||
std::swap( aOldSubNet, aNewSubNet );
|
trackList.reserve( item_count );
|
||||||
|
|
||||||
// Examine connections between intersecting pads
|
// Put track list in a temporary list to sort tracks by netcode
|
||||||
for( unsigned ii = 0; ii < m_sortedPads.size(); ii++ )
|
// 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];
|
pcb->m_Track->m_Param = ii;
|
||||||
if( curr_pad->GetSubNet() != aOldSubNet )
|
trackList.push_back( pcb->m_Track.PopFront() );
|
||||||
continue;
|
|
||||||
|
|
||||||
change_count++;
|
|
||||||
curr_pad->SetSubNet( aNewSubNet );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 )
|
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)
|
// Skip dummy net -1, and "not connected" net 0 (grouping all not connected pads)
|
||||||
if( aNetCode <= 0 )
|
if( aNetCode <= 0 )
|
||||||
return;
|
return;
|
||||||
|
@ -855,98 +162,5 @@ void PCB_BASE_FRAME::TestNetConnection( wxDC* aDC, int aNetCode )
|
||||||
SetStatusText( msg );
|
SetStatusText( msg );
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
#endif
|
||||||
|
|
||||||
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] );
|
|
||||||
}
|
}
|
||||||
|
|
225
pcbnew/connect.h
225
pcbnew/connect.h
|
@ -34,230 +34,5 @@
|
||||||
#include <class_board.h>
|
#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
|
#endif // ifndef CONNECT_H
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
#define PROFILE
|
|
||||||
|
|
||||||
#ifdef PROFILE
|
#ifdef PROFILE
|
||||||
#include <profile.h>
|
#include <profile.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -127,7 +125,6 @@ void CONNECTIVITY_DATA::updateRatsnest()
|
||||||
#ifdef PROFILE
|
#ifdef PROFILE
|
||||||
rnUpdate.Show();
|
rnUpdate.Show();
|
||||||
#endif /* PROFILE */
|
#endif /* PROFILE */
|
||||||
printf( "Dirty: %d\n", nDirty );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,6 +162,7 @@ void CONNECTIVITY_DATA::RecalculateRatsnest()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for( auto c : clusters )
|
for( auto c : clusters )
|
||||||
{
|
{
|
||||||
int net = c->OriginNet();
|
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;
|
std::vector<BOARD_CONNECTED_ITEM*> citems;
|
||||||
|
|
||||||
|
@ -231,7 +229,7 @@ void CONNECTIVITY_DATA::ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>&
|
||||||
|
|
||||||
m_dynamicRatsnest.clear();
|
m_dynamicRatsnest.clear();
|
||||||
|
|
||||||
blockRatsnestItems( aItems );
|
BlockRatsnestItems( aItems );
|
||||||
|
|
||||||
for( unsigned int nc = 1; nc < m_dynamicConnectivity->m_nets.size(); nc++ )
|
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
|
const KICAD_T aTypes[] ) const
|
||||||
{
|
{
|
||||||
std::list<BOARD_CONNECTED_ITEM*> rv;
|
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 )
|
for( auto cl : clusters )
|
||||||
if ( cl->Contains (aItem ) )
|
if( cl->Contains( aItem ) )
|
||||||
{
|
{
|
||||||
for ( const auto item : *cl )
|
for( const auto item : *cl )
|
||||||
rv.push_back( item->Parent() );
|
rv.push_back( item->Parent() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::list<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetNetItems(
|
const std::list<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetNetItems( int aNetCode,
|
||||||
int aNetCode,
|
|
||||||
const KICAD_T aTypes[] ) const
|
const KICAD_T aTypes[] ) const
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CONNECTIVITY_DATA::CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport )
|
bool CONNECTIVITY_DATA::CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport )
|
||||||
{
|
{
|
||||||
RecalculateRatsnest();
|
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;
|
CN_DISJOINT_NET_ENTRY ent;
|
||||||
ent.net = edge.GetSourceNode()->Parent()->GetNetCode();
|
ent.net = edge.GetSourceNode()->Parent()->GetNetCode();
|
||||||
ent.a = edge.GetSourceNode()->Parent();
|
ent.a = edge.GetSourceNode()->Parent();
|
||||||
ent.b = edge.GetTargetNode()->Parent();
|
ent.b = edge.GetTargetNode()->Parent();
|
||||||
ent.anchorA = edge.GetSourceNode()->Pos();
|
ent.anchorA = edge.GetSourceNode()->Pos();
|
||||||
ent.anchorB = edge.GetTargetNode()->Pos();
|
ent.anchorB = edge.GetTargetNode()->Pos();
|
||||||
aReport.push_back( ent );
|
aReport.push_back( ent );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return aReport.empty();
|
return aReport.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::vector<TRACK*> CONNECTIVITY_DATA::GetConnectedTracks( const BOARD_CONNECTED_ITEM* aItem )
|
||||||
|
const
|
||||||
|
{
|
||||||
|
auto& entry = m_connAlgo->ItemEntry( aItem );
|
||||||
|
|
||||||
|
std::set<TRACK*> tracks;
|
||||||
|
std::vector<TRACK*> rv;
|
||||||
|
|
||||||
|
for( auto citem : entry.GetItems() )
|
||||||
|
{
|
||||||
|
for( auto connected : citem->ConnectedItems() )
|
||||||
|
{
|
||||||
|
if( connected->Parent()->Type() == PCB_TRACE_T )
|
||||||
|
tracks.insert( static_cast<TRACK*> ( connected->Parent() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::copy( tracks.begin(), tracks.end(), std::back_inserter( rv ) );
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::vector<D_PAD*> CONNECTIVITY_DATA::GetConnectedPads( const BOARD_CONNECTED_ITEM* aItem )
|
||||||
|
const
|
||||||
|
{
|
||||||
|
auto& entry = m_connAlgo->ItemEntry( aItem );
|
||||||
|
|
||||||
|
std::set<D_PAD*> pads;
|
||||||
|
std::vector<D_PAD*> rv;
|
||||||
|
|
||||||
|
for( auto citem : entry.GetItems() )
|
||||||
|
{
|
||||||
|
for( auto connected : citem->ConnectedItems() )
|
||||||
|
{
|
||||||
|
if( connected->Parent()->Type() == PCB_PAD_T )
|
||||||
|
pads.insert( static_cast<D_PAD*> ( connected->Parent() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::copy( pads.begin(), pads.end(), std::back_inserter( rv ) );
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int CONNECTIVITY_DATA::GetLinksCount() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
assert( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int CONNECTIVITY_DATA::GetConnectedCount() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
assert( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int CONNECTIVITY_DATA::GetNodeCount( int aNet ) const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
assert( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int CONNECTIVITY_DATA::GetPadCount( int aNet ) const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
assert( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::vector<VECTOR2I> CONNECTIVITY_DATA::NearestUnconnectedTargets(
|
||||||
|
const BOARD_CONNECTED_ITEM* aRef,
|
||||||
|
const VECTOR2I& aPos,
|
||||||
|
int aNet )
|
||||||
|
{
|
||||||
|
CN_CLUSTER_PTR refCluster;
|
||||||
|
int refNet = -1;
|
||||||
|
|
||||||
|
if( aRef )
|
||||||
|
refNet = aRef->GetNetCode();
|
||||||
|
|
||||||
|
if( aNet >= 0 )
|
||||||
|
refNet = aNet;
|
||||||
|
|
||||||
|
if( aRef )
|
||||||
|
{
|
||||||
|
for( auto cl : m_connAlgo->GetClusters() )
|
||||||
|
{
|
||||||
|
if( cl->Contains( aRef ) )
|
||||||
|
{
|
||||||
|
refCluster = cl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set <VECTOR2I> anchors;
|
||||||
|
|
||||||
|
for( auto cl : m_connAlgo->GetClusters() )
|
||||||
|
{
|
||||||
|
if( cl != refCluster )
|
||||||
|
{
|
||||||
|
for( auto item : *cl )
|
||||||
|
{
|
||||||
|
if( item->Parent()->GetNetCode() == refNet
|
||||||
|
&& item->Parent()->Type() != PCB_ZONE_AREA_T )
|
||||||
|
for( auto anchor : item->Anchors() )
|
||||||
|
{
|
||||||
|
anchors.insert( anchor->Pos() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<VECTOR2I> rv;
|
||||||
|
|
||||||
|
std::copy( anchors.begin(), anchors.end(), std::back_inserter( rv ) );
|
||||||
|
std::sort( rv.begin(), rv.end(), [aPos] ( const VECTOR2I& a, const VECTOR2I& b )
|
||||||
|
{
|
||||||
|
auto da = (a - aPos).EuclideanNorm();
|
||||||
|
auto db = (b - aPos).EuclideanNorm();
|
||||||
|
|
||||||
|
return da < db;
|
||||||
|
} );
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ class BOARD_ITEM;
|
||||||
class ZONE_CONTAINER;
|
class ZONE_CONTAINER;
|
||||||
class RN_DATA;
|
class RN_DATA;
|
||||||
class RN_NET;
|
class RN_NET;
|
||||||
|
class TRACK;
|
||||||
|
class D_PAD;
|
||||||
|
|
||||||
struct CN_DISJOINT_NET_ENTRY
|
struct CN_DISJOINT_NET_ENTRY
|
||||||
{
|
{
|
||||||
|
@ -130,7 +132,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void PropagateNets();
|
void PropagateNets();
|
||||||
|
|
||||||
bool CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport );
|
bool CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function FindIsolatedCopperIslands()
|
* Function FindIsolatedCopperIslands()
|
||||||
|
@ -152,6 +154,18 @@ public:
|
||||||
*/
|
*/
|
||||||
unsigned int GetUnconnectedCount() const;
|
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()
|
* Function ClearDynamicRatsnest()
|
||||||
|
@ -188,11 +202,16 @@ public:
|
||||||
const std::list<BOARD_CONNECTED_ITEM*> GetNetItems( int aNetCode,
|
const std::list<BOARD_CONNECTED_ITEM*> GetNetItems( int aNetCode,
|
||||||
const KICAD_T aTypes[] ) const;
|
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:
|
private:
|
||||||
|
|
||||||
void updateRatsnest();
|
void updateRatsnest();
|
||||||
void addRatsnestCluster( std::shared_ptr<CN_CLUSTER> aCluster );
|
void addRatsnestCluster( std::shared_ptr<CN_CLUSTER> aCluster );
|
||||||
void blockRatsnestItems( const std::vector<BOARD_ITEM*>& aItems );
|
|
||||||
|
|
||||||
std::unique_ptr<CONNECTIVITY_DATA> m_dynamicConnectivity;
|
std::unique_ptr<CONNECTIVITY_DATA> m_dynamicConnectivity;
|
||||||
std::shared_ptr<CN_CONNECTIVITY_ALGO> m_connAlgo;
|
std::shared_ptr<CN_CONNECTIVITY_ALGO> m_connAlgo;
|
||||||
|
|
|
@ -160,10 +160,31 @@ public:
|
||||||
void SetTargetNode( const CN_ANCHOR_PTR& aNode ) { m_target = aNode; }
|
void SetTargetNode( const CN_ANCHOR_PTR& aNode ) { m_target = aNode; }
|
||||||
void SetWeight( unsigned int weight ) { m_weight = weight; }
|
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:
|
private:
|
||||||
CN_ANCHOR_PTR m_source;
|
CN_ANCHOR_PTR m_source;
|
||||||
CN_ANCHOR_PTR m_target;
|
CN_ANCHOR_PTR m_target;
|
||||||
unsigned int m_weight = 0;
|
unsigned int m_weight = 0;
|
||||||
|
bool m_visible = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CN_CLUSTER
|
class CN_CLUSTER
|
||||||
|
|
|
@ -238,10 +238,6 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete()
|
||||||
if( gen_rastnest )
|
if( gen_rastnest )
|
||||||
m_Parent->Compile_Ratsnest( NULL, true );
|
m_Parent->Compile_Ratsnest( NULL, true );
|
||||||
|
|
||||||
// There is a chance that some of tracks have changed their nets, so rebuild ratsnest from scratch
|
// There is a chance that some of tracks have changed their nets, so rebuild ratsnest from scratch
|
||||||
if( m_Parent->IsGalCanvasActive() )
|
m_Parent->GetCanvas()->Refresh();
|
||||||
pcb->GetRatsnest()->ProcessBoard();
|
|
||||||
else
|
|
||||||
m_Parent->GetCanvas()->Refresh();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <view/view.h>
|
#include <view/view.h>
|
||||||
#include <view/view_controls.h>
|
#include <view/view_controls.h>
|
||||||
#include <pcb_painter.h>
|
#include <pcb_painter.h>
|
||||||
|
#include <connectivity.h>
|
||||||
|
|
||||||
#define COL_NETNAME 0
|
#define COL_NETNAME 0
|
||||||
#define COL_NETINFO 1
|
#define COL_NETINFO 1
|
||||||
|
@ -141,7 +142,9 @@ void DIALOG_SELECT_NET_FROM_LIST::buildNetsList()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !m_cbShowZeroPad->IsChecked() && net->m_PadInNetList.size() == 0 )
|
unsigned nPads = m_brd->GetConnectivity()->GetPadCount( netcode );
|
||||||
|
|
||||||
|
if( !m_cbShowZeroPad->IsChecked() && nPads == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( m_netsListGrid->GetNumberRows() <= row_idx )
|
if( m_netsListGrid->GetNumberRows() <= row_idx )
|
||||||
|
@ -154,7 +157,7 @@ void DIALOG_SELECT_NET_FROM_LIST::buildNetsList()
|
||||||
|
|
||||||
if( netcode )
|
if( netcode )
|
||||||
{
|
{
|
||||||
txt.Printf( wxT( "%u" ), (unsigned) net->m_PadInNetList.size() );
|
txt.Printf( wxT( "%u" ), nPads );
|
||||||
m_netsListGrid->SetCellValue( row_idx, COL_NETINFO, txt );
|
m_netsListGrid->SetCellValue( row_idx, COL_NETINFO, txt );
|
||||||
}
|
}
|
||||||
else // For the net 0 (unconnected pads), the pad count is not known
|
else // For the net 0 (unconnected pads), the pad count is not known
|
||||||
|
|
|
@ -150,7 +150,7 @@ private:
|
||||||
/** Fills m_DragList with of track segments connected to pads in aConnections
|
/** Fills m_DragList with of track segments connected to pads in aConnections
|
||||||
* For each selected track segment the EDIT flag is set
|
* For each selected track segment the EDIT flag is set
|
||||||
*/
|
*/
|
||||||
void fillList( CONNECTIONS& aConnections );
|
void fillList( std::vector<D_PAD*>& aList );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,7 @@
|
||||||
|
|
||||||
#include <class_module.h>
|
#include <class_module.h>
|
||||||
#include <class_board.h>
|
#include <class_board.h>
|
||||||
#include <connect.h>
|
#include <connectivity.h>
|
||||||
|
|
||||||
|
|
||||||
/* a list of DRAG_SEGM_PICKER items used to move or drag tracks */
|
/* a list of DRAG_SEGM_PICKER items used to move or drag tracks */
|
||||||
std::vector<DRAG_SEGM_PICKER> g_DragSegmentList;
|
std::vector<DRAG_SEGM_PICKER> g_DragSegmentList;
|
||||||
|
@ -61,7 +60,6 @@ DRAG_SEGM_PICKER::DRAG_SEGM_PICKER( TRACK* aTrack )
|
||||||
m_Flipped = false;
|
m_Flipped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DRAG_SEGM_PICKER::SetAuxParameters()
|
void DRAG_SEGM_PICKER::SetAuxParameters()
|
||||||
{
|
{
|
||||||
MODULE* module = NULL;
|
MODULE* module = NULL;
|
||||||
|
@ -155,16 +153,14 @@ void DRAG_LIST::BuildDragListe( MODULE* aModule )
|
||||||
m_Pad = NULL;
|
m_Pad = NULL;
|
||||||
m_Module = aModule;
|
m_Module = aModule;
|
||||||
|
|
||||||
// Build connections info
|
std::vector<D_PAD*> padList;
|
||||||
CONNECTIONS connections( m_Brd );
|
|
||||||
std::vector<D_PAD*>&padList = connections.GetPadsList();
|
|
||||||
|
|
||||||
for( D_PAD* pad = aModule->Pads(); pad; pad = pad->Next() )
|
for ( auto pad : aModule->PadsIter() )
|
||||||
padList.push_back( pad );
|
padList.push_back( pad );
|
||||||
|
|
||||||
sort( padList.begin(), padList.end(), sortPadsByXthenYCoord );
|
sort( padList.begin(), padList.end(), sortPadsByXthenYCoord );
|
||||||
|
|
||||||
fillList( connections );
|
fillList( padList );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,11 +170,10 @@ void DRAG_LIST::BuildDragListe( D_PAD* aPad )
|
||||||
m_Module = NULL;
|
m_Module = NULL;
|
||||||
|
|
||||||
// Build connections info
|
// Build connections info
|
||||||
CONNECTIONS connections( m_Brd );
|
std::vector<D_PAD*> padList;
|
||||||
std::vector<D_PAD*>&padList = connections.GetPadsList();
|
|
||||||
padList.push_back( aPad );
|
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;
|
return ref.m_Track < tst.m_Track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DRAG_LIST::fillList( std::vector<D_PAD*>& aList )
|
||||||
void DRAG_LIST::fillList( CONNECTIONS& aConnections )
|
|
||||||
{
|
{
|
||||||
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
|
// 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
|
// 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->start = NULL;
|
||||||
track->end = NULL;
|
track->end = NULL;
|
||||||
track->SetState( START_ON_PAD|END_ON_PAD|BUSY, false );
|
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
|
// 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
|
// 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() ) )
|
if( pad->HitTest( track->GetStart() ) )
|
||||||
{
|
{
|
||||||
|
|
|
@ -196,19 +196,6 @@ void DRC::RunTests( wxTextCtrl* aMessages )
|
||||||
// ( the board can be reloaded )
|
// ( the board can be reloaded )
|
||||||
m_pcb = m_pcbEditorFrame->GetBoard();
|
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.
|
// someone should have cleared the two lists before calling this.
|
||||||
|
|
||||||
if( !testNetClasses() )
|
if( !testNetClasses() )
|
||||||
|
@ -636,7 +623,7 @@ void DRC::testZones()
|
||||||
// perhaps a "dead" net, which happens when all pads in this net were removed
|
// 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)
|
// Remark: a netcode < 0 should not happen (this is more a bug somewhere)
|
||||||
int pads_in_net = (test_area->GetNetCode() > 0) ?
|
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 )
|
if( ( netcode < 0 ) || pads_in_net == 0 )
|
||||||
{
|
{
|
||||||
|
|
|
@ -663,8 +663,6 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCurItem( NULL ); // CurItem might be deleted by this command, clear the pointer
|
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();
|
OnModify();
|
||||||
SetMsgPanel( GetBoard() );
|
SetMsgPanel( GetBoard() );
|
||||||
m_canvas->Refresh();
|
m_canvas->Refresh();
|
||||||
|
@ -673,7 +671,6 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
||||||
case ID_POPUP_PCB_FILL_ZONE:
|
case ID_POPUP_PCB_FILL_ZONE:
|
||||||
m_canvas->MoveCursorToCrossHair();
|
m_canvas->MoveCursorToCrossHair();
|
||||||
Fill_Zone( (ZONE_CONTAINER*) GetCurItem() );
|
Fill_Zone( (ZONE_CONTAINER*) GetCurItem() );
|
||||||
TestNetConnection( NULL, ( (ZONE_CONTAINER*) GetCurItem() )->GetNetCode() );
|
|
||||||
SetMsgPanel( GetBoard() );
|
SetMsgPanel( GetBoard() );
|
||||||
m_canvas->Refresh();
|
m_canvas->Refresh();
|
||||||
break;
|
break;
|
||||||
|
@ -1449,11 +1446,7 @@ void PCB_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent )
|
||||||
SetToolID( id, wxCURSOR_PENCIL, _( "Add tracks" ) );
|
SetToolID( id, wxCURSOR_PENCIL, _( "Add tracks" ) );
|
||||||
else
|
else
|
||||||
SetToolID( id, wxCURSOR_QUESTION_ARROW, _( "Add tracks" ) );
|
SetToolID( id, wxCURSOR_QUESTION_ARROW, _( "Add tracks" ) );
|
||||||
|
|
||||||
if( (GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
|
|
||||||
{
|
|
||||||
Compile_Ratsnest( &dc, true );
|
Compile_Ratsnest( &dc, true );
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1523,8 +1516,7 @@ void PCB_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent )
|
||||||
case ID_PCB_SHOW_1_RATSNEST_BUTT:
|
case ID_PCB_SHOW_1_RATSNEST_BUTT:
|
||||||
SetToolID( id, wxCURSOR_HAND, _( "Select rats nest" ) );
|
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;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -227,9 +227,9 @@ void PCB_EDIT_FRAME::Show_1_Ratsnest( EDA_ITEM* item, wxDC* DC )
|
||||||
if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) )
|
if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) )
|
||||||
return;
|
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 )
|
||||||
{
|
{
|
||||||
if( item->Type() == PCB_PAD_T )
|
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++ )
|
for( unsigned ii = 0; ii < GetBoard()->GetRatsnestsCount(); ii++ )
|
||||||
GetBoard()->m_FullRatsnest[ii].m_Status &= ~CH_VISIBLE;
|
GetBoard()->m_FullRatsnest[ii].m_Status &= ~CH_VISIBLE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include <class_board.h>
|
#include <class_board.h>
|
||||||
#include <class_track.h>
|
#include <class_track.h>
|
||||||
#include <class_zone.h>
|
#include <class_zone.h>
|
||||||
|
#include <connectivity.h>
|
||||||
|
|
||||||
|
|
||||||
static void Abort_Create_Track( EDA_DRAW_PANEL* panel, wxDC* DC );
|
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() );
|
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() );
|
DBG( g_CurrentTrackList.VerifyListIntegrity() );
|
||||||
|
|
||||||
|
@ -183,7 +188,6 @@ TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC )
|
||||||
|
|
||||||
if( pad )
|
if( pad )
|
||||||
{
|
{
|
||||||
g_CurrentTrackSegment->m_PadsConnected.push_back( pad );
|
|
||||||
// Useful to display track length, if the pad has a die length:
|
// Useful to display track length, if the pad has a die length:
|
||||||
g_CurrentTrackSegment->SetState( BEGIN_ONPAD, true );
|
g_CurrentTrackSegment->SetState( BEGIN_ONPAD, true );
|
||||||
g_CurrentTrackSegment->start = pad;
|
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 );
|
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;
|
newTrack->start = previousTrack->end;
|
||||||
|
|
||||||
DBG( g_CurrentTrackList.VerifyListIntegrity(); );
|
DBG( g_CurrentTrackList.VerifyListIntegrity(); );
|
||||||
|
@ -489,6 +487,7 @@ bool PCB_EDIT_FRAME::End_Route( TRACK* aTrack, wxDC* aDC )
|
||||||
ITEM_PICKER picker( track, UR_NEW );
|
ITEM_PICKER picker( track, UR_NEW );
|
||||||
s_ItemsListPicker.PushItem( picker );
|
s_ItemsListPicker.PushItem( picker );
|
||||||
GetBoard()->m_Track.Insert( track, insertBeforeMe );
|
GetBoard()->m_Track.Insert( track, insertBeforeMe );
|
||||||
|
GetBoard()->GetConnectivity()->Add( track );
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceAirWiresToTargets( aDC );
|
TraceAirWiresToTargets( aDC );
|
||||||
|
@ -534,6 +533,8 @@ bool PCB_EDIT_FRAME::End_Route( TRACK* aTrack, wxDC* aDC )
|
||||||
m_canvas->SetMouseCapture( NULL, NULL );
|
m_canvas->SetMouseCapture( NULL, NULL );
|
||||||
SetCurItem( NULL );
|
SetCurItem( NULL );
|
||||||
|
|
||||||
|
GetBoard()->GetConnectivity()->RecalculateRatsnest();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,7 +826,7 @@ void ShowNewTrackWhenMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPo
|
||||||
displ_opts->m_ShowTrackClearanceMode = showTrackClearanceMode;
|
displ_opts->m_ShowTrackClearanceMode = showTrackClearanceMode;
|
||||||
displ_opts->m_DisplayPcbTrackFill = tmp;
|
displ_opts->m_DisplayPcbTrackFill = tmp;
|
||||||
|
|
||||||
frame->BuildAirWiresTargetsList( NULL, g_CurrentTrackSegment->GetEnd(), false );
|
frame->BuildAirWiresTargetsList( NULL, g_CurrentTrackSegment->GetEnd(), g_CurrentTrackSegment->GetNetCode() );
|
||||||
frame->TraceAirWiresToTargets( aDC );
|
frame->TraceAirWiresToTargets( aDC );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -701,8 +701,6 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF
|
||||||
backupFileName = create_backup_file( aFileName );
|
backupFileName = create_backup_file( aFileName );
|
||||||
}
|
}
|
||||||
|
|
||||||
GetBoard()->m_Status_Pcb &= ~CONNEXION_OK;
|
|
||||||
|
|
||||||
GetBoard()->SynchronizeNetsAndNetClasses();
|
GetBoard()->SynchronizeNetsAndNetClasses();
|
||||||
|
|
||||||
// Select default Netclass before writing file.
|
// Select default Netclass before writing file.
|
||||||
|
@ -787,7 +785,6 @@ bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetBoard()->m_Status_Pcb &= ~CONNEXION_OK;
|
|
||||||
GetBoard()->SynchronizeNetsAndNetClasses();
|
GetBoard()->SynchronizeNetsAndNetClasses();
|
||||||
|
|
||||||
// Select default Netclass before writing file.
|
// Select default Netclass before writing file.
|
||||||
|
|
|
@ -238,8 +238,6 @@ void PCB_BASE_FRAME::GlobalChange_PadSettings( D_PAD* aPad,
|
||||||
{
|
{
|
||||||
if( pad->GetLayerSet() != aPad->GetLayerSet() )
|
if( pad->GetLayerSet() != aPad->GetLayerSet() )
|
||||||
continue;
|
continue;
|
||||||
else
|
|
||||||
m_Pcb->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change characteristics:
|
// Change characteristics:
|
||||||
|
|
|
@ -107,17 +107,3 @@ void PCB_EDIT_FRAME::HighLight( wxDC* DC )
|
||||||
|
|
||||||
GetBoard()->DrawHighLight( m_canvas, DC, GetBoard()->GetHighLightNetCode() );
|
GetBoard()->DrawHighLight( m_canvas, DC, GetBoard()->GetHighLightNetCode() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCB_EDIT_FRAME::HighlightUnconnectedPads( wxDC* DC )
|
|
||||||
{
|
|
||||||
for( unsigned ii = 0; ii < GetBoard()->GetRatsnestsCount(); ii++ )
|
|
||||||
{
|
|
||||||
RATSNEST_ITEM* net = &GetBoard()->m_FullRatsnest[ii];
|
|
||||||
|
|
||||||
if( (net->m_Status & CH_ACTIF) == 0 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
net->m_PadStart->Draw( m_canvas, DC, GR_OR | GR_HIGHLIGHT );
|
|
||||||
net->m_PadEnd->Draw( m_canvas, DC, GR_OR | GR_HIGHLIGHT );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include <wx/wfstream.h>
|
#include <wx/wfstream.h>
|
||||||
#include <boost/ptr_container/ptr_map.hpp>
|
#include <boost/ptr_container/ptr_map.hpp>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
#include <connectivity.h>
|
||||||
|
|
||||||
using namespace PCB_KEYS_T;
|
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
|
///> Removes empty nets (i.e. with node count equal zero) from net classes
|
||||||
void filterNetClass( const BOARD& aBoard, NETCLASS& aNetClass )
|
void filterNetClass( const BOARD& aBoard, NETCLASS& aNetClass )
|
||||||
{
|
{
|
||||||
|
auto connectivity = aBoard.GetConnectivity();
|
||||||
for( NETCLASS::iterator it = aNetClass.begin(); it != aNetClass.end(); )
|
for( NETCLASS::iterator it = aNetClass.begin(); it != aNetClass.end(); )
|
||||||
{
|
{
|
||||||
NETINFO_ITEM* netinfo = aBoard.FindNet( *it );
|
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..
|
aNetClass.Remove( it++ ); // node count, but you never know..
|
||||||
else
|
else
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -531,8 +534,8 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const
|
||||||
m_out->Print( 0, "\n" );
|
m_out->Print( 0, "\n" );
|
||||||
|
|
||||||
m_out->Print( aNestLevel, "(general\n" );
|
m_out->Print( aNestLevel, "(general\n" );
|
||||||
m_out->Print( aNestLevel+1, "(links %d)\n", aBoard->GetRatsnestsCount() );
|
m_out->Print( aNestLevel+1, "(links %d)\n", aBoard->GetConnectivity()->GetLinksCount() );
|
||||||
m_out->Print( aNestLevel+1, "(no_connects %d)\n", aBoard->GetUnconnectedNetCount() );
|
m_out->Print( aNestLevel+1, "(no_connects %d)\n", aBoard->GetConnectivity()->GetUnconnectedCount() );
|
||||||
|
|
||||||
// Write Bounding box info
|
// Write Bounding box info
|
||||||
EDA_RECT bbox = aBoard->GetBoundingBox();
|
EDA_RECT bbox = aBoard->GetBoundingBox();
|
||||||
|
|
|
@ -43,6 +43,8 @@
|
||||||
#include <drag.h>
|
#include <drag.h>
|
||||||
#include <dialog_get_footprint_by_name.h>
|
#include <dialog_get_footprint_by_name.h>
|
||||||
|
|
||||||
|
#include <connectivity.h>
|
||||||
|
|
||||||
static void MoveFootprint( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
|
static void MoveFootprint( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
|
||||||
const wxPoint& aPosition, bool aErase );
|
const wxPoint& aPosition, bool aErase );
|
||||||
static void Abort_MoveOrCopyModule( EDA_DRAW_PANEL* Panel, wxDC* DC );
|
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 );
|
SetMsgPanel( aModule );
|
||||||
|
|
||||||
/* Remove module from list, and put it in undo command list */
|
/* 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 );
|
aModule->SetState( IS_DELETED, true );
|
||||||
SaveCopyInUndoList( aModule, UR_DELETED );
|
SaveCopyInUndoList( aModule, UR_DELETED );
|
||||||
|
|
||||||
|
@ -322,7 +324,7 @@ void PCB_EDIT_FRAME::Change_Side_Module( MODULE* Module, wxDC* DC )
|
||||||
|
|
||||||
/* Flip the module */
|
/* Flip the module */
|
||||||
Module->Flip( Module->GetPosition() );
|
Module->Flip( Module->GetPosition() );
|
||||||
|
m_Pcb->GetConnectivity()->Update( Module );
|
||||||
SetMsgPanel( Module );
|
SetMsgPanel( Module );
|
||||||
|
|
||||||
if( !Module->IsMoving() ) /* Inversion simple */
|
if( !Module->IsMoving() ) /* Inversion simple */
|
||||||
|
@ -343,8 +345,8 @@ void PCB_EDIT_FRAME::Change_Side_Module( MODULE* Module, wxDC* DC )
|
||||||
DrawSegmentWhileMovingFootprint( m_canvas, 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;
|
return;
|
||||||
|
|
||||||
OnModify();
|
OnModify();
|
||||||
GetBoard()->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK);
|
|
||||||
|
|
||||||
if( aModule->IsNew() )
|
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();
|
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 );
|
TraceModuleRatsNest( aDC );
|
||||||
|
|
||||||
newpos = GetCrossHairPosition();
|
newpos = GetCrossHairPosition();
|
||||||
|
@ -410,6 +412,8 @@ void PCB_BASE_FRAME::PlaceModule( MODULE* aModule, wxDC* aDC, bool aDoNotRecreat
|
||||||
|
|
||||||
m_canvas->SetMouseCapture( NULL, NULL );
|
m_canvas->SetMouseCapture( NULL, NULL );
|
||||||
|
|
||||||
|
m_Pcb->GetConnectivity()->Update( aModule );
|
||||||
|
|
||||||
if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) && !aDoNotRecreateRatsnest )
|
if( GetBoard()->IsElementVisible( LAYER_RATSNEST ) && !aDoNotRecreateRatsnest )
|
||||||
Compile_Ratsnest( aDC, true );
|
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 )
|
if( incremental )
|
||||||
module->SetOrientation( module->GetOrientation() + angle );
|
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 );
|
module->SetOrientation( angle );
|
||||||
|
|
||||||
SetMsgPanel( module );
|
SetMsgPanel( module );
|
||||||
|
m_Pcb->GetConnectivity()->Update( module );
|
||||||
|
|
||||||
if( DC )
|
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
|
if( module->GetFlags() == 0 ) // module not in edit: redraw full screen
|
||||||
m_canvas->Refresh();
|
m_canvas->Refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Redraw in XOR mode the outlines of the module.
|
|
||||||
void MODULE::DrawOutlinesWhenMoving( EDA_DRAW_PANEL* panel, wxDC* DC,
|
|
||||||
const wxPoint& aMoveVector )
|
|
||||||
{
|
|
||||||
int pad_fill_tmp;
|
|
||||||
D_PAD* pt_pad;
|
|
||||||
|
|
||||||
DrawEdgesOnly( panel, DC, aMoveVector, GR_XOR );
|
|
||||||
DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
|
|
||||||
|
|
||||||
// Show pads in sketch mode to speedu up drawings
|
|
||||||
pad_fill_tmp = displ_opts->m_DisplayPadFill;
|
|
||||||
displ_opts->m_DisplayPadFill = true;
|
|
||||||
|
|
||||||
pt_pad = Pads();
|
|
||||||
|
|
||||||
for( ; pt_pad != NULL; pt_pad = pt_pad->Next() )
|
|
||||||
pt_pad->Draw( panel, DC, GR_XOR, aMoveVector );
|
|
||||||
|
|
||||||
displ_opts->m_DisplayPadFill = pad_fill_tmp;
|
|
||||||
|
|
||||||
if( displ_opts->m_Show_Module_Ratsnest )
|
|
||||||
{
|
|
||||||
PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) panel->GetParent();
|
|
||||||
frame->build_ratsnest_module( this );
|
|
||||||
frame->TraceModuleRatsNest( DC );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -206,5 +206,4 @@ void PCB_BASE_FRAME::PlacePad( D_PAD* aPad, wxDC* DC )
|
||||||
|
|
||||||
OnModify();
|
OnModify();
|
||||||
m_canvas->SetMouseCapture( NULL, NULL );
|
m_canvas->SetMouseCapture( NULL, NULL );
|
||||||
m_Pcb->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,9 +265,6 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME )
|
||||||
EVT_TOOL_RANGE( ID_PCB_MUWAVE_START_CMD, ID_PCB_MUWAVE_END_CMD,
|
EVT_TOOL_RANGE( ID_PCB_MUWAVE_START_CMD, ID_PCB_MUWAVE_END_CMD,
|
||||||
PCB_EDIT_FRAME::ProcessMuWaveFunctions )
|
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,
|
EVT_MENU_RANGE( ID_POPUP_PCB_START_RANGE, ID_POPUP_PCB_END_RANGE,
|
||||||
PCB_EDIT_FRAME::Process_Special_Functions )
|
PCB_EDIT_FRAME::Process_Special_Functions )
|
||||||
|
|
||||||
|
|
|
@ -41,118 +41,8 @@
|
||||||
|
|
||||||
#include <pcbnew.h>
|
#include <pcbnew.h>
|
||||||
|
|
||||||
#include <minimun_spanning_tree.h>
|
#include <connectivity.h>
|
||||||
|
#include <ratsnest_data.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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Compile_Ratsnest
|
* 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 )
|
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
|
GetBoard()->m_Status_Pcb = 0; // we want a full ratsnest computation, from the scratch
|
||||||
ClearMsgPanel();
|
|
||||||
|
|
||||||
// Rebuild the full pads and net info list
|
if( GetBoard()->IsElementVisible(LAYER_RATSNEST) && aDC )
|
||||||
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 )
|
|
||||||
DrawGeneralRatsnest( aDC, 0 );
|
DrawGeneralRatsnest( aDC, 0 );
|
||||||
|
|
||||||
|
wxString msg;
|
||||||
|
|
||||||
|
ClearMsgPanel();
|
||||||
|
|
||||||
if( aDisplayStatus )
|
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 );
|
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 )
|
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 ) )
|
if( ( m_Pcb->m_Status_Pcb & DO_NOT_SHOW_GENERAL_RASTNEST ) )
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if( aDC == NULL )
|
if( aDC == NULL )
|
||||||
return;
|
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 )
|
if( ( aNetcode <= 0 ) || ( aNetcode == i ) )
|
||||||
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
|
|
||||||
{
|
{
|
||||||
wxMessageBox( wxT( "build_ratsnest_module() error: net not found" ) );
|
for ( const auto& edge : net->GetEdges() )
|
||||||
return;
|
{
|
||||||
|
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 )
|
if( DC == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( ( m_Pcb->m_Status_Pcb & RATSNEST_ITEM_LOCAL_OK ) == 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
COLOR4D tmpcolor = g_ColorsSettings.GetItemColor( LAYER_RATSNEST );
|
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];
|
GRLine( m_canvas->GetClipBox(), DC, wxPoint(l.a.x, l.a.y), wxPoint(l.b.x, l.b.y), 0, tmpcolor );
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
* and when the mouse is moved, the g_MaxLinksShowed links to neighbors are
|
||||||
* drawn
|
* 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
|
static wxPoint s_CursorPos; // Coordinate of the moving point (mouse cursor and
|
||||||
* (rectilinear distance between s_CursorPos and item pos)
|
// end of current track segment)
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Function BuildAirWiresTargetsList
|
/* Function BuildAirWiresTargetsList
|
||||||
* Build a list of candidates that can be a coonection point
|
* 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)
|
* This functions prepares data to show airwires to nearest connecting points (pads)
|
||||||
* from the current new track to candidates during track creation
|
* 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,
|
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_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 )
|
static MODULE movedModule(nullptr);
|
||||||
return;
|
|
||||||
|
|
||||||
NETINFO_ITEM* net = m_Pcb->FindNet( net_code );
|
void PCB_BASE_FRAME::build_ratsnest_module( MODULE *mod, wxPoint aMoveVector )
|
||||||
|
{
|
||||||
if( net == NULL ) // Should not occur
|
auto connectivity = GetBoard()->GetConnectivity();
|
||||||
{
|
movedModule = *mod;
|
||||||
wxMessageBox( wxT( "BuildAirWiresTargetsList() error: net not found" ) );
|
movedModule.Move( -aMoveVector );
|
||||||
return;
|
connectivity->ClearDynamicRatsnest();
|
||||||
}
|
connectivity->BlockRatsnestItems( {mod} );
|
||||||
|
connectivity->ComputeDynamicRatsnest( {&movedModule} );
|
||||||
// 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::TraceAirWiresToTargets( wxDC* aDC )
|
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 )
|
if( aDC == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( s_TargetsLocations.size() == 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
GRSetDrawMode( aDC, GR_XOR );
|
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 )
|
auto p = targets[i];
|
||||||
break;
|
GRLine( m_canvas->GetClipBox(), aDC, s_CursorPos, wxPoint(p.x, p.y), 0, YELLOW );
|
||||||
|
}
|
||||||
|
|
||||||
GRLine( m_canvas->GetClipBox(), aDC, s_CursorPos, s_TargetsLocations[ii], 0, YELLOW );
|
}
|
||||||
|
|
||||||
|
// Redraw in XOR mode the outlines of the module.
|
||||||
|
void MODULE::DrawOutlinesWhenMoving( EDA_DRAW_PANEL* panel, wxDC* DC,
|
||||||
|
const wxPoint& aMoveVector )
|
||||||
|
{
|
||||||
|
int pad_fill_tmp;
|
||||||
|
D_PAD* pt_pad;
|
||||||
|
|
||||||
|
DrawEdgesOnly( panel, DC, aMoveVector, GR_XOR );
|
||||||
|
DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
|
||||||
|
|
||||||
|
// Show pads in sketch mode to speedu up drawings
|
||||||
|
pad_fill_tmp = displ_opts->m_DisplayPadFill;
|
||||||
|
displ_opts->m_DisplayPadFill = true;
|
||||||
|
|
||||||
|
pt_pad = Pads();
|
||||||
|
|
||||||
|
for( ; pt_pad != NULL; pt_pad = pt_pad->Next() )
|
||||||
|
pt_pad->Draw( panel, DC, GR_XOR, aMoveVector );
|
||||||
|
|
||||||
|
displ_opts->m_DisplayPadFill = pad_fill_tmp;
|
||||||
|
|
||||||
|
if( displ_opts->m_Show_Module_Ratsnest )
|
||||||
|
{
|
||||||
|
PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) panel->GetParent();
|
||||||
|
frame->build_ratsnest_module( this, aMoveVector );
|
||||||
|
frame->TraceModuleRatsNest( DC );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,7 +299,7 @@ public:
|
||||||
|
|
||||||
#include <profile.h>
|
#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 );
|
m_triangulator.reset( new TRIANGULATOR_STATE );
|
||||||
}
|
}
|
||||||
|
@ -709,3 +709,9 @@ unsigned int RN_NET::GetNodeCount() const
|
||||||
{
|
{
|
||||||
return m_nodes.size();
|
return m_nodes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RN_NET::SetVisible( bool aEnabled )
|
||||||
|
{
|
||||||
|
for ( auto& edge : m_rnEdges )
|
||||||
|
edge.SetVisible ( aEnabled );
|
||||||
|
}
|
||||||
|
|
|
@ -178,21 +178,8 @@ public:
|
||||||
* @param aEnabled is new state. True if ratsnest for a given net is meant to be displayed,
|
* @param aEnabled is new state. True if ratsnest for a given net is meant to be displayed,
|
||||||
* false otherwise.
|
* false otherwise.
|
||||||
*/
|
*/
|
||||||
void SetVisible( bool aEnabled )
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function MarkDirty()
|
* Function MarkDirty()
|
||||||
* Marks ratsnest for given net as 'dirty', i.e. requiring recomputation.
|
* 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.
|
///> Flag indicating necessity of recalculation of ratsnest for a net.
|
||||||
bool m_dirty;
|
bool m_dirty;
|
||||||
|
|
||||||
///> Visibility flag.
|
|
||||||
bool m_visible;
|
|
||||||
|
|
||||||
class TRIANGULATOR_STATE;
|
class TRIANGULATOR_STATE;
|
||||||
|
|
||||||
std::shared_ptr<TRIANGULATOR_STATE> m_triangulator;
|
std::shared_ptr<TRIANGULATOR_STATE> m_triangulator;
|
||||||
|
|
|
@ -97,15 +97,15 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
|
||||||
{
|
{
|
||||||
RN_NET* net = m_data->GetRatsnestForNet( i );
|
RN_NET* net = m_data->GetRatsnestForNet( i );
|
||||||
|
|
||||||
if( !net->IsVisible() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Draw the "static" ratsnest
|
// Draw the "static" ratsnest
|
||||||
if( i != highlightedNet )
|
if( i != highlightedNet )
|
||||||
gal->SetStrokeColor( color ); // using the default ratsnest color for not highlighted
|
gal->SetStrokeColor( color ); // using the default ratsnest color for not highlighted
|
||||||
|
|
||||||
for( const auto& edge : net->GetUnconnected() )
|
for( const auto& edge : net->GetUnconnected() )
|
||||||
{
|
{
|
||||||
|
if ( !edge.IsVisible() )
|
||||||
|
continue;
|
||||||
|
|
||||||
const auto& sourceNode = edge.GetSourceNode();
|
const auto& sourceNode = edge.GetSourceNode();
|
||||||
const auto& targetNode = edge.GetTargetNode();
|
const auto& targetNode = edge.GetTargetNode();
|
||||||
const VECTOR2I source( sourceNode->Pos() );
|
const VECTOR2I source( sourceNode->Pos() );
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include <class_module.h>
|
#include <class_module.h>
|
||||||
#include <class_track.h>
|
#include <class_track.h>
|
||||||
#include <board_commit.h>
|
#include <board_commit.h>
|
||||||
#include <ratsnest_data.h>
|
|
||||||
#include <layers_id_colors_and_visibility.h>
|
#include <layers_id_colors_and_visibility.h>
|
||||||
#include <geometry/convex_hull.h>
|
#include <geometry/convex_hull.h>
|
||||||
#include <wxPcbStruct.h>
|
#include <wxPcbStruct.h>
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <geometry/shape_line_chain.h>
|
#include <geometry/shape_line_chain.h>
|
||||||
#include <geometry/shape_rect.h>
|
#include <geometry/shape_rect.h>
|
||||||
#include <geometry/shape_circle.h>
|
#include <geometry/shape_circle.h>
|
||||||
|
#include <geometry/convex_hull.h>
|
||||||
|
|
||||||
#include "pns_node.h"
|
#include "pns_node.h"
|
||||||
#include "pns_line_placer.h"
|
#include "pns_line_placer.h"
|
||||||
|
@ -51,14 +52,6 @@
|
||||||
|
|
||||||
#include <router/router_preview_item.h>
|
#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 {
|
namespace PNS {
|
||||||
|
|
||||||
// an ugly singleton for drawing debug items within the router context.
|
// an ugly singleton for drawing debug items within the router context.
|
||||||
|
|
|
@ -44,8 +44,6 @@ using namespace std::placeholders;
|
||||||
#include <tools/pcb_actions.h>
|
#include <tools/pcb_actions.h>
|
||||||
#include <tools/grid_helper.h>
|
#include <tools/grid_helper.h>
|
||||||
|
|
||||||
#include <ratsnest_data.h>
|
|
||||||
|
|
||||||
#include "pns_kicad_iface.h"
|
#include "pns_kicad_iface.h"
|
||||||
#include "pns_tool_base.h"
|
#include "pns_tool_base.h"
|
||||||
#include "pns_segment.h"
|
#include "pns_segment.h"
|
||||||
|
|
|
@ -55,8 +55,6 @@ using namespace std::placeholders;
|
||||||
#include <tools/edit_tool.h>
|
#include <tools/edit_tool.h>
|
||||||
#include <tools/tool_event_utils.h>
|
#include <tools/tool_event_utils.h>
|
||||||
|
|
||||||
#include <ratsnest_data.h>
|
|
||||||
|
|
||||||
#include "router_tool.h"
|
#include "router_tool.h"
|
||||||
#include "pns_segment.h"
|
#include "pns_segment.h"
|
||||||
#include "pns_router.h"
|
#include "pns_router.h"
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
#include <class_track.h>
|
#include <class_track.h>
|
||||||
#include <class_zone.h>
|
#include <class_zone.h>
|
||||||
#include <class_drawsegment.h>
|
#include <class_drawsegment.h>
|
||||||
#include <ratsnest_data.h>
|
#include <connectivity.h>
|
||||||
#include <view/view.h>
|
#include <view/view.h>
|
||||||
|
|
||||||
#include <specctra.h>
|
#include <specctra.h>
|
||||||
|
@ -117,8 +117,8 @@ void PCB_EDIT_FRAME::ImportSpecctraSession( wxCommandEvent& event )
|
||||||
OnModify();
|
OnModify();
|
||||||
GetBoard()->m_Status_Pcb = 0;
|
GetBoard()->m_Status_Pcb = 0;
|
||||||
|
|
||||||
Compile_Ratsnest( NULL, true );
|
GetBoard()->GetConnectivity()->Clear();
|
||||||
GetBoard()->GetRatsnest()->ProcessBoard();
|
GetBoard()->GetConnectivity()->Build( GetBoard() );
|
||||||
|
|
||||||
if( GetGalCanvas() ) // Update view:
|
if( GetGalCanvas() ) // Update view:
|
||||||
{
|
{
|
||||||
|
|
|
@ -747,9 +747,7 @@ void PCB_EDIT_FRAME::OnSelectOptionToolbar( wxCommandEvent& event )
|
||||||
case ID_TB_OPTIONS_SHOW_RATSNEST:
|
case ID_TB_OPTIONS_SHOW_RATSNEST:
|
||||||
SetElementVisibility( LAYER_RATSNEST, state );
|
SetElementVisibility( LAYER_RATSNEST, state );
|
||||||
OnModify();
|
OnModify();
|
||||||
|
Compile_Ratsnest( NULL, true );
|
||||||
if( state && (GetBoard()->m_Status_Pcb & LISTE_RATSNEST_ITEM_OK) == 0 )
|
|
||||||
Compile_Ratsnest( NULL, true );
|
|
||||||
|
|
||||||
m_canvas->Refresh();
|
m_canvas->Refresh();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <pcbnew.h>
|
#include <pcbnew.h>
|
||||||
#include <protos.h>
|
#include <protos.h>
|
||||||
|
|
||||||
|
#include <connectivity.h>
|
||||||
|
|
||||||
static void ListSetState( EDA_ITEM* Start, int NbItem, STATUS_FLAGS State,
|
static void ListSetState( EDA_ITEM* Start, int NbItem, STATUS_FLAGS State,
|
||||||
bool onoff );
|
bool onoff );
|
||||||
|
@ -267,11 +268,13 @@ int PCB_EDIT_FRAME::EraseRedundantTrack( wxDC* aDC,
|
||||||
pt_del->UnLink();
|
pt_del->UnLink();
|
||||||
pt_del->SetStatus( 0 );
|
pt_del->SetStatus( 0 );
|
||||||
pt_del->ClearFlags();
|
pt_del->ClearFlags();
|
||||||
|
GetBoard()->GetConnectivity()->Remove ( pt_del );
|
||||||
ITEM_PICKER picker( pt_del, UR_DELETED );
|
ITEM_PICKER picker( pt_del, UR_DELETED );
|
||||||
aItemsListPicker->PushItem( picker );
|
aItemsListPicker->PushItem( picker );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
GetBoard()->GetConnectivity()->Remove ( pt_del );
|
||||||
pt_del->DeleteStructure();
|
pt_del->DeleteStructure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,10 +185,10 @@ int PCB_EDIT_FRAME::Fill_All_Zones( wxWindow * aActiveWindow, bool aVerbose )
|
||||||
aActiveWindow->Raise();
|
aActiveWindow->Raise();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
TestConnections();
|
//TestConnections();
|
||||||
|
|
||||||
// Recalculate the active ratsnest, i.e. the unconnected links
|
// Recalculate the active ratsnest, i.e. the unconnected links
|
||||||
TestForActiveLinksInRatsnest( 0 );
|
//TestForActiveLinksInRatsnest( 0 );
|
||||||
if( progressDialog )
|
if( progressDialog )
|
||||||
progressDialog->Destroy();
|
progressDialog->Destroy();
|
||||||
return errorLevel;
|
return errorLevel;
|
||||||
|
|
Loading…
Reference in New Issue