Skip to content

Commit d7349fb

Browse files
committed
WIP-CAP: working version for new joint detector
1 parent 8331e35 commit d7349fb

File tree

9 files changed

+265
-126
lines changed

9 files changed

+265
-126
lines changed

deps/eigen

Submodule eigen updated from f78dfe3 to 27f8176

src/diffCheck/geometry/DFPointCloud.hh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,24 @@ namespace diffCheck::geometry
6363
*
6464
* @return std::vector<Eigen::Vector3d> A vector of two Eigen::Vector3d, with the first one being the minimum
6565
* point and the second one the maximum point of the bounding box.
66+
* /// ------- x
67+
* /// /|
68+
* /// / |
69+
* /// / | z
70+
* /// y
71+
* /// 0 ------------------- 1
72+
* /// /| /|
73+
* /// / | / |
74+
* /// / | / |
75+
* /// / | / |
76+
* /// 2 ------------------- 7 |
77+
* /// | |____________|____| 6
78+
* /// | /3 | /
79+
* /// | / | /
80+
* /// | / | /
81+
* /// |/ |/
82+
* /// 5 ------------------- 4
83+
* ///
6684
*/
6785
std::vector<Eigen::Vector3d> GetTightBoundingBox();
6886

src/diffCheckApp.cc

Lines changed: 32 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,60 +7,45 @@
77
int main()
88
{
99
// import clouds
10-
std::shared_ptr<diffCheck::geometry::DFPointCloud> dfPointCloudPtr = std::make_shared<diffCheck::geometry::DFPointCloud>();
11-
std::shared_ptr<diffCheck::geometry::DFMesh> dfMeshPtr = std::make_shared<diffCheck::geometry::DFMesh>();
12-
std::shared_ptr<diffCheck::geometry::DFPointCloud> dfGroundTruth = std::make_shared<diffCheck::geometry::DFPointCloud>();
13-
14-
// std::string pathCloud = R"(C:\Users\andre\Downloads\scan_data_normals.ply\scan_data_normals.ply)";
15-
// std::string pathMesh = R"(F:\diffCheck\assets\dataset\mesh_fromRh_unfixedLength.ply)";
16-
// std::string pathMesh = R"(F:\diffCheck\temp\03_mesh.ply)";
10+
std::shared_ptr<diffCheck::geometry::DFPointCloud> dfPointCloudPtr
11+
= std::make_shared<diffCheck::geometry::DFPointCloud>();
12+
std::shared_ptr<diffCheck::geometry::DFMesh> dfMeshPtr
13+
= std::make_shared<diffCheck::geometry::DFMesh>();
1714

1815
// create a sphere from o3d
16+
std::string pathCloud = R"(C:\andre\Downloads\moved_04.ply)";
17+
std::string pathMesh = R"(C:\Users\andre\Downloads\meshtest.ply)";
1918

20-
std::string pathCloud = R"(C:\Users\localuser\Downloads\04_pt.ply)";
21-
std::string pathMesh = R"(C:\Users\localuser\Downloads\04_mesh.ply)";
22-
// std::string pathMesh = R"(F:\diffCheck\temp\03_mesh.ply)";
23-
19+
// dfPointCloudPtr->LoadFromPLY(pathCloud);
2420
dfMeshPtr->LoadFromPLY(pathMesh);
25-
dfPointCloudPtr->LoadFromPLY(pathCloud);
26-
27-
dfGroundTruth->Cvt2DFPointCloud(dfMeshPtr->Cvt2O3DTriangleMesh()->SamplePointsUniformly(10000));
28-
Eigen::Matrix4d transformation = Eigen::Matrix4d::Identity();
29-
transformation(0, 3) = 0.0;
30-
transformation(1, 3) = -0.02;
31-
transformation(2, 3) = 0.02;
32-
Eigen::Matrix3d rotation;
33-
rotation = Eigen::AngleAxisd(0.3, Eigen::Vector3d::UnitY());
34-
transformation.block<3, 3>(0, 0) = rotation * transformation.block<3, 3>(0, 0);
35-
36-
dfPointCloudPtr->ApplyTransformation(transformation);
37-
38-
diffCheck::transformation::DFTransformation simpleICPTransformation
39-
= diffCheck::registrations::RefinedRegistration::O3DICP(
40-
dfPointCloudPtr,
41-
dfGroundTruth,
42-
0.05);
43-
44-
diffCheck::transformation::DFTransformation generalizedICPTransformation
45-
= diffCheck::registrations::RefinedRegistration::O3DGeneralizedICP(
46-
dfPointCloudPtr,
47-
dfGroundTruth,
48-
0.05);
49-
dfPointCloudPtr->ApplyTransformation(simpleICPTransformation);
50-
51-
std::stringstream ss;
52-
ss << "Simple ICP Transformation:\n";
53-
ss << simpleICPTransformation.TransformationMatrix<<"\n";
54-
ss << "Generalized ICP Transformation:\n";
55-
ss << generalizedICPTransformation.TransformationMatrix;
56-
std::string matrixAsString = ss.str();
57-
DIFFCHECK_INFO(matrixAsString.c_str());
21+
22+
open3d::geometry::TriangleMesh meshO3d = *dfMeshPtr->Cvt2O3DTriangleMesh();
23+
24+
25+
// convert the sphere to a diffCheck point cloud
26+
// auto o3dPointCloud = meshO3d.SamplePointsUniformly(1000);
27+
28+
std::shared_ptr<open3d::geometry::PointCloud> tightBBOX = std::make_shared<open3d::geometry::PointCloud>();
29+
30+
// compute the bounding box
31+
open3d::geometry::OrientedBoundingBox bbox = meshO3d.GetMinimalOrientedBoundingBox();
32+
std::vector<Eigen::Vector3d> bboxPts = bbox.GetBoxPoints();
33+
for (auto &pt : bboxPts)
34+
{
35+
tightBBOX->points_.push_back(pt);
36+
}
37+
38+
39+
dfPointCloudPtr->Cvt2DFPointCloud(tightBBOX);
40+
41+
42+
5843

5944
std::shared_ptr<diffCheck::visualizer::Visualizer> vis = std::make_shared<diffCheck::visualizer::Visualizer>();
60-
// vis->AddPointCloud(dfPointCloudPtr);
61-
vis->AddMesh(dfMeshPtr);
62-
vis->AddPointCloud(dfGroundTruth);
6345
vis->AddPointCloud(dfPointCloudPtr);
46+
// vis->AddMesh(dfMeshPtr);
6447
vis->Run();
48+
49+
6550
return 0;
6651
}

src/gh/components/DF_xml_exporter/code.py

Lines changed: 118 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@
55

66
import Rhino
77
import Rhino.Geometry as rg
8+
import scriptcontext as sc
89

910
from ghpythonlib.componentbase import executingcomponent as component
1011

1112
import diffCheck
1213
from diffCheck.df_geometries import DFBeam, DFAssembly
14+
import diffCheck.df_transformations
15+
16+
import diffCheck.diffcheck_bindings
17+
import diffCheck.df_cvt_bindings
1318

1419

1520
class DFXMLExporter(component):
@@ -25,29 +30,128 @@ def RunScript(self,
2530
:param i_export_dir: directory to export the xml
2631
:param i_breps: list of breps
2732
"""
33+
################
2834
o_xml = None
2935
o_joints = None
3036
o_sides = None
3137
o_debug = None
38+
################
39+
########################################
40+
41+
# TODO: test
42+
o_debug = []
3243

33-
# beams
34-
beams: typing.List[DFBeam] = []
44+
# mass_ctrs = []
45+
# crt_brep = i_breps[5]
46+
breps_repaired = []
3547
for brep in i_breps:
36-
beam = DFBeam.from_brep(brep)
37-
beams.append(beam)
3848

39-
# assembly
40-
assembly1 = DFAssembly(beams, i_assembly_name)
49+
# convert mesh to brep object
50+
mesh=Rhino.Geometry.Mesh()
51+
mesh_parts=Rhino.Geometry.Mesh.CreateFromBrep(
52+
brep,
53+
Rhino.Geometry.MeshingParameters.Coarse)
54+
for mesh_part in mesh_parts: mesh.Append(mesh_part)
55+
mesh.Compact()
56+
mesh.MergeAllCoplanarFaces(Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance, True)
57+
# o_debug.append(mesh)
58+
59+
# get the obb
60+
df_mesh = diffCheck.df_cvt_bindings.cvt_rhmesh_2_dfmesh(mesh)
61+
df_cloud = df_mesh.sample_points_uniformly(200)
62+
df_OBB = df_cloud.get_tight_bounding_box()
63+
rh_OBB = diffCheck.df_cvt_bindings.cvt_dfOBB_2_rhbrep(df_OBB)
64+
65+
# check if the OBB is closed
66+
# print(f"OBB is closed: {rh_OBB.IsSolid}") # FIXME: brep is not closed
67+
# o_debug.append(rh_OBB)
68+
69+
# get OBB_center
70+
rh_OBB_center = rh_OBB.GetBoundingBox(True).Center
71+
# o_debug.append(rh_OBB_center)
72+
73+
# local axis system get the longest/shortes edge of the rh_OBB with a lambda function
74+
edges = rh_OBB.Edges
75+
edge_lengths = [edge.GetLength() for edge in edges]
76+
longest_edge = edges[edge_lengths.index(max(edge_lengths))]
77+
shortest_edge = edges[edge_lengths.index(min(edge_lengths))]
78+
79+
# scale the box in the longest edge direction by 1.5 from center on both directions
80+
rh_OBB_zaxis = rg.Vector3d(longest_edge.PointAt(1) - longest_edge.PointAt(0))
81+
rh_OBB_plane = rg.Plane(rh_OBB_center, rh_OBB_zaxis)
82+
scale_factor = 0.09
83+
xform = rg.Transform.Scale(
84+
rh_OBB_plane,
85+
1-scale_factor,
86+
1-scale_factor,
87+
1+scale_factor
88+
)
89+
rh_OBB.Transform(xform)
90+
91+
# get all the centers of the faces
92+
# face_centers = []
93+
faces = {}
94+
for idx, face in enumerate(brep.Faces):
95+
face_center = rg.AreaMassProperties.Compute(face).Centroid
96+
if rh_OBB.IsPointInside(face_center, sc.doc.ModelAbsoluteTolerance, True):
97+
# face_centers.append(face_center)
98+
faces[idx] = (face, True)
99+
# o_debug.append(brep.Faces[idx])
100+
else:
101+
faces[idx] = (face, False)
102+
# o_debug.append(brep.Faces[idx])
103+
104+
face_jointid = {} # face : joint id (int)
105+
joint_counter = 0
106+
for key, value in faces.items():
107+
# print(f"Face {key} is inside: {value[1]}")
108+
if value[1]:
109+
face_jointid[key] = joint_counter
110+
adjacent_faces = value[0].AdjacentFaces()
111+
for adj_face in adjacent_faces:
112+
if faces[adj_face][1]:
113+
face_jointid[value] = joint_counter
114+
joint_counter += 1
115+
else:
116+
face_jointid[value] = None
117+
118+
o_sides = [faces[key][0] for key, value in faces.items() if not value[1]]
119+
o_joints = [faces[key][0] for key, value in faces.items() if value[1]]
120+
121+
122+
123+
124+
# get the faces that are t
125+
126+
127+
########################################
128+
129+
# for f in crt_brep.Faces:
130+
# mass_ctr = rg.AreaMassProperties.Compute(f).Centroid
131+
# is_inside : bool = aabb.Contains(mass_ctr, strict=True)
132+
# print(f"Face {f} is inside: {is_inside}")
133+
# if is_inside:
134+
# mass_ctrs.append(mass_ctr)
135+
# o_debug = mass_ctrs
136+
137+
# # beams
138+
# beams: typing.List[DFBeam] = []
139+
# for brep in i_breps:
140+
# beam = DFBeam.from_brep(brep)
141+
# beams.append(beam)
142+
143+
# # assembly
144+
# assembly1 = DFAssembly(beams, i_assembly_name)
41145

42-
# dump the xml
43-
xml: str = assembly1.to_xml()
44-
if i_dump:
45-
assembly1.dump_xml(xml, i_export_dir)
46-
o_xml = xml
146+
# # dump the xml
147+
# xml: str = assembly1.to_xml()
148+
# if i_dump:
149+
# assembly1.dump_xml(xml, i_export_dir)
150+
# o_xml = xml
47151

48-
# show the joint/side faces
49-
o_joints = [jf.to_brep() for jf in assembly1.all_joint_faces]
50-
o_sides = [sf.to_brep() for sf in assembly1.all_side_faces]
152+
# # show the joint/side faces
153+
# o_joints = [jf.to_brep() for jf in assembly1.all_joint_faces]
154+
# o_sides = [sf.to_brep() for sf in assembly1.all_side_faces]
51155

52156
return o_xml, o_joints, o_sides, o_debug
53157

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@ Summary: DiffCheck is a package to check the differences between two timber stru
55
Home-page: https://github.com/diffCheckOrg/diffCheck
66
Author: Andrea Settimi, Damien Gilliard, Eleni Skevaki, Marirena Kladeftira, Julien Gamerro, Stefana Parascho, and Yves Weinand
77
Author-email: andrea.settimi@epfl.ch
8-
License: UNKNOWN
9-
Platform: UNKNOWN
108
Classifier: License :: OSI Approved :: MIT License
119
Classifier: Programming Language :: Python :: 3
1210
Classifier: Programming Language :: Python :: 3.9
1311
Description-Content-Type: text/markdown
12+
Requires-Dist: numpy
13+
Requires-Dist: pybind11>=2.5.0
1414

1515
# DiffCheck Grasshopper Plugin
1616

1717
DiffCheck is a plugin for Rhino/Grasshopper that allows the user to compare a 3D model with its scan.
1818

1919
More information to come
20-

src/gh/diffCheck/diffCheck/df_cvt_bindings.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import Rhino
88
import Rhino.Geometry as rg
9+
import scriptcontext as sc
910

1011
from diffCheck import diffcheck_bindings
1112

@@ -164,4 +165,34 @@ def cvt_rhmesh_2_dfmesh(rh_mesh: rg.Mesh) -> diffcheck_bindings.dfb_geometry.DFM
164165
colors_vertex.append([color.R, color.G, color.B])
165166
df_mesh.colors_vertex = colors_vertex
166167

167-
return df_mesh
168+
return df_mesh
169+
170+
def cvt_dfOBB_2_rhbrep(df_OBB) -> rg.Box:
171+
""" Convert a diffCheck OBB to a Rhino Brep.
172+
173+
:param df_OBB: diffCheck OBB
174+
175+
:return rh_obb_brep: the brep box object
176+
"""
177+
rh_pts = []
178+
for pt in df_OBB:
179+
rh_pts.append(rg.Point3d(pt[0], pt[1], pt[2]))
180+
181+
surfaces = []
182+
surfaces.append(rg.NurbsSurface.CreateFromCorners(rh_pts[0], rh_pts[1], rh_pts[7], rh_pts[2]))
183+
surfaces.append(rg.NurbsSurface.CreateFromCorners(rh_pts[0], rh_pts[1], rh_pts[6], rh_pts[3]))
184+
surfaces.append(rg.NurbsSurface.CreateFromCorners(rh_pts[3], rh_pts[6], rh_pts[4], rh_pts[5]))
185+
surfaces.append(rg.NurbsSurface.CreateFromCorners(rh_pts[2], rh_pts[7], rh_pts[4], rh_pts[5]))
186+
surfaces.append(rg.NurbsSurface.CreateFromCorners(rh_pts[1], rh_pts[6], rh_pts[4], rh_pts[7]))
187+
surfaces.append(rg.NurbsSurface.CreateFromCorners(rh_pts[0], rh_pts[3], rh_pts[5], rh_pts[2]))
188+
189+
rh_obb_brep = rg.Brep.JoinBreps([rg.Brep.CreateFromSurface(srf) for srf in surfaces], sc.doc.ModelAbsoluteTolerance)[0]
190+
191+
if rh_obb_brep is None:
192+
raise ValueError("The OBB could not be converted to a Rhino Brep")
193+
if not rh_obb_brep.IsValid:
194+
raise ValueError("The OBB Rhino Brep is not valid")
195+
if not rh_obb_brep.IsSolid:
196+
raise ValueError("The OBB Rhino Brep is not solid")
197+
198+
return rh_obb_brep

src/gh/diffCheck/diffCheck/df_joint_detector.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,22 @@ def run(self) :
7373
# bring to plane xy
7474
x_form = diffCheck.df_transformations.pln_2_pln_world_transform(self.brep)
7575
if x_form is None:
76+
raise ValueError("The brep is not planar, cannot bring to XY plane.")
7677
return None
7778

7879
# reverse the transformation
7980
x_form_back = diffCheck.df_transformations.get_inverse_transformation(x_form)
8081

8182
# compute the bounding box and inflate to include butt joints typo
82-
bbox = self.brep.GetBoundingBox(True)
83-
diagonal = bbox.Diagonal
83+
aabb = self.brep.GetBoundingBox(True)
84+
diagonal = aabb.Diagonal
8485
scaling_factor = diagonal.Length / 10
85-
bbox.Inflate(scaling_factor, 0, 0)
86-
bbox_b = bbox.ToBrep()
86+
aabb.Inflate(scaling_factor, -0.01, -0.01)
87+
aabb_b = aabb.ToBrep()
8788

8889
# boolean difference between the bounding box and the brep transformed
8990
breps_from_booldiff = Rhino.Geometry.Brep.CreateBooleanDifference(
90-
bbox_b, self.brep, sc.doc.ModelAbsoluteTolerance)
91+
aabb_b, self.brep, sc.doc.ModelAbsoluteTolerance)
9192
if breps_from_booldiff is None or len(breps_from_booldiff) == 0:
9293
ghenv.Component.AddRuntimeMessage(RML.Error, "No breps found after boolean difference.")
9394

0 commit comments

Comments
 (0)