10#if !defined(GEOGRAPHICLIB_NEARESTNEIGHBOR_HPP)
11#define GEOGRAPHICLIB_NEARESTNEIGHBOR_HPP 1
25#if defined(GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION) && \
26 GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION
27#include <boost/serialization/nvp.hpp>
28#include <boost/serialization/split_member.hpp>
29#include <boost/serialization/array.hpp>
30#include <boost/serialization/vector.hpp>
35# pragma warning (push)
36# pragma warning (disable: 4127)
102 template<
typename dist_t,
typename pos_t,
class distfun_t>
105 static const int version = 1;
108 static const int maxbucket =
109 (2 + ((4 *
sizeof(dist_t)) /
sizeof(int) >= 2 ?
110 (4 *
sizeof(dist_t)) /
sizeof(
int) : 2));
170 void Initialize(
const std::vector<pos_t>& pts,
const distfun_t& dist,
172 static_assert(std::numeric_limits<dist_t>::is_signed,
173 "dist_t must be a signed type");
174 if (!( 0 <= bucket && bucket <= maxbucket ))
176 (
"bucket must lie in [0, 2 + 4*sizeof(dist_t)/sizeof(int)]");
177 if (pts.size() > size_t(std::numeric_limits<int>::max()))
180 std::vector<item> ids(pts.size());
181 for (
int k =
int(ids.size()); k--;)
182 ids[k] = std::make_pair(dist_t(0), k);
184 std::vector<Node> tree;
185 init(pts, dist, bucket, tree, ids, cost,
186 0,
int(ids.size()),
int(ids.size()/2));
188 _numpoints = int(pts.size());
191 _cost = cost; _c1 = _k = _cmax = 0;
192 _cmin = std::numeric_limits<int>::max();
258 dist_t
Search(
const std::vector<pos_t>& pts,
const distfun_t& dist,
260 std::vector<int>& ind,
262 dist_t maxdist = std::numeric_limits<dist_t>::max(),
264 bool exhaustive =
true,
265 dist_t tol = 0)
const {
266 if (_numpoints !=
int(pts.size()))
268 std::priority_queue<item> results;
269 if (_numpoints > 0 && k > 0 && maxdist > mindist) {
271 dist_t tau = maxdist;
275 std::priority_queue<item> todo;
276 todo.push(std::make_pair(dist_t(1),
int(_tree.size()) - 1));
278 while (!todo.empty()) {
279 int n = todo.top().second;
280 dist_t d = -todo.top().first;
282 dist_t tau1 = tau - tol;
284 if (!( n >= 0 && tau1 >= d ))
continue;
285 const Node& current = _tree[n];
287 bool exitflag =
false, leaf = current.index < 0;
288 for (
int i = 0; i < (leaf ? _bucket : 1); ++i) {
289 int index = leaf ? current.leaves[i] : current.index;
290 if (index < 0)
break;
291 dst = dist(pts[index], query);
294 if (dst > mindist && dst <= tau) {
295 if (
int(results.size()) == k) results.pop();
296 results.push(std::make_pair(dst, index));
297 if (
int(results.size()) == k) {
299 tau = results.top().first;
313 if (current.index < 0)
continue;
315 for (
int l = 0; l < 2; ++l) {
316 if (current.data.child[l] >= 0 &&
317 dst + current.data.upper[l] >= mindist) {
318 if (dst < current.data.lower[l]) {
319 d = current.data.lower[l] - dst;
321 todo.push(std::make_pair(-d, current.data.child[l]));
322 }
else if (dst > current.data.upper[l]) {
323 d = dst - current.data.upper[l];
325 todo.push(std::make_pair(-d, current.data.child[l]));
327 todo.push(std::make_pair(dist_t(1), current.data.child[l]));
334 _mc += (c - omc) / _k;
335 _sc += (c - omc) * (c - _mc);
336 if (c > _cmax) _cmax = c;
337 if (c < _cmin) _cmin = c;
341 ind.resize(results.size());
343 for (
int i =
int(ind.size()); i--;) {
344 ind[i] = int(results.top().second);
345 if (i == 0) d = results.top().first;
374 void Save(std::ostream& os,
bool bin =
true)
const {
375 int realspec = std::numeric_limits<dist_t>::digits *
376 (std::numeric_limits<dist_t>::is_integer ? -1 : 1);
378 char id[] =
"NearestNeighbor_";
385 buf[4] = int(_tree.size());
387 os.write(
reinterpret_cast<const char *
>(buf), 6 *
sizeof(
int));
388 for (
int i = 0; i < int(_tree.size()); ++i) {
389 const Node& node = _tree[i];
390 os.write(
reinterpret_cast<const char *
>(&node.index),
sizeof(int));
391 if (node.index >= 0) {
392 os.write(
reinterpret_cast<const char *
>(node.data.lower),
394 os.write(
reinterpret_cast<const char *
>(node.data.upper),
396 os.write(
reinterpret_cast<const char *
>(node.data.child),
399 os.write(
reinterpret_cast<const char *
>(node.leaves),
400 _bucket *
sizeof(int));
404 std::stringstream ostring;
407 if (!std::numeric_limits<dist_t>::is_integer) {
408 static const int prec
409 = int(std::ceil(std::numeric_limits<dist_t>::digits *
410 std::log10(2.0) + 1));
411 ostring.precision(prec);
413 ostring << version <<
" " << realspec <<
" " << _bucket <<
" "
414 << _numpoints <<
" " << _tree.size() <<
" " << _cost;
415 for (
int i = 0; i < int(_tree.size()); ++i) {
416 const Node& node = _tree[i];
417 ostring <<
"\n" << node.index;
418 if (node.index >= 0) {
419 for (
int l = 0; l < 2; ++l)
420 ostring <<
" " << node.data.lower[l] <<
" " << node.data.upper[l]
421 <<
" " << node.data.child[l];
423 for (
int l = 0; l < _bucket; ++l)
424 ostring <<
" " << node.leaves[l];
452 void Load(std::istream& is,
bool bin =
true) {
453 int version1, realspec, bucket, numpoints, treesize, cost;
458 if (!(std::strcmp(
id,
"NearestNeighbor_") == 0))
460 is.read(
reinterpret_cast<char *
>(&version1),
sizeof(
int));
461 is.read(
reinterpret_cast<char *
>(&realspec),
sizeof(
int));
462 is.read(
reinterpret_cast<char *
>(&bucket),
sizeof(
int));
463 is.read(
reinterpret_cast<char *
>(&numpoints),
sizeof(
int));
464 is.read(
reinterpret_cast<char *
>(&treesize),
sizeof(
int));
465 is.read(
reinterpret_cast<char *
>(&cost),
sizeof(
int));
467 if (!( is >> version1 >> realspec >> bucket >> numpoints >> treesize
471 if (!( version1 == version ))
473 if (!( realspec == std::numeric_limits<dist_t>::digits *
474 (std::numeric_limits<dist_t>::is_integer ? -1 : 1) ))
476 if (!( 0 <= bucket && bucket <= maxbucket ))
478 if (!( 0 <= treesize && treesize <= numpoints ))
483 std::vector<Node> tree;
484 tree.reserve(treesize);
485 for (
int i = 0; i < treesize; ++i) {
488 is.read(
reinterpret_cast<char *
>(&node.index),
sizeof(
int));
489 if (node.index >= 0) {
490 is.read(
reinterpret_cast<char *
>(node.data.lower),
492 is.read(
reinterpret_cast<char *
>(node.data.upper),
494 is.read(
reinterpret_cast<char *
>(node.data.child),
497 is.read(
reinterpret_cast<char *
>(node.leaves),
498 bucket *
sizeof(
int));
499 for (
int l = bucket; l < maxbucket; ++l)
503 if (!( is >> node.index ))
505 if (node.index >= 0) {
506 for (
int l = 0; l < 2; ++l) {
507 if (!( is >> node.data.lower[l] >> node.data.upper[l]
508 >> node.data.child[l] ))
514 for (
int l = 0; l < bucket; ++l) {
515 if (!( is >> node.leaves[l] ))
518 for (
int l = bucket; l < maxbucket; ++l)
522 node.Check(numpoints, treesize, bucket);
523 tree.push_back(node);
526 _numpoints = numpoints;
529 _cost = cost; _c1 = _k = _cmax = 0;
530 _cmin = std::numeric_limits<int>::max();
542 { t.
Save(os,
false);
return os; }
553 { t.
Load(is,
false);
return is; }
587 void Statistics(
int& setupcost,
int& numsearches,
int& searchcost,
588 int& mincost,
int& maxcost,
589 double& mean,
double& sd)
const {
590 setupcost = _cost; numsearches = _k; searchcost = _c1;
591 mincost = _cmin; maxcost = _cmax;
592 mean = _mc; sd = std::sqrt(_sc / (_k - 1));
601 _c1 = _k = _cmax = 0;
602 _cmin = std::numeric_limits<int>::max();
608 typedef std::pair<dist_t, int> item;
613 dist_t lower[2], upper[2];
618 int leaves[maxbucket];
625 for (
int i = 0; i < 2; ++i) {
626 data.lower[i] = data.upper[i] = 0;
632 void Check(
int numpoints,
int treesize,
int bucket)
const {
633 if (!( -1 <= index && index < numpoints ))
636 if (!( -1 <= data.child[0] && data.child[0] < treesize &&
637 -1 <= data.child[1] && data.child[1] < treesize ))
639 if (!( 0 <= data.lower[0] && data.lower[0] <= data.upper[0] &&
640 data.upper[0] <= data.lower[1] &&
641 data.lower[1] <= data.upper[1] ))
647 for (
int l = 0; l < bucket; ++l) {
649 ((l == 0 ? 0 : -1) <= leaves[l] && leaves[l] < numpoints) :
652 start = leaves[l] >= 0;
654 for (
int l = bucket; l < maxbucket; ++l) {
661#if defined(GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION) && \
662 GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION
663 friend class boost::serialization::access;
664 template<
class Archive>
665 void save(Archive& ar,
const unsigned int)
const {
666 ar & boost::serialization::make_nvp(
"index", index);
668 ar & boost::serialization::make_nvp(
"leaves", leaves);
670 ar & boost::serialization::make_nvp(
"lower", data.lower)
671 & boost::serialization::make_nvp(
"upper", data.upper)
672 & boost::serialization::make_nvp(
"child", data.child);
674 template<
class Archive>
675 void load(Archive& ar,
const unsigned int) {
676 ar & boost::serialization::make_nvp(
"index", index);
678 ar & boost::serialization::make_nvp(
"leaves", leaves);
680 ar & boost::serialization::make_nvp(
"lower", data.lower)
681 & boost::serialization::make_nvp(
"upper", data.upper)
682 & boost::serialization::make_nvp(
"child", data.child);
684 template<
class Archive>
685 void serialize(Archive& ar,
const unsigned int file_version)
686 { boost::serialization::split_member(ar, *
this, file_version); }
690#if defined(GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION) && \
691 GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION
692 friend class boost::serialization::access;
693 template<
class Archive>
void save(Archive& ar,
const unsigned)
const {
694 int realspec = std::numeric_limits<dist_t>::digits *
695 (std::numeric_limits<dist_t>::is_integer ? -1 : 1);
698 int version1 = version;
699 ar & boost::serialization::make_nvp(
"version", version1)
700 & boost::serialization::make_nvp(
"realspec", realspec)
701 & boost::serialization::make_nvp(
"bucket", _bucket)
702 & boost::serialization::make_nvp(
"numpoints", _numpoints)
703 & boost::serialization::make_nvp(
"cost", _cost)
704 & boost::serialization::make_nvp(
"tree", _tree);
706 template<
class Archive>
void load(Archive& ar,
const unsigned) {
707 int version1, realspec, bucket, numpoints, cost;
708 ar & boost::serialization::make_nvp(
"version", version1);
709 if (version1 != version)
711 std::vector<Node> tree;
712 ar & boost::serialization::make_nvp(
"realspec", realspec);
713 if (!( realspec == std::numeric_limits<dist_t>::digits *
714 (std::numeric_limits<dist_t>::is_integer ? -1 : 1) ))
716 ar & boost::serialization::make_nvp(
"bucket", bucket);
717 if (!( 0 <= bucket && bucket <= maxbucket ))
719 ar & boost::serialization::make_nvp(
"numpoints", numpoints)
720 & boost::serialization::make_nvp(
"cost", cost)
721 & boost::serialization::make_nvp(
"tree", tree);
722 if (!( 0 <=
int(tree.size()) &&
int(tree.size()) <= numpoints ))
725 for (
int i = 0; i < int(tree.size()); ++i)
726 tree[i].Check(numpoints,
int(tree.size()), bucket);
728 _numpoints = numpoints;
731 _cost = cost; _c1 = _k = _cmax = 0;
732 _cmin = std::numeric_limits<int>::max();
734 template<
class Archive>
735 void serialize(Archive& ar,
const unsigned int file_version)
736 { boost::serialization::split_member(ar, *
this, file_version); }
739 int _numpoints, _bucket, _cost;
740 std::vector<Node> _tree;
742 mutable double _mc, _sc;
743 mutable int _c1, _k, _cmin, _cmax;
745 int init(
const std::vector<pos_t>& pts,
const distfun_t& dist,
int bucket,
746 std::vector<Node>& tree, std::vector<item>& ids,
int& cost,
747 int l,
int u,
int vp) {
753 if (u - l > (bucket == 0 ? 1 : bucket)) {
759 int m = (u + l + 1) / 2;
761 for (
int k = l + 1; k < u; ++k) {
762 ids[k].first = dist(pts[ids[l].second], pts[ids[k].second]);
766 std::nth_element(ids.begin() + l + 1,
769 node.index = ids[l].second;
771 typename std::vector<item>::iterator
772 t = std::min_element(ids.begin() + l + 1, ids.begin() + m);
773 node.data.lower[0] = t->first;
774 t = std::max_element(ids.begin() + l + 1, ids.begin() + m);
775 node.data.upper[0] = t->first;
778 node.data.child[0] = init(pts, dist, bucket, tree, ids, cost,
779 l + 1, m,
int(t - ids.begin()));
781 typename std::vector<item>::iterator
782 t = std::max_element(ids.begin() + m, ids.begin() + u);
783 node.data.lower[1] = ids[m].first;
784 node.data.upper[1] = t->first;
786 node.data.child[1] = init(pts, dist, bucket, tree, ids, cost,
787 m, u,
int(t - ids.begin()));
790 node.index = ids[l].second;
795 std::sort(ids.begin() + l, ids.begin() + u);
796 for (
int i = l; i < u; ++i)
797 node.leaves[i-l] = ids[i].second;
798 for (
int i = u - l; i < bucket; ++i)
800 for (
int i = bucket; i < maxbucket; ++i)
805 tree.push_back(node);
806 return int(tree.size()) - 1;
825 template<
typename dist_t,
typename pos_t,
class distfun_t>
834# pragma warning (pop)
Header for GeographicLib::Constants class.
Exception handling for GeographicLib.
Nearest-neighbor calculations.
void Statistics(int &setupcost, int &numsearches, int &searchcost, int &mincost, int &maxcost, double &mean, double &sd) const
friend std::istream & operator>>(std::istream &is, NearestNeighbor &t)
dist_t Search(const std::vector< pos_t > &pts, const distfun_t &dist, const pos_t &query, std::vector< int > &ind, int k=1, dist_t maxdist=std::numeric_limits< dist_t >::max(), dist_t mindist=-1, bool exhaustive=true, dist_t tol=0) const
void Initialize(const std::vector< pos_t > &pts, const distfun_t &dist, int bucket=4)
void Load(std::istream &is, bool bin=true)
void Save(std::ostream &os, bool bin=true) const
void ResetStatistics() const
NearestNeighbor(const std::vector< pos_t > &pts, const distfun_t &dist, int bucket=4)
void swap(NearestNeighbor &t)
friend std::ostream & operator<<(std::ostream &os, const NearestNeighbor &t)
Namespace for GeographicLib.
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)