/* * KiRouter - a push-and-(sometimes-)shove PCB router * * Copyright (C) 2013 CERN * 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 3 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, see . */ #ifndef __PNS_INDEX_H #define __PNS_INDEX_H #include #include #include #include #include "pns_item.h" /** * Class PNS_INDEX * * Custom spatial index, holding our board items and allowing for very fast searches. Items * are assigned to separate R-Tree subundices depending on their type and spanned layers, reducing * overlap and improving search time. **/ class PNS_INDEX { public: typedef std::list NetItemsList; typedef SHAPE_INDEX ItemShapeIndex; typedef boost::unordered_set ItemSet; PNS_INDEX(); ~PNS_INDEX(); void Add( PNS_ITEM* aItem ); void Remove( PNS_ITEM* aItem ); void Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ); template int Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& v ); template int Query( const SHAPE* aShape, int aMinDistance, Visitor& v ); void Clear(); NetItemsList* GetItemsForNet( int aNet ); ItemSet::iterator begin() { return m_allItems.begin(); } ItemSet::iterator end() { return m_allItems.end(); } bool Contains( PNS_ITEM* aItem ) const { return m_allItems.find( aItem ) != m_allItems.end(); } int Size() const { return m_allItems.size(); } private: static const int MaxSubIndices = 64; static const int SI_Multilayer = 2; static const int SI_SegDiagonal = 0; static const int SI_SegStraight = 1; static const int SI_Traces = 3; static const int SI_PadsTop = 0; static const int SI_PadsBottom = 1; template int querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& v ); ItemShapeIndex* getSubindex( const PNS_ITEM* aItem ); ItemShapeIndex* m_subIndices[MaxSubIndices]; std::map m_netMap; ItemSet m_allItems; }; PNS_INDEX::PNS_INDEX() { memset( m_subIndices, 0, sizeof( m_subIndices ) ); } PNS_INDEX::ItemShapeIndex* PNS_INDEX::getSubindex( const PNS_ITEM* aItem ) { int idx_n = -1; const PNS_LAYERSET l = aItem->GetLayers(); switch( aItem->GetKind() ) { case PNS_ITEM::VIA: idx_n = SI_Multilayer; break; case PNS_ITEM::SOLID: { if( l.IsMultilayer() ) idx_n = SI_Multilayer; else if( l.Start() == 0 ) // fixme: use kicad layer codes idx_n = SI_PadsTop; else if( l.Start() == 15 ) idx_n = SI_PadsBottom; break; } case PNS_ITEM::SEGMENT: case PNS_ITEM::LINE: idx_n = SI_Traces + 2 * l.Start() + SI_SegStraight; break; default: break; } assert( idx_n >= 0 && idx_n < MaxSubIndices ); if( !m_subIndices[idx_n] ) m_subIndices[idx_n] = new ItemShapeIndex; return m_subIndices[idx_n]; } void PNS_INDEX::Add( PNS_ITEM* aItem ) { ItemShapeIndex* idx = getSubindex( aItem ); idx->Add( aItem ); m_allItems.insert( aItem ); int net = aItem->GetNet(); if( net >= 0 ) { m_netMap[net].push_back( aItem ); } } void PNS_INDEX::Remove( PNS_ITEM* aItem ) { ItemShapeIndex* idx = getSubindex( aItem ); idx->Remove( aItem ); m_allItems.erase( aItem ); int net = aItem->GetNet(); if( net >= 0 && m_netMap.find( net ) != m_netMap.end() ) m_netMap[net].remove( aItem ); } void PNS_INDEX::Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem ) { Remove( aOldItem ); Add( aNewItem ); } template int PNS_INDEX::querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& v ) { if( !m_subIndices[index] ) return 0; return m_subIndices[index]->Query( aShape, aMinDistance, v, false ); } template int PNS_INDEX::Query( const PNS_ITEM* aItem, int aMinDistance, Visitor& v ) { const SHAPE* shape = aItem->GetShape(); int total = 0; total += querySingle( SI_Multilayer, shape, aMinDistance, v ); const PNS_LAYERSET layers = aItem->GetLayers(); if( layers.IsMultilayer() ) { total += querySingle( SI_PadsTop, shape, aMinDistance, v ); total += querySingle( SI_PadsBottom, shape, aMinDistance, v ); for( int i = layers.Start(); i <= layers.End(); ++i ) total += querySingle( SI_Traces + 2 * i + SI_SegStraight, shape, aMinDistance, v ); } else { int l = layers.Start(); if( l == 0 ) total += querySingle( SI_PadsTop, shape, aMinDistance, v ); else if( l == 15 ) total += querySingle( SI_PadsBottom, shape, aMinDistance, v ); total += querySingle( SI_Traces + 2 * l + SI_SegStraight, shape, aMinDistance, v ); } return total; } template int PNS_INDEX::Query( const SHAPE* aShape, int aMinDistance, Visitor& v ) { int total = 0; for( int i = 0; i < MaxSubIndices; i++ ) total += querySingle( i, aShape, aMinDistance, v ); return total; } void PNS_INDEX::Clear() { for( int i = 0; i < MaxSubIndices; ++i ) { ItemShapeIndex* idx = m_subIndices[i]; if( idx ) delete idx; m_subIndices[i] = NULL; } } PNS_INDEX::~PNS_INDEX() { Clear(); } PNS_INDEX::NetItemsList* PNS_INDEX::GetItemsForNet( int aNet ) { if( m_netMap.find( aNet ) == m_netMap.end() ) return NULL; return &m_netMap[aNet]; } #endif