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_KD_TREE_INL
00046 #define LASS_GUARDIAN_OF_INCLUSION_SPAT_KD_TREE_INL
00047
00048 #include "spat_common.h"
00049 #include "kd_tree.h"
00050
00051 #ifdef LASS_SPAT_KD_TREE_DIAGNOSTICS
00052 # include "../io/xml_o_file.h"
00053 # include "../meta/select.h"
00054 # include "../prim/aabb_2d.h"
00055 # include "../prim/aabb_3d.h"
00056 #endif
00057
00058 namespace lass
00059 {
00060 namespace spat
00061 {
00062
00063
00064
00065
00066
00067 template <class O, class OT>
00068 KdTree<O, OT>::KdTree():
00069 begin_(),
00070 end_()
00071 {
00072 }
00073
00074
00075
00076
00077
00078
00079 template <class O, class OT>
00080 KdTree<O, OT>::KdTree(TObjectIterator first, TObjectIterator last):
00081 begin_(first),
00082 end_(last)
00083 {
00084 size_ = std::distance(begin_, end_);
00085 heap_.resize(size_, Node(end_));
00086
00087 TObjectIterators input;
00088 for (TObjectIterator i = begin_; i != end_; ++i)
00089 {
00090 input.push_back(i);
00091 }
00092
00093 balance(0, input.begin(), input.end());
00094 }
00095
00096
00097
00098
00099
00100 template <class O, class OT>
00101 void KdTree<O, OT>::reset()
00102 {
00103 TSelf temp;
00104 swap(temp);
00105 }
00106
00107
00108
00109
00110
00111
00112 template <class O, class OT>
00113 void KdTree<O, OT>::reset(TObjectIterator first, TObjectIterator last)
00114 {
00115 TSelf temp(first, last);
00116 swap(temp);
00117 }
00118
00119
00120
00121
00122
00123 template <class O, class OT>
00124 typename KdTree<O, OT>::Neighbour
00125 KdTree<O, OT>::nearestNeighbour(const TPoint& target) const
00126 {
00127 if (isEmpty())
00128 {
00129 LASS_THROW("can't locate nearest neighbour in empty KdTree");
00130 }
00131
00132
00133
00134
00135 Neighbour result(end_, std::numeric_limits<TValue>::infinity());
00136 doNearestNeighbour(0, target, result);
00137 return result;
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 template <class O, class OT>
00157 typename KdTree<O, OT>::TValue
00158 KdTree<O, OT>::rangeSearch(
00159 const TPoint& target, TParam maxRadius, size_t maxCount,
00160 TNeighbourhood& neighbourhood) const
00161 {
00162 if (isEmpty())
00163 {
00164 LASS_THROW("can't perform range search in empty KdTree");
00165 }
00166
00167 if (maxCount == 0)
00168 {
00169 neighbourhood.clear();
00170 rangeSearch(target, maxRadius, std::back_inserter(neighbourhood));
00171
00172
00173 TValue maxSquaredDistance = TValue();
00174 const typename TNeighbourhood::const_iterator end = neighbourhood.end();
00175 for (typename TNeighbourhood::const_iterator i = neighbourhood.begin(); i != end; ++i)
00176 {
00177 maxSquaredDistance = std::max(maxSquaredDistance, i->squaredDistance());
00178 }
00179 return maxSquaredDistance;
00180 }
00181
00182 maxCount = std::min(maxCount, size_);
00183 neighbourhood.resize(maxCount + 1);
00184
00185 typename TNeighbourhood::iterator last = rangeSearch(
00186 target, maxRadius, maxCount, neighbourhood.begin());
00187 neighbourhood.erase(last, neighbourhood.end());
00188
00189 if (neighbourhood.empty())
00190 {
00191 return TValue();
00192 }
00193 return neighbourhood.front().squaredDistance();
00194 }
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 template <class O, class OT>
00214 template <typename OutputIterator>
00215 OutputIterator
00216 KdTree<O, OT>::rangeSearch(const TPoint& target, TParam maxRadius, OutputIterator first) const
00217 {
00218 if (isEmpty() || maxRadius == 0)
00219 {
00220 return first;
00221 }
00222 const TValue squaredRadius = maxRadius * maxRadius;
00223 return doRangeSearch(0, target, squaredRadius, first);
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 template <class O, class OT>
00251 template <typename RandomAccessIterator>
00252 RandomAccessIterator
00253 KdTree<O, OT>::rangeSearch(const TPoint& target, TParam maxRadius, size_t maxCount,
00254 RandomAccessIterator first) const
00255 {
00256 if (isEmpty() || maxRadius == 0)
00257 {
00258 return first;
00259 }
00260 const TValue squaredRadius = maxRadius * maxRadius;
00261 return doRangeSearch(0, target, squaredRadius, maxCount, first, first);
00262 }
00263
00264
00265
00266
00267
00268 template <class O, class OT>
00269 void KdTree<O, OT>::swap(TSelf& other)
00270 {
00271 std::swap(begin_, other.begin_);
00272 std::swap(end_, other.end_);
00273 heap_.swap(other.heap_);
00274 std::swap(size_, other.size_);
00275 }
00276
00277
00278
00279
00280
00281 template <class O, class OT>
00282 const bool KdTree<O, OT>::isEmpty() const
00283 {
00284 return heap_.empty();
00285 }
00286
00287
00288
00289
00290
00291 template <class O, class OT>
00292 void KdTree<O, OT>::clear()
00293 {
00294 TSelf temp;
00295 swap(temp);
00296 }
00297
00298
00299
00300 template <class O, class OT> inline
00301 const typename KdTree<O, OT>::TObjectIterator
00302 KdTree<O, OT>::end() const
00303 {
00304 return end_;
00305 }
00306
00307
00308
00309
00310
00311 template <class O, class OT>
00312 KdTree<O, OT>::Neighbour::Neighbour():
00313 object_(),
00314 squaredDistance_(0)
00315 {
00316 }
00317
00318
00319
00320 template <class O, class OT>
00321 KdTree<O, OT>::Neighbour::Neighbour(TObjectIterator object, TValue squaredDistance):
00322 object_(object),
00323 squaredDistance_(squaredDistance)
00324 {
00325 }
00326
00327
00328
00329 template <class O, class OT>
00330 inline typename KdTree<O, OT>::TObjectIterator
00331 KdTree<O, OT>::Neighbour::object() const
00332 {
00333 return object_;
00334 }
00335
00336
00337
00338 template <class O, class OT>
00339 inline typename KdTree<O, OT>::TPoint
00340 KdTree<O, OT>::Neighbour::position() const
00341 {
00342 return TObjectTraits::position(object_);
00343 }
00344
00345
00346
00347 template <class O, class OT>
00348 inline typename KdTree<O, OT>::TValue
00349 KdTree<O, OT>::Neighbour::squaredDistance() const
00350 {
00351 return squaredDistance_;
00352 }
00353
00354
00355
00356 template <class O, class OT>
00357 inline typename KdTree<O, OT>::TObjectReference
00358 KdTree<O, OT>::Neighbour::operator*() const
00359 {
00360 return *object_;
00361 }
00362
00363
00364
00365 template <class O, class OT>
00366 inline typename KdTree<O, OT>::TObjectIterator
00367 KdTree<O, OT>::Neighbour::operator->() const
00368 {
00369 return object_;
00370 }
00371
00372
00373
00374 template <class O, class OT>
00375 inline bool
00376 KdTree<O, OT>::Neighbour::operator<(const Neighbour& other) const
00377 {
00378 return squaredDistance_ < other.squaredDistance_;
00379 }
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 template <class O, class OT>
00390 void KdTree<O, OT>::balance(size_t index, TIteratorIterator first, TIteratorIterator last)
00391 {
00392 if (last == first)
00393 {
00394 return;
00395 }
00396
00397 if (last == first + 1)
00398 {
00399
00400 assignNode(index, *first, dummyAxis_);
00401 return;
00402 }
00403
00404
00405
00406 const TAxis split = findSplitAxis(first, last);
00407 const size_t size = last - first;;
00408 const TIteratorIterator median = first + size / 2;
00409 std::nth_element(first, median, last, LessDim(split));
00410 assignNode(index, *median, split);
00411
00412 balance(2 * index + 1, first, median);
00413 balance(2 * index + 2, median + 1, last);
00414 }
00415
00416
00417
00418 template <class O, class OT>
00419 typename KdTree<O, OT>::TAxis
00420 KdTree<O, OT>::findSplitAxis(TIteratorIterator first, TIteratorIterator last) const
00421 {
00422 TPoint min = TObjectTraits::position(*first);
00423 TPoint max = min;
00424
00425 for (TIteratorIterator i = first + 1; i != last; ++i)
00426 {
00427 const TPoint position = TObjectTraits::position(*i);
00428 for (TAxis k = 0; k < dimension; ++k)
00429 {
00430 min[k] = std::min(min[k], position[k]);
00431 max[k] = std::max(max[k], position[k]);
00432 }
00433 }
00434
00435 TAxis axis = 0;
00436 TValue maxDistance = max[0] - min[0];
00437 for (TAxis k = 1; k < dimension; ++k)
00438 {
00439 const TValue distance = max[k] - min[k];
00440 if (distance > maxDistance)
00441 {
00442 axis = k;
00443 maxDistance = distance;
00444 }
00445 }
00446
00447 return axis;
00448 }
00449
00450
00451
00452 template <class O, class OT>
00453 inline void KdTree<O, OT>::assignNode(size_t index, TObjectIterator object, TAxis splitAxis)
00454 {
00455 if (heap_.size() <= index)
00456 {
00457 heap_.resize(index + 1, Node(end_));
00458 }
00459 heap_[index] = Node(object, splitAxis);
00460 }
00461
00462
00463
00464 template <class O, class OT>
00465 size_t KdTree<O, OT>::findNode(size_t index, const TPoint& target) const
00466 {
00467 const size_t size = heap_.size();
00468 if (index >= size || heap_[index].object() == end_)
00469 {
00470 return size;
00471 }
00472 const Node& node = heap_[index];
00473
00474 const TAxis split = node.axis();
00475 if (split == dummyAxis_)
00476 {
00477 return index;
00478 }
00479
00480 const TPoint pivot = node.position();
00481 const TValue delta = target[split] - pivot[split];
00482 const bool isLeftSide = delta < 0;
00483 const size_t result = findNode(2 * index + (isLeftSide ? 1 : 2), target);
00484 return result != size ? result : index;
00485 }
00486
00487
00488
00489 template <class O, class OT>
00490 void KdTree<O, OT>::doNearestNeighbour(size_t index, const TPoint& target, Neighbour& best) const
00491 {
00492 if (index >= heap_.size() || heap_[index].object() == end_)
00493 {
00494 return;
00495 }
00496 const Node& node = heap_[index];
00497 const TPoint pivot = node.position();
00498
00499 const TAxis split = node.axis();
00500 if (split != dummyAxis_)
00501 {
00502 const TValue delta = target[split] - pivot[split];
00503 if (delta < 0)
00504 {
00505
00506 doNearestNeighbour(2 * index + 1, target, best);
00507 if (num::sqr(delta) < best.squaredDistance())
00508 {
00509 doNearestNeighbour(2 * index + 2, target, best);
00510 }
00511 }
00512 else
00513 {
00514
00515 doNearestNeighbour(2 * index + 2, target, best);
00516 if (num::sqr(delta) < best.squaredDistance())
00517 {
00518 doNearestNeighbour(2 * index + 1, target, best);
00519 }
00520 }
00521 }
00522
00523 const TValue sqrDistance = this->squaredDistance(pivot, target);
00524 if (sqrDistance < best.squaredDistance())
00525 {
00526 best = Neighbour(node.object(), sqrDistance);
00527 }
00528 }
00529
00530
00531
00532 template <class O, class OT>
00533 template <typename OutputIterator>
00534 OutputIterator KdTree<O, OT>::doRangeSearch(
00535 size_t index, const TPoint& target, TParam squaredDistance,
00536 OutputIterator output) const
00537 {
00538 if (index >= heap_.size() || heap_[index].object() == end_)
00539 {
00540 return output;
00541 }
00542 const Node& node = heap_[index];
00543
00544 const TPoint pivot = node.position();
00545 const TAxis split = node.axis();
00546 if (split != dummyAxis_)
00547 {
00548 const TValue delta = target[split] - pivot[split];
00549 if (delta < TValue())
00550 {
00551
00552 output = doRangeSearch(2 * index + 1, target, squaredDistance, output);
00553 if (num::sqr(delta) < squaredDistance)
00554 {
00555 output = doRangeSearch(2 * index + 2, target, squaredDistance, output);
00556 }
00557 }
00558 else
00559 {
00560
00561 output = doRangeSearch(2 * index + 2, target, squaredDistance, output);
00562 if (num::sqr(delta) < squaredDistance)
00563 {
00564 output = doRangeSearch(2 * index + 1, target, squaredDistance, output);
00565 }
00566 }
00567 }
00568
00569 const TValue sqrDistance = this->squaredDistance(pivot, target);
00570 if (sqrDistance < squaredDistance)
00571 {
00572 *output++ = Neighbour(node.object(), sqrDistance);
00573 }
00574 return output;
00575 }
00576
00577
00578
00579 template <class O, class OT>
00580 template <typename RandomIterator>
00581 RandomIterator KdTree<O, OT>::doRangeSearch(
00582 size_t index, const TPoint& target, TReference squaredRadius, size_t maxCount,
00583 RandomIterator first, RandomIterator last) const
00584 {
00585 if (index >= heap_.size() || heap_[index].object() == end_)
00586 {
00587 return last;
00588 }
00589 const Node& node = heap_[index];
00590
00591 const TPoint pivot = node.position();
00592 const TAxis split = node.axis();
00593 if (split != dummyAxis_)
00594 {
00595 const TValue delta = target[split] - pivot[split];
00596 if (delta < TValue())
00597 {
00598
00599 last = doRangeSearch(
00600 2 * index + 1, target, squaredRadius, maxCount, first, last);
00601 if (num::sqr(delta) < squaredRadius)
00602 {
00603 last = doRangeSearch(
00604 2 * index + 2, target, squaredRadius, maxCount, first, last);
00605 }
00606 }
00607 else
00608 {
00609
00610 last = doRangeSearch(
00611 2 * index + 2, target, squaredRadius, maxCount, first, last);
00612 if (num::sqr(delta) < squaredRadius)
00613 {
00614 last = doRangeSearch(
00615 2 * index + 1, target, squaredRadius, maxCount, first, last);
00616 }
00617 }
00618 }
00619
00620 const TValue sqrDistance = squaredDistance(pivot, target);
00621 if (sqrDistance < squaredRadius)
00622 {
00623 *last++ = Neighbour(node.object(), sqrDistance);
00624 std::push_heap(first, last);
00625 LASS_ASSERT(last >= first);
00626 if (static_cast<size_t>(last - first) > maxCount)
00627 {
00628 std::pop_heap(first, last);
00629 --last;
00630 squaredRadius = first->squaredDistance();
00631 }
00632 }
00633 return last;
00634 }
00635
00636
00637
00638 template <class O, class OT> inline
00639 typename KdTree<O, OT>::TValue
00640 KdTree<O, OT>::squaredDistance(const TPoint& a, const TPoint& b)
00641 {
00642 TValue result = TValue();
00643 for (unsigned k = 0; k < dimension; ++k)
00644 {
00645 result += num::sqr(a[k] - b[k]);
00646 }
00647 return result;
00648 }
00649
00650
00651
00652 #ifdef LASS_SPAT_KD_TREE_DIAGNOSTICS
00653 template <class O, class OT>
00654 void KdTree<O, OT>::diagnostics()
00655 {
00656 typedef typename meta::Select< meta::Bool<dimension == 2>, prim::Aabb2D<TValue>, prim::Aabb3D<TValue> >::Type TAabb;
00657 class Visitor
00658 {
00659 public:
00660 Visitor(const TNodes& heap, TObjectIterator end):
00661 xml_("kdtree.xml", "diagnostics"),
00662 heap_(heap),
00663 end_(end)
00664 {
00665 }
00666
00667 void visit(size_t index, const TAabb& aabb)
00668 {
00669 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
00670 using lass::prim::operator<<;
00671 #endif
00672 xml_ << aabb;
00673
00674 if (index >= heap_.size() || heap_[index].object() == end_)
00675 {
00676 return;
00677 }
00678 const Node& node = heap_[index];
00679
00680 const typename TObjectTraits::TPoint pivot = node.position();
00681 xml_ << pivot;
00682
00683 const TAxis split = node.axis();
00684 if (split == dummyAxis_)
00685 {
00686 return;
00687 }
00688
00689 TAabb less = aabb;
00690 typename TAabb::TPoint max = less.max();
00691 max[split] = pivot[split];
00692 less.setMax(max);
00693 visit(2 * index + 1, less);
00694
00695 TAabb greater = aabb;
00696 typename TAabb::TPoint min = greater.min();
00697 min[split] = pivot[split];
00698 greater.setMin(min);
00699 visit(2 * index + 2, greater);
00700 }
00701
00702 private:
00703 io::XmlOFile xml_;
00704 const TNodes& heap_;
00705 TObjectIterator end_;
00706 };
00707
00708 TAabb aabb;
00709 for (TObjectIterator i = begin_; i != end_; ++i)
00710 {
00711 aabb += TObjectTraits::position(i);
00712 }
00713
00714 Visitor visitor(heap_, end_);
00715 visitor.visit(0, aabb);
00716 }
00717 #endif
00718
00719
00720
00721
00722
00723
00724
00725 }
00726
00727 }
00728
00729 #endif
00730
00731