pcbnew: re-organizing connectivity
The connectivity files were unwieldy. This separates them logically into data, algo and items where the items classes are those that hold, surprise, surprise, the items, lists and clusters.
This commit is contained in:
parent
4460313104
commit
cfaf7c1f23
|
@ -440,6 +440,7 @@ set( PCB_COMMON_SRCS
|
|||
../pcbnew/class_zone.cpp
|
||||
../pcbnew/collectors.cpp
|
||||
../pcbnew/connectivity/connectivity_algo.cpp
|
||||
../pcbnew/connectivity/connectivity_items.cpp
|
||||
../pcbnew/connectivity/connectivity_data.cpp
|
||||
../pcbnew/convert_drawsegment_list_to_polygon.cpp
|
||||
../pcbnew/drc_item.cpp
|
||||
|
|
|
@ -11,6 +11,7 @@ include_directories(
|
|||
set( PCBNEW_CONN_SRCS
|
||||
connectivity_algo.cpp
|
||||
connectivity_data.cpp
|
||||
connectivity_items.cpp
|
||||
)
|
||||
|
||||
add_library( connectivity STATIC ${PCBNEW_CONN_SRCS} )
|
||||
|
|
|
@ -45,91 +45,8 @@ bool operator<( const CN_ANCHOR_PTR& a, const CN_ANCHOR_PTR& b )
|
|||
}
|
||||
|
||||
|
||||
CN_CLUSTER::CN_CLUSTER()
|
||||
{
|
||||
m_items.reserve( 64 );
|
||||
m_originPad = nullptr;
|
||||
m_originNet = -1;
|
||||
m_conflicting = false;
|
||||
}
|
||||
|
||||
|
||||
CN_CLUSTER::~CN_CLUSTER()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
wxString CN_CLUSTER::OriginNetName() const
|
||||
{
|
||||
if( !m_originPad || !m_originPad->Valid() )
|
||||
return "<none>";
|
||||
else
|
||||
return m_originPad->Parent()->GetNetname();
|
||||
}
|
||||
|
||||
|
||||
bool CN_CLUSTER::Contains( const CN_ITEM* aItem )
|
||||
{
|
||||
return std::find( m_items.begin(), m_items.end(), aItem ) != m_items.end();
|
||||
}
|
||||
|
||||
|
||||
bool CN_CLUSTER::Contains( const BOARD_CONNECTED_ITEM* aItem )
|
||||
{
|
||||
return std::find_if( m_items.begin(), m_items.end(), [ &aItem ] ( const CN_ITEM* item )
|
||||
{ return item->Valid() && item->Parent() == aItem; } ) != m_items.end();
|
||||
}
|
||||
|
||||
|
||||
void CN_ITEM::Dump()
|
||||
{
|
||||
printf(" valid: %d, connected: \n", !!Valid());
|
||||
|
||||
for( auto i : m_connected )
|
||||
{
|
||||
TRACK* t = static_cast<TRACK*>( i->Parent() );
|
||||
printf( " - %p %d\n", t, t->Type() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CN_CLUSTER::Dump()
|
||||
{
|
||||
for( auto item : m_items )
|
||||
{
|
||||
wxLogTrace( "CN", " - item : %p bitem : %p type : %d inet %s\n", item, item->Parent(),
|
||||
item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() );
|
||||
printf( "- item : %p bitem : %p type : %d inet %s\n", item, item->Parent(),
|
||||
item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() );
|
||||
item->Dump();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CN_CLUSTER::Add( CN_ITEM* item )
|
||||
{
|
||||
m_items.push_back( item );
|
||||
|
||||
if( m_originNet < 0 )
|
||||
{
|
||||
m_originNet = item->Net();
|
||||
}
|
||||
|
||||
if( item->Parent()->Type() == PCB_PAD_T )
|
||||
{
|
||||
if( !m_originPad )
|
||||
{
|
||||
m_originPad = item;
|
||||
m_originNet = item->Net();
|
||||
}
|
||||
|
||||
if( m_originPad && item->Net() != m_originNet )
|
||||
{
|
||||
m_conflicting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CN_CONNECTIVITY_ALGO::CN_CONNECTIVITY_ALGO()
|
||||
{
|
||||
|
@ -378,47 +295,6 @@ void CN_CONNECTIVITY_ALGO::searchConnections()
|
|||
}
|
||||
|
||||
|
||||
void CN_ITEM::RemoveInvalidRefs()
|
||||
{
|
||||
for( auto it = m_connected.begin(); it != m_connected.end(); )
|
||||
{
|
||||
if( !(*it)->Valid() )
|
||||
it = m_connected.erase( it );
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CN_LIST::RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage )
|
||||
{
|
||||
if( !m_hasInvalid )
|
||||
return;
|
||||
|
||||
auto lastItem = std::remove_if(m_items.begin(), m_items.end(), [&aGarbage] ( CN_ITEM* item )
|
||||
{
|
||||
if( !item->Valid() )
|
||||
{
|
||||
aGarbage.push_back ( item );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} );
|
||||
|
||||
m_items.resize( lastItem - m_items.begin() );
|
||||
|
||||
// fixme: mem leaks
|
||||
for( auto item : m_items )
|
||||
item->RemoveInvalidRefs();
|
||||
|
||||
for( auto item : aGarbage )
|
||||
m_index.Remove( item );
|
||||
|
||||
m_hasInvalid = false;
|
||||
}
|
||||
|
||||
|
||||
const CN_CONNECTIVITY_ALGO::CLUSTERS CN_CONNECTIVITY_ALGO::SearchClusters( CLUSTER_SEARCH_MODE aMode )
|
||||
{
|
||||
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_PAD_T, PCB_VIA_T, PCB_ZONE_AREA_T, PCB_MODULE_T, EOT };
|
||||
|
@ -850,93 +726,6 @@ bool CN_VISITOR::operator()( CN_ITEM* aCandidate )
|
|||
};
|
||||
|
||||
|
||||
int CN_ITEM::AnchorCount() const
|
||||
{
|
||||
if( !m_valid )
|
||||
return 0;
|
||||
|
||||
return m_parent->Type() == PCB_TRACE_T ? 2 : 1;
|
||||
}
|
||||
|
||||
|
||||
const VECTOR2I CN_ITEM::GetAnchor( int n ) const
|
||||
{
|
||||
if( !m_valid )
|
||||
return VECTOR2I();
|
||||
|
||||
switch( m_parent->Type() )
|
||||
{
|
||||
case PCB_PAD_T:
|
||||
return static_cast<const D_PAD*>( m_parent )->ShapePos();
|
||||
break;
|
||||
|
||||
case PCB_TRACE_T:
|
||||
{
|
||||
auto tr = static_cast<const TRACK*>( m_parent );
|
||||
return ( n == 0 ? tr->GetStart() : tr->GetEnd() );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_VIA_T:
|
||||
return static_cast<const VIA*>( m_parent )->GetStart();
|
||||
|
||||
default:
|
||||
assert( false );
|
||||
return VECTOR2I();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CN_ZONE::AnchorCount() const
|
||||
{
|
||||
if( !Valid() )
|
||||
return 0;
|
||||
|
||||
const auto zone = static_cast<const ZONE_CONTAINER*>( Parent() );
|
||||
const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex );
|
||||
|
||||
return outline.PointCount() ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
const VECTOR2I CN_ZONE::GetAnchor( int n ) const
|
||||
{
|
||||
if( !Valid() )
|
||||
return VECTOR2I();
|
||||
|
||||
const auto zone = static_cast<const ZONE_CONTAINER*> ( Parent() );
|
||||
const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex );
|
||||
|
||||
return outline.CPoint( 0 );
|
||||
}
|
||||
|
||||
|
||||
int CN_ITEM::Net() const
|
||||
{
|
||||
if( !m_parent || !m_valid )
|
||||
return -1;
|
||||
|
||||
return m_parent->GetNetCode();
|
||||
}
|
||||
|
||||
|
||||
BOARD_CONNECTED_ITEM* CN_ANCHOR::Parent() const
|
||||
{
|
||||
assert( m_item->Valid() );
|
||||
return m_item->Parent();
|
||||
}
|
||||
|
||||
|
||||
bool CN_ANCHOR::Valid() const
|
||||
{
|
||||
if( !m_item )
|
||||
return false;
|
||||
|
||||
return m_item->Valid();
|
||||
}
|
||||
|
||||
|
||||
void CN_CONNECTIVITY_ALGO::Clear()
|
||||
{
|
||||
m_ratsnestClusters.clear();
|
||||
|
@ -964,57 +753,6 @@ void CN_CONNECTIVITY_ALGO::ForEachAnchor( const std::function<void( CN_ANCHOR& )
|
|||
}
|
||||
|
||||
|
||||
bool CN_ANCHOR::IsDangling() const
|
||||
{
|
||||
if( !m_cluster )
|
||||
return true;
|
||||
|
||||
// Calculate the item count connected to this anchor.
|
||||
// m_cluster groups all items connected, but they are not necessary connected
|
||||
// at this coordinate point (they are only candidates)
|
||||
BOARD_CONNECTED_ITEM* item_ref = Parent();
|
||||
LSET layers = item_ref->GetLayerSet() & LSET::AllCuMask();
|
||||
|
||||
// the number of items connected to item_ref at ths anchor point
|
||||
int connected_items_count = 0;
|
||||
|
||||
// the minimal number of items connected to item_ref
|
||||
// at this anchor point to decide the anchor is *not* dangling
|
||||
int minimal_count = 1;
|
||||
|
||||
// a via can be removed if connected to only one other item.
|
||||
// the minimal_count is therefore 2
|
||||
if( item_ref->Type() == PCB_VIA_T )
|
||||
minimal_count = 2;
|
||||
|
||||
for( CN_ITEM* item : *m_cluster )
|
||||
{
|
||||
if( !item->Valid() )
|
||||
continue;
|
||||
|
||||
BOARD_CONNECTED_ITEM* brd_item = item->Parent();
|
||||
|
||||
if( brd_item == item_ref )
|
||||
continue;
|
||||
|
||||
// count only items on the same layer at this coordinate (especially for zones)
|
||||
if( !( brd_item->GetLayerSet() & layers ).any() )
|
||||
continue;
|
||||
|
||||
if( brd_item->Type() == PCB_ZONE_AREA_T )
|
||||
{
|
||||
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( brd_item );
|
||||
|
||||
if( zone->HitTestInsideZone( wxPoint( Pos() ) ) )
|
||||
connected_items_count++;
|
||||
}
|
||||
else if( brd_item->HitTest( wxPoint( Pos() ) ) )
|
||||
connected_items_count++;
|
||||
}
|
||||
|
||||
return connected_items_count < minimal_count;
|
||||
}
|
||||
|
||||
void CN_CONNECTIVITY_ALGO::SetProgressReporter( PROGRESS_REPORTER* aReporter )
|
||||
{
|
||||
m_progressReporter = aReporter;
|
||||
|
|
|
@ -45,116 +45,16 @@
|
|||
|
||||
#include <connectivity/connectivity_rtree.h>
|
||||
#include <connectivity/connectivity_data.h>
|
||||
#include <connectivity/connectivity_items.h>
|
||||
|
||||
class CN_ITEM;
|
||||
class CN_CONNECTIVITY_ALGO_IMPL;
|
||||
class CN_RATSNEST_NODES;
|
||||
class CN_CLUSTER;
|
||||
class BOARD;
|
||||
class BOARD_CONNECTED_ITEM;
|
||||
class BOARD_ITEM;
|
||||
class ZONE_CONTAINER;
|
||||
class PROGRESS_REPORTER;
|
||||
|
||||
class CN_ANCHOR
|
||||
{
|
||||
public:
|
||||
CN_ANCHOR()
|
||||
{
|
||||
m_item = nullptr;
|
||||
}
|
||||
|
||||
CN_ANCHOR( const VECTOR2I& aPos, CN_ITEM* aItem )
|
||||
{
|
||||
m_pos = aPos;
|
||||
m_item = aItem;
|
||||
assert( m_item );
|
||||
}
|
||||
|
||||
bool Valid() const;
|
||||
|
||||
|
||||
CN_ITEM* Item() const
|
||||
{
|
||||
return m_item;
|
||||
}
|
||||
|
||||
BOARD_CONNECTED_ITEM* Parent() const;
|
||||
|
||||
const VECTOR2I& Pos() const
|
||||
{
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
/// Returns tag, common identifier for connected nodes
|
||||
inline int GetTag() const
|
||||
{
|
||||
return m_tag;
|
||||
}
|
||||
|
||||
/// Sets tag, common identifier for connected nodes
|
||||
inline void SetTag( int aTag )
|
||||
{
|
||||
m_tag = aTag;
|
||||
}
|
||||
|
||||
/// Decides whether this node can be a ratsnest line target
|
||||
inline void SetNoLine( bool aEnable )
|
||||
{
|
||||
m_noline = aEnable;
|
||||
}
|
||||
|
||||
/// Returns true if this node can be a target for ratsnest lines
|
||||
inline const bool& GetNoLine() const
|
||||
{
|
||||
return m_noline;
|
||||
}
|
||||
|
||||
inline void SetCluster( std::shared_ptr<CN_CLUSTER> aCluster )
|
||||
{
|
||||
m_cluster = aCluster;
|
||||
}
|
||||
|
||||
inline std::shared_ptr<CN_CLUSTER> GetCluster() const
|
||||
{
|
||||
return m_cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* has meaning only for tracks and vias.
|
||||
* @return true if this anchor is dangling
|
||||
* The anchor point is dangling if the parent is a track
|
||||
* and this anchor point is not connected to another item
|
||||
* ( track, vas pad or zone) or if the parent is a via and this anchor point
|
||||
* is connected to only one track and not to another item
|
||||
*/
|
||||
bool IsDangling() const;
|
||||
|
||||
// Tag used for unconnected items.
|
||||
static const int TAG_UNCONNECTED = -1;
|
||||
|
||||
private:
|
||||
/// Position of the anchor
|
||||
VECTOR2I m_pos;
|
||||
|
||||
/// Item owning the anchor
|
||||
CN_ITEM* m_item = nullptr;
|
||||
|
||||
/// Tag for quick connection resolution
|
||||
int m_tag = -1;
|
||||
|
||||
/// Whether it the node can be a target for ratsnest lines
|
||||
bool m_noline = false;
|
||||
|
||||
/// Cluster to which the anchor belongs
|
||||
std::shared_ptr<CN_CLUSTER> m_cluster;
|
||||
};
|
||||
|
||||
|
||||
typedef std::shared_ptr<CN_ANCHOR> CN_ANCHOR_PTR;
|
||||
typedef std::vector<CN_ANCHOR_PTR> CN_ANCHORS;
|
||||
|
||||
|
||||
class CN_EDGE
|
||||
{
|
||||
public:
|
||||
|
@ -199,474 +99,6 @@ private:
|
|||
bool m_visible = true;
|
||||
};
|
||||
|
||||
|
||||
class CN_CLUSTER
|
||||
{
|
||||
private:
|
||||
|
||||
bool m_conflicting = false;
|
||||
int m_originNet = 0;
|
||||
CN_ITEM* m_originPad = nullptr;
|
||||
std::vector<CN_ITEM*> m_items;
|
||||
|
||||
public:
|
||||
CN_CLUSTER();
|
||||
~CN_CLUSTER();
|
||||
|
||||
bool HasValidNet() const
|
||||
{
|
||||
return m_originNet >= 0;
|
||||
}
|
||||
|
||||
int OriginNet() const
|
||||
{
|
||||
return m_originNet;
|
||||
}
|
||||
|
||||
wxString OriginNetName() const;
|
||||
|
||||
bool Contains( const CN_ITEM* aItem );
|
||||
bool Contains( const BOARD_CONNECTED_ITEM* aItem );
|
||||
void Dump();
|
||||
|
||||
int Size() const
|
||||
{
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
bool HasNet() const
|
||||
{
|
||||
return m_originNet >= 0;
|
||||
}
|
||||
|
||||
bool IsOrphaned() const
|
||||
{
|
||||
return m_originPad == nullptr;
|
||||
}
|
||||
|
||||
bool IsConflicting() const
|
||||
{
|
||||
return m_conflicting;
|
||||
}
|
||||
|
||||
void Add( CN_ITEM* item );
|
||||
|
||||
using ITER = decltype(m_items)::iterator;
|
||||
|
||||
ITER begin() { return m_items.begin(); };
|
||||
ITER end() { return m_items.end(); };
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<CN_CLUSTER> CN_CLUSTER_PTR;
|
||||
|
||||
|
||||
// basic connectivity item
|
||||
class CN_ITEM : public INTRUSIVE_LIST<CN_ITEM>
|
||||
{
|
||||
private:
|
||||
BOARD_CONNECTED_ITEM* m_parent;
|
||||
|
||||
using CONNECTED_ITEMS = std::set<CN_ITEM*>;
|
||||
|
||||
///> list of items physically connected (touching)
|
||||
CONNECTED_ITEMS m_connected;
|
||||
|
||||
CN_ANCHORS m_anchors;
|
||||
|
||||
///> visited flag for the BFS scan
|
||||
bool m_visited;
|
||||
|
||||
///> can the net propagator modify the netcode?
|
||||
bool m_canChangeNet;
|
||||
|
||||
///> valid flag, used to identify garbage items (we use lazy removal)
|
||||
bool m_valid;
|
||||
|
||||
protected:
|
||||
///> dirty flag, used to identify recently added item not yet scanned into the connectivity search
|
||||
bool m_dirty;
|
||||
|
||||
///> layer range over which the item exists
|
||||
LAYER_RANGE m_layers;
|
||||
|
||||
///> bounding box for the item
|
||||
BOX2I m_bbox;
|
||||
|
||||
public:
|
||||
void Dump();
|
||||
|
||||
CN_ITEM( BOARD_CONNECTED_ITEM* aParent, bool aCanChangeNet, int aAnchorCount = 2 )
|
||||
{
|
||||
m_parent = aParent;
|
||||
m_canChangeNet = aCanChangeNet;
|
||||
m_visited = false;
|
||||
m_valid = true;
|
||||
m_dirty = true;
|
||||
m_anchors.reserve( 2 );
|
||||
m_layers = LAYER_RANGE( 0, PCB_LAYER_ID_COUNT );
|
||||
}
|
||||
|
||||
virtual ~CN_ITEM() {};
|
||||
|
||||
void AddAnchor( const VECTOR2I& aPos )
|
||||
{
|
||||
m_anchors.emplace_back( std::make_unique<CN_ANCHOR>( aPos, this ) );
|
||||
}
|
||||
|
||||
CN_ANCHORS& Anchors()
|
||||
{
|
||||
return m_anchors;
|
||||
}
|
||||
|
||||
void SetValid( bool aValid )
|
||||
{
|
||||
m_valid = aValid;
|
||||
}
|
||||
|
||||
bool Valid() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
void SetDirty( bool aDirty )
|
||||
{
|
||||
m_dirty = aDirty;
|
||||
}
|
||||
|
||||
bool Dirty() const
|
||||
{
|
||||
return m_dirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function SetLayers()
|
||||
*
|
||||
* Sets the layers spanned by the item to aLayers.
|
||||
*/
|
||||
void SetLayers( const LAYER_RANGE& aLayers )
|
||||
{
|
||||
m_layers = aLayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function SetLayer()
|
||||
*
|
||||
* Sets the layers spanned by the item to a single layer aLayer.
|
||||
*/
|
||||
void SetLayer( int aLayer )
|
||||
{
|
||||
m_layers = LAYER_RANGE( aLayer, aLayer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function Layers()
|
||||
*
|
||||
* Returns the contiguous set of layers spanned by the item.
|
||||
*/
|
||||
const LAYER_RANGE& Layers() const
|
||||
{
|
||||
return m_layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function Layer()
|
||||
*
|
||||
* Returns the item's layer, for single-layered items only.
|
||||
*/
|
||||
virtual int Layer() const
|
||||
{
|
||||
return Layers().Start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function LayersOverlap()
|
||||
*
|
||||
* Returns true if the set of layers spanned by aOther overlaps our
|
||||
* layers.
|
||||
*/
|
||||
bool LayersOverlap( const CN_ITEM* aOther ) const
|
||||
{
|
||||
return Layers().Overlaps( aOther->Layers() );
|
||||
}
|
||||
|
||||
const BOX2I& BBox()
|
||||
{
|
||||
if( m_dirty && m_valid )
|
||||
{
|
||||
EDA_RECT box = m_parent->GetBoundingBox();
|
||||
m_bbox = BOX2I( box.GetPosition(), box.GetSize() );
|
||||
}
|
||||
return m_bbox;
|
||||
}
|
||||
|
||||
BOARD_CONNECTED_ITEM* Parent() const
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
const CONNECTED_ITEMS& ConnectedItems() const
|
||||
{
|
||||
return m_connected;
|
||||
}
|
||||
|
||||
void ClearConnections()
|
||||
{
|
||||
m_connected.clear();
|
||||
}
|
||||
|
||||
void SetVisited( bool aVisited )
|
||||
{
|
||||
m_visited = aVisited;
|
||||
}
|
||||
|
||||
bool Visited() const
|
||||
{
|
||||
return m_visited;
|
||||
}
|
||||
|
||||
bool CanChangeNet() const
|
||||
{
|
||||
return m_canChangeNet;
|
||||
}
|
||||
|
||||
bool isConnected( CN_ITEM* aItem ) const
|
||||
{
|
||||
return ( m_connected.find( aItem ) != m_connected.end() );
|
||||
}
|
||||
|
||||
static void Connect( CN_ITEM* a, CN_ITEM* b )
|
||||
{
|
||||
a->m_connected.insert( b );
|
||||
b->m_connected.insert( a );
|
||||
}
|
||||
|
||||
void RemoveInvalidRefs();
|
||||
|
||||
virtual int AnchorCount() const;
|
||||
virtual const VECTOR2I GetAnchor( int n ) const;
|
||||
|
||||
int Net() const;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<CN_ITEM> CN_ITEM_PTR;
|
||||
|
||||
class CN_ZONE : public CN_ITEM
|
||||
{
|
||||
public:
|
||||
CN_ZONE( ZONE_CONTAINER* aParent, bool aCanChangeNet, int aSubpolyIndex ) :
|
||||
CN_ITEM( aParent, aCanChangeNet ),
|
||||
m_subpolyIndex( aSubpolyIndex )
|
||||
{
|
||||
SHAPE_LINE_CHAIN outline = aParent->GetFilledPolysList().COutline( aSubpolyIndex );
|
||||
|
||||
outline.SetClosed( true );
|
||||
outline.Simplify();
|
||||
|
||||
m_cachedPoly.reset( new POLY_GRID_PARTITION( outline, 16 ) );
|
||||
}
|
||||
|
||||
int SubpolyIndex() const
|
||||
{
|
||||
return m_subpolyIndex;
|
||||
}
|
||||
|
||||
bool ContainsAnchor( const CN_ANCHOR_PTR anchor ) const
|
||||
{
|
||||
return ContainsPoint( anchor->Pos() );
|
||||
}
|
||||
|
||||
bool ContainsPoint( const VECTOR2I p ) const
|
||||
{
|
||||
auto zone = static_cast<ZONE_CONTAINER*> ( Parent() );
|
||||
return m_cachedPoly->ContainsPoint( p, zone->GetMinThickness() );
|
||||
}
|
||||
|
||||
const BOX2I& BBox()
|
||||
{
|
||||
if( m_dirty )
|
||||
m_bbox = m_cachedPoly->BBox();
|
||||
|
||||
return m_bbox;
|
||||
}
|
||||
|
||||
virtual int AnchorCount() const override;
|
||||
virtual const VECTOR2I GetAnchor( int n ) const override;
|
||||
|
||||
private:
|
||||
std::vector<VECTOR2I> m_testOutlinePoints;
|
||||
std::unique_ptr<POLY_GRID_PARTITION> m_cachedPoly;
|
||||
int m_subpolyIndex;
|
||||
};
|
||||
|
||||
class CN_LIST
|
||||
{
|
||||
private:
|
||||
bool m_dirty;
|
||||
bool m_hasInvalid;
|
||||
|
||||
CN_RTREE<CN_ITEM*> m_index;
|
||||
|
||||
protected:
|
||||
std::vector<CN_ITEM*> m_items;
|
||||
|
||||
void addItemtoTree( CN_ITEM* item )
|
||||
{
|
||||
m_index.Insert( item );
|
||||
}
|
||||
|
||||
public:
|
||||
CN_LIST()
|
||||
{
|
||||
m_dirty = false;
|
||||
m_hasInvalid = false;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for( auto item : m_items )
|
||||
delete item;
|
||||
|
||||
m_items.clear();
|
||||
m_index.RemoveAll();
|
||||
}
|
||||
|
||||
using ITER = decltype(m_items)::iterator;
|
||||
|
||||
ITER begin() { return m_items.begin(); };
|
||||
ITER end() { return m_items.end(); };
|
||||
|
||||
CN_ITEM* operator[] ( int aIndex ) { return m_items[aIndex]; }
|
||||
|
||||
template <class T>
|
||||
void FindNearby( CN_ITEM *aItem, T aFunc );
|
||||
|
||||
void SetHasInvalid( bool aInvalid = true )
|
||||
{
|
||||
m_hasInvalid = aInvalid;
|
||||
}
|
||||
|
||||
void SetDirty( bool aDirty = true )
|
||||
{
|
||||
m_dirty = aDirty;
|
||||
}
|
||||
|
||||
bool IsDirty() const
|
||||
{
|
||||
return m_dirty;
|
||||
}
|
||||
|
||||
void RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage );
|
||||
|
||||
void ClearDirtyFlags()
|
||||
{
|
||||
for( auto item : m_items )
|
||||
item->SetDirty( false );
|
||||
|
||||
SetDirty( false );
|
||||
}
|
||||
|
||||
void MarkAllAsDirty()
|
||||
{
|
||||
for( auto item : m_items )
|
||||
item->SetDirty( true );
|
||||
|
||||
SetDirty( true );
|
||||
}
|
||||
|
||||
int Size() const
|
||||
{
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
CN_ITEM* Add( D_PAD* pad )
|
||||
{
|
||||
auto item = new CN_ITEM( pad, false, 1 );
|
||||
item->AddAnchor( pad->ShapePos() );
|
||||
item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) );
|
||||
|
||||
switch( pad->GetAttribute() )
|
||||
{
|
||||
case PAD_ATTRIB_SMD:
|
||||
case PAD_ATTRIB_HOLE_NOT_PLATED:
|
||||
case PAD_ATTRIB_CONN:
|
||||
{
|
||||
LSET lmsk = pad->GetLayerSet();
|
||||
|
||||
for( int i = 0; i <= MAX_CU_LAYERS; i++ )
|
||||
{
|
||||
if( lmsk[i] )
|
||||
{
|
||||
item->SetLayer( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
addItemtoTree( item );
|
||||
m_items.push_back( item );
|
||||
SetDirty();
|
||||
return item;
|
||||
}
|
||||
|
||||
CN_ITEM* Add( TRACK* track )
|
||||
{
|
||||
auto item = new CN_ITEM( track, true );
|
||||
m_items.push_back( item );
|
||||
item->AddAnchor( track->GetStart() );
|
||||
item->AddAnchor( track->GetEnd() );
|
||||
item->SetLayer( track->GetLayer() );
|
||||
addItemtoTree( item );
|
||||
SetDirty();
|
||||
return item;
|
||||
}
|
||||
|
||||
CN_ITEM* Add( VIA* via )
|
||||
{
|
||||
auto item = new CN_ITEM( via, true, 1 );
|
||||
|
||||
m_items.push_back( item );
|
||||
item->AddAnchor( via->GetStart() );
|
||||
item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) );
|
||||
addItemtoTree( item );
|
||||
SetDirty();
|
||||
return item;
|
||||
}
|
||||
|
||||
const std::vector<CN_ITEM*> Add( ZONE_CONTAINER* zone )
|
||||
{
|
||||
const auto& polys = zone->GetFilledPolysList();
|
||||
|
||||
std::vector<CN_ITEM*> rv;
|
||||
|
||||
for( int j = 0; j < polys.OutlineCount(); j++ )
|
||||
{
|
||||
CN_ZONE* zitem = new CN_ZONE( zone, false, j );
|
||||
const auto& outline = zone->GetFilledPolysList().COutline( j );
|
||||
|
||||
for( int k = 0; k < outline.PointCount(); k++ )
|
||||
zitem->AddAnchor( outline.CPoint( k ) );
|
||||
|
||||
m_items.push_back( zitem );
|
||||
zitem->SetLayer( zone->GetLayer() );
|
||||
addItemtoTree( zitem );
|
||||
rv.push_back( zitem );
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void CN_LIST::FindNearby( CN_ITEM *aItem, T aFunc )
|
||||
{
|
||||
m_index.Query( aItem->BBox(), aItem->Layers(), aFunc );
|
||||
}
|
||||
|
||||
class CN_CONNECTIVITY_ALGO
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016-2018 CERN
|
||||
* Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
#include <connectivity/connectivity_items.h>
|
||||
|
||||
int CN_ITEM::AnchorCount() const
|
||||
{
|
||||
if( !m_valid )
|
||||
return 0;
|
||||
|
||||
return m_parent->Type() == PCB_TRACE_T ? 2 : 1;
|
||||
}
|
||||
|
||||
|
||||
const VECTOR2I CN_ITEM::GetAnchor( int n ) const
|
||||
{
|
||||
if( !m_valid )
|
||||
return VECTOR2I();
|
||||
|
||||
switch( m_parent->Type() )
|
||||
{
|
||||
case PCB_PAD_T:
|
||||
return static_cast<const D_PAD*>( m_parent )->ShapePos();
|
||||
break;
|
||||
|
||||
case PCB_TRACE_T:
|
||||
{
|
||||
auto tr = static_cast<const TRACK*>( m_parent );
|
||||
return ( n == 0 ? tr->GetStart() : tr->GetEnd() );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_VIA_T:
|
||||
return static_cast<const VIA*>( m_parent )->GetStart();
|
||||
|
||||
default:
|
||||
assert( false );
|
||||
return VECTOR2I();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CN_ITEM::Net() const
|
||||
{
|
||||
if( !m_parent || !m_valid )
|
||||
return -1;
|
||||
|
||||
return m_parent->GetNetCode();
|
||||
}
|
||||
|
||||
|
||||
void CN_ITEM::Dump()
|
||||
{
|
||||
printf(" valid: %d, connected: \n", !!Valid());
|
||||
|
||||
for( auto i : m_connected )
|
||||
{
|
||||
TRACK* t = static_cast<TRACK*>( i->Parent() );
|
||||
printf( " - %p %d\n", t, t->Type() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CN_ZONE::AnchorCount() const
|
||||
{
|
||||
if( !Valid() )
|
||||
return 0;
|
||||
|
||||
const auto zone = static_cast<const ZONE_CONTAINER*>( Parent() );
|
||||
const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex );
|
||||
|
||||
return outline.PointCount() ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
const VECTOR2I CN_ZONE::GetAnchor( int n ) const
|
||||
{
|
||||
if( !Valid() )
|
||||
return VECTOR2I();
|
||||
|
||||
const auto zone = static_cast<const ZONE_CONTAINER*> ( Parent() );
|
||||
const auto& outline = zone->GetFilledPolysList().COutline( m_subpolyIndex );
|
||||
|
||||
return outline.CPoint( 0 );
|
||||
}
|
||||
|
||||
|
||||
void CN_ITEM::RemoveInvalidRefs()
|
||||
{
|
||||
for( auto it = m_connected.begin(); it != m_connected.end(); )
|
||||
{
|
||||
if( !(*it)->Valid() )
|
||||
it = m_connected.erase( it );
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CN_LIST::RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage )
|
||||
{
|
||||
if( !m_hasInvalid )
|
||||
return;
|
||||
|
||||
auto lastItem = std::remove_if(m_items.begin(), m_items.end(), [&aGarbage] ( CN_ITEM* item )
|
||||
{
|
||||
if( !item->Valid() )
|
||||
{
|
||||
aGarbage.push_back ( item );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} );
|
||||
|
||||
m_items.resize( lastItem - m_items.begin() );
|
||||
|
||||
// fixme: mem leaks
|
||||
for( auto item : m_items )
|
||||
item->RemoveInvalidRefs();
|
||||
|
||||
for( auto item : aGarbage )
|
||||
m_index.Remove( item );
|
||||
|
||||
m_hasInvalid = false;
|
||||
}
|
||||
|
||||
|
||||
BOARD_CONNECTED_ITEM* CN_ANCHOR::Parent() const
|
||||
{
|
||||
assert( m_item->Valid() );
|
||||
return m_item->Parent();
|
||||
}
|
||||
|
||||
|
||||
bool CN_ANCHOR::Valid() const
|
||||
{
|
||||
if( !m_item )
|
||||
return false;
|
||||
|
||||
return m_item->Valid();
|
||||
}
|
||||
|
||||
|
||||
bool CN_ANCHOR::IsDangling() const
|
||||
{
|
||||
if( !m_cluster )
|
||||
return true;
|
||||
|
||||
// Calculate the item count connected to this anchor.
|
||||
// m_cluster groups all items connected, but they are not necessary connected
|
||||
// at this coordinate point (they are only candidates)
|
||||
BOARD_CONNECTED_ITEM* item_ref = Parent();
|
||||
LSET layers = item_ref->GetLayerSet() & LSET::AllCuMask();
|
||||
|
||||
// the number of items connected to item_ref at ths anchor point
|
||||
int connected_items_count = 0;
|
||||
|
||||
// the minimal number of items connected to item_ref
|
||||
// at this anchor point to decide the anchor is *not* dangling
|
||||
int minimal_count = 1;
|
||||
|
||||
// a via can be removed if connected to only one other item.
|
||||
// the minimal_count is therefore 2
|
||||
if( item_ref->Type() == PCB_VIA_T )
|
||||
minimal_count = 2;
|
||||
|
||||
for( CN_ITEM* item : *m_cluster )
|
||||
{
|
||||
if( !item->Valid() )
|
||||
continue;
|
||||
|
||||
BOARD_CONNECTED_ITEM* brd_item = item->Parent();
|
||||
|
||||
if( brd_item == item_ref )
|
||||
continue;
|
||||
|
||||
// count only items on the same layer at this coordinate (especially for zones)
|
||||
if( !( brd_item->GetLayerSet() & layers ).any() )
|
||||
continue;
|
||||
|
||||
if( brd_item->Type() == PCB_ZONE_AREA_T )
|
||||
{
|
||||
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( brd_item );
|
||||
|
||||
if( zone->HitTestInsideZone( wxPoint( Pos() ) ) )
|
||||
connected_items_count++;
|
||||
}
|
||||
else if( brd_item->HitTest( wxPoint( Pos() ) ) )
|
||||
connected_items_count++;
|
||||
}
|
||||
|
||||
return connected_items_count < minimal_count;
|
||||
}
|
||||
|
||||
|
||||
CN_CLUSTER::CN_CLUSTER()
|
||||
{
|
||||
m_items.reserve( 64 );
|
||||
m_originPad = nullptr;
|
||||
m_originNet = -1;
|
||||
m_conflicting = false;
|
||||
}
|
||||
|
||||
|
||||
CN_CLUSTER::~CN_CLUSTER()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
wxString CN_CLUSTER::OriginNetName() const
|
||||
{
|
||||
if( !m_originPad || !m_originPad->Valid() )
|
||||
return "<none>";
|
||||
else
|
||||
return m_originPad->Parent()->GetNetname();
|
||||
}
|
||||
|
||||
|
||||
bool CN_CLUSTER::Contains( const CN_ITEM* aItem )
|
||||
{
|
||||
return std::find( m_items.begin(), m_items.end(), aItem ) != m_items.end();
|
||||
}
|
||||
|
||||
|
||||
bool CN_CLUSTER::Contains( const BOARD_CONNECTED_ITEM* aItem )
|
||||
{
|
||||
return std::find_if( m_items.begin(), m_items.end(), [ &aItem ] ( const CN_ITEM* item )
|
||||
{ return item->Valid() && item->Parent() == aItem; } ) != m_items.end();
|
||||
}
|
||||
|
||||
|
||||
void CN_CLUSTER::Dump()
|
||||
{
|
||||
for( auto item : m_items )
|
||||
{
|
||||
wxLogTrace( "CN", " - item : %p bitem : %p type : %d inet %s\n", item, item->Parent(),
|
||||
item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() );
|
||||
printf( "- item : %p bitem : %p type : %d inet %s\n", item, item->Parent(),
|
||||
item->Parent()->Type(), (const char*) item->Parent()->GetNetname().c_str() );
|
||||
item->Dump();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CN_CLUSTER::Add( CN_ITEM* item )
|
||||
{
|
||||
m_items.push_back( item );
|
||||
|
||||
if( m_originNet < 0 )
|
||||
{
|
||||
m_originNet = item->Net();
|
||||
}
|
||||
|
||||
if( item->Parent()->Type() == PCB_PAD_T )
|
||||
{
|
||||
if( !m_originPad )
|
||||
{
|
||||
m_originPad = item;
|
||||
m_originNet = item->Net();
|
||||
}
|
||||
|
||||
if( m_originPad && item->Net() != m_originNet )
|
||||
{
|
||||
m_conflicting = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,619 @@
|
|||
/*
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013-2017 CERN
|
||||
* Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PCBNEW_CONNECTIVITY_CONNECTIVITY_ITEMS_H_
|
||||
#define PCBNEW_CONNECTIVITY_CONNECTIVITY_ITEMS_H_
|
||||
|
||||
#include <class_board.h>
|
||||
#include <class_pad.h>
|
||||
#include <class_module.h>
|
||||
#include <class_zone.h>
|
||||
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/poly_grid_partition.h>
|
||||
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <intrusive_list.h>
|
||||
|
||||
#include <connectivity/connectivity_rtree.h>
|
||||
#include <connectivity/connectivity_data.h>
|
||||
|
||||
class CN_ITEM;
|
||||
class CN_CLUSTER;
|
||||
|
||||
class CN_ANCHOR
|
||||
{
|
||||
public:
|
||||
CN_ANCHOR()
|
||||
{
|
||||
m_item = nullptr;
|
||||
}
|
||||
|
||||
CN_ANCHOR( const VECTOR2I& aPos, CN_ITEM* aItem )
|
||||
{
|
||||
m_pos = aPos;
|
||||
m_item = aItem;
|
||||
assert( m_item );
|
||||
}
|
||||
|
||||
bool Valid() const;
|
||||
|
||||
|
||||
CN_ITEM* Item() const
|
||||
{
|
||||
return m_item;
|
||||
}
|
||||
|
||||
BOARD_CONNECTED_ITEM* Parent() const;
|
||||
|
||||
const VECTOR2I& Pos() const
|
||||
{
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
/// Returns tag, common identifier for connected nodes
|
||||
inline int GetTag() const
|
||||
{
|
||||
return m_tag;
|
||||
}
|
||||
|
||||
/// Sets tag, common identifier for connected nodes
|
||||
inline void SetTag( int aTag )
|
||||
{
|
||||
m_tag = aTag;
|
||||
}
|
||||
|
||||
/// Decides whether this node can be a ratsnest line target
|
||||
inline void SetNoLine( bool aEnable )
|
||||
{
|
||||
m_noline = aEnable;
|
||||
}
|
||||
|
||||
/// Returns true if this node can be a target for ratsnest lines
|
||||
inline const bool& GetNoLine() const
|
||||
{
|
||||
return m_noline;
|
||||
}
|
||||
|
||||
inline void SetCluster( std::shared_ptr<CN_CLUSTER> aCluster )
|
||||
{
|
||||
m_cluster = aCluster;
|
||||
}
|
||||
|
||||
inline std::shared_ptr<CN_CLUSTER> GetCluster() const
|
||||
{
|
||||
return m_cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* has meaning only for tracks and vias.
|
||||
* @return true if this anchor is dangling
|
||||
* The anchor point is dangling if the parent is a track
|
||||
* and this anchor point is not connected to another item
|
||||
* ( track, vas pad or zone) or if the parent is a via and this anchor point
|
||||
* is connected to only one track and not to another item
|
||||
*/
|
||||
bool IsDangling() const;
|
||||
|
||||
// Tag used for unconnected items.
|
||||
static const int TAG_UNCONNECTED = -1;
|
||||
|
||||
private:
|
||||
/// Position of the anchor
|
||||
VECTOR2I m_pos;
|
||||
|
||||
/// Item owning the anchor
|
||||
CN_ITEM* m_item = nullptr;
|
||||
|
||||
/// Tag for quick connection resolution
|
||||
int m_tag = -1;
|
||||
|
||||
/// Whether it the node can be a target for ratsnest lines
|
||||
bool m_noline = false;
|
||||
|
||||
/// Cluster to which the anchor belongs
|
||||
std::shared_ptr<CN_CLUSTER> m_cluster;
|
||||
};
|
||||
|
||||
|
||||
typedef std::shared_ptr<CN_ANCHOR> CN_ANCHOR_PTR;
|
||||
typedef std::vector<CN_ANCHOR_PTR> CN_ANCHORS;
|
||||
|
||||
|
||||
// basic connectivity item
|
||||
class CN_ITEM : public INTRUSIVE_LIST<CN_ITEM>
|
||||
{
|
||||
private:
|
||||
BOARD_CONNECTED_ITEM* m_parent;
|
||||
|
||||
using CONNECTED_ITEMS = std::set<CN_ITEM*>;
|
||||
|
||||
///> list of items physically connected (touching)
|
||||
CONNECTED_ITEMS m_connected;
|
||||
|
||||
CN_ANCHORS m_anchors;
|
||||
|
||||
///> visited flag for the BFS scan
|
||||
bool m_visited;
|
||||
|
||||
///> can the net propagator modify the netcode?
|
||||
bool m_canChangeNet;
|
||||
|
||||
///> valid flag, used to identify garbage items (we use lazy removal)
|
||||
bool m_valid;
|
||||
|
||||
protected:
|
||||
///> dirty flag, used to identify recently added item not yet scanned into the connectivity search
|
||||
bool m_dirty;
|
||||
|
||||
///> layer range over which the item exists
|
||||
LAYER_RANGE m_layers;
|
||||
|
||||
///> bounding box for the item
|
||||
BOX2I m_bbox;
|
||||
|
||||
public:
|
||||
void Dump();
|
||||
|
||||
CN_ITEM( BOARD_CONNECTED_ITEM* aParent, bool aCanChangeNet, int aAnchorCount = 2 )
|
||||
{
|
||||
m_parent = aParent;
|
||||
m_canChangeNet = aCanChangeNet;
|
||||
m_visited = false;
|
||||
m_valid = true;
|
||||
m_dirty = true;
|
||||
m_anchors.reserve( 2 );
|
||||
m_layers = LAYER_RANGE( 0, PCB_LAYER_ID_COUNT );
|
||||
}
|
||||
|
||||
virtual ~CN_ITEM() {};
|
||||
|
||||
void AddAnchor( const VECTOR2I& aPos )
|
||||
{
|
||||
m_anchors.emplace_back( std::make_unique<CN_ANCHOR>( aPos, this ) );
|
||||
}
|
||||
|
||||
CN_ANCHORS& Anchors()
|
||||
{
|
||||
return m_anchors;
|
||||
}
|
||||
|
||||
void SetValid( bool aValid )
|
||||
{
|
||||
m_valid = aValid;
|
||||
}
|
||||
|
||||
bool Valid() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
void SetDirty( bool aDirty )
|
||||
{
|
||||
m_dirty = aDirty;
|
||||
}
|
||||
|
||||
bool Dirty() const
|
||||
{
|
||||
return m_dirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function SetLayers()
|
||||
*
|
||||
* Sets the layers spanned by the item to aLayers.
|
||||
*/
|
||||
void SetLayers( const LAYER_RANGE& aLayers )
|
||||
{
|
||||
m_layers = aLayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function SetLayer()
|
||||
*
|
||||
* Sets the layers spanned by the item to a single layer aLayer.
|
||||
*/
|
||||
void SetLayer( int aLayer )
|
||||
{
|
||||
m_layers = LAYER_RANGE( aLayer, aLayer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function Layers()
|
||||
*
|
||||
* Returns the contiguous set of layers spanned by the item.
|
||||
*/
|
||||
const LAYER_RANGE& Layers() const
|
||||
{
|
||||
return m_layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function Layer()
|
||||
*
|
||||
* Returns the item's layer, for single-layered items only.
|
||||
*/
|
||||
virtual int Layer() const
|
||||
{
|
||||
return Layers().Start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function LayersOverlap()
|
||||
*
|
||||
* Returns true if the set of layers spanned by aOther overlaps our
|
||||
* layers.
|
||||
*/
|
||||
bool LayersOverlap( const CN_ITEM* aOther ) const
|
||||
{
|
||||
return Layers().Overlaps( aOther->Layers() );
|
||||
}
|
||||
|
||||
const BOX2I& BBox()
|
||||
{
|
||||
if( m_dirty && m_valid )
|
||||
{
|
||||
EDA_RECT box = m_parent->GetBoundingBox();
|
||||
m_bbox = BOX2I( box.GetPosition(), box.GetSize() );
|
||||
}
|
||||
return m_bbox;
|
||||
}
|
||||
|
||||
BOARD_CONNECTED_ITEM* Parent() const
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
const CONNECTED_ITEMS& ConnectedItems() const
|
||||
{
|
||||
return m_connected;
|
||||
}
|
||||
|
||||
void ClearConnections()
|
||||
{
|
||||
m_connected.clear();
|
||||
}
|
||||
|
||||
void SetVisited( bool aVisited )
|
||||
{
|
||||
m_visited = aVisited;
|
||||
}
|
||||
|
||||
bool Visited() const
|
||||
{
|
||||
return m_visited;
|
||||
}
|
||||
|
||||
bool CanChangeNet() const
|
||||
{
|
||||
return m_canChangeNet;
|
||||
}
|
||||
|
||||
bool isConnected( CN_ITEM* aItem ) const
|
||||
{
|
||||
return ( m_connected.find( aItem ) != m_connected.end() );
|
||||
}
|
||||
|
||||
static void Connect( CN_ITEM* a, CN_ITEM* b )
|
||||
{
|
||||
a->m_connected.insert( b );
|
||||
b->m_connected.insert( a );
|
||||
}
|
||||
|
||||
void RemoveInvalidRefs();
|
||||
|
||||
virtual int AnchorCount() const;
|
||||
virtual const VECTOR2I GetAnchor( int n ) const;
|
||||
|
||||
int Net() const;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<CN_ITEM> CN_ITEM_PTR;
|
||||
|
||||
class CN_ZONE : public CN_ITEM
|
||||
{
|
||||
public:
|
||||
CN_ZONE( ZONE_CONTAINER* aParent, bool aCanChangeNet, int aSubpolyIndex ) :
|
||||
CN_ITEM( aParent, aCanChangeNet ),
|
||||
m_subpolyIndex( aSubpolyIndex )
|
||||
{
|
||||
SHAPE_LINE_CHAIN outline = aParent->GetFilledPolysList().COutline( aSubpolyIndex );
|
||||
|
||||
outline.SetClosed( true );
|
||||
outline.Simplify();
|
||||
|
||||
m_cachedPoly.reset( new POLY_GRID_PARTITION( outline, 16 ) );
|
||||
}
|
||||
|
||||
int SubpolyIndex() const
|
||||
{
|
||||
return m_subpolyIndex;
|
||||
}
|
||||
|
||||
bool ContainsAnchor( const CN_ANCHOR_PTR anchor ) const
|
||||
{
|
||||
return ContainsPoint( anchor->Pos() );
|
||||
}
|
||||
|
||||
bool ContainsPoint( const VECTOR2I p ) const
|
||||
{
|
||||
auto zone = static_cast<ZONE_CONTAINER*> ( Parent() );
|
||||
return m_cachedPoly->ContainsPoint( p, zone->GetMinThickness() );
|
||||
}
|
||||
|
||||
const BOX2I& BBox()
|
||||
{
|
||||
if( m_dirty )
|
||||
m_bbox = m_cachedPoly->BBox();
|
||||
|
||||
return m_bbox;
|
||||
}
|
||||
|
||||
virtual int AnchorCount() const override;
|
||||
virtual const VECTOR2I GetAnchor( int n ) const override;
|
||||
|
||||
private:
|
||||
std::vector<VECTOR2I> m_testOutlinePoints;
|
||||
std::unique_ptr<POLY_GRID_PARTITION> m_cachedPoly;
|
||||
int m_subpolyIndex;
|
||||
};
|
||||
|
||||
class CN_LIST
|
||||
{
|
||||
private:
|
||||
bool m_dirty;
|
||||
bool m_hasInvalid;
|
||||
|
||||
CN_RTREE<CN_ITEM*> m_index;
|
||||
|
||||
protected:
|
||||
std::vector<CN_ITEM*> m_items;
|
||||
|
||||
void addItemtoTree( CN_ITEM* item )
|
||||
{
|
||||
m_index.Insert( item );
|
||||
}
|
||||
|
||||
public:
|
||||
CN_LIST()
|
||||
{
|
||||
m_dirty = false;
|
||||
m_hasInvalid = false;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for( auto item : m_items )
|
||||
delete item;
|
||||
|
||||
m_items.clear();
|
||||
m_index.RemoveAll();
|
||||
}
|
||||
|
||||
using ITER = decltype(m_items)::iterator;
|
||||
|
||||
ITER begin() { return m_items.begin(); };
|
||||
ITER end() { return m_items.end(); };
|
||||
|
||||
CN_ITEM* operator[] ( int aIndex ) { return m_items[aIndex]; }
|
||||
|
||||
template <class T>
|
||||
void FindNearby( CN_ITEM *aItem, T aFunc );
|
||||
|
||||
void SetHasInvalid( bool aInvalid = true )
|
||||
{
|
||||
m_hasInvalid = aInvalid;
|
||||
}
|
||||
|
||||
void SetDirty( bool aDirty = true )
|
||||
{
|
||||
m_dirty = aDirty;
|
||||
}
|
||||
|
||||
bool IsDirty() const
|
||||
{
|
||||
return m_dirty;
|
||||
}
|
||||
|
||||
void RemoveInvalidItems( std::vector<CN_ITEM*>& aGarbage );
|
||||
|
||||
void ClearDirtyFlags()
|
||||
{
|
||||
for( auto item : m_items )
|
||||
item->SetDirty( false );
|
||||
|
||||
SetDirty( false );
|
||||
}
|
||||
|
||||
void MarkAllAsDirty()
|
||||
{
|
||||
for( auto item : m_items )
|
||||
item->SetDirty( true );
|
||||
|
||||
SetDirty( true );
|
||||
}
|
||||
|
||||
int Size() const
|
||||
{
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
CN_ITEM* Add( D_PAD* pad )
|
||||
{
|
||||
auto item = new CN_ITEM( pad, false, 1 );
|
||||
item->AddAnchor( pad->ShapePos() );
|
||||
item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) );
|
||||
|
||||
switch( pad->GetAttribute() )
|
||||
{
|
||||
case PAD_ATTRIB_SMD:
|
||||
case PAD_ATTRIB_HOLE_NOT_PLATED:
|
||||
case PAD_ATTRIB_CONN:
|
||||
{
|
||||
LSET lmsk = pad->GetLayerSet();
|
||||
|
||||
for( int i = 0; i <= MAX_CU_LAYERS; i++ )
|
||||
{
|
||||
if( lmsk[i] )
|
||||
{
|
||||
item->SetLayer( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
addItemtoTree( item );
|
||||
m_items.push_back( item );
|
||||
SetDirty();
|
||||
return item;
|
||||
}
|
||||
|
||||
CN_ITEM* Add( TRACK* track )
|
||||
{
|
||||
auto item = new CN_ITEM( track, true );
|
||||
m_items.push_back( item );
|
||||
item->AddAnchor( track->GetStart() );
|
||||
item->AddAnchor( track->GetEnd() );
|
||||
item->SetLayer( track->GetLayer() );
|
||||
addItemtoTree( item );
|
||||
SetDirty();
|
||||
return item;
|
||||
}
|
||||
|
||||
CN_ITEM* Add( VIA* via )
|
||||
{
|
||||
auto item = new CN_ITEM( via, true, 1 );
|
||||
|
||||
m_items.push_back( item );
|
||||
item->AddAnchor( via->GetStart() );
|
||||
item->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) );
|
||||
addItemtoTree( item );
|
||||
SetDirty();
|
||||
return item;
|
||||
}
|
||||
|
||||
const std::vector<CN_ITEM*> Add( ZONE_CONTAINER* zone )
|
||||
{
|
||||
const auto& polys = zone->GetFilledPolysList();
|
||||
|
||||
std::vector<CN_ITEM*> rv;
|
||||
|
||||
for( int j = 0; j < polys.OutlineCount(); j++ )
|
||||
{
|
||||
CN_ZONE* zitem = new CN_ZONE( zone, false, j );
|
||||
const auto& outline = zone->GetFilledPolysList().COutline( j );
|
||||
|
||||
for( int k = 0; k < outline.PointCount(); k++ )
|
||||
zitem->AddAnchor( outline.CPoint( k ) );
|
||||
|
||||
m_items.push_back( zitem );
|
||||
zitem->SetLayer( zone->GetLayer() );
|
||||
addItemtoTree( zitem );
|
||||
rv.push_back( zitem );
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void CN_LIST::FindNearby( CN_ITEM *aItem, T aFunc )
|
||||
{
|
||||
m_index.Query( aItem->BBox(), aItem->Layers(), aFunc );
|
||||
}
|
||||
|
||||
class CN_CLUSTER
|
||||
{
|
||||
private:
|
||||
|
||||
bool m_conflicting = false;
|
||||
int m_originNet = 0;
|
||||
CN_ITEM* m_originPad = nullptr;
|
||||
std::vector<CN_ITEM*> m_items;
|
||||
|
||||
public:
|
||||
CN_CLUSTER();
|
||||
~CN_CLUSTER();
|
||||
|
||||
bool HasValidNet() const
|
||||
{
|
||||
return m_originNet >= 0;
|
||||
}
|
||||
|
||||
int OriginNet() const
|
||||
{
|
||||
return m_originNet;
|
||||
}
|
||||
|
||||
wxString OriginNetName() const;
|
||||
|
||||
bool Contains( const CN_ITEM* aItem );
|
||||
bool Contains( const BOARD_CONNECTED_ITEM* aItem );
|
||||
void Dump();
|
||||
|
||||
int Size() const
|
||||
{
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
bool HasNet() const
|
||||
{
|
||||
return m_originNet >= 0;
|
||||
}
|
||||
|
||||
bool IsOrphaned() const
|
||||
{
|
||||
return m_originPad == nullptr;
|
||||
}
|
||||
|
||||
bool IsConflicting() const
|
||||
{
|
||||
return m_conflicting;
|
||||
}
|
||||
|
||||
void Add( CN_ITEM* item );
|
||||
|
||||
using ITER = decltype(m_items)::iterator;
|
||||
|
||||
ITER begin() { return m_items.begin(); };
|
||||
ITER end() { return m_items.end(); };
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<CN_CLUSTER> CN_CLUSTER_PTR;
|
||||
|
||||
|
||||
#endif /* PCBNEW_CONNECTIVITY_CONNECTIVITY_ITEMS_H_ */
|
Loading…
Reference in New Issue