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_AABP_TREE_INL
00046 #define LASS_GUARDIAN_OF_INCLUSION_SPAT_AABP_TREE_INL
00047
00048 #include "spat_common.h"
00049 #include "aabp_tree.h"
00050
00051 namespace lass
00052 {
00053 namespace spat
00054 {
00055
00056
00057
00058 template <typename O, typename OT, typename SH>
00059 AabpTree<O, OT, SH>::AabpTree():
00060 aabb_(TObjectTraits::aabbEmpty()),
00061 objects_(),
00062 nodes_(),
00063 end_()
00064 {
00065 }
00066
00067
00068
00069 template <typename O, typename OT, typename SH>
00070 AabpTree<O, OT, SH>::AabpTree(TObjectIterator first, TObjectIterator last):
00071 aabb_(TObjectTraits::aabbEmpty()),
00072 objects_(),
00073 nodes_(),
00074 end_(last)
00075 {
00076 if (first != last)
00077 {
00078 TInputs inputs;
00079 for (TObjectIterator i = first; i != last; ++i)
00080 {
00081 TAabb aabb = TObjectTraits::objectAabb(i);
00082 aabb_ = TObjectTraits::aabbJoin(aabb_, aabb);
00083 inputs.push_back(Input(aabb, i));
00084 }
00085 balance(inputs.begin(), inputs.end());
00086 }
00087 }
00088
00089
00090
00091 template <typename O, typename OT, typename SH>
00092 void AabpTree<O, OT, SH>::reset()
00093 {
00094 TSelf temp;
00095 swap(temp);
00096 }
00097
00098
00099
00100 template <typename O, typename OT, typename SH>
00101 void AabpTree<O, OT, SH>::reset(TObjectIterator first, TObjectIterator last)
00102 {
00103 TSelf temp(first, last);
00104 swap(temp);
00105 }
00106
00107
00108
00109 template <typename O, typename OT, typename SH>
00110 const typename AabpTree<O, OT, SH>::TAabb&
00111 AabpTree<O, OT, SH>::aabb() const
00112 {
00113 return aabb_;
00114 }
00115
00116
00117
00118 template <typename O, typename OT, typename SH>
00119 const bool AabpTree<O, OT, SH>::contains(const TPoint& point, const TInfo* info) const
00120 {
00121 if (isEmpty() || !TObjectTraits::aabbContains(aabb_, point))
00122 {
00123 return false;
00124 }
00125 return doContains(0, point, info);
00126 }
00127
00128
00129
00130 template <typename O, typename OT, typename SH>
00131 template <typename OutputIterator>
00132 OutputIterator AabpTree<O, OT, SH>::find(
00133 const TPoint& point, OutputIterator result, const TInfo* info) const
00134 {
00135 if (isEmpty() || !TObjectTraits::aabbContains(aabb_, point))
00136 {
00137 return result;
00138 }
00139 return doFind(0, point, result, info);
00140 }
00141
00142
00143
00144 template <typename O, typename OT, typename SH>
00145 const typename AabpTree<O, OT, SH>::TObjectIterator
00146 AabpTree<O, OT, SH>::intersect(const TRay& ray, TReference t, TParam tMin, const TInfo* info) const
00147 {
00148 TValue tNear;
00149 if (isEmpty() || !TObjectTraits::aabbIntersect(aabb_, ray, tNear, tMin))
00150 {
00151 return end_;
00152 }
00153 TValue tFar;
00154 if (!TObjectTraits::aabbIntersect(aabb_, ray, tFar, tNear))
00155 {
00156 tFar = tNear;
00157 tNear = tMin;
00158 }
00159 const TVector reciprocalDirection = TObjectTraits::vectorReciprocal(TObjectTraits::rayDirection(ray));
00160 TObjectIterator hit = doIntersect(0, ray, t, tMin, info, reciprocalDirection, tNear, tFar);
00161 LASS_ASSERT((t > tMin && t >= tNear && t <= tFar * (1 + 1e-7f)) || hit == end_);
00162 return hit;
00163 }
00164
00165
00166
00167 template <typename O, typename OT, typename SH>
00168 const bool AabpTree<O, OT, SH>::intersects(
00169 const TRay& ray, TParam tMin, TParam tMax, const TInfo* info) const
00170 {
00171 TValue tNear;
00172 if (isEmpty() || !TObjectTraits::aabbIntersect(aabb_, ray, tNear, tMin))
00173 {
00174 return false;
00175 }
00176 TValue tFar;
00177 if (!TObjectTraits::aabbIntersect(aabb_, ray, tFar, tNear))
00178 {
00179 tFar = tNear;
00180 tNear = tMin;
00181 }
00182 if (tNear > tMax || tFar < tMin)
00183 {
00184 return false;
00185 }
00186 const TVector reciprocalDirection = TObjectTraits::vectorReciprocal(TObjectTraits::rayDirection(ray));
00187 return doIntersects(0, ray, tMin, tMax, info, reciprocalDirection, tNear, tFar);
00188 }
00189
00190
00191
00192 template <typename O, typename OT, typename SH>
00193 const typename AabpTree<O, OT, SH>::Neighbour
00194 AabpTree<O, OT, SH>::nearestNeighbour(const TPoint& target, const TInfo* info) const
00195 {
00196 Neighbour nearest(end_, std::numeric_limits<TValue>::infinity());
00197 if (!isEmpty())
00198 {
00199 doNearestNeighbour(0, target, info, nearest);
00200 }
00201 return nearest;
00202 }
00203
00204
00205
00206 template <class O, class OT, typename SH>
00207 template <typename RandomAccessIterator>
00208 RandomAccessIterator
00209 AabpTree<O, OT, SH>::rangeSearch(
00210 const TPoint& target, TParam maxRadius, size_t maxCount, RandomAccessIterator first,
00211 const TInfo* info) const
00212 {
00213 if (isEmpty() || maxRadius == 0)
00214 {
00215 return first;
00216 }
00217 TValue squaredRadius = maxRadius * maxRadius;
00218 return doRangeSearch(0, target, squaredRadius, maxCount, first, first, info);
00219 }
00220
00221
00222
00223 template <typename O, typename OT, typename SH>
00224 void AabpTree<O, OT, SH>::swap(TSelf& other)
00225 {
00226 std::swap(aabb_, other.aabb_);
00227 nodes_.swap(other.nodes_);
00228 objects_.swap(other.objects_);
00229 std::swap(end_, other.end_);
00230 }
00231
00232
00233
00234 template <typename O, typename OT, typename SH>
00235 const bool AabpTree<O, OT, SH>::isEmpty() const
00236 {
00237 return objects_.empty();
00238 }
00239
00240
00241
00242 template <typename O, typename OT, typename SH>
00243 const typename AabpTree<O, OT, SH>::TObjectIterator
00244 AabpTree<O, OT, SH>::end() const
00245 {
00246 return end_;
00247 }
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 template <typename O, typename OT, typename SH>
00258 const typename AabpTree<O, OT, SH>::BalanceResult
00259 AabpTree<O, OT, SH>::balance(TInputIterator first, TInputIterator last)
00260 {
00261 const SplitInfo<OT> split = TSplitHeuristics::template split<OT>(first, last);
00262 if (split.axis < 0)
00263 {
00264 return BalanceResult(split.aabb, addLeafNode(first, last));
00265 }
00266
00267 TInputIterator middle = std::partition(first, last, impl::Splitter<TObjectTraits>(split));
00268 if (middle == first || middle == last)
00269 {
00270 const ptrdiff_t halfSize = (last - first) / 2;
00271 LASS_ASSERT(halfSize > 0);
00272 middle = first + halfSize;
00273 std::nth_element(first, middle, last, impl::LessAxis<TObjectTraits>(split.axis));
00274 }
00275 LASS_ASSERT(middle != first && middle != last);
00276
00277 const int index = addInternalNode(split.axis);
00278 const BalanceResult left = balance(first, middle);
00279 const BalanceResult right = balance(middle, last);
00280
00281 Node& node = nodes_[index];
00282 node.leftBound() = TObjectTraits::coord(TObjectTraits::aabbMax(left.aabb), split.axis);
00283 node.rightBound() = TObjectTraits::coord(TObjectTraits::aabbMin(right.aabb), split.axis);
00284 LASS_ASSERT(left.index == index + 1);
00285 node.right() = right.index;
00286
00287 return BalanceResult(split.aabb, index);
00288 }
00289
00290
00291
00292 template <typename O, typename OT, typename SH>
00293 const int AabpTree<O, OT, SH>::addLeafNode(TInputIterator first, TInputIterator last)
00294 {
00295 const int begin = static_cast<int>(objects_.size());
00296 while (first != last)
00297 {
00298 objects_.push_back((first++)->object);
00299 }
00300 const int end = static_cast<int>(objects_.size());
00301
00302 LASS_ASSERT(begin >= 0 && end >= 0);
00303 nodes_.push_back(Node(begin, end));
00304
00305 LASS_ASSERT(static_cast<int>(nodes_.size()) > 0);
00306 return static_cast<int>(nodes_.size()) - 1;
00307 }
00308
00309
00310
00311 template <typename O, typename OT, typename SH>
00312 const int AabpTree<O, OT, SH>::addInternalNode(int axis)
00313 {
00314 nodes_.push_back(Node(axis));
00315 LASS_ASSERT(static_cast<int>(nodes_.size()) > 0);
00316 return static_cast<int>(nodes_.size()) - 1;
00317 }
00318
00319
00320
00321 template <typename O, typename OT, typename SH>
00322 const bool AabpTree<O, OT, SH>::doContains(int index, const TPoint& point, const TInfo* info) const
00323 {
00324 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00325 LASS_ASSERT(index >= 0 && static_cast<size_t>(index) < nodes_.size());
00326 const Node& node = nodes_[index];
00327
00328 if (node.isLeaf())
00329 {
00330 for (int i = node.first(); i != node.last(); ++i)
00331 {
00332 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00333 if (TObjectTraits::objectContains(objects_[i], point, info))
00334 {
00335 return true;
00336 }
00337 }
00338 return false;
00339 }
00340
00341 const TValue x = TObjectTraits::coord(point, node.axis());
00342 if (x <= node.leftBound() && doContains(index + 1, point, info))
00343 {
00344 return true;
00345 }
00346 if (x >= node.rightBound() && doContains(node.right(), point, info))
00347 {
00348 return true;
00349 }
00350 return false;
00351 }
00352
00353
00354
00355 template <typename O, typename OT, typename SH>
00356 template <typename OutputIterator>
00357 OutputIterator AabpTree<O, OT, SH>::doFind(
00358 int index, const TPoint& point, OutputIterator result, const TInfo* info) const
00359 {
00360 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00361 LASS_ASSERT(index >= 0 && static_cast<size_t>(index) < nodes_.size());
00362 const Node& node = nodes_[index];
00363
00364 if (node.isLeaf())
00365 {
00366 for (int i = node.first(); i != node.last(); ++i)
00367 {
00368 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00369 if (TObjectTraits::objectContains(objects_[i], point, info))
00370 {
00371 *result++ = objects_[i];
00372 }
00373 }
00374 return result;
00375 }
00376
00377 const TValue x = TObjectTraits::coord(point, node.axis());
00378 if (x <= node.leftBound())
00379 {
00380 result = doFind(index + 1, point, result, info);
00381 }
00382 if (x >= node.rightBound())
00383 {
00384 result = doFind(node.right(), point, result, info);
00385 }
00386 return result;
00387 }
00388
00389
00390
00391 template <typename O, typename OT, typename SH>
00392 const typename AabpTree<O, OT, SH>::TObjectIterator
00393 AabpTree<O, OT, SH>::doIntersect(
00394 int index, const TRay& ray, TReference t, TParam tMin, const TInfo* info,
00395 const TVector& reciprocalDirection, TParam tNear, TParam tFar) const
00396 {
00397 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00398 LASS_ASSERT(index >= 0 && static_cast<size_t>(index) < nodes_.size());
00399 LASS_ASSERT(tFar > tNear);
00400 const Node& node = nodes_[index];
00401
00402 if (node.isLeaf())
00403 {
00404 TValue tBest = 0;
00405 TObjectIterator best = end_;
00406 for (int i = node.first(); i != node.last(); ++i)
00407 {
00408 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00409 TValue tCandidate = 0;
00410 if (TObjectTraits::objectIntersect(objects_[i], ray, tCandidate, tMin, info))
00411 {
00412 LASS_ASSERT(tCandidate > tMin);
00413 if (best == end_ || tCandidate < tBest)
00414 {
00415
00416 best = objects_[i];
00417 tBest = tCandidate;
00418 }
00419 }
00420 }
00421 if (best != end_)
00422 {
00423 t = tBest;
00424 }
00425 return best;
00426 }
00427
00428
00429 const int leftIndex = index + 1;
00430 const int rightIndex = node.right();
00431 const TValue s = TObjectTraits::coord(TObjectTraits::raySupport(ray), node.axis());
00432 const TValue d = TObjectTraits::coord(TObjectTraits::rayDirection(ray), node.axis());
00433 const TValue invD = TObjectTraits::coord(reciprocalDirection, node.axis());
00434 const TValue tLeftBound = (node.leftBound() - s) * invD;
00435 const TValue tRightBound = (node.rightBound() - s) * invD;
00436
00437 TValue tLeft = 0;
00438 TValue tRight = 0;
00439 TObjectIterator objectLeft = end_;
00440 TObjectIterator objectRight = end_;
00441 if (d > 0)
00442 {
00443 if (tLeftBound > tNear)
00444 {
00445 objectLeft = doIntersect(leftIndex, ray, tLeft, tMin, info, reciprocalDirection,
00446 tNear, std::min(tLeftBound, tFar));
00447 }
00448 if (tRightBound < tFar)
00449 {
00450 objectRight = doIntersect(rightIndex, ray, tRight, tMin, info, reciprocalDirection,
00451 std::max(tRightBound, tNear), tFar);
00452 }
00453 }
00454 else if (d < 0)
00455 {
00456 if (tLeftBound < tFar)
00457 {
00458 objectLeft = doIntersect(leftIndex, ray, tLeft, tMin, info, reciprocalDirection,
00459 std::max(tLeftBound, tNear), tFar);
00460 }
00461 if (tRightBound > tNear)
00462 {
00463 objectRight = doIntersect(rightIndex, ray, tRight, tMin, info, reciprocalDirection,
00464 tNear, std::min(tRightBound, tFar));
00465 }
00466 }
00467 else
00468 {
00469 if (s <= node.leftBound())
00470 {
00471 objectLeft = doIntersect(leftIndex, ray, tLeft, tMin, info, reciprocalDirection,
00472 tNear, tFar);
00473 }
00474 if (s >= node.rightBound())
00475 {
00476 objectRight = doIntersect(rightIndex, ray, tRight, tMin, info, reciprocalDirection,
00477 tNear, tFar);
00478 }
00479 }
00480
00481
00482 if (objectLeft != end_ && (objectRight == end_ || tLeft < tRight))
00483 {
00484 LASS_ASSERT(tLeft > tMin);
00485 t = tLeft;
00486 return objectLeft;
00487 }
00488 if (objectRight != end_)
00489 {
00490 LASS_ASSERT(objectLeft == end_ || !(tLeft < tRight));
00491 LASS_ASSERT(tRight > tMin);
00492 t = tRight;
00493 return objectRight;
00494 }
00495 return end_;
00496 }
00497
00498
00499
00500 template <typename O, typename OT, typename SH>
00501 const bool AabpTree<O, OT, SH>::doIntersects(
00502 int index, const TRay& ray, TParam tMin, TParam tMax, const TInfo* info,
00503 const TVector& reciprocalDirection, TParam tNear, TParam tFar) const
00504 {
00505 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00506 LASS_ASSERT(index >= 0 && static_cast<size_t>(index) < nodes_.size());
00507 LASS_ASSERT(tMax > tMin);
00508 const Node& node = nodes_[index];
00509
00510 if (node.isLeaf())
00511 {
00512 for (int i = node.first(); i != node.last(); ++i)
00513 {
00514 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00515 if (TObjectTraits::objectIntersects(objects_[i], ray, tMin, tMax, info))
00516 {
00517 return true;
00518 }
00519 }
00520 return false;
00521 }
00522
00523
00524 const int leftIndex = index + 1;
00525 const int rightIndex = node.right();
00526 const TValue s = TObjectTraits::coord(TObjectTraits::raySupport(ray), node.axis());
00527 const TValue d = TObjectTraits::coord(TObjectTraits::rayDirection(ray), node.axis());
00528 const TValue invD = TObjectTraits::coord(reciprocalDirection, node.axis());
00529 const TValue tLeftBound = (node.leftBound() - s) * invD;
00530 const TValue tRightBound = (node.rightBound() - s) * invD;
00531
00532 if (d > 0)
00533 {
00534 if ((tLeftBound > tNear) && doIntersects(leftIndex, ray, tMin, tMax, info,
00535 reciprocalDirection, tNear, std::min(tLeftBound, tFar)))
00536 {
00537 return true;
00538 }
00539 if ((tRightBound < tFar) && doIntersects(rightIndex, ray, tMin, tMax, info,
00540 reciprocalDirection, std::max(tRightBound, tNear), tFar))
00541 {
00542 return true;
00543 }
00544 }
00545 else if (d < 0)
00546 {
00547 if ((tLeftBound < tFar) && doIntersects(leftIndex, ray, tMin, tMax, info,
00548 reciprocalDirection, std::max(tLeftBound, tNear), tFar))
00549 {
00550 return true;
00551 }
00552 if ((tRightBound > tNear) && doIntersects(rightIndex, ray, tMin, tMax, info,
00553 reciprocalDirection, tNear, std::min(tRightBound, tFar)))
00554 {
00555 return true;
00556 }
00557 }
00558 else
00559 {
00560 if ((s <= node.leftBound()) && doIntersects(rightIndex, ray, tMin, tMax, info,
00561 reciprocalDirection, tNear, tFar))
00562 {
00563 return true;
00564 }
00565 if ((s >= node.rightBound()) && doIntersects(rightIndex, ray, tMin, tMax, info,
00566 reciprocalDirection, tNear, tFar))
00567 {
00568 return true;
00569 }
00570 }
00571 return false;
00572 }
00573
00574
00575
00576 template <typename O, typename OT, typename SH>
00577 void AabpTree<O, OT, SH>::doNearestNeighbour(
00578 int index, const TPoint& target, const TInfo* info, Neighbour& best) const
00579 {
00580 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00581 LASS_ASSERT(best.squaredDistance() >= 0);
00582
00583 const Node& node = nodes_[index];
00584
00585 if (node.isLeaf())
00586 {
00587 for (int i = node.first(); i != node.last(); ++i)
00588 {
00589 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00590 const TValue squaredDistance =
00591 TObjectTraits::objectSquaredDistance(objects_[i], target, info);
00592 if (squaredDistance < best.squaredDistance())
00593 {
00594 best = Neighbour(objects_[i], squaredDistance);
00595 }
00596 }
00597 }
00598 else
00599 {
00600 int children[2];
00601 TValue signedDist[2];
00602 getChildren(index, target, children, signedDist);
00603 if (signedDist[0] <= 0 || (signedDist[0] * signedDist[0]) < best.squaredDistance())
00604 {
00605 doNearestNeighbour(children[0], target, info, best);
00606 if (signedDist[1] <= 0 || (signedDist[1] * signedDist[1]) < best.squaredDistance())
00607 {
00608 doNearestNeighbour(children[1], target, info, best);
00609 }
00610 }
00611 }
00612 }
00613
00614
00615
00616 template <typename O, typename OT, typename SH>
00617 template <typename RandomIterator>
00618 RandomIterator AabpTree<O, OT, SH>::doRangeSearch(
00619 int index, const TPoint& target, TReference squaredRadius, size_t maxCount,
00620 RandomIterator first, RandomIterator last, const TInfo* info) const
00621 {
00622 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_INIT_NODE(TInfo, info);
00623 LASS_ASSERT(squaredRadius >= 0);
00624
00625 const Node& node = nodes_[index];
00626
00627 if (node.isLeaf())
00628 {
00629 for (int i = node.first(); i != node.last(); ++i)
00630 {
00631 LASS_SPAT_OBJECT_TREES_DIAGNOSTICS_VISIT_OBJECT;
00632 const TValue sqrDist = TObjectTraits::objectSquaredDistance(objects_[i], target, info);
00633 if (sqrDist < squaredRadius)
00634 {
00635 *last++ = Neighbour(objects_[i], sqrDist);
00636 std::push_heap(first, last);
00637 LASS_ASSERT(last >= first);
00638 if (static_cast<size_t>(last - first) > maxCount)
00639 {
00640 std::pop_heap(first, last);
00641 --last;
00642 squaredRadius = first->squaredDistance();
00643 }
00644 }
00645 }
00646 return last;
00647 }
00648
00649 int children[2];
00650 TValue signedDist[2];
00651 getChildren(index, target, children, signedDist);
00652 if (signedDist[0] <= 0 || (signedDist[0] * signedDist[0]) < squaredRadius)
00653 {
00654 last = doRangeSearch(children[0], target, squaredRadius, maxCount, first, last, info);
00655 if (signedDist[1] <= 0 || (signedDist[1] * signedDist[1]) < squaredRadius)
00656 {
00657 last = doRangeSearch(children[1], target, squaredRadius, maxCount, first, last, info);
00658 }
00659 }
00660 return last;
00661 }
00662
00663
00664
00665 template <typename O, typename OT, typename SH>
00666 void AabpTree<O, OT, SH>::getChildren(
00667 int index, const TPoint& target, int indices[2], TValue signedDistances[2]) const
00668 {
00669 const Node& node = nodes_[index];
00670 indices[0] = index + 1;
00671 indices[1] = node.right();
00672 const TValue x = TObjectTraits::coord(target, node.axis());
00673 signedDistances[0] = x - node.leftBound();
00674 signedDistances[1] = node.rightBound() - x;
00675
00676 if (signedDistances[1] < signedDistances[0])
00677 {
00678 std::swap(signedDistances[0], signedDistances[1]);
00679 std::swap(indices[0], indices[1]);
00680 }
00681 }
00682
00683
00684
00685
00686
00687 }
00688
00689 }
00690
00691 #endif
00692
00693