| 118 | } |
| 119 | |
| 120 | void PlaneFitFilter::setPlaneFit(PointView& view, const PointId& i) |
| 121 | { |
| 122 | // Find k-nearest neighbors of i. |
| 123 | const KD3Index& kdi = view.build3dIndex(); |
| 124 | PointIdList ni = kdi.neighbors(i, m_knn + 1); |
| 125 | |
| 126 | // Normal based only on neighbors, so exclude first point. |
| 127 | PointIdList neighbors(ni.begin() + 1, ni.end()); |
| 128 | |
| 129 | // Covariance and normal are based off demeaned coordinates, so we record |
| 130 | // the centroid to properly offset the coordinates when computing point to |
| 131 | // plance distance. |
| 132 | Vector3d centroid = math::computeCentroid(view, neighbors); |
| 133 | |
| 134 | // Compute covariance of the neighbors. |
| 135 | Matrix3d B = math::computeCovariance(view, neighbors); |
| 136 | |
| 137 | // Check if the covariance matrix is all zeros |
| 138 | if (B.isZero()) |
| 139 | { |
| 140 | log()->get(LogLevel::Info) |
| 141 | << "Skipping point " << i |
| 142 | << ". Covariance matrix is all zeros. This suggests a large " |
| 143 | "number of redundant points. Consider using filters.sample " |
| 144 | "with a small radius to remove redundant points.\n"; |
| 145 | return; |
| 146 | } |
| 147 | |
| 148 | // Perform the eigen decomposition, using the eigenvector of the smallest |
| 149 | // eigenvalue as the normal. |
| 150 | Eigen::SelfAdjointEigenSolver<Matrix3d> solver(B); |
| 151 | if (solver.info() != Eigen::Success) |
| 152 | throwError("Cannot perform eigen decomposition."); |
| 153 | Vector3d normal = solver.eigenvectors().col(0); |
| 154 | |
| 155 | // Compute point to plane distance of the query point. |
| 156 | double d = absDistance(view, i, centroid, normal); |
| 157 | |
| 158 | // Compute mean point to plane distance of neighbors. |
| 159 | double d_sum(0.0); |
| 160 | for (PointId const& j : neighbors) |
| 161 | { |
| 162 | d_sum += absDistance(view, j, centroid, normal); |
| 163 | } |
| 164 | double d_bar(d_sum / m_knn); |
| 165 | |
| 166 | // Compute and set the plane fit criterion. |
| 167 | view.setField(Id::PlaneFit, i, d / (d + d_bar)); |
| 168 | } |
| 169 | |
| 170 | } // namespace pdal |
nothing calls this directly
no test coverage detected