ivox3d_node.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. #include <pcl/common/centroid.h>
  2. #include <algorithm>
  3. #include <cmath>
  4. #include <list>
  5. #include <vector>
  6. #include <pcl/point_cloud.h>
  7. #include <pcl/point_types.h>
  8. #include <pcl/filters/voxel_grid.h>
  9. #include "hilbert.hpp"
  10. namespace faster_lio {
  11. // squared distance of two pcl points
  12. template <typename PointT>
  13. inline double distance2(const PointT& pt1, const PointT& pt2) {
  14. Eigen::Vector3f d = pt1.getVector3fMap() - pt2.getVector3fMap();
  15. return d.squaredNorm();
  16. }
  17. // convert from pcl point to eigen
  18. template <typename T, int dim, typename PointType>
  19. inline Eigen::Matrix<T, dim, 1> ToEigen(const PointType& pt) {
  20. return Eigen::Matrix<T, dim, 1>(pt.x, pt.y, pt.z);
  21. }
  22. template <>
  23. inline Eigen::Matrix<float, 3, 1> ToEigen<float, 3, pcl::PointXYZ>(const pcl::PointXYZ& pt) {
  24. return pt.getVector3fMap();
  25. }
  26. template <>
  27. inline Eigen::Matrix<float, 3, 1> ToEigen<float, 3, pcl::PointXYZI>(const pcl::PointXYZI& pt) {
  28. return pt.getVector3fMap();
  29. }
  30. template <>
  31. inline Eigen::Matrix<float, 3, 1> ToEigen<float, 3, pcl::PointXYZINormal>(const pcl::PointXYZINormal& pt) {
  32. return pt.getVector3fMap();
  33. }
  34. template <typename PointT, int dim = 3>
  35. class IVoxNode {
  36. public:
  37. EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
  38. struct DistPoint;
  39. IVoxNode() = default;
  40. IVoxNode(const PointT& center, const float& side_length) {} /// same with phc
  41. void InsertPoint(const PointT& pt);
  42. std::vector<PointT> Points(){return points_;}
  43. inline bool Empty() const;
  44. inline std::size_t Size() const;
  45. void DownSample(double leafSize=0.02);
  46. inline PointT GetPoint(const std::size_t idx) const;
  47. int KNNPointByCondition(std::vector<DistPoint>& dis_points, const PointT& point, const int& K,
  48. const double& max_range);
  49. int UpdateRecord();
  50. private:
  51. std::vector<PointT> points_;
  52. };
  53. template <typename PointT, int dim = 3>
  54. class IVoxNodePhc {
  55. public:
  56. EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
  57. struct DistPoint;
  58. struct PhcCube;
  59. IVoxNodePhc() = default;
  60. IVoxNodePhc(const PointT& center, const float& side_length, const int& phc_order = 6);
  61. void InsertPoint(const PointT& pt);
  62. void ErasePoint(const PointT& pt, const double erase_distance_th_);
  63. inline bool Empty() const;
  64. inline std::size_t Size() const;
  65. PointT GetPoint(const std::size_t idx) const;
  66. bool NNPoint(const PointT& cur_pt, DistPoint& dist_point) const;
  67. int KNNPointByCondition(std::vector<DistPoint>& dis_points, const PointT& cur_pt, const int& K = 5,
  68. const double& max_range = 5.0);
  69. private:
  70. uint32_t CalculatePhcIndex(const PointT& pt) const;
  71. private:
  72. std::vector<PhcCube> phc_cubes_;
  73. PointT center_;
  74. float side_length_ = 0;
  75. int phc_order_ = 6;
  76. float phc_side_length_ = 0;
  77. float phc_side_length_inv_ = 0;
  78. Eigen::Matrix<float, dim, 1> min_cube_;
  79. };
  80. template <typename PointT, int dim>
  81. struct IVoxNode<PointT, dim>::DistPoint {
  82. double dist = 0;
  83. IVoxNode* node = nullptr;
  84. int idx = 0;
  85. DistPoint() = default;
  86. DistPoint(const double d, IVoxNode* n, const int i) : dist(d), node(n), idx(i) {}
  87. PointT Get() { return node->GetPoint(idx); }
  88. inline bool operator()(const DistPoint& p1, const DistPoint& p2) { return p1.dist < p2.dist; }
  89. inline bool operator<(const DistPoint& rhs) { return dist < rhs.dist; }
  90. };
  91. template <typename PointT, int dim>
  92. void IVoxNode<PointT, dim>::InsertPoint(const PointT& pt) {
  93. points_.emplace_back(pt);
  94. }
  95. template <typename PointT, int dim>
  96. void IVoxNode<PointT, dim>::DownSample(double leafSize)
  97. {
  98. /*pcl::PointCloud<PointT> result;
  99. pcl::VoxelGrid<PointT> grid;
  100. grid.setLeafSize(leafSize,leafSize,leafSize);
  101. grid.setInputCloud(points_.makeShared());
  102. grid.filter(result);
  103. points_=result;*/
  104. }
  105. template <typename PointT, int dim>
  106. bool IVoxNode<PointT, dim>::Empty() const {
  107. return points_.empty();
  108. }
  109. template <typename PointT, int dim>
  110. std::size_t IVoxNode<PointT, dim>::Size() const {
  111. return points_.size();
  112. }
  113. template <typename PointT, int dim>
  114. PointT IVoxNode<PointT, dim>::GetPoint(const std::size_t idx) const {
  115. return points_[idx];
  116. }
  117. template <typename PointT, int dim>
  118. int IVoxNode<PointT, dim>::KNNPointByCondition(std::vector<DistPoint>& dis_points, const PointT& point, const int& K,
  119. const double& max_range) {
  120. std::size_t old_size = dis_points.size();
  121. // #define INNER_TIMER
  122. #ifdef INNER_TIMER
  123. static std::unordered_map<std::string, std::vector<int64_t>> stats;
  124. if (stats.empty()) {
  125. stats["dis"] = std::vector<int64_t>();
  126. stats["put"] = std::vector<int64_t>();
  127. stats["nth"] = std::vector<int64_t>();
  128. }
  129. #endif
  130. for (const auto& pt : points_) {
  131. #ifdef INNER_TIMER
  132. auto t0 = std::chrono::high_resolution_clock::now();
  133. #endif
  134. double d = distance2(pt, point);
  135. #ifdef INNER_TIMER
  136. auto t1 = std::chrono::high_resolution_clock::now();
  137. #endif
  138. if (d < max_range * max_range) {
  139. dis_points.template emplace_back(DistPoint(d, this, &pt - points_.data()));
  140. }
  141. #ifdef INNER_TIMER
  142. auto t2 = std::chrono::high_resolution_clock::now();
  143. auto dis = std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0).count();
  144. stats["dis"].emplace_back(dis);
  145. auto put = std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count();
  146. stats["put"].emplace_back(put);
  147. #endif
  148. }
  149. #ifdef INNER_TIMER
  150. auto t1 = std::chrono::high_resolution_clock::now();
  151. #endif
  152. // sort by distance
  153. if (old_size + K >= dis_points.size()) {
  154. } else {
  155. std::nth_element(dis_points.begin() + old_size, dis_points.begin() + old_size + K - 1, dis_points.end());
  156. dis_points.resize(old_size + K);
  157. }
  158. #ifdef INNER_TIMER
  159. auto t2 = std::chrono::high_resolution_clock::now();
  160. auto nth = std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count();
  161. stats["nth"].emplace_back(nth);
  162. constexpr int STAT_PERIOD = 100000;
  163. if (!stats["nth"].empty() && stats["nth"].size() % STAT_PERIOD == 0) {
  164. for (auto& it : stats) {
  165. const std::string& key = it.first;
  166. std::vector<int64_t>& stat = it.second;
  167. int64_t sum_ = std::accumulate(stat.begin(), stat.end(), 0);
  168. int64_t num_ = stat.size();
  169. stat.clear();
  170. std::cout << "inner_" << key << "(ns): sum=" << sum_ << " num=" << num_ << " ave=" << 1.0 * sum_ / num_
  171. << " ave*n=" << 1.0 * sum_ / STAT_PERIOD << std::endl;
  172. }
  173. }
  174. #endif
  175. return dis_points.size();
  176. }
  177. template <typename PointT, int dim>
  178. struct IVoxNodePhc<PointT, dim>::DistPoint {
  179. double dist = 0;
  180. IVoxNodePhc* node = nullptr;
  181. int idx = 0;
  182. DistPoint() {}
  183. DistPoint(const double d, IVoxNodePhc* n, const int i) : dist(d), node(n), idx(i) {}
  184. PointT Get() { return node->GetPoint(idx); }
  185. inline bool operator()(const DistPoint& p1, const DistPoint& p2) { return p1.dist < p2.dist; }
  186. inline bool operator<(const DistPoint& rhs) { return dist < rhs.dist; }
  187. };
  188. template <typename PointT, int dim>
  189. struct IVoxNodePhc<PointT, dim>::PhcCube {
  190. uint32_t idx = 0;
  191. pcl::CentroidPoint<PointT> mean;
  192. PhcCube(uint32_t index, const PointT& pt) { mean.add(pt); }
  193. void AddPoint(const PointT& pt) { mean.add(pt); }
  194. PointT GetPoint() const {
  195. PointT pt;
  196. mean.get(pt);
  197. return std::move(pt);
  198. }
  199. };
  200. template <typename PointT, int dim>
  201. IVoxNodePhc<PointT, dim>::IVoxNodePhc(const PointT& center, const float& side_length, const int& phc_order)
  202. : center_(center), side_length_(side_length), phc_order_(phc_order) {
  203. assert(phc_order <= 8);
  204. phc_side_length_ = side_length_ / (std::pow(2, phc_order_));
  205. phc_side_length_inv_ = (std::pow(2, phc_order_)) / side_length_;
  206. min_cube_ = center_.getArray3fMap() - side_length / 2.0;
  207. phc_cubes_.reserve(64);
  208. }
  209. template <typename PointT, int dim>
  210. void IVoxNodePhc<PointT, dim>::InsertPoint(const PointT& pt) {
  211. uint32_t idx = CalculatePhcIndex(pt);
  212. PhcCube cube{idx, pt};
  213. auto it = std::lower_bound(phc_cubes_.begin(), phc_cubes_.end(), cube,
  214. [](const PhcCube& a, const PhcCube& b) { return a.idx < b.idx; });
  215. if (it == phc_cubes_.end()) {
  216. phc_cubes_.emplace_back(cube);
  217. } else {
  218. if (it->idx == idx) {
  219. it->AddPoint(pt);
  220. } else {
  221. phc_cubes_.insert(it, cube);
  222. }
  223. }
  224. }
  225. template <typename PointT, int dim>
  226. void IVoxNodePhc<PointT, dim>::ErasePoint(const PointT& pt, const double erase_distance_th_) {
  227. uint32_t idx = CalculatePhcIndex(pt);
  228. PhcCube cube{idx, pt};
  229. auto it = std::lower_bound(phc_cubes_.begin(), phc_cubes_.end(), cube,
  230. [](const PhcCube& a, const PhcCube& b) { return a.idx < b.idx; });
  231. if (erase_distance_th_ > 0) {
  232. }
  233. if (it != phc_cubes_.end() && it->idx == idx) {
  234. phc_cubes_.erase(it);
  235. }
  236. }
  237. template <typename PointT, int dim>
  238. bool IVoxNodePhc<PointT, dim>::Empty() const {
  239. return phc_cubes_.empty();
  240. }
  241. template <typename PointT, int dim>
  242. std::size_t IVoxNodePhc<PointT, dim>::Size() const {
  243. return phc_cubes_.size();
  244. }
  245. template <typename PointT, int dim>
  246. PointT IVoxNodePhc<PointT, dim>::GetPoint(const std::size_t idx) const {
  247. return phc_cubes_[idx].GetPoint();
  248. }
  249. template <typename PointT, int dim>
  250. bool IVoxNodePhc<PointT, dim>::NNPoint(const PointT& cur_pt, DistPoint& dist_point) const {
  251. if (phc_cubes_.empty()) {
  252. return false;
  253. }
  254. uint32_t cur_idx = CalculatePhcIndex(cur_pt);
  255. PhcCube cube{cur_idx, cur_pt};
  256. auto it = std::lower_bound(phc_cubes_.begin(), phc_cubes_.end(), cube,
  257. [](const PhcCube& a, const PhcCube& b) { return a.idx < b.idx; });
  258. if (it == phc_cubes_.end()) {
  259. it--;
  260. dist_point = DistPoint(distance2(cur_pt, it->GetPoint()), this, it - phc_cubes_.begin());
  261. } else if (it == phc_cubes_.begin()) {
  262. dist_point = DistPoint(distance2(cur_pt, it->GetPoint()), this, it - phc_cubes_.begin());
  263. } else {
  264. auto last_it = it;
  265. last_it--;
  266. double d1 = distance2(cur_pt, it->GetPoint());
  267. double d2 = distance2(cur_pt, last_it->GetPoint());
  268. if (d1 > d2) {
  269. dist_point = DistPoint(d2, this, it - phc_cubes_.begin());
  270. } else {
  271. dist_point = DistPoint(d1, this, it - phc_cubes_.begin());
  272. }
  273. }
  274. return true;
  275. }
  276. template <typename PointT, int dim>
  277. int IVoxNodePhc<PointT, dim>::KNNPointByCondition(std::vector<DistPoint>& dis_points, const PointT& cur_pt,
  278. const int& K, const double& max_range) {
  279. uint32_t cur_idx = CalculatePhcIndex(cur_pt);
  280. PhcCube cube{cur_idx, cur_pt};
  281. auto it = std::lower_bound(phc_cubes_.begin(), phc_cubes_.end(), cube,
  282. [](const PhcCube& a, const PhcCube& b) { return a.idx < b.idx; });
  283. const int max_search_cube_side_length = std::pow(2, std::ceil(std::log2(max_range * phc_side_length_inv_)));
  284. const int max_search_idx_th =
  285. 8 * max_search_cube_side_length * max_search_cube_side_length * max_search_cube_side_length;
  286. auto create_dist_point = [&cur_pt, this](typename std::vector<PhcCube>::const_iterator forward_it) {
  287. double d = distance2(forward_it->GetPoint(), cur_pt);
  288. return DistPoint(d, this, forward_it - phc_cubes_.begin());
  289. };
  290. typename std::vector<PhcCube>::const_iterator forward_it(it);
  291. typename std::vector<PhcCube>::const_reverse_iterator backward_it(it);
  292. if (it != phc_cubes_.end()) {
  293. dis_points.emplace_back(create_dist_point(it));
  294. forward_it++;
  295. }
  296. if (backward_it != phc_cubes_.rend()) {
  297. backward_it++;
  298. }
  299. auto forward_reach_boundary = [&]() {
  300. return forward_it == phc_cubes_.end() || forward_it->idx - cur_idx > max_search_idx_th;
  301. };
  302. auto backward_reach_boundary = [&]() {
  303. return backward_it == phc_cubes_.rend() || cur_idx - backward_it->idx > max_search_idx_th;
  304. };
  305. while (!forward_reach_boundary() && !backward_reach_boundary()) {
  306. if (forward_it->idx - cur_idx > cur_idx - backward_it->idx) {
  307. dis_points.emplace_back(create_dist_point(forward_it));
  308. forward_it++;
  309. } else {
  310. dis_points.emplace_back(create_dist_point(backward_it.base()));
  311. backward_it++;
  312. }
  313. if (dis_points.size() > K) {
  314. break;
  315. }
  316. }
  317. if (forward_reach_boundary()) {
  318. while (!backward_reach_boundary() && dis_points.size() < K) {
  319. dis_points.emplace_back(create_dist_point(backward_it.base()));
  320. backward_it++;
  321. }
  322. }
  323. if (backward_reach_boundary()) {
  324. while (!forward_reach_boundary() && dis_points.size() < K) {
  325. dis_points.emplace_back(create_dist_point(forward_it));
  326. forward_it++;
  327. }
  328. }
  329. return dis_points.size();
  330. }
  331. template <typename PointT, int dim>
  332. uint32_t IVoxNodePhc<PointT, dim>::CalculatePhcIndex(const PointT& pt) const {
  333. Eigen::Matrix<float, dim, 1> eposf = (pt.getVector3fMap() - min_cube_) * phc_side_length_inv_;
  334. Eigen::Matrix<int, dim, 1> eposi = eposf.template cast<int>();
  335. for (int i = 0; i < dim; ++i) {
  336. if (eposi(i, 0) < 0) {
  337. eposi(i, 0) = 0;
  338. }
  339. if (eposi(i, 0) > std::pow(2, phc_order_)) {
  340. eposi(i, 0) = std::pow(2, phc_order_) - 1;
  341. }
  342. }
  343. std::array<uint8_t, 3> apos{eposi(0), eposi(1), eposi(2)};
  344. std::array<uint8_t, 3> tmp = hilbert::v2::PositionToIndex(apos);
  345. uint32_t idx = (uint32_t(tmp[0]) << 16) + (uint32_t(tmp[1]) << 8) + (uint32_t(tmp[2]));
  346. return idx;
  347. }
  348. } // namespace faster_lio