00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #ifndef LASS_GUARDIAN_OF_INCLUSION_SPAT_AABB_TREE_INL
00046 #define LASS_GUARDIAN_OF_INCLUSION_SPAT_AABB_TREE_INL
00047
00048 #include "spat_common.h"
00049 #include "aabb_tree.h"
00050
00051 namespace lass
00052 {
00053 namespace spat
00054 {
00055
00056
00057
00058 template <typename O, typename OT, typename SH>
00059 AabbTree<O, OT, SH>::AabbTree():
00060 objects_(),
00061 nodes_(),
00062 end_()
00063 {
00064 }
00065
00066
00067
00068 template <typename O, typename OT, typename SH>
00069 AabbTree<O, OT, SH>::AabbTree(TObjectIterator first, TObjectIterator last):
00070 objects_(),
00071 nodes_(),
00072 end_(last)
00073 {
00074 if (first != last)
00075 {
00076 TInputs inputs;
00077 for (TObjectIterator i = first; i != last; ++i)
00078 {
00079 inputs.push_back(Input(TObjectTraits::objectAabb(i), i));
00080 }
00081 balance(inputs.begin(), inputs.end());
00082 }
00083 }
00084
00085
00086
00087 template <typename O, typename OT, typename SH>
00088 void AabbTree<O, OT, SH>::reset(TObjectIterator first, TObjectIterator last)
00089 {
00090 TSelf temp(first, last);
00091 swap(temp);
00092 }
00093
00094
00095
00096 template <typename O, typename OT, typename SH> inline
00097 const typename AabbTree<O, OT, SH>::TAabb
00098 AabbTree<O, OT, SH>::aabb() const
00099 {
00100 if (isEmpty())
00101 {
00102 return TObjectTraits::aabbEmpty();
00103 }
00104 return nodes_[0].aabb();
00105 }
00106
00107
00108
00109 template <typename O, typename OT, typename SH> inline
00110 bool AabbTree<O, OT, SH>::contains(const TPoint& point, const TInfo* info) const
00111 {
00112 if (isEmpty())
00113 {
00114 return false;
00115 }
00116 return doContains(0, point, info);
00117 }
00118
00119
00120
00121 template <typename O, typename OT, typename SH>
00122 template <typename OutputIterator> inline
00123 OutputIterator AabbTree<O, OT, SH>::find(
00124 const TPoint& point, OutputIterator result, const TInfo* info) const
00125 {
00126 if (isEmpty())
00127 {
00128 return result;
00129 }
00130 return doFind(0, point, result, info);
00131 }
00132
00133
00134
00135 template <typename O, typename OT, typename SH>
00136 typename AabbTree<O, OT, SH>::TObjectIterator inline
00137 AabbTree<O, OT, SH>::intersect(const TRay& ray, TReference t, TParam tMin, const TInfo* info) const
00138 {
00139 if (isEmpty())
00140 {
00141 return end_;
00142 }
00143 return doIntersect(0, ray, t, tMin, info);
00144 }
00145
00146
00147
00148 template <typename O, typename OT, typename SH>
00149 bool inline AabbTree<O, OT, SH>::intersects(const TRay& ray, TParam tMin, TParam tMax, const TInfo* info) const
00150 {
00151 if (isEmpty())
00152 {
00153 return false;
00154 }
00155 return doIntersects(0, ray, tMin, tMax, info);
00156 }
00157
00158
00159
00160 template <typename O, typename OT, typename SH>
00161 const typename AabbTree<O, OT, SH>::Neighbour
00162 AabbTree<O, OT, SH>::nearestNeighbour(const TPoint& point, const TInfo* info) const
00163 {
00164 Neighbour nearest(end_, std::numeric_limits<TValue>::infinity());
00165 if (!isEmpty())
00166 {
00167 doNearestNeighbour(0, point, info, nearest);
00168 }
00169 return nearest;
00170 }
00171
00172
00173
00174 template <class O, class OT, typename SH>
00175 template <typename RandomAccessIterator>
00176 RandomAccessIterator
00177 AabbTree<O, OT, SH>::rangeSearch(
00178 const TPoint& target, TParam maxRadius, size_t maxCount, RandomAccessIterator first,
00179 const TInfo* info) const
00180 {
00181 if (isEmpty() || maxRadius == 0)
00182 {
00183 return first;
00184 }
00185 TValue squaredRadius = maxRadius * maxRadius;
00186 return doRangeSearch(0, target, squaredRadius, maxCount, first, first, info);
00187 }
00188
00189
00190
00191 template <typename O, typename OT, typename SH>
00192 void AabbTree<O, OT, SH>::swap(TSelf& other)
00193 {
00194 nodes_.swap(other.nodes_);
00195 objects_.swap(other.objects_);
00196 std::swap(end_, other.end_);
00197 }
00198
00199
00200
00201 template <typename O, typename OT, typename SH>
00202 const bool AabbTree<O, OT, SH>::isEmpty() const
00203 {
00204 return objects_.empty();
00205 }
00206
00207
00208
00209 template <typename O, typename OT, typename SH>
00210 const typename AabbTree<O, OT, SH>::TObjectIterator
00211 AabbTree<O, OT, SH>::end() const
00212 {
00213 return end_;
00214 }
00215
00216
00217
00218 template <typename O, typename OT, typename SH>
00219 void AabbTree<O, OT, SH>::reset()
00220 {
00221 TSelf temp;
00222 swap(temp);
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 template <typename O, typename OT, typename SH>
00234 const int AabbTree<O, OT, SH>::balance(TInputIterator first, TInputIterator last)
00235 {
00236 const SplitInfo<OT> split = TSplitHeuristics::template split<OT>(first, last);
00237 if (split.axis < 0)
00238 {
00239 return addLeafNode(split.aabb, first, last);
00240 }
00241
00242 TInputIterator middle = std::partition(first, last, impl::Splitter<TObjectTraits>(split));
00243 if (middle == first || middle == last)
00244 {
00245 const ptrdiff_t halfSize = (last - first) / 2;
00246 LASS_ASSERT(halfSize > 0);
00247 middle = first + halfSize;
00248 std::nth_element(first, middle, last, impl::LessAxis<TObjectTraits>(split.axis));
00249 }
00250 LASS_ASSERT(middle != first && middle != last);
00251
00252 const int node = addInternalNode(split.aabb);
00253 const int left = balance(first, middle);
00254 LASS_ASSERT(left == node + 1);
00255 const int right = balance(middle, last);
00256 nodes_[node].right() = right;
00257 return node;
00258 }
00259
00260
00261
00262 template <typename O, typename OT, typename SH>
00263 const int AabbTree<O, OT, SH>::addLeafNode(
00264 const TAabb& aabb, TInputIterator first, TInputIterator last)
00265 {
00266 const int begin = static_cast<int>(objects_.size());
00267 while (first != last)
00268 {
00269 objects_.push_back((first++)->object);
00270 }
00271 const int end = static_cast<int>(objects_.size());
00272
00273 LASS_ASSERT(begin >= 0 && end >= 0);
00274 nodes_.push_back(Node(aabb, begin, end));
00275
00276 LASS_ASSERT(static_cast<int>(nodes_.size()) > 0);
00277 return static_cast<int>(nodes_.size()) - 1;
00278 }
00279
00280
00281
00282 template <typename O, typename OT, typename SH>
00283 const int AabbTree<O, OT, SH>::addInternalNode(const TAabb& aabb)
00284 {
00285 nodes_.push_back(Node(aabb));
00286
00287 LASS_ASSERT(static_cast<int>(nodes_.size()) > 0);
00288 return static_cast<int>(nodes_.size()) - 1;
00289 }
00290
00291
00292
00293 template <typename O, typename OT, typename SH>
00294 bool AabbTree<O, OT, SH>::doContains(int index, const TPoint& point, const TInfo* info) const
00295 {
00296 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00297 LASS_ASSERT(index >= 0 && static_cast<size_t>(index) < nodes_.size());
00298 const Node& node = nodes_[index];
00299
00300 if (!TObjectTraits::aabbContains(node.aabb(), point))
00301 {
00302 return false;
00303 }
00304 if (node.isInternal())
00305 {
00306 return doContains(index + 1, point, info) || doContains(node.right(), point, info);
00307 }
00308 for (int i = node.first(); i != node.last(); ++i)
00309 {
00310 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00311 if (TObjectTraits::objectContains(objects_[i], point, info))
00312 {
00313 return true;
00314 }
00315 }
00316 return false;
00317 }
00318
00319
00320
00321 template <typename O, typename OT, typename SH>
00322 template <typename OutputIterator>
00323 OutputIterator AabbTree<O, OT, SH>::doFind(
00324 int index, const TPoint& point, OutputIterator result, const TInfo* info) const
00325 {
00326 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00327 LASS_ASSERT(index >= 0 && static_cast<size_t>(index) < nodes_.size());
00328 const Node& node = nodes_[index];
00329
00330 if (!TObjectTraits::aabbContains(node.aabb(), point))
00331 {
00332 return result;
00333 }
00334 if (node.isInternal())
00335 {
00336 result = doFind(index + 1, point, result, info);
00337 return doFind(node.right(), point, result, info);
00338 }
00339 for (int i = node.first(); i != node.last(); ++i)
00340 {
00341 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00342 if (TObjectTraits::objectContains(objects_[i], point, info))
00343 {
00344 *result++ = objects_[i];
00345 }
00346 }
00347 return result;
00348 }
00349
00350
00351
00352 template <typename O, typename OT, typename SH>
00353 typename AabbTree<O, OT, SH>::TObjectIterator
00354 AabbTree<O, OT, SH>::doIntersect(
00355 int index, const TRay& ray, TReference t, TParam tMin, const TInfo* info) const
00356 {
00357 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00358 LASS_ASSERT(index >= 0 && static_cast<size_t>(index) < nodes_.size());
00359 const Node& node = nodes_[index];
00360
00361 TValue tDummy;
00362 if (!TObjectTraits::aabbIntersect(node.aabb(), ray, tDummy, tMin))
00363 {
00364 return end_;
00365 }
00366
00367 if (node.isInternal())
00368 {
00369 TValue tLeft;
00370 TObjectIterator left = doIntersect(index + 1, ray, tLeft, tMin, info);
00371 TValue tRight;
00372 TObjectIterator right = doIntersect(node.right(), ray, tRight, tMin, info);
00373
00374 if (left != end_ && (right == end_ || tLeft < tRight))
00375 {
00376 t = tLeft;
00377 return left;
00378 }
00379 if (right != end_)
00380 {
00381 LASS_ASSERT(left == end_ || !(tLeft < tRight));
00382 t = tRight;
00383 return right;
00384 }
00385 return end_;
00386 }
00387
00388 TValue tBest = 0;
00389 TObjectIterator best = end_;
00390 for (int i = node.first(); i != node.last(); ++i)
00391 {
00392 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00393 TValue tCandidate = 0;
00394 if (TObjectTraits::objectIntersect(objects_[i], ray, tCandidate, tMin, info))
00395 {
00396 if (best == end_ || tCandidate < tBest)
00397 {
00398 tBest = tCandidate;
00399 best = objects_[i];
00400 }
00401 }
00402 }
00403 if (best != end_)
00404 {
00405 t = tBest;
00406 }
00407 return best;
00408 }
00409
00410
00411
00412 template <typename O, typename OT, typename SH>
00413 bool AabbTree<O, OT, SH>::doIntersects(
00414 int index, const TRay& ray, TParam tMin, const TParam tMax, const TInfo* info) const
00415 {
00416 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00417 LASS_ASSERT(index >= 0 && static_cast<size_t>(index) < nodes_.size());
00418 const Node& node = nodes_[index];
00419
00420 TValue tDummy = 0;
00421 if (!TObjectTraits::aabbIntersect(node.aabb(), ray, tDummy, tMin))
00422 {
00423 return false;
00424 }
00425 if (node.isInternal())
00426 {
00427 return doIntersects(index + 1, ray, tMin, tMax, info)
00428 || doIntersects(node.right(), ray, tMin, tMax, info);
00429 }
00430 for (int i = node.first(); i != node.last(); ++i)
00431 {
00432 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00433 if (TObjectTraits::objectIntersects(objects_[i], ray, tMin, tMax, info))
00434 {
00435 return true;
00436 }
00437 }
00438 return false;
00439 }
00440
00441
00442
00443 template <typename O, typename OT, typename SH>
00444 void AabbTree<O, OT, SH>::doNearestNeighbour(
00445 int index, const TPoint& target, const TInfo* info, Neighbour& best) const
00446 {
00447 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00448 LASS_ASSERT(best.squaredDistance() >= 0);
00449
00450 const Node& node = nodes_[index];
00451
00452 if (node.isLeaf())
00453 {
00454 for (int i = node.first(); i != node.last(); ++i)
00455 {
00456 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00457 const TValue squaredDistance = TObjectTraits::objectSquaredDistance(objects_[i], target, info);
00458 if (squaredDistance < best.squaredDistance())
00459 {
00460 best = Neighbour(objects_[i], squaredDistance);
00461 }
00462 }
00463 }
00464 else
00465 {
00466 int children[2];
00467 TValue squaredDistances[2];
00468 getChildren(index, target, children, squaredDistances);
00469 if (squaredDistances[0] < best.squaredDistance())
00470 {
00471 doNearestNeighbour(children[0], target, info, best);
00472 if (squaredDistances[1] < best.squaredDistance())
00473 {
00474 doNearestNeighbour(children[1], target, info, best);
00475 }
00476 }
00477 }
00478 }
00479
00480
00481
00482 template <typename O, typename OT, typename SH>
00483 template <typename RandomIterator>
00484 RandomIterator AabbTree<O, OT, SH>::doRangeSearch(
00485 int index, const TPoint& target, TReference squaredRadius, size_t maxCount,
00486 RandomIterator first, RandomIterator last, const TInfo* info) const
00487 {
00488 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00489 LASS_ASSERT(squaredRadius >= 0);
00490
00491 const Node& node = nodes_[index];
00492
00493 if (node.isLeaf())
00494 {
00495 for (int i = node.first(); i != node.last(); ++i)
00496 {
00497 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00498 const TValue sqrDist = TObjectTraits::objectSquaredDistance(objects_[i], target, info);
00499 if (sqrDist < squaredRadius)
00500 {
00501 *last++ = Neighbour(objects_[i], sqrDist);
00502 std::push_heap(first, last);
00503 LASS_ASSERT(last >= first);
00504 if (static_cast<size_t>(last - first) > maxCount)
00505 {
00506 std::pop_heap(first, last);
00507 --last;
00508 squaredRadius = first->squaredDistance();
00509 }
00510 }
00511 }
00512 return last;
00513 }
00514
00515 int children[2];
00516 TValue squaredDistances[2];
00517 getChildren(index, target, children, squaredDistances);
00518 if (squaredDistances[0] < squaredRadius)
00519 {
00520 last = doRangeSearch(children[0], target, squaredRadius, maxCount, first, last, info);
00521 if (squaredDistances[1] < squaredRadius)
00522 {
00523 last = doRangeSearch(children[1], target, squaredRadius, maxCount, first, last, info);
00524 }
00525 }
00526
00527 return last;
00528 }
00529
00530
00531
00532 template <typename O, typename OT, typename SH>
00533 void AabbTree<O, OT, SH>::getChildren(
00534 int index, const TPoint& target, int indices[2], TValue squaredDistances[2]) const
00535 {
00536 const Node& node = nodes_[index];
00537 indices[0] = index + 1;
00538 indices[1] = node.right();
00539
00540 for (size_t i = 0; i < 2; ++i)
00541 {
00542 const Node& child = nodes_[indices[i]];
00543 squaredDistances[i] = 0;
00544 const TPoint& min = TObjectTraits::aabbMin(child.aabb());
00545 const TPoint& max = TObjectTraits::aabbMax(child.aabb());
00546 for (size_t k = 0; k < dimension; ++k)
00547 {
00548 const TValue x = TObjectTraits::coord(target, k);
00549 const TValue d = std::max(TObjectTraits::coord(min, k) - x, x - TObjectTraits::coord(max, k));
00550 if (d > 0)
00551 {
00552 squaredDistances[i] += d * d;
00553 }
00554 }
00555 }
00556
00557 if (squaredDistances[1] < squaredDistances[0])
00558 {
00559 std::swap(squaredDistances[0], squaredDistances[1]);
00560 std::swap(indices[0], indices[1]);
00561 }
00562 }
00563
00564
00565
00566
00567
00568
00569
00570 }
00571
00572 }
00573
00574 #endif
00575
00576