|
2 | 2 | #include "Progress.h" |
3 | 3 | #include "myomp.h" |
4 | 4 | #include "SpatialIndex.h" |
| 5 | +#include "nanoflann.hpp" |
5 | 6 | #include <limits> |
6 | 7 |
|
7 | 8 | using namespace lidR; |
8 | 9 |
|
| 10 | +class DataFrameAdaptor |
| 11 | +{ |
| 12 | +public: |
| 13 | + std::vector<Rcpp::NumericVector> coords; |
| 14 | + size_t dim; |
| 15 | + |
| 16 | + DataFrameAdaptor(const Rcpp::DataFrame& df, std::vector<std::string> col_names) |
| 17 | + { |
| 18 | + dim = col_names.size(); |
| 19 | + coords.reserve(dim); |
| 20 | + for (const auto& name : col_names) |
| 21 | + coords.push_back(df[name]); |
| 22 | + } |
| 23 | + |
| 24 | + inline size_t kdtree_get_point_count() const { return coords[0].size(); } |
| 25 | + inline double kdtree_get_pt(const size_t idx, const size_t d) const { |
| 26 | + return coords[d][idx]; |
| 27 | + } |
| 28 | + template <class BBOX> bool kdtree_get_bbox(BBOX&) const { return false; } |
| 29 | +}; |
| 30 | + |
| 31 | +using KDTree = nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<double, DataFrameAdaptor>, DataFrameAdaptor, 3>; |
| 32 | + |
| 33 | + |
9 | 34 | bool pnpoly(NumericMatrix polygon, double x, double y) |
10 | 35 | { |
11 | 36 | int nvert = polygon.nrow(); |
@@ -1547,6 +1572,112 @@ List LAS::point_metrics(unsigned int k, double r, DataFrame data, int nalloc, SE |
1547 | 1572 | } |
1548 | 1573 | #endif |
1549 | 1574 |
|
| 1575 | +DataFrame LAS::fast_knn_eigen_decomposition(int k, bool get_coef) |
| 1576 | +{ |
| 1577 | + int n = npoints; |
| 1578 | + |
| 1579 | + NumericVector eigen_largest(n); |
| 1580 | + NumericVector eigen_medium(n); |
| 1581 | + NumericVector eigen_smallest(n); |
| 1582 | + NumericVector coeff0; |
| 1583 | + NumericVector coeff1; |
| 1584 | + NumericVector coeff2; |
| 1585 | + NumericVector coeff3; |
| 1586 | + NumericVector coeff4; |
| 1587 | + NumericVector coeff5; |
| 1588 | + NumericVector coeff6; |
| 1589 | + NumericVector coeff7; |
| 1590 | + NumericVector coeff8; |
| 1591 | + |
| 1592 | + if (get_coef) |
| 1593 | + { |
| 1594 | + coeff0 = NumericVector(n); |
| 1595 | + coeff1 = NumericVector(n); |
| 1596 | + coeff2 = NumericVector(n); |
| 1597 | + coeff3 = NumericVector(n); |
| 1598 | + coeff4 = NumericVector(n); |
| 1599 | + coeff5 = NumericVector(n); |
| 1600 | + coeff6 = NumericVector(n); |
| 1601 | + coeff7 = NumericVector(n); |
| 1602 | + coeff8 = NumericVector(n); |
| 1603 | + } |
| 1604 | + |
| 1605 | + bool abort = false; |
| 1606 | + |
| 1607 | + DataFrame df = as<DataFrame>(las.slot("data")); |
| 1608 | + DataFrameAdaptor adaptor(df, {"X", "Y", "Z"}); |
| 1609 | + KDTree tree = KDTree(3, adaptor, nanoflann::KDTreeSingleIndexAdaptorParams(10)); |
| 1610 | + tree.buildIndex(); |
| 1611 | + |
| 1612 | + Progress pb(npoints, "Eigen decomposition: "); |
| 1613 | + |
| 1614 | + #pragma omp parallel for num_threads(ncpu) |
| 1615 | + for (unsigned int i = 0 ; i < npoints ; i++) |
| 1616 | + { |
| 1617 | + if (abort) continue; |
| 1618 | + if (pb.check_interrupt()) abort = true; |
| 1619 | + pb.increment(); |
| 1620 | + |
| 1621 | + std::vector<uint32_t> indices(k); |
| 1622 | + std::vector<KDTree::DistanceType> dists(k); |
| 1623 | + double p[3] = { X[i], Y[i], Z[i] }; |
| 1624 | + tree.knnSearch(p, k, indices.data(), dists.data()); |
| 1625 | + |
| 1626 | + |
| 1627 | + arma::mat A(k,3); |
| 1628 | + arma::mat coeff; // Principle component matrix |
| 1629 | + arma::mat score; |
| 1630 | + arma::vec latent; // Eigenvalues in descending order |
| 1631 | + |
| 1632 | + for (unsigned int j = 0 ; j < indices.size() ; j++) |
| 1633 | + { |
| 1634 | + A(j,0) = X[indices[j]]; |
| 1635 | + A(j,1) = Y[indices[j]]; |
| 1636 | + A(j,2) = Z[indices[j]]; |
| 1637 | + } |
| 1638 | + |
| 1639 | + arma::princomp(coeff, score, latent, A); |
| 1640 | + |
| 1641 | + eigen_largest[i] = latent[0]; |
| 1642 | + eigen_medium[i] = latent[1]; |
| 1643 | + eigen_smallest[i] = latent[2]; |
| 1644 | + |
| 1645 | + if (get_coef) |
| 1646 | + { |
| 1647 | + coeff0[i] = coeff(0,0); |
| 1648 | + coeff1[i] = coeff(0,1); |
| 1649 | + coeff2[i] = coeff(0,2); |
| 1650 | + coeff3[i] = coeff(1,0); |
| 1651 | + coeff4[i] = coeff(1,1); |
| 1652 | + coeff5[i] = coeff(1,2); |
| 1653 | + coeff6[i] = coeff(2,0); |
| 1654 | + coeff7[i] = coeff(2,1); |
| 1655 | + coeff8[i] = coeff(2,2); |
| 1656 | + } |
| 1657 | + } |
| 1658 | + |
| 1659 | + DataFrame out; |
| 1660 | + out.push_back(eigen_largest, "eigen_largest"); |
| 1661 | + out.push_back(eigen_medium, "eigen_medium"); |
| 1662 | + out.push_back(eigen_smallest, "eigen_smallest"); |
| 1663 | + |
| 1664 | + if (get_coef) |
| 1665 | + { |
| 1666 | + out.push_back(coeff0, "coeff00"); |
| 1667 | + out.push_back(coeff1, "coeff01"); |
| 1668 | + out.push_back(coeff2, "coeff02"); |
| 1669 | + out.push_back(coeff3, "coeff10"); |
| 1670 | + out.push_back(coeff4, "coeff11"); |
| 1671 | + out.push_back(coeff5, "coeff12"); |
| 1672 | + out.push_back(coeff6, "coeff20"); |
| 1673 | + out.push_back(coeff7, "coeff21"); |
| 1674 | + out.push_back(coeff8, "coeff22"); |
| 1675 | + } |
| 1676 | + |
| 1677 | + return out; |
| 1678 | +} |
| 1679 | + |
| 1680 | + |
1550 | 1681 | DataFrame LAS::eigen_decomposition(int k, double r, bool get_coef) |
1551 | 1682 | { |
1552 | 1683 | int n = std::count(skip.begin(), skip.end(), true); |
|
0 commit comments