Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
d5ed24e
feat: add principal axes calculation for pointclouds for pose estimation
DamienGilliard Apr 9, 2025
f43e197
fix: add cilantro KMeans clustering to main header
DamienGilliard Apr 9, 2025
4809f30
feat: add empty component for axis calculation. code must be written
DamienGilliard Apr 9, 2025
3486fa4
feat: add python binding for axis calculation
DamienGilliard Apr 9, 2025
ad8e895
feat: add poses module for pose historic saving
DamienGilliard May 7, 2025
4d5c71b
feat-wip: add code to main axis calculation component. OK but reliabi…
DamienGilliard May 7, 2025
256fd88
feat: add 'save' mathod to DFPoses classes to dump it in a JSON
DamienGilliard May 9, 2025
3971d40
fix: update the metadata of the axis calculation component
DamienGilliard May 9, 2025
13c4759
feat: make pose calculation component leaner
DamienGilliard May 9, 2025
78231f7
feat: slight refactor of df_poses module
DamienGilliard May 9, 2025
d967ea8
fix: simplify k-means clustering implementation
DamienGilliard May 9, 2025
9aadeff
Merge branch 'patch_ws' into implement_pca
DamienGilliard May 9, 2025
188dc81
feat: add unit test to KMeans clustering of normals
DamienGilliard May 10, 2025
e80b266
feat-wip: tentative planning added for DF2 development - TBD
DamienGilliard May 15, 2025
136e3dc
ADD Http Listener
eleniv3d May 15, 2025
56a80d5
fix: marameter name from singular to plural, and corresponding list a…
DamienGilliard May 16, 2025
38aab63
ADD TCP Listener
eleniv3d May 16, 2025
2fd80df
FIX lintering
eleniv3d May 27, 2025
aeecaa2
FIX tcp component + add example file sender
eleniv3d May 27, 2025
5cacef1
Merge branch 'main' into IO
eleniv3d May 28, 2025
4aafbf8
WIP FIX WS Receiver
eleniv3d May 28, 2025
0d98ad0
fix: have new elements pick-up the indexes of the already-existing el…
DamienGilliard May 28, 2025
00ceefa
fix: typo in nickname of i_clouds
DamienGilliard May 28, 2025
3c90378
feat: add a component to crop point clouds
DamienGilliard Jun 17, 2025
a514125
feat: add cropping capability to DFPointCloud
DamienGilliard Jun 17, 2025
e09fb79
FIX websocket component
eleniv3d Jun 17, 2025
f07431f
feat: add binding for cropping capability of point cloud
DamienGilliard Jun 17, 2025
46c6d6f
FIX light refactoring and input reorder
eleniv3d Jun 22, 2025
c546fec
ADD drop btns and panel with standard inputs similar to vizualization…
eleniv3d Jun 22, 2025
a0289fc
fix: simplify cropping component
DamienGilliard Jul 22, 2025
a98b80f
feat: add point cloud subtraction method and implement it in component
DamienGilliard Jul 22, 2025
9964b85
feat-wip: add sequence schema of the df2 workflow as it is now developed
DamienGilliard Jul 22, 2025
8509138
FIX rename python file
eleniv3d Jul 24, 2025
2588656
FIX remove repeated ws from stickys
eleniv3d Jul 25, 2025
683b4e8
ADD warning if trying to load data from tcp/ws listener without start…
eleniv3d Jul 25, 2025
27cad32
ADD sleep to prevent CPU spin
eleniv3d Jul 25, 2025
bd004f7
ADD doc strings
eleniv3d Jul 25, 2025
b383bc1
FIX add docstrings
eleniv3d Jul 25, 2025
7f11249
FIX missing lines from PKG-INFO
eleniv3d Jul 25, 2025
484810f
FIX RML.Warning
eleniv3d Jul 25, 2025
fcc1936
feat: add point cloud duplication for python binding
DamienGilliard Jul 30, 2025
d65fb17
feat: add capacity to crop with any brep, and keep trace of in and ou…
DamienGilliard Jul 30, 2025
10d1943
feat: add point cloud intersection calculation
DamienGilliard Jul 30, 2025
02b4756
feat: add point cloud intersection calculation component
DamienGilliard Jul 30, 2025
bbbee07
feat: add point cloud merge component
DamienGilliard Jul 30, 2025
718a3a6
feat: add point cloud intersection calculation to DFPointCloud
DamienGilliard Jul 30, 2025
4d287f2
FIX cleanup warnings that didnt work
eleniv3d Jul 30, 2025
c65b4ae
Merge pull request #152 from diffCheckOrg/IO
DamienGilliard Jul 30, 2025
f7b1ae6
Update code.py
DamienGilliard Jul 30, 2025
3d33b61
remove unused import
DamienGilliard Jul 30, 2025
f684ca0
Merge pull request #160 from diffCheckOrg/DamienGilliard-patch-3-to-m…
DamienGilliard Jul 30, 2025
e7dad06
fix: rename SubstractCloud to CloudDifference and fix mistakes in met…
DamienGilliard Aug 4, 2025
5308e44
fix: rename MergeCloud to CloudUnion and fix mistakes in metadata
DamienGilliard Aug 4, 2025
164ef82
fix: metadata in CropCloud and IntersectCloud
DamienGilliard Aug 4, 2025
1baf875
fix: small typos again in the metadata
DamienGilliard Aug 4, 2025
8cdd175
feat: add possibility to crop pc with any box
DamienGilliard Aug 4, 2025
3eebaa5
feat: improve cropping component following @eleniv3d 's comments
DamienGilliard Aug 4, 2025
bc42fe2
fix: rename CloudCrop to CloudSplit
DamienGilliard Aug 4, 2025
e2dead4
feat-wip: creation of pose comparison component
DamienGilliard Aug 7, 2025
cdef3ba
fix: remove unneeded markdown file
DamienGilliard Aug 7, 2025
961b28b
fix: committing insignificant changes to example file because ignorin…
DamienGilliard Aug 10, 2025
3828e8e
fix: improvements to code component and metadata following @eleniv3d …
DamienGilliard Aug 10, 2025
2181ad9
feat: add plane property to DFBeam
DamienGilliard Aug 11, 2025
cedfcc1
feat: add max id to CAD segmentation to allow segmentation during fab…
DamienGilliard Aug 11, 2025
953f5f4
feat: remove the i_stop_after_id parameter because it is moved to a d…
DamienGilliard Sep 2, 2025
adf1576
feat: create new truncate_assembly component
DamienGilliard Sep 2, 2025
f7016b4
fix: main axis of DFBeam computed such that the main axes are also th…
DamienGilliard Sep 2, 2025
de7b580
fix: add ghpythonlib. to the overrides of mypy
DamienGilliard Sep 2, 2025
5745db8
feat: update DFMainPCAxes to save the new poses only when user trigge…
DamienGilliard Sep 2, 2025
a4e54d2
fix: name of class in truncate_assembly component
DamienGilliard Sep 9, 2025
a637b5d
fix: remove unused function parameter in DF_CAD_segmentator component
DamienGilliard Sep 9, 2025
a1d5266
FIX minor cosmetic changes
eleniv3d Oct 2, 2025
eb3ab9a
Merge pull request #155 from diffCheckOrg/feature/point_cloud_utils
eleniv3d Oct 2, 2025
2513713
fix: change index in TruncateAssembly component
DamienGilliard Oct 2, 2025
a851476
fix: change sign of index change in TruncateAssembly component
DamienGilliard Oct 2, 2025
b00e145
fix: output the history as ghtree
DamienGilliard Oct 15, 2025
6b38623
feat: add fallback to obb when knn on normals gives insufficiently di…
DamienGilliard Oct 15, 2025
daff8bb
ADD check i_assembly has enough beams and if there is an error on a c…
eleniv3d Oct 20, 2025
067903e
FIX rename files assossiated with Pose Estimation component to have t…
eleniv3d Oct 20, 2025
1fad289
FIX typo and use not all sticky but a single namespaced key df_poses
eleniv3d Oct 20, 2025
2995041
FIX remove re-assignying new_xDirection and fix projection to use tth…
eleniv3d Oct 20, 2025
f29ec53
Merge pull request #163 from diffCheckOrg/implement_pca_patch/improve…
eleniv3d Oct 20, 2025
22d4fda
Merge branch 'release/2.0.0' into implement_pca
DamienGilliard Oct 20, 2025
4d2f3b1
fix: small merge issue
DamienGilliard Oct 20, 2025
b2af2b8
Merge pull request #149 from diffCheckOrg/implement_pca
DamienGilliard Oct 20, 2025
d5f437c
fix: update insubordinate gh file
DamienGilliard Oct 20, 2025
7d41f20
Merge branch 'release/2.0.0' of https://github.com/diffCheckOrg/diffC…
DamienGilliard Oct 20, 2025
9475b6e
feat: add a plane property to beams, automatically computed and with …
DamienGilliard Oct 28, 2025
7348919
feat: bump up version from 1.3.0 to 1.3.1 in manifest.yml
DamienGilliard Jul 10, 2025
f15c055
Update manifest.yml
DamienGilliard Jul 10, 2025
0c3835d
ACTION_BOT: Sync version for release (#158)
github-actions[bot] Jul 10, 2025
3d1be89
Update manifest.yml
DamienGilliard Jul 10, 2025
63feaf7
Update manifest.yml
DamienGilliard Jul 10, 2025
eb0b20d
feat-wip: creation of pose comparison component
DamienGilliard Aug 7, 2025
b2a10b3
fix: remove unneeded markdown file
DamienGilliard Aug 7, 2025
af989eb
feat: add a plane property to beams, automatically computed and with …
DamienGilliard Oct 28, 2025
28d6bb2
feat-wip: use assembly instead of explicit list of planes
DamienGilliard Oct 28, 2025
b97e8c6
rebasing to release/2.0.0 so the pose comparison component has the la…
DamienGilliard Oct 28, 2025
c1f2c86
feat: remove unneeded message about evaluation during assembly of aft…
DamienGilliard Oct 28, 2025
b466cd1
fix: rebase variable name mixup
DamienGilliard Oct 28, 2025
32d9456
feat: update metadata of pose comparison conponent
DamienGilliard Oct 28, 2025
0500f54
feat: adapt pose comparison component so it also works with the full …
DamienGilliard Oct 30, 2025
12bd9e3
feat: remove type hint for i_measured_poses so it takes datatree as well
DamienGilliard Oct 30, 2025
5683c05
fix: use plane instead of pose
DamienGilliard Oct 30, 2025
6660ecb
fix: use consistent naming between pose estimation and pose comparison
DamienGilliard Oct 30, 2025
e0e314c
feat-fix: pose comparison takes (or converts to) data tree as input a…
DamienGilliard Oct 30, 2025
8f430e6
feat: CleanAssociatedClusters now keep the per-face structure
DamienGilliard Nov 24, 2025
de36ecb
feat: implement the per-face change to CleanAssociatedClusters in the…
DamienGilliard Nov 24, 2025
f51f3c0
feat: update component to use datatree with cloud per face
DamienGilliard Nov 24, 2025
4ea8161
feat: add FitPlaneRANSAC method to DFPointCloud
DamienGilliard Nov 24, 2025
765090c
feat; add fit_plane_ransac to binding
DamienGilliard Nov 24, 2025
f0d0a23
fix-wip: temporarily disacctivate test on KMeansClusteringOfNormals, …
DamienGilliard Nov 24, 2025
4ada8de
feat: add test for RANSAC plane fitting
DamienGilliard Nov 26, 2025
afddd46
fix: remove unneeded ply file
DamienGilliard Nov 26, 2025
9e6eed5
fix: make variable names coherent-er
DamienGilliard Nov 26, 2025
5beaaaf
fix: more robust check for validity of poses that are used in the pos…
DamienGilliard Jan 7, 2026
8c54bc5
fix: create DFBeam base plane with coherent orientation with plane de…
DamienGilliard Jan 8, 2026
ddcbf3c
fix: discard null face normals in the pose estimation
DamienGilliard Jan 8, 2026
c892eaa
fix: remove unused lists previously used for debugging
DamienGilliard Jan 8, 2026
9f57cd8
fix: actually update the o_beam_cloud point cloud list
DamienGilliard Jan 8, 2026
71ea6bc
fix: correct the null vector check
DamienGilliard Jan 8, 2026
b512b99
Merge pull request #168 from diffCheckOrg/implement_pca_patch/plane_d…
eleniv3d Jan 13, 2026
2395fb0
FIX remove bc from bc * []
eleniv3d Jan 13, 2026
bb9b60c
Merge pull request #161 from diffCheckOrg/feature/pose_comparison
eleniv3d Jan 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ repos:
types-requests==2.31.0,
numpy==2.0.1,
pytest==8.3.1,
websockets>=10.4,
types-setuptools>=71.1.0.20240818
]
args: [--config=pyproject.toml]
Expand Down
63 changes: 49 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,24 +64,59 @@ gantt
title diffCheck - general overview
excludes weekends

section Publication
Abstract edition :active, absed, 2024-03-01, 2024-03-15
Submission abstract ICSA :milestone, icsaabs, 2024-03-15, 0d
Paper edition :paperd, 2024-10-01, 2024-10-30
Submission paper ICSA :milestone, icsapap, 2024-10-30, 0d

section Code development
Backend development :backenddev, after icsaabs, 6w
Rhino/Grasshopper integration :rhghinteg, after backenddev, 6w
Documentation & Interface :docuint, after fabar, 3w
section Workshop
Workshop dryrun :milestone, crit, dryrun, 2025-09-15, 1d
Workshop in Boston :workshop, 2025-11-16, 2d

section Component development
Pose estimation :CD1, 2025-05-15, 1w
Communication w/ hardware :CD2, after CD1, 3w
Pose comparison :CD3, after CD1, 3w
General PC manipulation :CD4, after CD1, 6w
Data analysis component :CD5, after CD3, 3w

section Workshop preparation
Workshop scenario :doc1, 2025-08-01, 1w
New compilation documentation :doc2, after mac, 2w
New components documentation :doc2, 2025-08-01, 4w
Development of special pipeline for data:doc3, after doc1, 3w

section Cross-platform
adaptation of CMake for mac compilation :mac, 2025-07-01, 3w

section Prototype testing
Fabrication of AR Prototype :crit, fabar, 2024-07-01, 2024-08-30
Fabrication of CNC Prototype :crit, fabcnc, 2024-07-01, 2024-08-30
Fabrication of Robot Prototype :crit, fabrob, 2024-07-01, 2024-08-30
Data collection and evaluation :dataeval, after fabrob, 4w
Fabrication of iterative prototype :fab, 2025-08-01, 2w
```



## How to contribute

If you want to contribute to the project, please refer to the [contribution guidelines]([./CONTRIBUTING.md](https://diffcheckorg.github.io/diffCheck/contribute.html)).

## Logic
The logic of the workflow is currently as follows:

```mermaid
stateDiagram-v2
state "[breps to assemble]" as s1
state "scan of latest element placed" as s2
state "get pose of i-th brep" as s3
state "get pose of i-1-th brep" as s4
state "compute pose of i-1-th element from scan" as s5
state "compute pose difference" as s6
state "compute pose correction" as s7
state "assemble i-th-element" as s8
state "i += 1" as s9
[*]-->s2
s1-->s3
s1-->s4
s2-->s5
s5-->s6
s4-->s6
s6-->s7
s3-->s7
s7-->s8
s8-->s9
s9-->[*]
```
2 changes: 1 addition & 1 deletion deps/eigen
Submodule eigen updated from 11fd34 to 954e21
2 changes: 1 addition & 1 deletion deps/pybind11
Submodule pybind11 updated 159 files
Binary file modified environment.yml
Binary file not shown.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ module = [
"GH_IO.*",
"clr.*",
"diffcheck_bindings",
"diffCheck.diffcheck_bindings"
"diffCheck.diffcheck_bindings",
"ghpythonlib.*"
]
ignore_missing_imports = true

Expand Down
3 changes: 3 additions & 0 deletions src/diffCheck.hh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include <loguru.hpp>

#include <cilantro/cilantro.hpp>
#include <cilantro/clustering/kmeans.hpp>

#include <Eigen/Dense>

// diffCheck includes
#include "diffCheck/log.hh"
Expand Down
7 changes: 7 additions & 0 deletions src/diffCheck/IOManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,11 @@ namespace diffCheck::io
std::filesystem::path pathCloud = pathTestData / "test_pc_for_SOR_101pts_with_1_outlier.ply";
return pathCloud.string();
}

std::string GetTwoConnectedPlanesPlyPath()
{
std::filesystem::path pathTestData = GetTestDataDir();
std::filesystem::path pathCloud = pathTestData / "two_connected_planes_with_normals.ply";
return pathCloud.string();
}
} // namespace diffCheck::io
2 changes: 2 additions & 0 deletions src/diffCheck/IOManager.hh
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ namespace diffCheck::io
std::string GetRoofQuarterPlyPath();
/// @brief Get the path to the plane point cloud with one outlier
std::string GetPlanePCWithOneOutliers();
/// @brief Get the path to the two connected planes ply test file
std::string GetTwoConnectedPlanesPlyPath();
} // namespace diffCheck::io
135 changes: 135 additions & 0 deletions src/diffCheck/geometry/DFPointCloud.cc
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,61 @@ namespace diffCheck::geometry
this->Normals.push_back(normal);
}

Eigen::Vector3d DFPointCloud::FitPlaneRANSAC(
double distanceThreshold,
int ransacN,
int numIterations)
{
if (this->Points.size() < ransacN)
{
DIFFCHECK_ERROR("Not enough points to fit a plane with RANSAC.");
return Eigen::Vector3d::Zero();
}

auto O3DPointCloud = this->Cvt2O3DPointCloud();
std::tuple< Eigen::Vector4d, std::vector<size_t>> planeModel = O3DPointCloud->SegmentPlane(distanceThreshold, ransacN, numIterations);
Eigen::Vector3d planeParameters = std::get<0>(planeModel).head<3>();
return planeParameters;
}

void DFPointCloud::Crop(const Eigen::Vector3d &minBound, const Eigen::Vector3d &maxBound)
{
auto O3DPointCloud = this->Cvt2O3DPointCloud();
auto O3DPointCloudCropped = O3DPointCloud->Crop(open3d::geometry::AxisAlignedBoundingBox(minBound, maxBound));
this->Points.clear();
for (auto &point : O3DPointCloudCropped->points_)
this->Points.push_back(point);
this->Colors.clear();
for (auto &color : O3DPointCloudCropped->colors_)
this->Colors.push_back(color);
this->Normals.clear();
for (auto &normal : O3DPointCloudCropped->normals_)
this->Normals.push_back(normal);
}

void DFPointCloud::Crop(const std::vector<Eigen::Vector3d> &corners)
{
if (corners.size() != 8)
throw std::invalid_argument("The corners vector must contain exactly 8 points.");
open3d::geometry::OrientedBoundingBox obb = open3d::geometry::OrientedBoundingBox::CreateFromPoints(corners);
auto O3DPointCloud = this->Cvt2O3DPointCloud();
auto O3DPointCloudCropped = O3DPointCloud->Crop(obb);
this->Points.clear();
for (auto &point : O3DPointCloudCropped->points_)
this->Points.push_back(point);
this->Colors.clear();
for (auto &color : O3DPointCloudCropped->colors_)
this->Colors.push_back(color);
this->Normals.clear();
for (auto &normal : O3DPointCloudCropped->normals_)
this->Normals.push_back(normal);
}

DFPointCloud DFPointCloud::Duplicate() const
{
return DFPointCloud(this->Points, this->Colors, this->Normals);
}

void DFPointCloud::UniformDownsample(int everyKPoints)
{
auto O3DPointCloud = this->Cvt2O3DPointCloud();
Expand Down Expand Up @@ -258,6 +313,86 @@ namespace diffCheck::geometry
return bboxPts;
}

void DFPointCloud::SubtractPoints(const DFPointCloud &pointCloud, double distanceThreshold)
{
if (this->Points.size() == 0 || pointCloud.Points.size() == 0)
throw std::invalid_argument("One of the point clouds is empty.");

auto O3DSourcePointCloud = this->Cvt2O3DPointCloud();
auto O3DTargetPointCloud = std::make_shared<DFPointCloud>(pointCloud)->Cvt2O3DPointCloud();
auto O3DResultPointCloud = std::make_shared<open3d::geometry::PointCloud>();

open3d::geometry::KDTreeFlann threeDTree;
threeDTree.SetGeometry(*O3DTargetPointCloud);
std::vector<int> indices;
std::vector<double> distances;
for (const auto &point : O3DSourcePointCloud->points_)
{
threeDTree.SearchRadius(point, distanceThreshold, indices, distances);
if (indices.empty())
{
O3DResultPointCloud->points_.push_back(point);
if (O3DSourcePointCloud->HasColors())
{
O3DResultPointCloud->colors_.push_back(O3DSourcePointCloud->colors_[&point - &O3DSourcePointCloud->points_[0]]);
}
if (O3DSourcePointCloud->HasNormals())
{
O3DResultPointCloud->normals_.push_back(O3DSourcePointCloud->normals_[&point - &O3DSourcePointCloud->points_[0]]);
}
}
}
this->Points.clear();
for (auto &point : O3DResultPointCloud->points_)
this->Points.push_back(point);
if (O3DResultPointCloud->HasColors())
{
this->Colors.clear();
for (auto &color : O3DResultPointCloud->colors_){this->Colors.push_back(color);};
}
if (O3DResultPointCloud->HasNormals())
{
this->Normals.clear();
for (auto &normal : O3DResultPointCloud->normals_){this->Normals.push_back(normal);};
}
}

diffCheck::geometry::DFPointCloud DFPointCloud::Intersect(const DFPointCloud &pointCloud, double distanceThreshold)
{
if (this->Points.size() == 0 || pointCloud.Points.size() == 0)
throw std::invalid_argument("One of the point clouds is empty.");

auto O3DSourcePointCloud = this->Cvt2O3DPointCloud();
auto O3DTargetPointCloud = std::make_shared<DFPointCloud>(pointCloud)->Cvt2O3DPointCloud();
auto O3DResultPointCloud = std::make_shared<open3d::geometry::PointCloud>();

open3d::geometry::KDTreeFlann threeDTree;
threeDTree.SetGeometry(*O3DTargetPointCloud);
std::vector<int> indices;
std::vector<double> distances;
for (const auto &point : O3DSourcePointCloud->points_)
{
threeDTree.SearchRadius(point, distanceThreshold, indices, distances);
if (!indices.empty())
{
O3DResultPointCloud->points_.push_back(point);
if (O3DSourcePointCloud->HasColors())
{
O3DResultPointCloud->colors_.push_back(O3DSourcePointCloud->colors_[&point - &O3DSourcePointCloud->points_[0]]);
}
if (O3DSourcePointCloud->HasNormals())
{
O3DResultPointCloud->normals_.push_back(O3DSourcePointCloud->normals_[&point - &O3DSourcePointCloud->points_[0]]);
}
}
}
diffCheck::geometry::DFPointCloud result;
result.Points = O3DResultPointCloud->points_;
result.Colors = O3DResultPointCloud->colors_;
result.Normals = O3DResultPointCloud->normals_;
return result;
}

void DFPointCloud::ApplyTransformation(const diffCheck::transformation::DFTransformation &transformation)
{
auto O3DPointCloud = this->Cvt2O3DPointCloud();
Expand Down
54 changes: 54 additions & 0 deletions src/diffCheck/geometry/DFPointCloud.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include <cilantro/utilities/point_cloud.hpp>
#include <cilantro/core/nearest_neighbors.hpp>
#include <cilantro/clustering/kmeans.hpp>


namespace diffCheck::geometry
{
Expand Down Expand Up @@ -89,6 +91,40 @@ namespace diffCheck::geometry
*/
void RemoveStatisticalOutliers(int nbNeighbors, double stdRatio);

/**
* @brief Fit a plane to the point cloud using RANSAC
*
* @param distanceThreshold the distance threshold to consider a point as an inlier
* @param ransacN the number of points to sample for each RANSAC iteration
* @param numIterations the number of RANSAC iterations
* @return The Normal vector of the fitted plane as an Eigen::Vector3d
*/
Eigen::Vector3d FitPlaneRANSAC(
double distanceThreshold = 0.01,
int ransacN = 3,
int numIterations = 100);

/**
* @brief Crop the point cloud to a bounding box defined by the min and max bounds
*
* @param minBound the minimum bound of the bounding box as an Eigen::Vector3d
* @param maxBound the maximum bound of the bounding box as an Eigen::Vector3d
*/
void Crop(const Eigen::Vector3d &minBound, const Eigen::Vector3d &maxBound);

/**
* @brief Crop the point cloud to a bounding box defined by the 8 corners of the box
* @param corners the 8 corners of the bounding box as a vector of Eigen::Vector3d
*/
void Crop(const std::vector<Eigen::Vector3d> &corners);

/**
* @brief Get the duplicate of the point cloud. This is mainly used in the python bindings
*
* @return DFPointCloud a copy of the point cloud
*/
diffCheck::geometry::DFPointCloud Duplicate() const;

public: ///< Downsamplers
/**
* @brief Downsample the point cloud with voxel grid
Expand Down Expand Up @@ -136,6 +172,24 @@ namespace diffCheck::geometry
* ///
*/
std::vector<Eigen::Vector3d> GetTightBoundingBox();

public: ///< Point cloud subtraction and intersection
/**
* @brief Subtract the points, colors and normals from another point cloud when they are too close to the points of another point cloud.
*
* @param pointCloud the other point cloud to subtract from this one
* @param distanceThreshold the distance threshold to consider a point as too close. Default is 0.01.
*/
void SubtractPoints(const DFPointCloud &pointCloud, double distanceThreshold = 0.01);

/**
* @brief Intersect the points, colors and normals from another point cloud when they are close enough to the points of another point cloud. Is the point cloud interpretation of a boolean intersection.
*
* @param pointCloud the other point cloud to intersect with this one
* @param distanceThreshold the distance threshold to consider a point as too close. Default is 0.01.
* @return diffCheck::geometry::DFPointCloud the intersected point cloud
*/
diffCheck::geometry::DFPointCloud Intersect(const DFPointCloud &pointCloud, double distanceThreshold = 0.01);

public: ///< Transformers
/**
Expand Down
6 changes: 3 additions & 3 deletions src/diffCheck/segmentation/DFSegmentation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ namespace diffCheck::segmentation
void DFSegmentation::CleanUnassociatedClusters(
bool isCylinder,
std::vector<std::shared_ptr<geometry::DFPointCloud>> &unassociatedClusters,
std::vector<std::shared_ptr<geometry::DFPointCloud>> &existingPointCloudSegments,
std::vector<std::vector<std::shared_ptr<geometry::DFPointCloud>>> &existingPointCloudSegments,
std::vector<std::vector<std::shared_ptr<geometry::DFMesh>>> meshes,
double angleThreshold,
double associationThreshold)
Expand Down Expand Up @@ -459,12 +459,12 @@ namespace diffCheck::segmentation
DIFFCHECK_WARN("No mesh face found for the cluster. Skipping the cluster.");
continue;
}
if (goodMeshIndex >= existingPointCloudSegments.size())
if (goodMeshIndex >= existingPointCloudSegments.size() || goodFaceIndex >= existingPointCloudSegments[goodMeshIndex].size())
{
DIFFCHECK_WARN("No segment found for the face. Skipping the face.");
continue;
}
std::shared_ptr<geometry::DFPointCloud> completed_segment = existingPointCloudSegments[goodMeshIndex];
std::shared_ptr<geometry::DFPointCloud> completed_segment = existingPointCloudSegments[goodMeshIndex][goodFaceIndex];

for (Eigen::Vector3d point : cluster->Points)
{
Expand Down
4 changes: 2 additions & 2 deletions src/diffCheck/segmentation/DFSegmentation.hh
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ namespace diffCheck::segmentation
/** @brief Iterated through clusters and finds the corresponding mesh face. It then associates the points of the cluster that are on the mesh face to the segment already associated with the mesh face.
* @param isCylinder a boolean to indicate if the model is a cylinder. If true, the method will use the GetCenterAndAxis method of the mesh to find the center and axis of the mesh. based on that, we only want points that have normals more or less perpendicular to the cylinder axis.
* @param unassociatedClusters the clusters from the normal-based segmentatinon that haven't been associated yet.
* @param existingPointCloudSegments the already associated segments
* @param existingPointCloudSegments the already associated segments per mesh face.
* @param meshes the mesh faces for all the model. This is used to associate the clusters to the mesh faces.
* * @param angleThreshold the threshold to consider the a cluster as potential candidate for association. the value passed is the minimum sine of the angles. A value of 0 requires perfect alignment (angle = 0), while a value of 0.1 allows an angle of 5.7 degrees.
* @param associationThreshold the threshold to consider the points of a segment and a mesh face as associable. It is the ratio between the surface of the closest mesh triangle and the sum of the areas of the three triangles that form the rest of the pyramid described by the mesh triangle and the point we want to associate or not. The lower the number, the more strict the association will be and some poinnts on the mesh face might be wrongfully excluded.
*/
static void DFSegmentation::CleanUnassociatedClusters(
bool isCylinder,
std::vector<std::shared_ptr<geometry::DFPointCloud>> &unassociatedClusters,
std::vector<std::shared_ptr<geometry::DFPointCloud>> &existingPointCloudSegments,
std::vector<std::vector<std::shared_ptr<geometry::DFPointCloud>>> &existingPointCloudSegments,
std::vector<std::vector<std::shared_ptr<geometry::DFMesh>>> meshes,
double angleThreshold = 0.1,
double associationThreshold = 0.1);
Expand Down
Loading
Loading