2017-03-22 13:43:10 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KICAD, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013-2017 CERN
|
2021-01-27 22:15:38 +00:00
|
|
|
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
|
|
|
*
|
2017-03-22 13:43:10 +00:00
|
|
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
|
|
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
|
2020-11-12 20:19:22 +00:00
|
|
|
#include <board.h>
|
|
|
|
#include <pad.h>
|
|
|
|
#include <footprint.h>
|
2020-11-11 23:05:59 +00:00
|
|
|
#include <zone.h>
|
2017-03-22 13:43:10 +00:00
|
|
|
|
|
|
|
#include <geometry/shape_poly_set.h>
|
|
|
|
#include <geometry/poly_grid_partition.h>
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <functional>
|
|
|
|
#include <vector>
|
|
|
|
#include <deque>
|
2017-06-23 12:45:38 +00:00
|
|
|
#include <intrusive_list.h>
|
2017-03-22 13:43:10 +00:00
|
|
|
|
2018-10-12 06:17:15 +00:00
|
|
|
#include <connectivity/connectivity_rtree.h>
|
|
|
|
#include <connectivity/connectivity_data.h>
|
2018-10-12 21:29:16 +00:00
|
|
|
#include <connectivity/connectivity_items.h>
|
2017-03-22 13:43:10 +00:00
|
|
|
|
|
|
|
class CN_CONNECTIVITY_ALGO_IMPL;
|
|
|
|
class CN_RATSNEST_NODES;
|
|
|
|
class BOARD;
|
|
|
|
class BOARD_CONNECTED_ITEM;
|
|
|
|
class BOARD_ITEM;
|
2020-11-11 23:05:59 +00:00
|
|
|
class ZONE;
|
2017-11-23 16:20:27 +00:00
|
|
|
class PROGRESS_REPORTER;
|
2017-03-22 13:43:10 +00:00
|
|
|
|
2021-11-30 14:19:39 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
|
|
|
|
* or a ratsnest line).
|
|
|
|
*/
|
2017-03-22 13:43:10 +00:00
|
|
|
class CN_EDGE
|
|
|
|
{
|
|
|
|
public:
|
2020-06-18 02:25:46 +00:00
|
|
|
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 )
|
|
|
|
{}
|
|
|
|
|
|
|
|
/**
|
2021-01-27 22:15:38 +00:00
|
|
|
* This sort operator provides a sort-by-weight for the ratsnest operation.
|
|
|
|
*
|
|
|
|
* @param aOther the other edge to compare.
|
|
|
|
* @return true if our weight is smaller than the other weight.
|
2020-06-18 02:25:46 +00:00
|
|
|
*/
|
|
|
|
bool operator<( CN_EDGE aOther ) const
|
|
|
|
{
|
2020-06-21 15:56:24 +00:00
|
|
|
return m_weight < aOther.m_weight;
|
2020-06-18 02:25:46 +00:00
|
|
|
}
|
2017-03-22 13:43:10 +00:00
|
|
|
|
|
|
|
CN_ANCHOR_PTR GetSourceNode() const { return m_source; }
|
|
|
|
CN_ANCHOR_PTR GetTargetNode() const { return m_target; }
|
2020-06-18 02:25:46 +00:00
|
|
|
unsigned GetWeight() const { return m_weight; }
|
2017-03-22 13:43:10 +00:00
|
|
|
|
|
|
|
void SetSourceNode( const CN_ANCHOR_PTR& aNode ) { m_source = aNode; }
|
|
|
|
void SetTargetNode( const CN_ANCHOR_PTR& aNode ) { m_target = aNode; }
|
2020-06-18 02:25:46 +00:00
|
|
|
void SetWeight( unsigned weight ) { m_weight = weight; }
|
2017-03-22 13:43:10 +00:00
|
|
|
|
2017-03-22 13:51:07 +00:00
|
|
|
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();
|
|
|
|
}
|
2017-03-28 16:30:49 +00:00
|
|
|
|
2017-03-22 13:43:10 +00:00
|
|
|
private:
|
|
|
|
CN_ANCHOR_PTR m_source;
|
|
|
|
CN_ANCHOR_PTR m_target;
|
2021-11-30 14:19:39 +00:00
|
|
|
unsigned m_weight;
|
|
|
|
bool m_visible;
|
2017-03-22 13:43:10 +00:00
|
|
|
};
|
|
|
|
|
2021-11-30 14:19:39 +00:00
|
|
|
|
2017-03-22 13:43:10 +00:00
|
|
|
class CN_CONNECTIVITY_ALGO
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum CLUSTER_SEARCH_MODE
|
|
|
|
{
|
|
|
|
CSM_PROPAGATE,
|
|
|
|
CSM_CONNECTIVITY_CHECK,
|
|
|
|
CSM_RATSNEST
|
|
|
|
};
|
|
|
|
|
|
|
|
using CLUSTERS = std::vector<CN_CLUSTER_PTR>;
|
|
|
|
|
|
|
|
class ITEM_MAP_ENTRY
|
|
|
|
{
|
2018-10-13 00:06:10 +00:00
|
|
|
public:
|
2017-03-22 13:43:10 +00:00
|
|
|
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<CN_ITEM*> GetItems() const
|
|
|
|
{
|
|
|
|
return m_items;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::list<CN_ITEM*> m_items;
|
|
|
|
};
|
|
|
|
|
2018-10-12 06:47:33 +00:00
|
|
|
CN_CONNECTIVITY_ALGO() {}
|
|
|
|
~CN_CONNECTIVITY_ALGO() { Clear(); }
|
2017-03-22 13:43:10 +00:00
|
|
|
|
2020-04-12 19:10:57 +00:00
|
|
|
bool ItemExists( const BOARD_CONNECTED_ITEM* aItem ) const
|
2017-09-28 16:38:54 +00:00
|
|
|
{
|
|
|
|
return m_itemMap.find( aItem ) != m_itemMap.end();
|
|
|
|
}
|
|
|
|
|
2017-03-22 13:43:10 +00:00
|
|
|
ITEM_MAP_ENTRY& ItemEntry( const BOARD_CONNECTED_ITEM* aItem )
|
|
|
|
{
|
|
|
|
return m_itemMap[ aItem ];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsNetDirty( int aNet ) const
|
|
|
|
{
|
2017-07-01 21:54:17 +00:00
|
|
|
if( aNet < 0 )
|
|
|
|
return false;
|
|
|
|
|
2017-03-22 13:43:10 +00:00
|
|
|
return m_dirtyNets[ aNet ];
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClearDirtyFlags()
|
|
|
|
{
|
|
|
|
for( auto i = m_dirtyNets.begin(); i != m_dirtyNets.end(); ++i )
|
|
|
|
*i = false;
|
|
|
|
}
|
|
|
|
|
2020-04-12 19:10:57 +00:00
|
|
|
void GetDirtyClusters( CLUSTERS& aClusters ) const
|
2017-03-22 13:43:10 +00:00
|
|
|
{
|
2019-12-05 15:20:59 +00:00
|
|
|
for( const auto& cl : m_ratsnestClusters )
|
2017-03-22 13:43:10 +00:00
|
|
|
{
|
|
|
|
int net = cl->OriginNet();
|
|
|
|
|
|
|
|
if( net >= 0 && m_dirtyNets[net] )
|
|
|
|
aClusters.push_back( cl );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int NetCount() const
|
|
|
|
{
|
|
|
|
return m_dirtyNets.size();
|
|
|
|
}
|
|
|
|
|
2020-11-11 23:05:59 +00:00
|
|
|
void Build( BOARD* aBoard, PROGRESS_REPORTER* aReporter = nullptr );
|
|
|
|
void Build( const std::vector<BOARD_ITEM*>& aItems );
|
2017-03-22 13:43:10 +00:00
|
|
|
|
|
|
|
void Clear();
|
|
|
|
|
2020-11-11 23:05:59 +00:00
|
|
|
bool Remove( BOARD_ITEM* aItem );
|
|
|
|
bool Add( BOARD_ITEM* aItem );
|
2017-03-22 13:43:10 +00:00
|
|
|
|
2020-11-11 23:05:59 +00:00
|
|
|
const CLUSTERS SearchClusters( CLUSTER_SEARCH_MODE aMode, const KICAD_T aTypes[],
|
2022-02-06 17:26:30 +00:00
|
|
|
int aSingleNet, CN_ITEM* rootItem = nullptr );
|
2020-11-11 23:05:59 +00:00
|
|
|
const CLUSTERS SearchClusters( CLUSTER_SEARCH_MODE aMode );
|
2017-03-22 13:43:10 +00:00
|
|
|
|
2019-05-25 01:55:40 +00:00
|
|
|
/**
|
2021-06-04 16:21:48 +00:00
|
|
|
* Propagate nets from pads to other items in clusters.
|
|
|
|
* @param aCommit is used to store undo information for items modified by the call.
|
|
|
|
* @param aMode controls how clusters with conflicting nets are resolved.
|
2019-05-25 01:55:40 +00:00
|
|
|
*/
|
2021-03-23 21:42:56 +00:00
|
|
|
void PropagateNets( BOARD_COMMIT* aCommit = nullptr,
|
|
|
|
PROPAGATE_MODE aMode = PROPAGATE_MODE::SKIP_CONFLICTS );
|
2019-05-25 01:55:40 +00:00
|
|
|
|
2020-11-11 23:05:59 +00:00
|
|
|
void FindIsolatedCopperIslands( ZONE* aZone, PCB_LAYER_ID aLayer, std::vector<int>& aIslands );
|
2018-06-26 06:12:11 +00:00
|
|
|
|
|
|
|
/**
|
2021-06-04 16:21:48 +00:00
|
|
|
* Find the copper islands that are not connected to a net.
|
|
|
|
*
|
|
|
|
* These are added to the m_islands vector.
|
2018-06-26 06:12:11 +00:00
|
|
|
* N.B. This must be called after aZones has been refreshed.
|
2021-06-04 16:21:48 +00:00
|
|
|
*
|
|
|
|
* @param: aZones is the set of zones to search for islands.
|
2018-06-26 06:12:11 +00:00
|
|
|
*/
|
2020-11-11 23:05:59 +00:00
|
|
|
void FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones );
|
2017-11-23 16:20:27 +00:00
|
|
|
|
2017-03-22 13:43:10 +00:00
|
|
|
const CLUSTERS& GetClusters();
|
2017-03-28 16:30:49 +00:00
|
|
|
|
2020-04-12 19:10:57 +00:00
|
|
|
const CN_LIST& ItemList() const
|
|
|
|
{
|
|
|
|
return m_itemList;
|
|
|
|
}
|
2017-04-18 15:32:05 +00:00
|
|
|
|
2020-04-12 19:10:57 +00:00
|
|
|
template <typename Func>
|
|
|
|
void ForEachAnchor( Func&& aFunc ) const
|
|
|
|
{
|
|
|
|
for( auto&& item : m_itemList )
|
|
|
|
{
|
|
|
|
for( auto&& anchor : item->Anchors() )
|
|
|
|
aFunc( *anchor );
|
|
|
|
}
|
|
|
|
}
|
2020-04-12 18:59:13 +00:00
|
|
|
|
|
|
|
template <typename Func>
|
2020-04-12 19:10:57 +00:00
|
|
|
void ForEachItem( Func&& aFunc ) const
|
2020-04-12 18:59:13 +00:00
|
|
|
{
|
|
|
|
for( auto&& item : m_itemList )
|
|
|
|
aFunc( *item );
|
|
|
|
}
|
|
|
|
|
2017-07-01 21:54:17 +00:00
|
|
|
void MarkNetAsDirty( int aNet );
|
2017-11-23 16:20:27 +00:00
|
|
|
void SetProgressReporter( PROGRESS_REPORTER* aReporter );
|
2021-06-04 16:21:48 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
void searchConnections();
|
|
|
|
|
|
|
|
void propagateConnections( BOARD_COMMIT* aCommit = nullptr,
|
|
|
|
PROPAGATE_MODE aMode = PROPAGATE_MODE::SKIP_CONFLICTS );
|
|
|
|
|
|
|
|
template <class Container, class BItem>
|
|
|
|
void add( Container& c, BItem brditem )
|
|
|
|
{
|
|
|
|
auto item = c.Add( brditem );
|
|
|
|
|
|
|
|
m_itemMap[ brditem ] = ITEM_MAP_ENTRY( item );
|
|
|
|
}
|
|
|
|
|
|
|
|
void markItemNetAsDirty( const BOARD_ITEM* aItem );
|
|
|
|
|
2021-11-30 14:19:39 +00:00
|
|
|
private:
|
|
|
|
CN_LIST m_itemList;
|
2021-06-04 16:21:48 +00:00
|
|
|
std::unordered_map<const BOARD_ITEM*, ITEM_MAP_ENTRY> m_itemMap;
|
|
|
|
|
2021-11-30 14:19:39 +00:00
|
|
|
CLUSTERS m_connClusters;
|
|
|
|
CLUSTERS m_ratsnestClusters;
|
|
|
|
std::vector<bool> m_dirtyNets;
|
2021-06-04 16:21:48 +00:00
|
|
|
|
2021-11-30 14:19:39 +00:00
|
|
|
PROGRESS_REPORTER* m_progressReporter = nullptr;
|
2017-03-22 13:43:10 +00:00
|
|
|
};
|
|
|
|
|
2021-11-30 14:19:39 +00:00
|
|
|
|
2021-01-27 22:15:38 +00:00
|
|
|
class CN_VISITOR
|
|
|
|
{
|
2018-05-21 00:06:01 +00:00
|
|
|
public:
|
2018-10-13 00:06:10 +00:00
|
|
|
CN_VISITOR( CN_ITEM* aItem ) :
|
|
|
|
m_item( aItem )
|
2018-05-21 00:06:01 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
bool operator()( CN_ITEM* aCandidate );
|
|
|
|
|
|
|
|
protected:
|
2020-09-23 19:02:21 +00:00
|
|
|
void checkZoneItemConnection( CN_ZONE_LAYER* aZoneLayer, CN_ITEM* aItem );
|
2018-05-21 00:06:01 +00:00
|
|
|
|
2020-09-23 19:02:21 +00:00
|
|
|
void checkZoneZoneConnection( CN_ZONE_LAYER* aZoneLayerA, CN_ZONE_LAYER* aZoneLayerB );
|
2018-05-21 00:06:01 +00:00
|
|
|
|
2021-11-30 14:19:39 +00:00
|
|
|
protected:
|
|
|
|
CN_ITEM* m_item; ///< The item we are looking for connections to.
|
2018-05-21 00:06:01 +00:00
|
|
|
};
|
|
|
|
|
2017-03-22 13:43:10 +00:00
|
|
|
#endif
|