Closest point to a path

后端 未结 3 1299
感动是毒
感动是毒 2020-12-10 18:01

I have two sets of points, called path and centers. For each point in path, I would like an efficient method for finding the ID of the

3条回答
  •  萌比男神i
    2020-12-10 18:54

    This solution reduces processing time for the sample dataset by almost half that achieved by the RANN solution.

    It can be installed using devtools::install_github("thell/Rcppnanoflann")

    The Rcppnanoflann solution takes advantage of Rcpp, RcppEigen and the nanoflann EigenMatrixAdaptor along with the c++11 to yield identical unique indexes to the original question.

    library(Rcppnanoflann)
    system.time(o.nano<-nnIndex(centers,path))
    
    ##    user  system elapsed 
    ##    0.62    0.05    0.67
    

    * using path and centers values as defined in the original question

    To achieve identical results to the original sample the RANN solution needs slight modification which we time here...

    library(RANN)
    system.time(o.flann<-unique(as.numeric(nn2(centers,path,1)$nn.idx)))
    
    ##    user  system elapsed 
    ##    1.24    0.07    1.30
    

    identical(o.flann,o.nano)
    
    ## [1] TRUE
    

    The working function of Rcppnanoflann takes advantage of Eigen's Map capabilities to create the input for a fixed type Eigen matrix from the given P dataframe.

    Testing was done with the RcppParallel package but the kd_tree object does not have a copy constructor, so the tree needed to be created for each thread which ate up any gains in the parallel query processing.

    RcppEigen and Rcpp11 currently don't play together so the idea of using Rcpp11's parallel sapply for the query isn't easily tested.


    // [[Rcpp::export]]
    std::vector nnIndex(const Rcpp::DataFrame & P, const Rcpp::DataFrame & Q )
    {
      using namespace Eigen;
      using namespace Rcpp;
      using namespace nanoflann;
    
      // Matrix of points to be queried against.
      const NumericVector & Px(P[0]);
      const NumericVector & Py(P[1]);
      MatrixX2d M(Px.size(), 2);
      M.col(0) = VectorXd::Map(&Px[0],Px.size());
      M.col(1) = VectorXd::Map(&Py[0],Py.size());
    
      // The points to query.
      const NumericVector & Qx(Q[0]);
      const NumericVector & Qy(Q[1]);
      double query_pt[2];
      size_t query_count(Qx.size());
    
      // Populate a 2d tree.
      KD_Tree kd_tree( 2, M, 10 );
      kd_tree.index->buildIndex();
    
      std::set nn;
      std::vector out;
      out.reserve(query_count);
    
      size_t index(0);
      double quadrance;
      for( size_t i=0 ; i < query_count; ++i ) {
        query_pt[0] = Qx[i];
        query_pt[1] = Qy[i];
        kd_tree.index->knnSearch( &query_pt[0],1, &index, &quadrance);
        if( nn.emplace(index).second ) out.emplace_back(index+1);
      }
    
      return out;
    }
    

提交回复
热议问题