/* * KiRouter - a push-and-(sometimes-)shove PCB router * * Copyright (C) 2013-2014 CERN * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors. * 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 #include #include "pns_item.h" namespace PNS { /** * Class INDEX * * Custom spatial index, holding our board items and allowing for very fast searches. Items * are assigned to separate R-Tree subindices depending on their type and spanned layers, reducing * overlap and improving search time. **/ class INDEX { public: typedef std::list NET_ITEMS_LIST; typedef SHAPE_INDEX ITEM_SHAPE_INDEX; typedef std::unordered_set ITEM_SET; INDEX(); ~INDEX(); /** * Function Add() * * Adds item to the spatial index. */ void Add( ITEM* aItem ); /** * Function Remove() * * Removes an item from the spatial index. */ void Remove( ITEM* aItem ); /** * Function Add() * * Replaces one item with another. */ void Replace( ITEM* aOldItem, ITEM* aNewItem ); /** * Function Query() * * Searches items in the index that are in proximity of aItem. * For each item, function object aVisitor is called. Only items on * overlapping layers are considered. * * @param aItem item to search against * @param aMinDistance proximity distance (wrs to the item's shape) * @param aVisitor function object called on each found item. Return false from the visitor to stop searching. * @return number of items found. */ template int Query( const ITEM* aItem, int aMinDistance, Visitor& aVisitor ); /** * Function Query() * * Searches items in the index that are in proximity of aShape. * For each item, function object aVisitor is called. Treats all * layers as colliding. * * @param aShape shape to search against * @param aMinDistance proximity distance (wrs to the item's shape) * @param aVisitor function object called on each found item. Return false from the visitor to stop searching. * @return number of items found. */ template int Query( const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ); /** * Function Clear() * * Removes all items from the index. */ void Clear(); /** * Function GetItemsForNet() * * Returns list of all items in a given net. */ NET_ITEMS_LIST* GetItemsForNet( int aNet ); /** * Function Contains() * * Returns true if item aItem exists in the index. */ bool Contains( ITEM* aItem ) const { return m_allItems.find( aItem ) != m_allItems.end(); } /** * Function Size() * * Returns number of items stored in the index. */ int Size() const { return m_allItems.size(); } ITEM_SET::iterator begin() { return m_allItems.begin(); } ITEM_SET::iterator end() { return m_allItems.end(); } private: static const int MaxSubIndices = 128; 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& aVisitor ); ITEM_SHAPE_INDEX* getSubindex( const ITEM* aItem ); ITEM_SHAPE_INDEX* m_subIndices[MaxSubIndices]; std::map m_netMap; ITEM_SET m_allItems; }; template int INDEX::querySingle( int index, const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ) { if( !m_subIndices[index] ) return 0; return m_subIndices[index]->Query( aShape, aMinDistance, aVisitor, false ); } template int INDEX::Query( const ITEM* aItem, int aMinDistance, Visitor& aVisitor ) { const SHAPE* shape = aItem->Shape(); int total = 0; total += querySingle( SI_Multilayer, shape, aMinDistance, aVisitor ); const LAYER_RANGE& layers = aItem->Layers(); if( layers.IsMultilayer() ) { total += querySingle( SI_PadsTop, shape, aMinDistance, aVisitor ); total += querySingle( SI_PadsBottom, shape, aMinDistance, aVisitor ); for( int i = layers.Start(); i <= layers.End(); ++i ) total += querySingle( SI_Traces + 2 * i + SI_SegStraight, shape, aMinDistance, aVisitor ); } else { int l = layers.Start(); if( l == B_Cu ) total += querySingle( SI_PadsTop, shape, aMinDistance, aVisitor ); else if( l == F_Cu ) total += querySingle( SI_PadsBottom, shape, aMinDistance, aVisitor ); total += querySingle( SI_Traces + 2 * l + SI_SegStraight, shape, aMinDistance, aVisitor ); } return total; } template int INDEX::Query( const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ) { int total = 0; for( int i = 0; i < MaxSubIndices; i++ ) total += querySingle( i, aShape, aMinDistance, aVisitor ); return total; } }; #endif