nanoflann_gui_example_R3.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /***********************************************************************
  2. * Software License Agreement (BSD License)
  3. *
  4. * Copyright 2011-2024 Jose Luis Blanco (joseluisblancoc@gmail.com).
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. *************************************************************************/
  28. #include <mrpt/gui/CDisplayWindow3D.h>
  29. #include <mrpt/opengl/COpenGLScene.h>
  30. #include <mrpt/opengl/CPointCloud.h>
  31. #include <mrpt/opengl/CSphere.h>
  32. #include <mrpt/opengl/stock_objects.h>
  33. #include <mrpt/random/RandomGenerators.h>
  34. #include <mrpt/system/CTimeLogger.h>
  35. #include <cstdlib>
  36. #include <ctime>
  37. #include <iostream>
  38. #include <nanoflann.hpp>
  39. #include "../../utils.h" // PointCloud<>
  40. mrpt::opengl::CPointCloud::Ptr pc_to_viz(const PointCloud<double>& pc)
  41. {
  42. auto gl = mrpt::opengl::CPointCloud::Create();
  43. for (const auto pt : pc.pts) { gl->insertPoint(pt.x, pt.y, pt.z); }
  44. gl->setPointSize(3.0f);
  45. return gl;
  46. }
  47. void kdtree_demo(const size_t N)
  48. {
  49. mrpt::gui::CDisplayWindow3D win("nanoflann example GUI", 800, 600);
  50. PointCloud<double> cloud;
  51. const double maxRangeXY = 100, maxRangeZ = 100;
  52. // Generate points:
  53. generateRandomPointCloudRanges(cloud, N, maxRangeXY, maxRangeXY, maxRangeZ);
  54. // viz:
  55. auto glQueryPt = mrpt::opengl::CPointCloud::Create();
  56. auto glFoundPts = mrpt::opengl::CPointCloud::Create();
  57. auto glQuerySphere = mrpt::opengl::CSphere::Create();
  58. {
  59. mrpt::opengl::COpenGLScene::Ptr scene;
  60. mrpt::gui::CDisplayWindow3DLocker lck(win, scene);
  61. auto glPts = pc_to_viz(cloud);
  62. scene->insert(glPts);
  63. scene->insert(mrpt::opengl::stock_objects::CornerXYZSimple());
  64. glQueryPt->setPointSize(10.0f);
  65. glQueryPt->setColor_u8(0xff, 0x00, 0x00);
  66. scene->insert(glQueryPt);
  67. glFoundPts->setPointSize(7.0f);
  68. glFoundPts->setColor_u8(0x00, 0x00, 0xff, 0x80);
  69. scene->insert(glFoundPts);
  70. #if defined(USE_RADIUS_SEARCH) || defined(USE_RKNN_SEARCH)
  71. glQuerySphere->setColor_u8(0xe0, 0xe0, 0xe0, 0x30);
  72. glQuerySphere->enableDrawSolid3D(true);
  73. #else
  74. glQuerySphere->setColor_u8(0xe0, 0xe0, 0xe0, 0x30);
  75. glQuerySphere->enableDrawSolid3D(false);
  76. #endif
  77. scene->insert(glQuerySphere);
  78. }
  79. // construct a kd-tree index:
  80. using my_kd_tree_t = nanoflann::KDTreeSingleIndexAdaptor<
  81. nanoflann::L2_Simple_Adaptor<double, PointCloud<double>>,
  82. PointCloud<double>, 3 /* dim */
  83. >;
  84. mrpt::system::CTimeLogger profiler;
  85. mrpt::system::CTimeLoggerEntry tle(profiler, "build_kd_tree");
  86. my_kd_tree_t index(3 /*dim*/, cloud, {10 /* max leaf */});
  87. tle.stop();
  88. auto& rng = mrpt::random::getRandomGenerator();
  89. // Declare here to avoid reallocations:
  90. #if defined(USE_RADIUS_SEARCH)
  91. std::vector<nanoflann::ResultItem<size_t, double>> indicesDists;
  92. #elif defined(USE_KNN_SEARCH) || defined(USE_RKNN_SEARCH)
  93. std::vector<size_t> indices;
  94. std::vector<double> distances;
  95. #else
  96. #error Expected either KNN, radius, or RKNN search build flag!
  97. #endif
  98. // Loop: different searches until the window is closed:
  99. while (win.isOpen())
  100. {
  101. // Unsorted radius search:
  102. #if defined(USE_RADIUS_SEARCH) || defined(USE_RKNN_SEARCH)
  103. const double radius = rng.drawUniform(0.1, maxRangeXY * 0.5);
  104. const double sqRadius = radius * radius;
  105. #endif
  106. #if defined(USE_KNN_SEARCH) || defined(USE_RKNN_SEARCH)
  107. const size_t nnToSearch = (rng.drawUniform32bit() % 10) + 1;
  108. #endif
  109. const double queryPt[3] = {
  110. rng.drawUniform(-0.3, maxRangeXY + 0.3),
  111. rng.drawUniform(-0.3, maxRangeXY + 0.3),
  112. rng.drawUniform(-0.3, maxRangeZ + 0.3)};
  113. mrpt::system::CTimeLoggerEntry tle2(profiler, "query");
  114. #if defined(USE_RADIUS_SEARCH)
  115. indicesDists.clear();
  116. nanoflann::RadiusResultSet<double, size_t> resultSet(
  117. sqRadius, indicesDists);
  118. index.findNeighbors(resultSet, queryPt);
  119. #else
  120. #if defined(USE_RKNN_SEARCH)
  121. nanoflann::RKNNResultSet<double, size_t> resultSet(
  122. nnToSearch, sqRadius);
  123. #elif defined(USE_KNN_SEARCH)
  124. nanoflann::KNNResultSet<double, size_t> resultSet(nnToSearch);
  125. #else
  126. #error Should not reach here!
  127. #endif
  128. indices.resize(nnToSearch);
  129. distances.resize(nnToSearch);
  130. resultSet.init(indices.data(), distances.data());
  131. index.findNeighbors(resultSet, queryPt);
  132. indices.resize(resultSet.size());
  133. distances.resize(resultSet.size());
  134. const double worstDist = std::sqrt(resultSet.worstDist());
  135. #endif
  136. tle2.stop();
  137. std::cout << "\nQuery point: (" << queryPt[0] << "," << queryPt[1]
  138. << "," << queryPt[2] << ") => " << resultSet.size()
  139. << " results.\n";
  140. if (!resultSet.empty())
  141. {
  142. #if defined(USE_RADIUS_SEARCH)
  143. nanoflann::ResultItem<size_t, double> worstPair =
  144. resultSet.worst_item();
  145. std::cout << "Worst pair: idx=" << worstPair.first
  146. << " dist=" << std::sqrt(worstPair.second) << std::endl;
  147. #else
  148. std::cout << "nnToSearch=" << nnToSearch
  149. << " actual found=" << indices.size()
  150. << " Worst found dist=" << worstDist << std::endl;
  151. #endif
  152. }
  153. // Color results:
  154. {
  155. win.get3DSceneAndLock();
  156. glQueryPt->clear();
  157. glQueryPt->insertPoint(queryPt[0], queryPt[1], queryPt[2]);
  158. glQuerySphere->setLocation(queryPt[0], queryPt[1], queryPt[2]);
  159. #if defined(USE_RADIUS_SEARCH) || defined(USE_RKNN_SEARCH)
  160. glQuerySphere->setRadius(radius);
  161. #else
  162. glQuerySphere->setRadius(worstDist);
  163. #endif
  164. glFoundPts->clear();
  165. #if defined(USE_RADIUS_SEARCH)
  166. for (const auto& [idx, dist] : indicesDists)
  167. #else
  168. for (const auto idx : indices)
  169. #endif
  170. {
  171. const auto& pt = cloud.pts.at(idx);
  172. glFoundPts->insertPoint(pt.x, pt.y, pt.z);
  173. }
  174. win.unlockAccess3DScene();
  175. win.repaint();
  176. }
  177. std::cout << "Press any key to pick another random query point. Close "
  178. "the GUI window to exit."
  179. << std::endl;
  180. win.waitForKey();
  181. }
  182. }
  183. int main()
  184. {
  185. kdtree_demo(1000);
  186. return 0;
  187. }