PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/ZoneServer/QuadTreeNode.cpp

http://github.com/swganh/mmoserver
C++ | 432 lines | 218 code | 58 blank | 156 comment | 60 complexity | c62dcbc5ef9d8940bbef59962e2a41f8 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. ---------------------------------------------------------------------------------------
  3. This source file is part of SWG:ANH (Star Wars Galaxies - A New Hope - Server Emulator)
  4. For more information, visit http://www.swganh.com
  5. Copyright (c) 2006 - 2010 The SWG:ANH Team
  6. ---------------------------------------------------------------------------------------
  7. Use of this source code is governed by the GPL v3 license that can be found
  8. in the COPYING file or at http://www.gnu.org/licenses/gpl-3.0.html
  9. This library is free software; you can redistribute it and/or
  10. modify it under the terms of the GNU Lesser General Public
  11. License as published by the Free Software Foundation; either
  12. version 2.1 of the License, or (at your option) any later version.
  13. This library is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. Lesser General Public License for more details.
  17. You should have received a copy of the GNU Lesser General Public
  18. License along with this library; if not, write to the Free Software
  19. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. ---------------------------------------------------------------------------------------
  21. */
  22. #include "QuadTreeNode.h"
  23. #include "WorldManager.h"
  24. #include "MathLib/Rectangle.h"
  25. #include "MathLib/Circle.h"
  26. #include <cassert>
  27. //======================================================================================================================
  28. //
  29. // Constructor
  30. //
  31. QuadTreeNode::QuadTreeNode(float lowX,float lowZ,float width,float height) :
  32. Rectangle(lowX,lowZ,width,height),mSubNodes(NULL)
  33. {
  34. }
  35. //======================================================================================================================
  36. //
  37. // Deconstructor
  38. //
  39. QuadTreeNode::~QuadTreeNode()
  40. {
  41. // if its a branch, free our children
  42. if(mSubNodes)
  43. {
  44. for(uint8 i = 0; i < 4; i++)
  45. {
  46. delete(mSubNodes[i]);
  47. }
  48. free(mSubNodes);
  49. }
  50. }
  51. //======================================================================================================================
  52. //
  53. // grow the tree by one level
  54. //
  55. void QuadTreeNode::subDivide()
  56. {
  57. // this is a leaf, so make it a branch and grow 4 leafs
  58. if(!mSubNodes)
  59. {
  60. // make them a quarter size of their parent
  61. float width = mWidth * 0.5f;
  62. float height = mHeight * 0.5f;
  63. // create them
  64. mSubNodes = (QuadTreeNode**)::malloc(4 * sizeof(QuadTreeNode*));
  65. mSubNodes[0] = new QuadTreeNode(mPosition.x,mPosition.z + height,width,height);
  66. mSubNodes[1] = new QuadTreeNode(mPosition.x + width,mPosition.z + height,width,height);
  67. mSubNodes[2] = new QuadTreeNode(mPosition.x + width,mPosition.z,width,height);
  68. mSubNodes[3] = new QuadTreeNode(mPosition.x,mPosition.z,width,height);
  69. }
  70. // its a branch, so traverse its children
  71. else
  72. {
  73. for(uint8 i = 0; i < 4; i++)
  74. {
  75. mSubNodes[i]->subDivide();
  76. }
  77. }
  78. }
  79. //======================================================================================================================
  80. //
  81. // insert an object
  82. //
  83. int32 QuadTreeNode::addObject(Object* object)
  84. {
  85. // Validate input. Should be interesting to see.
  86. assert(object && "QuadTreeNode::addObject this method does not accept NULL objects");
  87. assert(object->getId() && "QuadTreeNode::addObject this method requires an object with a valid id");
  88. // gLogger->log(LogManager::DEBUG,"Trying to add Object %"PRIu64" @ %.2f %.2f ", object->getId(), object->mPosition.x, object->mPosition.z);
  89. // its a leaf, add it
  90. if(!mSubNodes)
  91. {
  92. // make sure it doesn't already exists
  93. StdObjectMap::iterator it = mObjects.find(object->getId());
  94. if (it == mObjects.end())
  95. {
  96. mObjects.insert(std::make_pair(object->getId(),object));
  97. // gLogger->log(LogManager::DEBUG,"QuadTreeNode::addObject: INSERTED OBJECT with id = %"PRIu64"", object->getId());
  98. }
  99. else
  100. {
  101. DLOG(INFO) << "QuadTreeNode::addObject: INSERTED OBJECT already exist = " << object->getId();
  102. return(2);
  103. }
  104. return(1);
  105. }
  106. // its a branch, see to which children it goes
  107. else
  108. {
  109. for(uint8 i = 0; i < 4; i++)
  110. {
  111. // found the one it belongs in
  112. if(mSubNodes[i]->checkBounds(object))
  113. {
  114. // add it and break out
  115. mSubNodes[i]->addObject(object);
  116. return(0);
  117. }
  118. }
  119. }
  120. assert(false && "QuadTreeNode::addObject unable to add object to a node");
  121. return(0);
  122. }
  123. //======================================================================================================================
  124. //
  125. // checks if an object belongs into this node
  126. //
  127. bool QuadTreeNode::checkBounds(Object* object)
  128. {
  129. if(object->mPosition.x >= mPosition.x && object->mPosition.x < mPosition.x + mWidth
  130. && object->mPosition.z >= mPosition.z && object->mPosition.z < mPosition.z + mHeight)
  131. {
  132. return(true);
  133. }
  134. return(false);
  135. }
  136. //======================================================================================================================
  137. //
  138. // gather all objects in range of object(all objects from the intersecting leafs)
  139. // given resultList as the visitor and a shape for intersection
  140. //
  141. void QuadTreeNode::getObjectsInRange(Object* object,ObjectSet* resultSet,uint32 typeMask,Anh_Math::Shape* shape)
  142. {
  143. // this is a leaf,add the contents
  144. if(!mSubNodes)
  145. {
  146. StdObjectMap::iterator it = mObjects.begin();
  147. while(it != mObjects.end())
  148. {
  149. if ((*it).first)
  150. {
  151. Object* currentObject = (*it).second;
  152. // don't add ourself
  153. if(currentObject != object && ((currentObject->getType() & typeMask) == static_cast<uint32>(currentObject->getType())))
  154. {
  155. // gLogger->log(LogManager::DEBUG,"QuadTreeNode::getObjectsInRange FINDING object with id = %"PRIu64"", currentObject->getId());
  156. resultSet->insert(currentObject);
  157. }
  158. }
  159. else
  160. {
  161. assert(false && "QuadTreeNode::getObjectsInRange ERROR INVALID ID");
  162. }
  163. ++it;
  164. }
  165. }
  166. // traverse the intersecting sub branches
  167. else
  168. {
  169. for(uint8 i = 0; i < 4; i++)
  170. {
  171. if(mSubNodes[i]->intersects(shape))
  172. {
  173. mSubNodes[i]->getObjectsInRange(object,resultSet,typeMask,shape);
  174. }
  175. }
  176. }
  177. }
  178. //used by camps to get all contained objects out of the host node
  179. void QuadTreeNode::getObjectsInRangeContains(Object* object,ObjectSet* resultSet,uint32 typeMask,Anh_Math::Shape* shape)
  180. {
  181. // this is a leaf,add the contents
  182. if(!mSubNodes)
  183. {
  184. StdObjectMap::iterator it = mObjects.begin();
  185. while(it != mObjects.end())
  186. {
  187. Object* currentObject = (*it).second;
  188. // don't add ourself
  189. if(currentObject != object && ((currentObject->getType() & typeMask) == static_cast<uint32>(currentObject->getType())))
  190. {
  191. if(ObjectContained(shape,currentObject))
  192. resultSet->insert(currentObject);
  193. }
  194. ++it;
  195. }
  196. }
  197. // traverse the intersecting sub branches
  198. else
  199. {
  200. for(uint8 i = 0; i < 4; i++)
  201. {
  202. if(mSubNodes[i]->intersects(shape))
  203. {
  204. mSubNodes[i]->getObjectsInRangeContains(object,resultSet,typeMask,shape);
  205. }
  206. }
  207. }
  208. }
  209. //======================================================================================================================
  210. //
  211. // checks if a node intersects with a given region
  212. //
  213. bool QuadTreeNode::intersects(Anh_Math::Shape* shape)
  214. {
  215. // rectangular
  216. if(Anh_Math::Rectangle* rectangle = dynamic_cast<Anh_Math::Rectangle*>(shape))
  217. {
  218. const glm::vec3& rectPos = rectangle->getPosition();
  219. // check intersection
  220. if(rectPos.x > mPosition.x + mWidth || rectPos.x + rectangle->getWidth() < mPosition.x
  221. || rectPos.z > mPosition.z + mHeight || rectPos.z + rectangle->getHeight() < mPosition.z)
  222. {
  223. return(false);
  224. }
  225. return(true);
  226. }
  227. // circle
  228. else if(dynamic_cast<Anh_Math::Circle*>(shape))
  229. {
  230. // TODO
  231. return(false);
  232. }
  233. return(false);
  234. }
  235. bool QuadTreeNode::ObjectContained(Anh_Math::Shape* shape, Object* object)
  236. {
  237. // rectangular
  238. if(Anh_Math::Rectangle* rectangle = dynamic_cast<Anh_Math::Rectangle*>(shape))
  239. {
  240. const glm::vec3& rectPos = rectangle->getPosition();
  241. // check intersection
  242. if(rectPos.x > object->mPosition.x || rectPos.x + rectangle->getWidth() < object->mPosition.x
  243. || rectPos.z > object->mPosition.z || rectPos.z + rectangle->getHeight() < object->mPosition.z)
  244. {
  245. return(false);
  246. }
  247. return(true);
  248. }
  249. // circle
  250. else if(dynamic_cast<Anh_Math::Circle*>(shape))
  251. {
  252. // TODO
  253. return(false);
  254. }
  255. return(false);
  256. }
  257. //======================================================================================================================
  258. //
  259. // removes an object
  260. //
  261. int32 QuadTreeNode::removeObject(Object* object)
  262. {
  263. // Validate input. Should be interesting to see.
  264. assert(object && "QuadTreeNode::removeObject this method does not accept NULL objects");
  265. assert(object->getId() && "QuadTreeNode::removeObject this method requires an object with a valid id");
  266. // make sure its a leaf
  267. if(!mSubNodes)
  268. {
  269. // make sure it doesn't already exists
  270. StdObjectMap::iterator it = mObjects.find(object->getId());
  271. if (it != mObjects.end())
  272. {
  273. // gLogger->log(LogManager::DEBUG,"QuadTreeNode::removeObject REMOVE object with id = %"PRIu64"", object->getId());
  274. mObjects.erase(it);
  275. return(1);
  276. }
  277. DLOG(INFO) << "QuadTreeNode::removeObject ERROR FAILED to REMOVE object with id = " << object->getId();
  278. return(2);
  279. }
  280. // traverse our children
  281. else
  282. {
  283. for(uint8 i = 0; i < 4; i++)
  284. {
  285. // found the one it should be in
  286. if(mSubNodes[i]->checkBounds(object))
  287. {
  288. // remove it and break out
  289. mSubNodes[i]->removeObject(object);
  290. return(0);
  291. }
  292. }
  293. }
  294. assert(false && "QuadTreeNode::removeObject unable to remove object");
  295. return(0);
  296. }
  297. //======================================================================================================================
  298. //
  299. // update an objects position in the tree, TODO: optimize
  300. //
  301. // int32 QuadTreeNode::addMyObject(Object* object);
  302. int32 QuadTreeNode::updateObject(Object* object, const glm::vec3& newPosition)
  303. {
  304. // Validate input. Should be interesting to see.
  305. assert(object && "QuadTreeNode::updateObject this method does not accept NULL objects");
  306. assert(object->getId() && "QuadTreeNode::updateObject this method requires an object with a valid id");
  307. // shouldnt be called on leafs
  308. if(mSubNodes)
  309. {
  310. // gLogger->log(LogManager::DEBUG,"Remove Object %"PRIu64" @ %.2f %.2f ", object->getId(), object->mPosition.x, object->mPosition.z);
  311. removeObject(object);
  312. object->mPosition = newPosition;
  313. // gLogger->log(LogManager::DEBUG,"Add Object %"PRIu64" @ %.2f %.2f ", object->getId(), object->mPosition.x, object->mPosition.z);
  314. addObject(object);
  315. // addMyObject(object);
  316. }
  317. return(0);
  318. }
  319. //======================================================================================================================
  320. //======================================================================================================================
  321. //
  322. // FOR TEST
  323. // insert an object
  324. //
  325. /*
  326. int32 QuadTreeNode::addMyObject(Object* object)
  327. {
  328. // Validate input. Should be interesting to see.
  329. assert(object);
  330. assert(object->getId());
  331. // its a leaf, add it
  332. if(!mSubNodes)
  333. {
  334. // make sure it doesn't already exists
  335. StdObjectMap::iterator it = mObjects.find(object->getId());
  336. if (it == mObjects.end())
  337. {
  338. mObjects.insert(std::make_pair(object->getId(),object));
  339. gLogger->log(LogManager::DEBUG,"QuadTreeNode::addMyObject: INSERTED OBJECT with id = %"PRIu64"", object->getId());
  340. }
  341. else
  342. {
  343. gLogger->log(LogManager::DEBUG,"QuadTreeNode::addMyObject: ERROR INSERTED OBJECT already exist = %"PRIu64"", object->getId());
  344. return(2);
  345. }
  346. return(1);
  347. }
  348. // its a branch, see to which children it goes
  349. else
  350. {
  351. for(uint8 i = 0;i < 4;i++)
  352. {
  353. // found the one it belongs in
  354. if(mSubNodes[i]->checkBounds(object))
  355. {
  356. // add it and break out
  357. mSubNodes[i]->addMyObject(object);
  358. return(0);
  359. }
  360. }
  361. }
  362. assert(false);
  363. return(0);
  364. }
  365. */