123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- #include "knn.h"
- #include "parallel_for.h"
- #include <cmath>
- #include <queue>
- namespace igl {
- template <typename DerivedP, typename KType, typename IndexType,
- typename DerivedCH, typename DerivedCN, typename DerivedW,
- typename DerivedI>
- IGL_INLINE void knn(const Eigen::MatrixBase<DerivedP>& P,
- const KType & k,
- const std::vector<std::vector<IndexType> > & point_indices,
- const Eigen::MatrixBase<DerivedCH>& CH,
- const Eigen::MatrixBase<DerivedCN>& CN,
- const Eigen::MatrixBase<DerivedW>& W,
- Eigen::PlainObjectBase<DerivedI> & I)
- {
- typedef typename DerivedCN::Scalar CentersType;
- typedef typename DerivedW::Scalar WidthsType;
-
- typedef Eigen::Matrix<typename DerivedP::Scalar, 1, 3> RowVector3PType;
-
- int n = P.rows();
- const KType real_k = std::min(n,k);
-
- auto distance_to_width_one_cube = [](RowVector3PType point){
- return std::sqrt(std::pow(std::max(std::abs(point(0))-1,0.0),2)
- + std::pow(std::max(std::abs(point(1))-1,0.0),2)
- + std::pow(std::max(std::abs(point(2))-1,0.0),2));
- };
-
- auto distance_to_cube = [&distance_to_width_one_cube]
- (RowVector3PType point,
- Eigen::Matrix<CentersType,1,3> cube_center,
- WidthsType cube_width){
- RowVector3PType transformed_point = (point-cube_center)/cube_width;
- return cube_width*distance_to_width_one_cube(transformed_point);
- };
-
- I.resize(n,real_k);
-
- igl::parallel_for(n,[&](int i)
- {
- int points_found = 0;
- RowVector3PType point_of_interest = P.row(i);
-
- //To make my priority queue take both points and octree cells,
- //I use the indices 0 to n-1 for the n points,
- // and the indices n to n+m-1 for the m octree cells
-
- // Using lambda to compare elements.
- auto cmp = [&point_of_interest, &P, &CN, &W,
- &n, &distance_to_cube](int left, int right) {
- double leftdistance, rightdistance;
- if(left < n){ //left is a point index
- leftdistance = (P.row(left) - point_of_interest).norm();
- } else { //left is an octree cell
- leftdistance = distance_to_cube(point_of_interest,
- CN.row(left-n),
- W(left-n));
- }
-
- if(right < n){ //left is a point index
- rightdistance = (P.row(right) - point_of_interest).norm();
- } else { //left is an octree cell
- rightdistance = distance_to_cube(point_of_interest,
- CN.row(right-n),
- W(right-n));
- }
- return leftdistance > rightdistance;
- };
-
- std::priority_queue<IndexType, std::vector<IndexType>,
- decltype(cmp)> queue(cmp);
-
- queue.push(n); //This is the 0th octree cell (ie the root)
- while(points_found < real_k){
- IndexType curr_cell_or_point = queue.top();
- queue.pop();
- if(curr_cell_or_point < n){ //current index is for is a point
- I(i,points_found) = curr_cell_or_point;
- points_found++;
- } else {
- IndexType curr_cell = curr_cell_or_point - n;
- if(CH(curr_cell,0) == -1){ //In the case of a leaf
- if(point_indices.at(curr_cell).size() > 0){
- //Assumption: Leaves either have one point, or none
- queue.push(point_indices.at(curr_cell).at(0));
- }
- } else { //Not a leaf
- for(int j = 0; j < 8; j++){
- //+n to adjust for the octree cells
- queue.push(CH(curr_cell,j)+n);
- }
- }
- }
- }
- },1000);
- }
- }
- #ifdef IGL_STATIC_LIBRARY
- template void igl::knn<Eigen::Matrix<double, -1, -1, 0, -1, -1>, int, int, Eigen::Matrix<int, -1, 8, 0, -1, 8>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 8, 0, -1, 8> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
- #endif
|