Skip to content

Commit 3501087

Browse files
committed
WIP-FIX update gh components cloud2cloud and mesh2cloud to use the new df_mesh.compute_distance, df_cloud.compute_distance functions
1 parent a61efff commit 3501087

File tree

9 files changed

+29
-151
lines changed

9 files changed

+29
-151
lines changed

deps/eigen

Submodule eigen updated from 02bcf9b to d791d48

src/gh/components/DF_cloud_to_mesh_distance/code.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
class CloudToMeshDistance(component):
2020
def RunScript(self,
2121
i_cloud_source: rg.PointCloud,
22-
i_mesh_target: rg.PointCloud,
22+
i_beam,
2323
i_signed_flag: bool):
2424
"""
2525
The cloud-to-cloud component computes the distance between each point in the source point cloud and its nearest neighbour in thr target point cloud.
@@ -32,12 +32,13 @@ def RunScript(self,
3232
:return o_max_deviation: the max deviation between source and target (Hausdorff Distance)
3333
:return o_min_deviation: the min deviation between source and target
3434
"""
35-
if i_cloud_source is None or i_mesh_target is None:
35+
if i_cloud_source is None or i_beam is None:
3636
ghenv.Component.AddRuntimeMessage(RML.Warning, "Please provide an object of type point cloud and an object of type mesh to compare")
3737
return None
3838

3939
# conversion
4040
df_cloud_source = df_cvt_bindings.cvt_rhcloud_2_dfcloud(i_cloud_source)
41+
i_mesh_target = i_beam.to_mesh()
4142
df_mesh_target = df_cvt_bindings.cvt_rhmesh_2_dfmesh(i_mesh_target)
4243

4344
# calculate distances
@@ -53,5 +54,6 @@ def RunScript(self,
5354
com = CloudToMeshDistance()
5455
o_distances, o_mse, o_max_deviation, o_min_deviation = com.RunScript(
5556
i_cloud_source,
56-
i_mesh_target
57+
i_mesh_target,
58+
i_signed_flag
5759
)

src/gh/diffCheck/diffCheck.egg-info/PKG-INFO

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ Classifier: Programming Language :: Python :: 3
1010
Classifier: Programming Language :: Python :: 3.9
1111
Description-Content-Type: text/markdown
1212
Requires-Dist: numpy
13-
Requires-Dist: open3d
1413
Requires-Dist: pybind11>=2.5.0
1514

1615
# DiffCheck Grasshopper Plugin

src/gh/diffCheck/diffCheck.egg-info/SOURCES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ diffCheck/df_geometries.py
77
diffCheck/df_joint_detector.py
88
diffCheck/df_transformations.py
99
diffCheck/df_util.py
10+
diffCheck/diffcheck_bindings.cp39-win_amd64.pyd
1011
diffCheck.egg-info/PKG-INFO
1112
diffCheck.egg-info/SOURCES.txt
1213
diffCheck.egg-info/dependency_links.txt
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
numpy
2-
open3d
32
pybind11>=2.5.0

src/gh/diffCheck/diffCheck/df_error_estimation.py

Lines changed: 9 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -5,166 +5,32 @@
55

66
import numpy as np
77
import open3d as o3d
8-
98
from diffCheck import diffcheck_bindings
109

1110
def cloud_2_cloud_distance(source, target, signed=False):
1211
"""
1312
Compute the Euclidean distance for every point of a source pcd to its closest point on a target pointcloud
1413
"""
15-
distances = np.asarray(source.compute_P2PDistance(target))
16-
1714
if signed:
18-
19-
# Build a KD-tree for the target points
20-
pcd = o3d.geometry.PointCloud()
21-
pcd.points = o3d.utility.Vector3dVector(target.points)
22-
kdtree = o3d.geometry.KDTreeFlann(pcd)
23-
print("KD-tree built successfully.")
24-
25-
for i in range(len(source.points)):
26-
27-
query = np.asarray(source.points[i], dtype=np.float64).reshape(3)
28-
# Query the KD-tree to find the nearest neighbor
29-
try:
30-
_, idx, _ = kdtree.search_knn_vector_3d(query, 1)
31-
except Exception as e:
32-
print(f"Error querying KD-tree for point {i}: {e}")
33-
continue
34-
35-
closest_idx = idx[0]
36-
# Calculate the direction from target to source
37-
direction = source.points[i] - target.points[closest_idx]
38-
39-
# Calculate the signed distance
40-
dot_product = np.dot(direction, target.normals[closest_idx])
41-
if dot_product < 0:
42-
distances[i] = -distances[i]
15+
distances = np.asarray(source.compute_distance(target, is_abs=False))
16+
else:
17+
distances = np.asarray(source.compute_distance(target, is_abs=True))
4318

4419
return distances
4520

4621

47-
def cloud_2_mesh_distance(source, target):
22+
def cloud_2_mesh_distance(source, target, signed=False):
4823
"""
49-
Calculate the distance between every point of a source pcd to its closest point on a target mesh
24+
Calculate the distance between every point of a source pcd to its closest point on a target beam
5025
"""
5126

5227
# for every point on the PCD compute the point_2_mesh_distance
53-
54-
distances = np.ones(len(source.points), dtype=float)
55-
56-
for i in range(len(source.points)):
57-
distances[i] = point_2_mesh_distance(target, source.points[i])
58-
59-
return distances
60-
61-
62-
def point_2_mesh_distance(geo, query_point):
63-
"""
64-
Calculate the closest distance between a point and a target geometry
65-
"""
66-
# make a kdtree of the vertices to get the relevant vertices indexes
67-
pcd = diffcheck_bindings.dfb_geometry.DFPointCloud()
68-
pcd.points = geo.vertices
69-
kd_tree = o3d.geometry.KDTreeFlann(pcd)
70-
71-
# assume smallest distance is the distance to the closest vertex
72-
_, idx, _ = kd_tree.search_knn_vector_3d(query_point, 1)
73-
if idx:
74-
nearest_vertex_idx = idx[0]
75-
else:
76-
raise ValueError("The mesh or brep has no vertices. Please provide a valid geometry.")
77-
nearest_vertex = np.asarray(geo.vertices)[nearest_vertex_idx]
78-
dist = np.linalg.norm(query_point - nearest_vertex)
79-
80-
# Find its neighbors with distance less than _dist_ multiplied by two.
81-
search_distance = dist * 2
82-
_, v_indices, _ = kd_tree.search_radius_vector_3d(query_point, search_distance)
83-
84-
# Find the faces that belong to these filtered vertices.
85-
geo_triangles = np.asarray(geo.triangles)
86-
candidate_mask = np.isin(geo_triangles, v_indices)
87-
candidate_faces = geo_triangles[np.any(candidate_mask, axis=1)]
88-
89-
# Step 4: Loop over candidate faces
90-
shortest_distance = float('inf')
91-
92-
for face in candidate_faces:
93-
#v0, v1, v2 = np.asarray(geo.vertices)[face]
94-
pt_face_dist = point_2_face_distance(face, query_point)
95-
if pt_face_dist < shortest_distance:
96-
shortest_distance = pt_face_dist
97-
98-
return shortest_distance
99-
100-
101-
def point_2_face_distance(face, point):
102-
"""
103-
Calculate the closest distance between a point and a face
104-
"""
105-
106-
if len(face.vertices) == 3:
107-
return point_2_triangle_distance(point, face)
108-
elif len(face.vertices) == 4:
109-
return point_2_quad_distance(point, face)
110-
else:
111-
raise ValueError("Face must be a triangle or quadrilateral")
112-
113-
114-
def point_2_triangle_distance(point, triangle):
115-
"""
116-
Calculate the shortest distance from a point to a triangle.
117-
"""
118-
a, b, c = triangle
119-
120-
bary_coords = barycentric_coordinates(point, a, b, c)
121-
122-
# If the point is inside or on the triangle, use the barycentric coordinates to find the closest point
123-
if np.all(bary_coords >= 0):
124-
closest_point = bary_coords[0] * a + bary_coords[1] * b + bary_coords[2] * c
125-
126-
# If the point is outside the triangle, project it onto the triangle edges and find the closest point
28+
if signed:
29+
distances = np.asarray(target.compute_distance(source, is_abs=False))
12730
else:
128-
proj = np.array([np.dot(point - a, b - a) / np.dot(b - a, b - a),
129-
np.dot(point - b, c - b) / np.dot(c - b, c - b),
130-
np.dot(point - c, a - c) / np.dot(a - c, a - c)])
131-
proj = np.clip(proj, 0, 1)
132-
closest_point = np.array([a + proj[0] * (b - a), b + proj[1] * (c - b), c + proj[2] * (a - c)]).min(axis=0)
133-
134-
return np.linalg.norm(closest_point - point)
135-
31+
distances = np.asarray(target.compute_distance(source, is_abs=True))
13632

137-
def barycentric_coordinates(p, a, b, c):
138-
"""
139-
Calculate the barycentric coordinates of point p with respect to the triangle defined by points a, b, and c.
140-
"""
141-
v0 = b - a
142-
v1 = c - a
143-
v2 = p - a
144-
145-
d00 = np.dot(v0, v0)
146-
d01 = np.dot(v0, v1)
147-
d11 = np.dot(v1, v1)
148-
d20 = np.dot(v2, v0)
149-
d21 = np.dot(v2, v1)
150-
151-
denom = d00 * d11 - d01 * d01
152-
v = (d11 * d20 - d01 * d21) / denom
153-
w = (d00 * d21 - d01 * d20) / denom
154-
u = 1.0 - v - w
155-
156-
return np.array([u, v, w])
157-
158-
159-
def point_2_quad_distance(point, quad):
160-
"""
161-
Calculate the shortest distance from a point to a quadrilateral.
162-
"""
163-
a, b, c, d = quad.vertices
164-
165-
# Calculate the distance to the two triangles that form the quadrilateral
166-
return min(point_2_triangle_distance(point, [a, b, c]),
167-
point_2_triangle_distance(point, [c, d, a]))
33+
return distances
16834

16935

17036
def compute_mse(distances):

src/gh/diffCheck/diffCheck/df_geometries.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,18 @@ def to_brep(self):
238238

239239
return brep
240240

241+
def to_mesh(self):
242+
"""
243+
Convert the beam to a Rhino Mesh object
244+
"""
245+
mesh = rg.Mesh()
246+
for face in self.faces:
247+
mesh_part = face.to_mesh()
248+
mesh.Append(mesh_part)
249+
mesh.Compact()
250+
251+
return mesh
252+
241253
def __repr__(self):
242254
return f"Beam: {self.name}, Faces: {len(self.faces)}"
243255

src/gh/diffCheck/setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
packages=find_packages(),
1313
install_requires=[
1414
"numpy",
15-
"open3d",
1615
"pybind11>=2.5.0"
1716
# other dependencies...
1817
],

0 commit comments

Comments
 (0)