areastore.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*
  2. Minetest
  3. Copyright (C) 2015 est31 <mtest31@outlook.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "util/areastore.h"
  17. #include "util/serialize.h"
  18. #include "util/container.h"
  19. #if USE_SPATIAL
  20. #include <spatialindex/SpatialIndex.h>
  21. #include <spatialindex/RTree.h>
  22. #include <spatialindex/Point.h>
  23. #endif
  24. #define AST_SMALLER_EQ_AS(p, q) (((p).X <= (q).X) && ((p).Y <= (q).Y) && ((p).Z <= (q).Z))
  25. #define AST_OVERLAPS_IN_DIMENSION(amine, amaxe, b, d) \
  26. (!(((amine).d > (b)->maxedge.d) || ((amaxe).d < (b)->minedge.d)))
  27. #define AST_CONTAINS_PT(a, p) (AST_SMALLER_EQ_AS((a)->minedge, (p)) && \
  28. AST_SMALLER_EQ_AS((p), (a)->maxedge))
  29. #define AST_CONTAINS_AREA(amine, amaxe, b) \
  30. (AST_SMALLER_EQ_AS((amine), (b)->minedge) \
  31. && AST_SMALLER_EQ_AS((b)->maxedge, (amaxe)))
  32. #define AST_AREAS_OVERLAP(amine, amaxe, b) \
  33. (AST_OVERLAPS_IN_DIMENSION((amine), (amaxe), (b), X) && \
  34. AST_OVERLAPS_IN_DIMENSION((amine), (amaxe), (b), Y) && \
  35. AST_OVERLAPS_IN_DIMENSION((amine), (amaxe), (b), Z))
  36. AreaStore *AreaStore::getOptimalImplementation()
  37. {
  38. #if USE_SPATIAL
  39. return new SpatialAreaStore();
  40. #else
  41. return new VectorAreaStore();
  42. #endif
  43. }
  44. const Area *AreaStore::getArea(u32 id) const
  45. {
  46. AreaMap::const_iterator it = areas_map.find(id);
  47. if (it == areas_map.end())
  48. return nullptr;
  49. return &it->second;
  50. }
  51. void AreaStore::serialize(std::ostream &os) const
  52. {
  53. writeU8(os, 0); // Serialisation version
  54. // TODO: Compression?
  55. writeU16(os, areas_map.size());
  56. for (const auto &it : areas_map) {
  57. const Area &a = it.second;
  58. writeV3S16(os, a.minedge);
  59. writeV3S16(os, a.maxedge);
  60. writeU16(os, a.data.size());
  61. os.write(a.data.data(), a.data.size());
  62. }
  63. }
  64. void AreaStore::deserialize(std::istream &is)
  65. {
  66. u8 ver = readU8(is);
  67. if (ver != 0)
  68. throw SerializationError("Unknown AreaStore "
  69. "serialization version!");
  70. u16 num_areas = readU16(is);
  71. for (u32 i = 0; i < num_areas; ++i) {
  72. Area a;
  73. a.minedge = readV3S16(is);
  74. a.maxedge = readV3S16(is);
  75. u16 data_len = readU16(is);
  76. char *data = new char[data_len];
  77. is.read(data, data_len);
  78. a.data = std::string(data, data_len);
  79. insertArea(&a);
  80. delete [] data;
  81. }
  82. }
  83. void AreaStore::invalidateCache()
  84. {
  85. if (m_cache_enabled) {
  86. m_res_cache.invalidate();
  87. }
  88. }
  89. void AreaStore::setCacheParams(bool enabled, u8 block_radius, size_t limit)
  90. {
  91. m_cache_enabled = enabled;
  92. m_cacheblock_radius = MYMAX(block_radius, 16);
  93. m_res_cache.setLimit(MYMAX(limit, 20));
  94. invalidateCache();
  95. }
  96. void AreaStore::cacheMiss(void *data, const v3s16 &mpos, std::vector<Area *> *dest)
  97. {
  98. AreaStore *as = (AreaStore *)data;
  99. u8 r = as->m_cacheblock_radius;
  100. // get the points at the edges of the mapblock
  101. v3s16 minedge(mpos.X * r, mpos.Y * r, mpos.Z * r);
  102. v3s16 maxedge(
  103. minedge.X + r - 1,
  104. minedge.Y + r - 1,
  105. minedge.Z + r - 1);
  106. as->getAreasInArea(dest, minedge, maxedge, true);
  107. /* infostream << "Cache miss with " << dest->size() << " areas, between ("
  108. << minedge.X << ", " << minedge.Y << ", " << minedge.Z
  109. << ") and ("
  110. << maxedge.X << ", " << maxedge.Y << ", " << maxedge.Z
  111. << ")" << std::endl; // */
  112. }
  113. void AreaStore::getAreasForPos(std::vector<Area *> *result, v3s16 pos)
  114. {
  115. if (m_cache_enabled) {
  116. v3s16 mblock = getContainerPos(pos, m_cacheblock_radius);
  117. const std::vector<Area *> *pre_list = m_res_cache.lookupCache(mblock);
  118. size_t s_p_l = pre_list->size();
  119. for (size_t i = 0; i < s_p_l; i++) {
  120. Area *b = (*pre_list)[i];
  121. if (AST_CONTAINS_PT(b, pos)) {
  122. result->push_back(b);
  123. }
  124. }
  125. } else {
  126. return getAreasForPosImpl(result, pos);
  127. }
  128. }
  129. ////
  130. // VectorAreaStore
  131. ////
  132. bool VectorAreaStore::insertArea(Area *a)
  133. {
  134. if (a->id == U32_MAX)
  135. a->id = getNextId();
  136. std::pair<AreaMap::iterator, bool> res =
  137. areas_map.insert(std::make_pair(a->id, *a));
  138. if (!res.second)
  139. // ID is not unique
  140. return false;
  141. m_areas.push_back(&res.first->second);
  142. invalidateCache();
  143. return true;
  144. }
  145. bool VectorAreaStore::removeArea(u32 id)
  146. {
  147. AreaMap::iterator it = areas_map.find(id);
  148. if (it == areas_map.end())
  149. return false;
  150. Area *a = &it->second;
  151. for (std::vector<Area *>::iterator v_it = m_areas.begin();
  152. v_it != m_areas.end(); ++v_it) {
  153. if (*v_it == a) {
  154. m_areas.erase(v_it);
  155. break;
  156. }
  157. }
  158. areas_map.erase(it);
  159. invalidateCache();
  160. return true;
  161. }
  162. void VectorAreaStore::getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos)
  163. {
  164. for (Area *area : m_areas) {
  165. if (AST_CONTAINS_PT(area, pos)) {
  166. result->push_back(area);
  167. }
  168. }
  169. }
  170. void VectorAreaStore::getAreasInArea(std::vector<Area *> *result,
  171. v3s16 minedge, v3s16 maxedge, bool accept_overlap)
  172. {
  173. for (Area *area : m_areas) {
  174. if (accept_overlap ? AST_AREAS_OVERLAP(minedge, maxedge, area) :
  175. AST_CONTAINS_AREA(minedge, maxedge, area)) {
  176. result->push_back(area);
  177. }
  178. }
  179. }
  180. #if USE_SPATIAL
  181. static inline SpatialIndex::Region get_spatial_region(const v3s16 minedge,
  182. const v3s16 maxedge)
  183. {
  184. const double p_low[] = {(double)minedge.X,
  185. (double)minedge.Y, (double)minedge.Z};
  186. const double p_high[] = {(double)maxedge.X, (double)maxedge.Y,
  187. (double)maxedge.Z};
  188. return SpatialIndex::Region(p_low, p_high, 3);
  189. }
  190. static inline SpatialIndex::Point get_spatial_point(const v3s16 pos)
  191. {
  192. const double p[] = {(double)pos.X, (double)pos.Y, (double)pos.Z};
  193. return SpatialIndex::Point(p, 3);
  194. }
  195. bool SpatialAreaStore::insertArea(Area *a)
  196. {
  197. if (a->id == U32_MAX)
  198. a->id = getNextId();
  199. if (!areas_map.insert(std::make_pair(a->id, *a)).second)
  200. // ID is not unique
  201. return false;
  202. m_tree->insertData(0, nullptr, get_spatial_region(a->minedge, a->maxedge), a->id);
  203. invalidateCache();
  204. return true;
  205. }
  206. bool SpatialAreaStore::removeArea(u32 id)
  207. {
  208. std::map<u32, Area>::iterator itr = areas_map.find(id);
  209. if (itr != areas_map.end()) {
  210. Area *a = &itr->second;
  211. bool result = m_tree->deleteData(get_spatial_region(a->minedge,
  212. a->maxedge), id);
  213. areas_map.erase(itr);
  214. invalidateCache();
  215. return result;
  216. } else {
  217. return false;
  218. }
  219. }
  220. void SpatialAreaStore::getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos)
  221. {
  222. VectorResultVisitor visitor(result, this);
  223. m_tree->pointLocationQuery(get_spatial_point(pos), visitor);
  224. }
  225. void SpatialAreaStore::getAreasInArea(std::vector<Area *> *result,
  226. v3s16 minedge, v3s16 maxedge, bool accept_overlap)
  227. {
  228. VectorResultVisitor visitor(result, this);
  229. if (accept_overlap) {
  230. m_tree->intersectsWithQuery(get_spatial_region(minedge, maxedge),
  231. visitor);
  232. } else {
  233. m_tree->containsWhatQuery(get_spatial_region(minedge, maxedge), visitor);
  234. }
  235. }
  236. SpatialAreaStore::~SpatialAreaStore()
  237. {
  238. delete m_tree;
  239. }
  240. SpatialAreaStore::SpatialAreaStore()
  241. {
  242. m_storagemanager =
  243. SpatialIndex::StorageManager::createNewMemoryStorageManager();
  244. SpatialIndex::id_type id;
  245. m_tree = SpatialIndex::RTree::createNewRTree(
  246. *m_storagemanager,
  247. .7, // Fill factor
  248. 100, // Index capacity
  249. 100, // Leaf capacity
  250. 3, // dimension :)
  251. SpatialIndex::RTree::RV_RSTAR,
  252. id);
  253. }
  254. #endif