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