/* * This program source code file is part of KICAD, a free EDA CAD application. * * Copyright (C) 2013-2017 CERN * Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors. * @author Maciej Suminski * @author Tomasz Wlostowski * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ // #define CONNECTIVITY_DEBUG #ifndef __CONNECTIVITY_ALGO_H #define __CONNECTIVITY_ALGO_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class CN_CONNECTIVITY_ALGO_IMPL; class CN_RATSNEST_NODES; class BOARD; class BOARD_CONNECTED_ITEM; class BOARD_ITEM; class ZONE_CONTAINER; class PROGRESS_REPORTER; class CN_EDGE { public: CN_EDGE() : m_weight( 0 ), m_visible( true ) {} CN_EDGE( CN_ANCHOR_PTR aSource, CN_ANCHOR_PTR aTarget, unsigned aWeight = 0 ) : m_source( aSource ), m_target( aTarget ), m_weight( aWeight ), m_visible( true ) {} /** * This sort operator provides a sort-by-weight for the ratsnest operation * @param aOther Other edge to compare * @return true if our weight is smaller than the other weight */ bool operator<( CN_EDGE aOther ) const { return m_weight < aOther.m_weight; } CN_ANCHOR_PTR GetSourceNode() const { return m_source; } CN_ANCHOR_PTR GetTargetNode() const { return m_target; } unsigned GetWeight() const { return m_weight; } void SetSourceNode( const CN_ANCHOR_PTR& aNode ) { m_source = aNode; } void SetTargetNode( const CN_ANCHOR_PTR& aNode ) { m_target = aNode; } void SetWeight( unsigned 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 m_weight; bool m_visible; }; class CN_CONNECTIVITY_ALGO { public: enum CLUSTER_SEARCH_MODE { CSM_PROPAGATE, CSM_CONNECTIVITY_CHECK, CSM_RATSNEST }; using CLUSTERS = std::vector; private: class ITEM_MAP_ENTRY { public: ITEM_MAP_ENTRY( CN_ITEM* aItem = nullptr ) { if( aItem ) m_items.push_back( aItem ); } void MarkItemsAsInvalid() { for( auto item : m_items ) { item->SetValid( false ); } } void Link( CN_ITEM* aItem ) { m_items.push_back( aItem ); } const std::list GetItems() const { return m_items; } std::list m_items; }; CN_LIST m_itemList; std::unordered_map m_itemMap; CLUSTERS m_connClusters; CLUSTERS m_ratsnestClusters; std::vector m_dirtyNets; PROGRESS_REPORTER* m_progressReporter = nullptr; void searchConnections(); void update(); void propagateConnections( BOARD_COMMIT* aCommit = nullptr ); template void add( Container& c, BItem brditem ) { auto item = c.Add( brditem ); m_itemMap[ brditem ] = ITEM_MAP_ENTRY( item ); } void markItemNetAsDirty( const BOARD_ITEM* aItem ); public: CN_CONNECTIVITY_ALGO() {} ~CN_CONNECTIVITY_ALGO() { Clear(); } bool ItemExists( const BOARD_CONNECTED_ITEM* aItem ) const { return m_itemMap.find( aItem ) != m_itemMap.end(); } ITEM_MAP_ENTRY& ItemEntry( const BOARD_CONNECTED_ITEM* aItem ) { return m_itemMap[ aItem ]; } bool IsNetDirty( int aNet ) const { if( aNet < 0 ) return false; return m_dirtyNets[ aNet ]; } void ClearDirtyFlags() { for( auto i = m_dirtyNets.begin(); i != m_dirtyNets.end(); ++i ) *i = false; } void GetDirtyClusters( CLUSTERS& aClusters ) const { for( const auto& cl : m_ratsnestClusters ) { int net = cl->OriginNet(); if( net >= 0 && m_dirtyNets[net] ) aClusters.push_back( cl ); } } int NetCount() const { return m_dirtyNets.size(); } void Build( BOARD* aBoard ); void Build( const std::vector& aItems ); void Clear(); bool Remove( BOARD_ITEM* aItem ); bool Add( BOARD_ITEM* aItem ); const CLUSTERS SearchClusters( CLUSTER_SEARCH_MODE aMode, const KICAD_T aTypes[], int aSingleNet ); const CLUSTERS SearchClusters( CLUSTER_SEARCH_MODE aMode ); /** * Propagates nets from pads to other items in clusters * @param aCommit is used to store undo information for items modified by the call */ void PropagateNets( BOARD_COMMIT* aCommit = nullptr ); void FindIsolatedCopperIslands( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer, std::vector& aIslands ); /** * Finds the copper islands that are not connected to a net. These are added to * the m_islands vector. * N.B. This must be called after aZones has been refreshed. * @param: aZones The set of zones to search for islands */ void FindIsolatedCopperIslands( std::vector& aZones ); const CLUSTERS& GetClusters(); const CN_LIST& ItemList() const { return m_itemList; } template void ForEachAnchor( Func&& aFunc ) const { for( auto&& item : m_itemList ) { for( auto&& anchor : item->Anchors() ) aFunc( *anchor ); } } template void ForEachItem( Func&& aFunc ) const { for( auto&& item : m_itemList ) aFunc( *item ); } void MarkNetAsDirty( int aNet ); void SetProgressReporter( PROGRESS_REPORTER* aReporter ); }; /** * Struct CN_VISTOR **/ class CN_VISITOR { public: CN_VISITOR( CN_ITEM* aItem ) : m_item( aItem ) {} bool operator()( CN_ITEM* aCandidate ); protected: void checkZoneItemConnection( CN_ZONE* aZone, CN_ITEM* aItem ); void checkZoneZoneConnection( CN_ZONE* aZoneA, CN_ZONE* aZoneB ); ///> the item we are looking for connections to CN_ITEM* m_item; }; #endif