You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

276 lines
7.8 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
  5. * Copyright (C) 2020 CERN
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-3.0.html
  20. * or you may search the http://www.gnu.org website for the version 3 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #ifndef EESCHEMA_SCH_RTREE_H_
  25. #define EESCHEMA_SCH_RTREE_H_
  26. #include <core/typeinfo.h>
  27. #include <eda_rect.h>
  28. #include <sch_item.h>
  29. #include <set>
  30. #include <vector>
  31. #include <geometry/rtree.h>
  32. /**
  33. * EE_RTREE -
  34. * Implements an R-tree for fast spatial and type indexing of schematic items.
  35. * Non-owning.
  36. */
  37. class EE_RTREE
  38. {
  39. private:
  40. using ee_rtree = RTree<SCH_ITEM*, int, 3, double>;
  41. public:
  42. EE_RTREE()
  43. {
  44. this->m_tree = new ee_rtree();
  45. m_count = 0;
  46. }
  47. ~EE_RTREE()
  48. {
  49. delete this->m_tree;
  50. }
  51. /**
  52. * Function Insert()
  53. * Inserts an item into the tree. Item's bounding box is taken via its BBox() method.
  54. */
  55. void insert( SCH_ITEM* aItem )
  56. {
  57. const EDA_RECT& bbox = aItem->GetBoundingBox();
  58. const int type = int( aItem->Type() );
  59. const int mmin[3] = { type, bbox.GetX(), bbox.GetY() };
  60. const int mmax[3] = { type, bbox.GetRight(), bbox.GetBottom() };
  61. m_tree->Insert( mmin, mmax, aItem );
  62. m_count++;
  63. }
  64. /**
  65. * Function Remove()
  66. * Removes an item from the tree. Removal is done by comparing pointers, attempting
  67. * to remove a copy of the item will fail.
  68. */
  69. bool remove( SCH_ITEM* aItem )
  70. {
  71. // First, attempt to remove the item using its given BBox
  72. const EDA_RECT& bbox = aItem->GetBoundingBox();
  73. const int type = int( aItem->Type() );
  74. const int mmin[3] = { type, bbox.GetX(), bbox.GetY() };
  75. const int mmax[3] = { type, bbox.GetRight(), bbox.GetBottom() };
  76. // If we are not successful ( true == not found ), then we expand
  77. // the search to the full tree
  78. if( m_tree->Remove( mmin, mmax, aItem ) )
  79. {
  80. // N.B. We must search the whole tree for the pointer to remove
  81. // because the item may have been moved before we have the chance to
  82. // delete it from the tree
  83. const int mmin2[3] = { INT_MIN, INT_MIN, INT_MIN };
  84. const int mmax2[3] = { INT_MAX, INT_MAX, INT_MAX };
  85. if( m_tree->Remove( mmin2, mmax2, aItem ) )
  86. return false;
  87. }
  88. m_count--;
  89. return true;
  90. }
  91. /**
  92. * Function RemoveAll()
  93. * Removes all items from the RTree
  94. */
  95. void clear()
  96. {
  97. m_tree->RemoveAll();
  98. m_count = 0;
  99. }
  100. /**
  101. * Determine if a given item exists in the tree. Note that this does not search the full tree
  102. * so if the item has been moved, this will return false when it should be true.
  103. *
  104. * @param aItem Item that may potentially exist in the tree
  105. * @param aRobust If true, search the whole tree, not just the bounding box
  106. * @return true if the item definitely exists, false if it does not exist within bbox
  107. */
  108. bool contains( const SCH_ITEM* aItem, bool aRobust = false ) const
  109. {
  110. const EDA_RECT& bbox = aItem->GetBoundingBox();
  111. const int type = int( aItem->Type() );
  112. const int mmin[3] = { type, bbox.GetX(), bbox.GetY() };
  113. const int mmax[3] = { type, bbox.GetRight(), bbox.GetBottom() };
  114. bool found = false;
  115. auto search = [&found, &aItem]( const SCH_ITEM* aSearchItem ) {
  116. if( aSearchItem == aItem )
  117. {
  118. found = true;
  119. return false;
  120. }
  121. return true;
  122. };
  123. m_tree->Search( mmin, mmax, search );
  124. if( !found && aRobust )
  125. {
  126. // N.B. We must search the whole tree for the pointer to remove
  127. // because the item may have been moved. We do not expand the item
  128. // type search as this should not change.
  129. const int mmin2[3] = { type, INT_MIN, INT_MIN };
  130. const int mmax2[3] = { type, INT_MAX, INT_MAX };
  131. m_tree->Search( mmin2, mmax2, search );
  132. }
  133. return found;
  134. }
  135. /**
  136. * Returns the number of items in the tree
  137. * @return number of elements in the tree;
  138. */
  139. size_t size() const
  140. {
  141. return m_count;
  142. }
  143. bool empty() const
  144. {
  145. return m_count == 0;
  146. }
  147. using iterator = typename ee_rtree::Iterator;
  148. /**
  149. * The EE_TYPE struct provides a type-specific auto-range iterator to the RTree. Using
  150. * this struct, one can write lines like:
  151. *
  152. * for( auto item : rtree.OfType( SCH_COMPONENT_T ) )
  153. *
  154. * and iterate over the RTree items that are symbols only
  155. */
  156. struct EE_TYPE
  157. {
  158. EE_TYPE( ee_rtree* aTree, KICAD_T aType ) : type_tree( aTree )
  159. {
  160. KICAD_T type = BaseType( aType );
  161. if( type == SCH_LOCATE_ANY_T )
  162. m_rect = { { INT_MIN, INT_MIN, INT_MIN }, { INT_MAX, INT_MAX, INT_MAX } };
  163. else
  164. m_rect = { { type, INT_MIN, INT_MIN }, { type, INT_MAX, INT_MAX } };
  165. };
  166. EE_TYPE( ee_rtree* aTree, KICAD_T aType, const EDA_RECT aRect ) : type_tree( aTree )
  167. {
  168. KICAD_T type = BaseType( aType );
  169. if( type == SCH_LOCATE_ANY_T )
  170. m_rect = { { INT_MIN, aRect.GetX(), aRect.GetY() },
  171. { INT_MAX, aRect.GetRight(), aRect.GetBottom() } };
  172. else
  173. m_rect = { { type, aRect.GetX(), aRect.GetY() },
  174. { type, aRect.GetRight(), aRect.GetBottom() } };
  175. };
  176. ee_rtree::Rect m_rect;
  177. ee_rtree* type_tree;
  178. iterator begin()
  179. {
  180. return type_tree->begin( m_rect );
  181. }
  182. iterator end()
  183. {
  184. return type_tree->end( m_rect );
  185. }
  186. };
  187. EE_TYPE OfType( KICAD_T aType ) const
  188. {
  189. return EE_TYPE( m_tree, aType );
  190. }
  191. EE_TYPE Overlapping( const EDA_RECT& aRect )
  192. {
  193. return EE_TYPE( m_tree, SCH_LOCATE_ANY_T, aRect );
  194. }
  195. EE_TYPE Overlapping( const wxPoint& aPoint, int aAccuracy = 0 )
  196. {
  197. EDA_RECT rect( aPoint, wxSize( 0, 0 ) );
  198. rect.Inflate( aAccuracy );
  199. return EE_TYPE( m_tree, SCH_LOCATE_ANY_T, rect );
  200. }
  201. EE_TYPE Overlapping( KICAD_T aType, const wxPoint& aPoint, int aAccuracy = 0 )
  202. {
  203. EDA_RECT rect( aPoint, wxSize( 0, 0 ) );
  204. rect.Inflate( aAccuracy );
  205. return EE_TYPE( m_tree, aType, rect );
  206. }
  207. EE_TYPE Overlapping( KICAD_T aType, const EDA_RECT& aRect )
  208. {
  209. return EE_TYPE( m_tree, aType, aRect );
  210. }
  211. iterator begin()
  212. {
  213. return m_tree->begin();
  214. }
  215. iterator end()
  216. {
  217. return m_tree->end();
  218. }
  219. const iterator begin() const
  220. {
  221. return m_tree->begin();
  222. }
  223. const iterator end() const
  224. {
  225. return m_tree->end();
  226. }
  227. private:
  228. ee_rtree* m_tree;
  229. size_t m_count;
  230. };
  231. #endif /* EESCHEMA_SCH_RTREE_H_ */