Skip to content

Commit a98b80f

Browse files
feat: add point cloud subtraction method and implement it in component
1 parent a0289fc commit a98b80f

File tree

6 files changed

+145
-0
lines changed

6 files changed

+145
-0
lines changed

src/diffCheck/geometry/DFPointCloud.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,50 @@ namespace diffCheck::geometry
273273
return bboxPts;
274274
}
275275

276+
void DFPointCloud::SubtractPoints(const DFPointCloud &pointCloud, double distanceThreshold)
277+
{
278+
if (this->Points.size() == 0 || pointCloud.Points.size() == 0)
279+
throw std::invalid_argument("One of the point clouds is empty.");
280+
281+
auto O3DSourcePointCloud = this->Cvt2O3DPointCloud();
282+
auto O3DTargetPointCloud = std::make_shared<DFPointCloud>(pointCloud)->Cvt2O3DPointCloud();
283+
auto O3DResultPointCloud = std::make_shared<open3d::geometry::PointCloud>();
284+
285+
open3d::geometry::KDTreeFlann threeDTree;
286+
threeDTree.SetGeometry(*O3DTargetPointCloud);
287+
std::vector<int> indices;
288+
std::vector<double> distances;
289+
for (const auto &point : O3DSourcePointCloud->points_)
290+
{
291+
threeDTree.SearchRadius(point, distanceThreshold, indices, distances);
292+
if (indices.empty())
293+
{
294+
O3DResultPointCloud->points_.push_back(point);
295+
if (O3DSourcePointCloud->HasColors())
296+
{
297+
O3DResultPointCloud->colors_.push_back(O3DSourcePointCloud->colors_[&point - &O3DSourcePointCloud->points_[0]]);
298+
}
299+
if (O3DSourcePointCloud->HasNormals())
300+
{
301+
O3DResultPointCloud->normals_.push_back(O3DSourcePointCloud->normals_[&point - &O3DSourcePointCloud->points_[0]]);
302+
}
303+
}
304+
}
305+
this->Points.clear();
306+
for (auto &point : O3DResultPointCloud->points_)
307+
this->Points.push_back(point);
308+
if (O3DResultPointCloud->HasColors())
309+
{
310+
this->Colors.clear();
311+
for (auto &color : O3DResultPointCloud->colors_){this->Colors.push_back(color);};
312+
}
313+
if (O3DResultPointCloud->HasNormals())
314+
{
315+
this->Normals.clear();
316+
for (auto &normal : O3DResultPointCloud->normals_){this->Normals.push_back(normal);};
317+
}
318+
}
319+
276320
void DFPointCloud::ApplyTransformation(const diffCheck::transformation::DFTransformation &transformation)
277321
{
278322
auto O3DPointCloud = this->Cvt2O3DPointCloud();

src/diffCheck/geometry/DFPointCloud.hh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,15 @@ namespace diffCheck::geometry
144144
* ///
145145
*/
146146
std::vector<Eigen::Vector3d> GetTightBoundingBox();
147+
148+
public: ///< Point cloud subtraction
149+
/**
150+
* @brief Subtract the points, colors and normals from another point cloud when they are too close to the points of another point cloud.
151+
*
152+
* @param pointCloud the other point cloud to subtract from this one
153+
* @param distanceThreshold the distance threshold to consider a point as too close. Default is 0.01.
154+
*/
155+
void SubtractPoints(const DFPointCloud &pointCloud, double distanceThreshold = 0.01);
147156

148157
public: ///< Transformers
149158
/**

src/diffCheckBindings.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ PYBIND11_MODULE(diffcheck_bindings, m) {
4141
.def("downsample_by_size", &diffCheck::geometry::DFPointCloud::DownsampleBySize,
4242
py::arg("target_size"))
4343

44+
.def("subtract_points", &diffCheck::geometry::DFPointCloud::SubtractPoints,
45+
py::arg("point_cloud"), py::arg("distance_threshold"))
46+
4447
.def("apply_transformation", &diffCheck::geometry::DFPointCloud::ApplyTransformation,
4548
py::arg("transformation"))
4649

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from diffCheck import df_cvt_bindings as df_cvt
2+
3+
import Rhino
4+
from Grasshopper.Kernel import GH_RuntimeMessageLevel as RML
5+
6+
from ghpythonlib.componentbase import executingcomponent as component
7+
8+
class DFCloudSubtract(component):
9+
def __init__(self):
10+
super(DFCloudSubtract, self).__init__()
11+
def RunScript(self,
12+
i_cloud_subtract_from: Rhino.Geometry.PointCloud,
13+
i_cloud_subtract_with: Rhino.Geometry.PointCloud,
14+
i_distance_threshold: float):
15+
df_cloud = df_cvt.cvt_rhcloud_2_dfcloud(i_cloud_subtract_from)
16+
df_cloud_substract = df_cvt.cvt_rhcloud_2_dfcloud(i_cloud_subtract_with)
17+
if i_distance_threshold is None:
18+
ghenv.Component.AddRuntimeMessage(RML.Warning, "Distance threshold not defined. 0.01 used as default value.")# noqa: F821
19+
i_distance_threshold = 0.01
20+
if i_distance_threshold <= 0:
21+
ghenv.Component.AddRuntimeMessage(RML.Warning, "Distance threshold must be greater than 0. Please provide a valid distance threshold.")# noqa: F821
22+
return None
23+
df_cloud.subtract_points(df_cloud_substract, i_distance_threshold)
24+
rh_cloud = df_cvt.cvt_dfcloud_2_rhcloud(df_cloud)
25+
return [rh_cloud]
12.1 KB
Loading
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"name": "DFSubtractCloud",
3+
"nickname": "Subtract",
4+
"category": "diffCheck",
5+
"subcategory": "Cloud",
6+
"description": "Subtracts points from a point cloud based on a distance threshold.",
7+
"exposure": 4,
8+
"instanceGuid": "9ef299aa-76dc-4417-9b95-2a374e2b36af",
9+
"ghpython": {
10+
"hideOutput": true,
11+
"hideInput": true,
12+
"isAdvancedMode": true,
13+
"marshalOutGuids": true,
14+
"iconDisplay": 2,
15+
"inputParameters": [
16+
{
17+
"name": "i_cloud_subtract_from",
18+
"nickname": "i_cloud_subtract_from",
19+
"description": "The point cloud to subtract from.",
20+
"optional": false,
21+
"allowTreeAccess": true,
22+
"showTypeHints": true,
23+
"scriptParamAccess": "item",
24+
"wireDisplay": "default",
25+
"sourceCount": 0,
26+
"typeHintID": "pointcloud"
27+
},
28+
{
29+
"name": "i_cloud_subtract_with",
30+
"nickname": "i_cloud_subtract_with",
31+
"description": "The point cloud to subtract with.",
32+
"optional": false,
33+
"allowTreeAccess": true,
34+
"showTypeHints": true,
35+
"scriptParamAccess": "item",
36+
"wireDisplay": "default",
37+
"sourceCount": 0,
38+
"typeHintID": "pointcloud"
39+
},
40+
{
41+
"name": "i_distance_threshold",
42+
"nickname": "i_distance_threshold",
43+
"description": "The distance threshold to consider a point as too close.",
44+
"optional": true,
45+
"allowTreeAccess": true,
46+
"showTypeHints": true,
47+
"scriptParamAccess": "item",
48+
"wireDisplay": "default",
49+
"sourceCount": 0,
50+
"typeHintID": "brep"
51+
}
52+
],
53+
"outputParameters": [
54+
{
55+
"name": "o_cloud",
56+
"nickname": "o_cloud",
57+
"description": "The resulting cloud after subtraction.",
58+
"optional": false,
59+
"sourceCount": 0,
60+
"graft": false
61+
}
62+
]
63+
}
64+
}

0 commit comments

Comments
 (0)