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.

308 lines
8.8 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2019-2021 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 <sch_item.h>
  28. #include <set>
  29. #include <vector>
  30. #include <geometry/rtree.h>
  31. /**
  32. * Implements an R-tree for fast spatial and type indexing of schematic items.
  33. * Non-owning.
  34. */
  35. class EE_RTREE
  36. {
  37. private:
  38. using ee_rtree = RTree<SCH_ITEM*, int, 3, double>;
  39. public:
  40. EE_RTREE()
  41. {
  42. this->m_tree = new ee_rtree();
  43. m_count = 0;
  44. }
  45. ~EE_RTREE()
  46. {
  47. delete this->m_tree;
  48. }
  49. /**
  50. * Insert an item into the tree. Item's bounding box is taken via its BBox() method.
  51. */
  52. void insert( SCH_ITEM* aItem )
  53. {
  54. BOX2I bbox = aItem->GetBoundingBox();
  55. // Inflate a bit for safety, selection shadows, etc.
  56. bbox.Inflate( aItem->GetPenWidth() );
  57. const int type = int( aItem->Type() );
  58. const int mmin[3] = { type, bbox.GetX(), bbox.GetY() };
  59. const int mmax[3] = { type, bbox.GetRight(), bbox.GetBottom() };
  60. m_tree->Insert( mmin, mmax, aItem );
  61. m_count++;
  62. }
  63. /**
  64. * Remove an item from the tree. Removal is done by comparing pointers, attempting
  65. * to remove a copy of the item will fail.
  66. */
  67. bool remove( SCH_ITEM* aItem )
  68. {
  69. // First, attempt to remove the item using its given BBox
  70. BOX2I bbox = aItem->GetBoundingBox();
  71. // Inflate a bit for safety, selection shadows, etc.
  72. bbox.Inflate( aItem->GetPenWidth() );
  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. * Remove all items from the RTree
  93. */
  94. void clear()
  95. {
  96. m_tree->RemoveAll();
  97. m_count = 0;
  98. }
  99. /**
  100. * Determine if a given item exists in the tree. Note that this does not search the full tree
  101. * so if the item has been moved, this will return false when it should be true.
  102. *
  103. * @param aItem Item that may potentially exist in the tree.
  104. * @param aRobust If true, search the whole tree, not just the bounding box.
  105. * @return true if the item definitely exists, false if it does not exist within bbox.
  106. */
  107. bool contains( const SCH_ITEM* aItem, bool aRobust = false ) const
  108. {
  109. BOX2I bbox = aItem->GetBoundingBox();
  110. // Inflate a bit for safety, selection shadows, etc.
  111. bbox.Inflate( aItem->GetPenWidth() );
  112. const int type = int( aItem->Type() );
  113. const int mmin[3] = { type, bbox.GetX(), bbox.GetY() };
  114. const int mmax[3] = { type, bbox.GetRight(), bbox.GetBottom() };
  115. bool found = false;
  116. auto search =
  117. [&found, &aItem]( const SCH_ITEM* aSearchItem )
  118. {
  119. if( aSearchItem == aItem )
  120. {
  121. found = true;
  122. return false;
  123. }
  124. return true;
  125. };
  126. m_tree->Search( mmin, mmax, search );
  127. if( !found && aRobust )
  128. {
  129. // N.B. We must search the whole tree for the pointer to remove
  130. // because the item may have been moved. We do not expand the item
  131. // type search as this should not change.
  132. const int mmin2[3] = { type, INT_MIN, INT_MIN };
  133. const int mmax2[3] = { type, INT_MAX, INT_MAX };
  134. m_tree->Search( mmin2, mmax2, search );
  135. }
  136. return found;
  137. }
  138. /**
  139. * Return the number of items in the tree.
  140. *
  141. * @return number of elements in the tree.
  142. */
  143. size_t size() const
  144. {
  145. return m_count;
  146. }
  147. bool empty() const
  148. {
  149. return m_count == 0;
  150. }
  151. using iterator = typename ee_rtree::Iterator;
  152. /**
  153. * The #EE_TYPE struct provides a type-specific auto-range iterator to the RTree. Using
  154. * this struct, one can write lines like:
  155. *
  156. * for( auto item : rtree.OfType( SCH_SYMBOL_T ) )
  157. *
  158. * and iterate over the RTree items that are symbols only
  159. */
  160. struct EE_TYPE
  161. {
  162. EE_TYPE( ee_rtree* aTree, KICAD_T aType ) : type_tree( aTree )
  163. {
  164. KICAD_T type = BaseType( aType );
  165. if( type == SCH_LOCATE_ANY_T )
  166. m_rect = { { INT_MIN, INT_MIN, INT_MIN }, { INT_MAX, INT_MAX, INT_MAX } };
  167. else
  168. m_rect = { { type, INT_MIN, INT_MIN }, { type, INT_MAX, INT_MAX } };
  169. };
  170. EE_TYPE( ee_rtree* aTree, KICAD_T aType, const BOX2I& aRect ) : type_tree( aTree )
  171. {
  172. KICAD_T type = BaseType( aType );
  173. if( type == SCH_LOCATE_ANY_T )
  174. {
  175. m_rect = { { INT_MIN, aRect.GetX(), aRect.GetY() },
  176. { INT_MAX, aRect.GetRight(), aRect.GetBottom() } };
  177. }
  178. else
  179. {
  180. m_rect = { { type, aRect.GetX(), aRect.GetY() },
  181. { type, aRect.GetRight(), aRect.GetBottom() } };
  182. }
  183. };
  184. ee_rtree::Rect m_rect;
  185. ee_rtree* type_tree;
  186. iterator begin()
  187. {
  188. return type_tree->begin( m_rect );
  189. }
  190. iterator end()
  191. {
  192. return type_tree->end( m_rect );
  193. }
  194. bool empty()
  195. {
  196. return type_tree->Count() == 0;
  197. }
  198. };
  199. EE_TYPE OfType( KICAD_T aType ) const
  200. {
  201. return EE_TYPE( m_tree, aType );
  202. }
  203. EE_TYPE Overlapping( const BOX2I& aRect ) const
  204. {
  205. return EE_TYPE( m_tree, SCH_LOCATE_ANY_T, aRect );
  206. }
  207. EE_TYPE Overlapping( const VECTOR2I& aPoint, int aAccuracy = 0 ) const
  208. {
  209. BOX2I rect( aPoint, VECTOR2I( 0, 0 ) );
  210. rect.Inflate( aAccuracy );
  211. return EE_TYPE( m_tree, SCH_LOCATE_ANY_T, rect );
  212. }
  213. EE_TYPE Overlapping( KICAD_T aType, const VECTOR2I& aPoint, int aAccuracy = 0 ) const
  214. {
  215. BOX2I rect( aPoint, VECTOR2I( 0, 0 ) );
  216. rect.Inflate( aAccuracy );
  217. return EE_TYPE( m_tree, aType, rect );
  218. }
  219. EE_TYPE Overlapping( KICAD_T aType, const BOX2I& aRect ) const
  220. {
  221. return EE_TYPE( m_tree, aType, aRect );
  222. }
  223. /**
  224. * Returns a read/write iterator that points to the first
  225. * element in the %EE_RTREE
  226. * N.B. The iteration order of the RTree is not readily apparent and will change
  227. * if/when you add or move items and the RTree is re-balanced. Any exposure of the
  228. * RTree contents to the user MUST be sorted before being presented. See SCH_SEXPR_PLUGIN::Format
  229. * or SCH_EDITOR_CONTROL::nextMatch for examples.
  230. * @return Complete RTree of the screen's items
  231. */
  232. iterator begin()
  233. {
  234. return m_tree->begin();
  235. }
  236. /**
  237. * Returns a read/write iterator that points to one past the last
  238. * element in the %EE_RTREE
  239. */
  240. iterator end()
  241. {
  242. return m_tree->end();
  243. }
  244. const iterator begin() const
  245. {
  246. return m_tree->begin();
  247. }
  248. const iterator end() const
  249. {
  250. return m_tree->end();
  251. }
  252. private:
  253. ee_rtree* m_tree;
  254. size_t m_count;
  255. };
  256. #endif /* EESCHEMA_SCH_RTREE_H_ */