@@ -216,74 +216,21 @@ namespace diffCheck::geometry
216216 this ->Normals .push_back (normal);
217217 }
218218
219- std::vector<Eigen::Vector3d> DFPointCloud::GetPrincipalAxes (int nComponents)
219+ Eigen::Vector3d DFPointCloud::FitPlaneRANSAC (
220+ double distanceThreshold,
221+ int ransacN,
222+ int numIterations)
220223 {
221- std::vector<Eigen::Vector3d> principalAxes;
222-
223- if (! this ->HasNormals ())
224- {
225- DIFFCHECK_WARN (" The point cloud has no normals. Normals will be estimated with knn = 20." );
226- this ->EstimateNormals (true , 20 );
227- }
228-
229- // Convert normals to Eigen matrix
230- Eigen::Matrix<double , 3 , Eigen::Dynamic> normalMatrix (3 , this ->Normals .size ());
231- for (size_t i = 0 ; i < this ->Normals .size (); ++i)
232- {
233- normalMatrix.col (i) = this ->Normals [i].cast <double >();
234- }
235-
236- cilantro::KMeans<double , 3 > kmeans (normalMatrix);
237- kmeans.cluster (nComponents);
238-
239- const cilantro::VectorSet3d& centroids = kmeans.getClusterCentroids ();
240- const std::vector<size_t >& assignments = kmeans.getPointToClusterIndexMap ();
241- std::vector<int > clusterSizes (nComponents, 0 );
242- for (size_t i = 0 ; i < assignments.size (); ++i)
243- {
244- clusterSizes[assignments[i]]++;
245- }
246- // Sort clusters by size
247- std::vector<std::pair<int , Eigen::Vector3d>> sortedClustersBySize (nComponents);
248- for (size_t i = 0 ; i < nComponents; ++i)
224+ if (this ->Points .size () < ransacN)
249225 {
250- sortedClustersBySize[i] = {clusterSizes[i], centroids.col (i)};
226+ DIFFCHECK_ERROR (" Not enough points to fit a plane with RANSAC." );
227+ return Eigen::Vector3d::Zero ();
251228 }
252- std::sort (sortedClustersBySize.begin (), sortedClustersBySize.end (), [](const auto & a, const auto & b)
253- {
254- return a.first > b.first ;
255- });
256-
257- for (size_t i = 0 ; i < nComponents; ++i)
258- {
259- if (principalAxes.size () == 0 )
260- {
261- principalAxes.push_back (sortedClustersBySize[i].second );
262- }
263- else
264- {
265- bool isAlreadyPresent = false ;
266- for (const auto & axis : principalAxes)
267- {
268- double dotProduct = std::abs (axis.dot (sortedClustersBySize[i].second ));
269- if (std::abs (dotProduct) > 0.7 ) // Threshold to consider as similar direction
270- {
271- isAlreadyPresent = true ;
272- break ;
273- }
274- }
275- if (!isAlreadyPresent)
276- {
277- principalAxes.push_back (sortedClustersBySize[i].second );
278- }
279- }
280- }
281- if (principalAxes.size () < 2 ) // Fallback to OBB if k-means fails to provide enough distinct axes
282- {
283- open3d::geometry::OrientedBoundingBox obb = this ->Cvt2O3DPointCloud ()->GetOrientedBoundingBox ();
284- principalAxes = {obb.R_ .col (0 ), obb.R_ .col (1 ), obb.R_ .col (2 )};
285- }
286- return principalAxes;
229+
230+ auto O3DPointCloud = this ->Cvt2O3DPointCloud ();
231+ std::tuple< Eigen::Vector4d, std::vector<size_t >> planeModel = O3DPointCloud->SegmentPlane (distanceThreshold, ransacN, numIterations);
232+ Eigen::Vector3d planeParameters = std::get<0 >(planeModel).head <3 >();
233+ return planeParameters;
287234 }
288235
289236 void DFPointCloud::Crop (const Eigen::Vector3d &minBound, const Eigen::Vector3d &maxBound)
0 commit comments