pcbnew: Split Layers in connectivity

Splits the connectivity search RTree by layers to avoid large penalty on
zone searches.

(cherry picked from commit dc1736eb87)
This commit is contained in:
Seth Hillbrand 2018-07-05 14:16:25 -07:00
parent 2ae8f6337d
commit d769d1649a
2 changed files with 102 additions and 38 deletions

View File

@ -288,6 +288,9 @@ 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;
@ -302,6 +305,7 @@ public:
m_valid = true;
m_dirty = true;
m_anchors.reserve( 2 );
m_layers = LAYER_RANGE( 0, PCB_LAYER_ID_COUNT );
}
virtual ~CN_ITEM() {};
@ -336,7 +340,58 @@ public:
return m_dirty;
}
const BOX2I BBox()
/**
* 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 )
{
@ -498,8 +553,31 @@ public:
CN_ITEM* Add( D_PAD* pad )
{
auto item = new CN_ITEM( pad, false, 2 );
auto item = new CN_ITEM( pad, false, 1 );
item->AddAnchor( pad->ShapePos() );
item->SetLayers( LAYER_RANGE( 0, PCB_LAYER_ID_COUNT ) );
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;
}
}
}
default:
break;
}
addItemtoTree( item );
m_items.push_back( item );
SetDirty();
@ -512,6 +590,7 @@ public:
m_items.push_back( item );
item->AddAnchor( track->GetStart() );
item->AddAnchor( track->GetEnd() );
item->SetLayer( track->GetLayer() );
addItemtoTree( item );
SetDirty();
return item;
@ -519,10 +598,11 @@ public:
CN_ITEM* Add( VIA* via )
{
auto item = new CN_ITEM( via, true );
auto item = new CN_ITEM( via, true, 1 );
m_items.push_back( item );
item->AddAnchor( via->GetStart() );
item->SetLayers( LAYER_RANGE( 0, PCB_LAYER_ID_COUNT ) );
addItemtoTree( item );
SetDirty();
return item;
@ -599,6 +679,7 @@ public:
zitem->AddAnchor( outline.CPoint( k ) );
m_items.push_back( zitem );
zitem->SetLayer( zone->GetLayer() );
addItemtoTree( zitem );
rv.push_back( zitem );
SetDirty();
@ -606,33 +687,12 @@ public:
return rv;
}
template <class T>
void FindNearbyZones( BOX2I aBBox, T aFunc, bool aDirtyOnly = false );
};
template <class T>
void CN_ZONE_LIST::FindNearbyZones( BOX2I aBBox, T aFunc, bool aDirtyOnly )
{
for( auto item : m_items )
{
auto zone = static_cast<CN_ZONE*>( item );
if( aBBox.Intersects( zone->BBox() ) )
{
if( !aDirtyOnly || zone->Dirty() )
{
aFunc( zone );
}
}
}
}
template <class T>
void CN_LIST::FindNearby( CN_ITEM *aItem, T aFunc )
{
m_index.Query( aItem->BBox(), aFunc );
m_index.Query( aItem->BBox(), aItem->Layers(), aFunc );
}
class CN_CONNECTIVITY_ALGO

View File

@ -25,6 +25,7 @@
#define PCBNEW_CONNECTIVITY_RTREE_H_
#include <math/box2.h>
#include <router/pns_layerset.h>
#include <geometry/rtree.h>
@ -41,7 +42,7 @@ public:
CN_RTREE()
{
this->m_tree = new RTree<T, int, 2, float>();
this->m_tree = new RTree<T, int, 3, double>();
}
~CN_RTREE()
@ -55,9 +56,11 @@ public:
*/
void Insert( T aItem )
{
const BOX2I& bbox = aItem->BBox();
const int mmin[2] = { bbox.GetX(), bbox.GetY() };
const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
const BOX2I& bbox = aItem->BBox();
const LAYER_RANGE layers = aItem->Layers();
const int mmin[3] = { layers.Start(), bbox.GetX(), bbox.GetY() };
const int mmax[3] = { layers.End(), bbox.GetRight(), bbox.GetBottom() };
m_tree->Insert( mmin, mmax, aItem );
}
@ -71,9 +74,10 @@ public:
{
// First, attempt to remove the item using its given BBox
const BOX2I& bbox = aItem->BBox();
const int mmin[2] = { bbox.GetX(), bbox.GetY() };
const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
const BOX2I& bbox = aItem->BBox();
const LAYER_RANGE layers = aItem->Layers();
const int mmin[3] = { layers.Start(), bbox.GetX(), bbox.GetY() };
const int mmax[3] = { layers.End(), bbox.GetRight(), bbox.GetBottom() };
// If we are not successful ( 1 == not found ), then we expand
// the search to the full tree
@ -82,8 +86,8 @@ public:
// N.B. We must search the whole tree for the pointer to remove
// because the item may have been moved before we have the chance to
// delete it from the tree
const int mmin2[2] = { INT_MIN, INT_MIN };
const int mmax2[2] = { INT_MAX, INT_MAX };
const int mmin2[3] = { INT_MIN, INT_MIN, INT_MIN };
const int mmax2[3] = { INT_MAX, INT_MAX, INT_MAX };
m_tree->Remove( mmin2, mmax2, aItem );
}
}
@ -103,17 +107,17 @@ public:
* with aBounds.
*/
template <class Visitor>
void Query( const BOX2I& aBounds, Visitor& aVisitor )
void Query( const BOX2I& aBounds, const LAYER_RANGE& aRange, Visitor& aVisitor )
{
const int mmin[2] = { aBounds.GetX(), aBounds.GetY() };
const int mmax[2] = { aBounds.GetRight(), aBounds.GetBottom() };
const int mmin[3] = { aRange.Start(), aBounds.GetX(), aBounds.GetY() };
const int mmax[3] = { aRange.End(), aBounds.GetRight(), aBounds.GetBottom() };
m_tree->Search( mmin, mmax, aVisitor );
}
private:
RTree<T, int, 2, float>* m_tree;
RTree<T, int, 3, double>* m_tree;
};