00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "xrb_engine2_quadtree.hpp"
00012
00013 #include "xrb_engine2_entity.hpp"
00014
00015 namespace Xrb
00016 {
00017
00018 Engine2::QuadTree::~QuadTree ()
00019 {
00020
00021 for (ObjectSet::iterator it = m_object_set.begin(),
00022 it_end = m_object_set.end();
00023 it != it_end;
00024 ++it)
00025 {
00026 Object *object = *it;
00027 ASSERT1(object != NULL);
00028 Delete(object);
00029 }
00030 m_object_set.clear();
00031
00032 if (HasChildren())
00033 for (Uint8 i = 0; i < 4; ++i)
00034 Delete(m_child[i]);
00035 }
00036
00037 Engine2::QuadTree const *Engine2::QuadTree::RootNode () const
00038 {
00039 QuadTree const *quad_node = this;
00040 while (quad_node->m_parent != NULL)
00041 quad_node = quad_node->m_parent;
00042 return quad_node;
00043 }
00044
00045 Engine2::Object *Engine2::QuadTree::SmallestObjectTouchingPoint (
00046 FloatVector2 const &point)
00047 {
00048 Object *retval = NULL;
00049
00050
00051 if (SubordinateObjectCount() == 0)
00052 return retval;
00053
00054
00055 if ((point - m_center).LengthSquared() > 4.0*m_radius*m_radius)
00056 return retval;
00057
00058 Object *smallest_candidate;
00059
00060
00061 if (m_child[0] != NULL)
00062 {
00063 for (Uint8 i = 0; i < 4; ++i)
00064 {
00065 ASSERT2(m_child[i] != NULL);
00066 smallest_candidate = m_child[i]->SmallestObjectTouchingPoint(point);
00067 if (retval == NULL ||
00068 (smallest_candidate != NULL &&
00069 smallest_candidate->Radius(GetQuadTreeType()) < retval->Radius(GetQuadTreeType())))
00070 retval = smallest_candidate;
00071 }
00072 }
00073
00074
00075
00076
00077 if (retval != NULL && !IsAllowableObjectRadius(retval))
00078 return retval;
00079
00080
00081 for (ObjectSet::iterator it = m_object_set.begin(),
00082 it_end = m_object_set.end();
00083 it != it_end;
00084 ++it)
00085 {
00086 smallest_candidate = *it;
00087 ASSERT1(smallest_candidate != NULL);
00088
00089
00090 if ((point - smallest_candidate->Translation()).LengthSquared() <=
00091 smallest_candidate->RadiusSquared(GetQuadTreeType()))
00092
00093 if (retval == NULL ||
00094 smallest_candidate->Radius(GetQuadTreeType()) < retval->Radius(GetQuadTreeType()))
00095
00096 retval = smallest_candidate;
00097 }
00098
00099 return retval;
00100 }
00101
00102 bool Engine2::QuadTree::DoesAreaOverlapAnyObject (
00103 FloatVector2 const &area_center,
00104 Float const area_radius) const
00105 {
00106
00107 if (SubordinateObjectCount() == 0)
00108 return false;
00109
00110
00111 if (!DoesAreaOverlapQuadBounds(area_center, area_radius))
00112 return false;
00113
00114
00115 for (ObjectSet::const_iterator it = m_object_set.begin(),
00116 it_end = m_object_set.end();
00117 it != it_end;
00118 ++it)
00119 {
00120 Object const *object = *it;
00121 ASSERT1(object != NULL);
00122 ASSERT1(object->OwnerQuadTree(m_quad_tree_type) == this);
00123 if ((object->Translation() - area_center).Length()
00124 <
00125 (object->Radius(GetQuadTreeType()) + area_radius))
00126 return true;
00127 }
00128
00129
00130 if (HasChildren())
00131 return
00132 m_child[0]->DoesAreaOverlapAnyObject(
00133 area_center,
00134 area_radius)
00135 ||
00136 m_child[1]->DoesAreaOverlapAnyObject(
00137 area_center,
00138 area_radius)
00139 ||
00140 m_child[2]->DoesAreaOverlapAnyObject(
00141 area_center,
00142 area_radius)
00143 ||
00144 m_child[3]->DoesAreaOverlapAnyObject(
00145 area_center,
00146 area_radius);
00147 else
00148 return false;
00149 }
00150
00151 bool Engine2::QuadTree::DoesAreaOverlapAnyObjectWrapped (
00152 FloatVector2 const &area_center,
00153 Float const area_radius,
00154 Float const object_layer_side_length,
00155 Float const half_object_layer_side_length) const
00156 {
00157
00158 if (SubordinateObjectCount() == 0)
00159 return false;
00160
00161
00162 if (!DoesAreaOverlapQuadBoundsWrapped(
00163 area_center,
00164 area_radius,
00165 object_layer_side_length,
00166 half_object_layer_side_length))
00167 return false;
00168
00169
00170 for (ObjectSet::const_iterator it = m_object_set.begin(),
00171 it_end = m_object_set.end();
00172 it != it_end;
00173 ++it)
00174 {
00175 Object const *object = *it;
00176 ASSERT1(object != NULL);
00177 ASSERT1(object->OwnerQuadTree(m_quad_tree_type) == this);
00178
00179 FloatVector2 object_translation(object->Translation());
00180 FloatVector2 adjusted_area_center(area_center);
00181
00182 while (adjusted_area_center[Dim::X] < object_translation[Dim::X] - half_object_layer_side_length)
00183 adjusted_area_center[Dim::X] += object_layer_side_length;
00184 while (adjusted_area_center[Dim::X] > object_translation[Dim::X] + half_object_layer_side_length)
00185 adjusted_area_center[Dim::X] -= object_layer_side_length;
00186
00187 while (adjusted_area_center[Dim::Y] < object_translation[Dim::Y] - half_object_layer_side_length)
00188 adjusted_area_center[Dim::Y] += object_layer_side_length;
00189 while (adjusted_area_center[Dim::Y] > object_translation[Dim::Y] + half_object_layer_side_length)
00190 adjusted_area_center[Dim::Y] -= object_layer_side_length;
00191
00192 if ((object_translation - adjusted_area_center).Length()
00193 <
00194 (object->Radius(GetQuadTreeType()) + area_radius))
00195 return true;
00196 }
00197
00198
00199 if (HasChildren())
00200 return
00201 m_child[0]->DoesAreaOverlapAnyObjectWrapped(
00202 area_center,
00203 area_radius,
00204 object_layer_side_length,
00205 half_object_layer_side_length)
00206 ||
00207 m_child[1]->DoesAreaOverlapAnyObjectWrapped(
00208 area_center,
00209 area_radius,
00210 object_layer_side_length,
00211 half_object_layer_side_length)
00212 ||
00213 m_child[2]->DoesAreaOverlapAnyObjectWrapped(
00214 area_center,
00215 area_radius,
00216 object_layer_side_length,
00217 half_object_layer_side_length)
00218 ||
00219 m_child[3]->DoesAreaOverlapAnyObjectWrapped(
00220 area_center,
00221 area_radius,
00222 object_layer_side_length,
00223 half_object_layer_side_length);
00224 else
00225 return false;
00226 }
00227
00228 void Engine2::QuadTree::Clear ()
00229 {
00230
00231 m_object_set.clear();
00232
00233 if (HasChildren())
00234 {
00235 for (Uint8 i = 0; i < 4; ++i)
00236 {
00237 ASSERT2(m_child[i] != NULL);
00238 m_child[i]->Clear();
00239 }
00240 }
00241 }
00242
00243 bool Engine2::QuadTree::AddObject (Engine2::Object *const object)
00244 {
00245 ASSERT1(object != NULL);
00246 ASSERT1(object->OwnerQuadTree(m_quad_tree_type) == NULL);
00247
00248
00249
00250 ASSERT1(object->Radius(GetQuadTreeType()) <= m_radius);
00251
00252
00253 if (!IsPointInsideQuad(object->Translation()))
00254 return false;
00255
00256
00257
00258
00259 if (IsAllowableObjectRadius(object) || !HasChildren())
00260 {
00261
00262 object->SetOwnerQuadTree(m_quad_tree_type, this);
00263 m_object_set.insert(object);
00264 ++m_subordinate_object_count;
00265 if (!object->IsDynamic())
00266 ++m_subordinate_static_object_count;
00267 }
00268 else
00269 {
00270 for (Uint8 i = 0; i < 4; ++i)
00271 ASSERT2(m_child[i] != NULL);
00272
00273 bool add_succeeded = false;
00274 for (Uint8 i = 0; i < 4; ++i)
00275 {
00276 add_succeeded = add_succeeded || m_child[i]->AddObject(object);
00277
00278 if (add_succeeded)
00279 break;
00280 }
00281 ASSERT1(add_succeeded);
00282
00283 ++m_subordinate_object_count;
00284 if (!object->IsDynamic())
00285 ++m_subordinate_static_object_count;
00286 }
00287 return true;
00288 }
00289
00290 bool Engine2::QuadTree::RemoveObject (Engine2::Object *const object)
00291 {
00292 ASSERT1(object != NULL);
00293 ASSERT1(object->OwnerQuadTree(m_quad_tree_type) == this);
00294
00295 ObjectSet::iterator it = m_object_set.find(object);
00296 if (it != m_object_set.end())
00297 {
00298
00299 object->OwnerQuadTree(m_quad_tree_type)->m_object_set.erase(it);
00300
00301 object->SetOwnerQuadTree(m_quad_tree_type, NULL);
00302
00303 DecrementSubordinateObjectCount();
00304
00305 if (!object->IsDynamic())
00306 DecrementSubordinateStaticObjectCount();
00307
00308 return true;
00309 }
00310 else
00311 {
00312
00313 return false;
00314 }
00315 }
00316
00317 bool Engine2::QuadTree::ReAddObject (Engine2::Object *const object)
00318 {
00319 ASSERT1(object != NULL);
00320 ASSERT1(object->OwnerQuadTree(m_quad_tree_type) != NULL);
00321
00322 bool object_was_added = false;
00323
00324
00325 if (IsPointInsideQuad(object->Translation()))
00326 {
00327 Float object_radius_over_quad_radius = object->Radius(GetQuadTreeType()) / m_radius;
00328
00329 if (object_radius_over_quad_radius > 1.0f)
00330 {
00331 if (m_parent != NULL)
00332 {
00333
00334 object_was_added = m_parent->ReAddObject(object);
00335 ASSERT1(object_was_added);
00336 }
00337 else
00338 {
00339
00340 AddObjectIfNotAlreadyAdded(object);
00341 object_was_added = true;
00342 }
00343 }
00344
00345 else if (object_radius_over_quad_radius <= 0.5f)
00346 {
00347 if (HasChildren())
00348 {
00349 FloatVector2 object_translation(object->Translation());
00350 if (object_translation[Dim::X] >= m_center[Dim::X])
00351 {
00352 if (object_translation[Dim::Y] >= m_center[Dim::Y])
00353 {
00354 ASSERT1(m_child[0]->IsPointInsideQuad(object->Translation()));
00355 object_was_added = m_child[0]->ReAddObject(object);
00356 }
00357 else
00358 {
00359 ASSERT1(m_child[3]->IsPointInsideQuad(object->Translation()));
00360 object_was_added = m_child[3]->ReAddObject(object);
00361 }
00362 }
00363 else
00364 {
00365 if (object_translation[Dim::Y] >= m_center[Dim::Y])
00366 {
00367 ASSERT1(m_child[1]->IsPointInsideQuad(object->Translation()));
00368 object_was_added = m_child[1]->ReAddObject(object);
00369 }
00370 else
00371 {
00372 ASSERT1(m_child[2]->IsPointInsideQuad(object->Translation()));
00373 object_was_added = m_child[2]->ReAddObject(object);
00374 }
00375 }
00376 ASSERT1(object_was_added);
00377 }
00378 else
00379 {
00380
00381 AddObjectIfNotAlreadyAdded(object);
00382 object_was_added = true;
00383 }
00384 }
00385
00386 else
00387 {
00388
00389 AddObjectIfNotAlreadyAdded(object);
00390 object_was_added = true;
00391 }
00392 }
00393
00394 else
00395 {
00396 if (m_parent != NULL)
00397 {
00398
00399 object_was_added = m_parent->ReAddObject(object);
00400 }
00401 else
00402 {
00403 ASSERT1(object_was_added == false);
00404 Fprint(stderr, object->Translation());
00405 ASSERT1(false);
00406
00407 }
00408 }
00409
00410 ASSERT1(object_was_added);
00411 return object_was_added;
00412 }
00413
00414 Engine2::QuadTree::QuadTree (QuadTree *const parent)
00415 {
00416 m_parent = parent;
00417 m_half_side_length = 0.0f;
00418 m_radius = 0.0f;
00419 for (Uint8 i = 0; i < 4; ++i)
00420 m_child[i] = NULL;
00421 m_subordinate_object_count = 0;
00422 m_subordinate_static_object_count = 0;
00423 m_quad_tree_type = QTT_COUNT;
00424 }
00425
00426 bool Engine2::QuadTree::IsPointInsideQuad (FloatVector2 const &point) const
00427 {
00428 ASSERT1(m_half_side_length > 0.0);
00429
00430 if (point[Dim::X] < m_center[Dim::X] - m_half_side_length)
00431 return false;
00432 else if (point[Dim::X] > m_center[Dim::X] + m_half_side_length)
00433 return false;
00434 else if (point[Dim::Y] < m_center[Dim::Y] - m_half_side_length)
00435 return false;
00436 else if (point[Dim::Y] > m_center[Dim::Y] + m_half_side_length)
00437 return false;
00438 else
00439 return true;
00440 }
00441
00442 bool Engine2::QuadTree::DoesAreaOverlapQuadBoundsWrapped (
00443 FloatVector2 area_center,
00444 Float const area_radius,
00445 Float const object_layer_side_length,
00446 Float const half_object_layer_side_length) const
00447 {
00448 ASSERT1(area_center[Dim::X] >= -half_object_layer_side_length);
00449 ASSERT1(area_center[Dim::X] <= half_object_layer_side_length);
00450 ASSERT1(area_center[Dim::Y] >= -half_object_layer_side_length);
00451 ASSERT1(area_center[Dim::Y] <= half_object_layer_side_length);
00452
00453 if (area_center[Dim::X] < m_center[Dim::X] - half_object_layer_side_length)
00454 area_center[Dim::X] += object_layer_side_length;
00455 else if (area_center[Dim::X] > m_center[Dim::X] + half_object_layer_side_length)
00456 area_center[Dim::X] -= object_layer_side_length;
00457
00458 if (area_center[Dim::Y] < m_center[Dim::Y] - half_object_layer_side_length)
00459 area_center[Dim::Y] += object_layer_side_length;
00460 else if (area_center[Dim::Y] > m_center[Dim::Y] + half_object_layer_side_length)
00461 area_center[Dim::Y] -= object_layer_side_length;
00462
00463 return DoesAreaOverlapQuadBounds(area_center, area_radius);
00464 }
00465
00466 void Engine2::QuadTree::SetQuadTreeType (QuadTreeType const quad_tree_type)
00467 {
00468 ASSERT1(quad_tree_type < QTT_COUNT);
00469 m_quad_tree_type = quad_tree_type;
00470 if (HasChildren())
00471 for (Uint8 i = 0; i < 4; ++i)
00472 m_child[i]->SetQuadTreeType(m_quad_tree_type);
00473 }
00474
00475 void Engine2::QuadTree::IncrementSubordinateObjectCount ()
00476 {
00477 QuadTree *quad_node = this;
00478 while (quad_node != NULL)
00479 {
00480 ASSERT3(quad_node->m_subordinate_object_count < UINT32_UPPER_BOUND);
00481 ++quad_node->m_subordinate_object_count;
00482 quad_node = quad_node->m_parent;
00483 }
00484 }
00485
00486 void Engine2::QuadTree::IncrementSubordinateStaticObjectCount ()
00487 {
00488 QuadTree *quad_node = this;
00489 while (quad_node != NULL)
00490 {
00491 ASSERT3(quad_node->m_subordinate_static_object_count < UINT32_UPPER_BOUND);
00492 ++quad_node->m_subordinate_static_object_count;
00493 quad_node = quad_node->m_parent;
00494 }
00495 }
00496
00497 void Engine2::QuadTree::DecrementSubordinateObjectCount ()
00498 {
00499 QuadTree *quad_node = this;
00500 while (quad_node != NULL)
00501 {
00502 ASSERT3(quad_node->m_subordinate_object_count > 0);
00503 --quad_node->m_subordinate_object_count;
00504 quad_node = quad_node->m_parent;
00505 }
00506 }
00507
00508 void Engine2::QuadTree::DecrementSubordinateStaticObjectCount ()
00509 {
00510 QuadTree *quad_node = this;
00511 while (quad_node != NULL)
00512 {
00513 ASSERT3(quad_node->m_subordinate_static_object_count > 0);
00514 --quad_node->m_subordinate_static_object_count;
00515 quad_node = quad_node->m_parent;
00516 }
00517 }
00518
00519 void Engine2::QuadTree::NonRecursiveAddObject (Object *const object)
00520 {
00521 ASSERT1(object != NULL);
00522 ASSERT1(object->OwnerQuadTree(m_quad_tree_type) == NULL);
00523
00524
00525
00526 if (object->Radius(GetQuadTreeType()) > m_radius)
00527 object->SetScaleFactor(m_radius);
00528
00529 ASSERT1(IsPointInsideQuad(object->Translation()));
00530
00531
00532
00533
00534 ASSERT1(IsAllowableObjectRadius(object) || !HasChildren());
00535
00536 object->SetOwnerQuadTree(m_quad_tree_type, this);
00537 m_object_set.insert(object);
00538 IncrementSubordinateObjectCount();
00539 if (!object->IsDynamic())
00540 IncrementSubordinateStaticObjectCount();
00541 }
00542
00543 void Engine2::QuadTree::AddObjectIfNotAlreadyAdded (
00544 Engine2::Object *const object)
00545 {
00546 ASSERT1(object != NULL);
00547 ASSERT1(object->OwnerQuadTree(m_quad_tree_type) != NULL);
00548
00549
00550 if (object->OwnerQuadTree(m_quad_tree_type) != this)
00551 {
00552 object->OwnerQuadTree(m_quad_tree_type)->RemoveObject(object);
00553 NonRecursiveAddObject(object);
00554 }
00555 }
00556
00557 }