Skip to content

Feature/point cloud utils #155

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: release/2.0.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
59 changes: 59 additions & 0 deletions src/diffCheck/geometry/DFPointCloud.cc
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,21 @@ namespace diffCheck::geometry
this->Normals.push_back(normal);
}

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::UniformDownsample(int everyKPoints)
{
auto O3DPointCloud = this->Cvt2O3DPointCloud();
Expand Down Expand Up @@ -258,6 +273,50 @@ 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);};
}
}

void DFPointCloud::ApplyTransformation(const diffCheck::transformation::DFTransformation &transformation)
{
auto O3DPointCloud = this->Cvt2O3DPointCloud();
Expand Down
17 changes: 17 additions & 0 deletions src/diffCheck/geometry/DFPointCloud.hh
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ namespace diffCheck::geometry
*/
void RemoveStatisticalOutliers(int nbNeighbors, double stdRatio);

/**
* @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);

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

public: ///< Point cloud subtraction
/**
* @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);

public: ///< Transformers
/**
Expand Down
5 changes: 5 additions & 0 deletions src/diffCheckBindings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ PYBIND11_MODULE(diffcheck_bindings, m) {
.def("downsample_by_size", &diffCheck::geometry::DFPointCloud::DownsampleBySize,
py::arg("target_size"))

.def("subtract_points", &diffCheck::geometry::DFPointCloud::SubtractPoints,
py::arg("point_cloud"), py::arg("distance_threshold"))

.def("apply_transformation", &diffCheck::geometry::DFPointCloud::ApplyTransformation,
py::arg("transformation"))

Expand All @@ -54,6 +57,8 @@ PYBIND11_MODULE(diffcheck_bindings, m) {

.def("remove_statistical_outliers", &diffCheck::geometry::DFPointCloud::RemoveStatisticalOutliers,
py::arg("nb_neighbors"), py::arg("std_ratio"))
.def("crop", &diffCheck::geometry::DFPointCloud::Crop,
py::arg("min_bound"), py::arg("max_bound"))

.def("load_from_PLY", &diffCheck::geometry::DFPointCloud::LoadFromPLY)
.def("save_to_PLY", &diffCheck::geometry::DFPointCloud::SaveToPLY)
Expand Down
25 changes: 25 additions & 0 deletions src/gh/components/DF_cloud_subtractor/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from diffCheck import df_cvt_bindings as df_cvt

import Rhino
from Grasshopper.Kernel import GH_RuntimeMessageLevel as RML

from ghpythonlib.componentbase import executingcomponent as component

class DFCloudSubtract(component):
def __init__(self):
super(DFCloudSubtract, self).__init__()
def RunScript(self,
i_cloud_subtract_from: Rhino.Geometry.PointCloud,
i_cloud_subtract_with: Rhino.Geometry.PointCloud,
i_distance_threshold: float):
df_cloud = df_cvt.cvt_rhcloud_2_dfcloud(i_cloud_subtract_from)
df_cloud_substract = df_cvt.cvt_rhcloud_2_dfcloud(i_cloud_subtract_with)
if i_distance_threshold is None:
ghenv.Component.AddRuntimeMessage(RML.Warning, "Distance threshold not defined. 0.01 used as default value.")# noqa: F821
i_distance_threshold = 0.01
if i_distance_threshold <= 0:
ghenv.Component.AddRuntimeMessage(RML.Warning, "Distance threshold must be greater than 0. Please provide a valid distance threshold.")# noqa: F821
return None
df_cloud.subtract_points(df_cloud_substract, i_distance_threshold)
rh_cloud = df_cvt.cvt_dfcloud_2_rhcloud(df_cloud)
return [rh_cloud]
Binary file added src/gh/components/DF_cloud_subtractor/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 64 additions & 0 deletions src/gh/components/DF_cloud_subtractor/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"name": "DFSubtractCloud",
"nickname": "Subtract",
"category": "diffCheck",
"subcategory": "Cloud",
"description": "Subtracts points from a point cloud based on a distance threshold.",
"exposure": 4,
"instanceGuid": "9ef299aa-76dc-4417-9b95-2a374e2b36af",
"ghpython": {
"hideOutput": true,
"hideInput": true,
"isAdvancedMode": true,
"marshalOutGuids": true,
"iconDisplay": 2,
"inputParameters": [
{
"name": "i_cloud_subtract_from",
"nickname": "i_cloud_subtract_from",
"description": "The point cloud to subtract from.",
"optional": false,
"allowTreeAccess": true,
"showTypeHints": true,
"scriptParamAccess": "item",
"wireDisplay": "default",
"sourceCount": 0,
"typeHintID": "pointcloud"
},
{
"name": "i_cloud_subtract_with",
"nickname": "i_cloud_subtract_with",
"description": "The point cloud to subtract with.",
"optional": false,
"allowTreeAccess": true,
"showTypeHints": true,
"scriptParamAccess": "item",
"wireDisplay": "default",
"sourceCount": 0,
"typeHintID": "pointcloud"
},
{
"name": "i_distance_threshold",
"nickname": "i_distance_threshold",
"description": "The distance threshold to consider a point as too close.",
"optional": true,
"allowTreeAccess": true,
"showTypeHints": true,
"scriptParamAccess": "item",
"wireDisplay": "default",
"sourceCount": 0,
"typeHintID": "brep"
}
],
"outputParameters": [
{
"name": "o_cloud",
"nickname": "o_cloud",
"description": "The resulting cloud after subtraction.",
"optional": false,
"sourceCount": 0,
"graft": false
}
]
}
}
31 changes: 31 additions & 0 deletions src/gh/components/DF_crop_cloud/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from diffCheck import df_cvt_bindings as df_cvt

import numpy as np

import Rhino
from Grasshopper.Kernel import GH_RuntimeMessageLevel as RML

from ghpythonlib.componentbase import executingcomponent as component

class DFCloudCrop(component):
def __init__(self):
super(DFCloudCrop, self).__init__()
def RunScript(self,
i_cloud: Rhino.Geometry.PointCloud,
i_box: Rhino.Geometry.Brep):
if i_cloud is None:
ghenv.Component.AddRuntimeMessage(RML.Warning, "No point cloud provided. Please connect a point cloud to the input.") # noqa: F821
return None

if i_box is not None:
bbox = i_box.GetBoundingBox(True)
bb_min_as_array = np.asarray([bbox.Min.X, bbox.Min.Y, bbox.Min.Z])
bb_max_as_array = np.asarray([bbox.Max.X, bbox.Max.Y, bbox.Max.Z])

else:
ghenv.Component.AddRuntimeMessage(RML.Warning, "Please provide a box to crop the point cloud with") # noqa: F821

df_cloud = df_cvt.cvt_rhcloud_2_dfcloud(i_cloud)
df_cloud.crop(bb_min_as_array, bb_max_as_array)
rh_cloud = df_cvt.cvt_dfcloud_2_rhcloud(df_cloud)
return [rh_cloud]
Binary file added src/gh/components/DF_crop_cloud/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions src/gh/components/DF_crop_cloud/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "DFCropCloud",
"nickname": "Crop",
"category": "diffCheck",
"subcategory": "Cloud",
"description": "Crops a point cloud by giving the bounding box or limit values.",
"exposure": 4,
"instanceGuid": "f0461287-b1aa-47ec-87c4-0f03924cea24",
"ghpython": {
"hideOutput": true,
"hideInput": true,
"isAdvancedMode": true,
"marshalOutGuids": true,
"iconDisplay": 2,
"inputParameters": [
{
"name": "i_cloud",
"nickname": "i_cloud",
"description": "The point cloud to crop.",
"optional": false,
"allowTreeAccess": true,
"showTypeHints": true,
"scriptParamAccess": "item",
"wireDisplay": "default",
"sourceCount": 0,
"typeHintID": "pointcloud"
},
{
"name": "i_box",
"nickname": "i_box",
"description": "The brep box to crop the point cloud with.",
"optional": false,
"allowTreeAccess": true,
"showTypeHints": true,
"scriptParamAccess": "item",
"wireDisplay": "default",
"sourceCount": 0,
"typeHintID": "brep"
}
],
"outputParameters": [
{
"name": "o_cloud",
"nickname": "o_cloud",
"description": "The downsampled cloud.",
"optional": false,
"sourceCount": 0,
"graft": false
}
]
}
}
Loading