Skip to content

Commit 029c5d2

Browse files
committed
WIP-CAP: need cleaning but the new joint detector is in place
1 parent 41bea3f commit 029c5d2

File tree

3 files changed

+83
-138
lines changed

3 files changed

+83
-138
lines changed

src/gh/components/DF_xml_exporter/code.py

Lines changed: 6 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
import diffCheck.diffcheck_bindings
1717
import diffCheck.df_cvt_bindings
1818

19+
import diffCheck.df_joint_detector
20+
import diffCheck.df_geometries
21+
1922

2023
class DFXMLExporter(component):
2124
def RunScript(self,
@@ -36,80 +39,12 @@ def RunScript(self,
3639
o_sides = None
3740
o_debug = None
3841
################
39-
########################################
40-
41-
# # TODO: test
42-
# breps_repaired = []
43-
# for brep in i_breps:
44-
45-
46-
# # brep vertices to cloud
47-
# df_cloud = diffCheck.diffcheck_bindings.dfb_geometry.DFPointCloud()
48-
# brep_vertices = []
49-
# for vertex in brep.Vertices:
50-
# brep_vertices.append(np.array([vertex.Location.X, vertex.Location.Y, vertex.Location.Z]).reshape(3, 1))
51-
# df_cloud.points = brep_vertices
52-
53-
# df_OBB = df_cloud.get_tight_bounding_box()
54-
# rh_OBB = diffCheck.df_cvt_bindings.cvt_dfOBB_2_rhbrep(df_OBB)
55-
56-
# # scale the box in the longest edge direction by 1.5 from center on both directions
57-
# rh_OBB_center = rh_OBB.GetBoundingBox(True).Center
58-
# edges = rh_OBB.Edges
59-
# edge_lengths = [edge.GetLength() for edge in edges]
60-
# longest_edge = edges[edge_lengths.index(max(edge_lengths))]
61-
# shortest_edge = edges[edge_lengths.index(min(edge_lengths))]
62-
63-
# rh_OBB_zaxis = rg.Vector3d(longest_edge.PointAt(1) - longest_edge.PointAt(0))
64-
# rh_OBB_plane = rg.Plane(rh_OBB_center, rh_OBB_zaxis)
65-
# scale_factor = 0.09
66-
# xform = rg.Transform.Scale(
67-
# rh_OBB_plane,
68-
# 1-scale_factor,
69-
# 1-scale_factor,
70-
# 1+scale_factor
71-
# )
72-
# rh_OBB.Transform(xform)
73-
74-
# # check if face's centers are inside the OBB
75-
# faces = {}
76-
# for idx, face in enumerate(brep.Faces):
77-
# face_center = rg.AreaMassProperties.Compute(face).Centroid
78-
# if rh_OBB.IsPointInside(face_center, sc.doc.ModelAbsoluteTolerance, True):
79-
# faces[idx] = (face, True)
80-
# else:
81-
# faces[idx] = (face, False)
82-
83-
# face_jointid = {} # face : joint id (int) or None
84-
# joint_counter = 0
85-
# for key, value in faces.items():
86-
# if value[1]:
87-
# face_jointid[key] = joint_counter
88-
# adjacent_faces = value[0].AdjacentFaces()
89-
# for adj_face in adjacent_faces:
90-
# if faces[adj_face][1]:
91-
# face_jointid[value] = joint_counter
92-
# joint_counter += 1
93-
# else:
94-
# face_jointid[value] = None
95-
96-
# faces_data = []
97-
# for key, value in faces.items():
98-
# faces_data.append((value[0], value[1]))
99-
# print(faces_data)
100-
101-
# o_sides = [faces[key][0] for key, value in faces.items() if not value[1]]
102-
# o_joints = [faces[key][0] for key, value in faces.items() if value[1]]
103-
104-
105-
106-
10742
########################################
10843

10944
# beams
11045
beams: typing.List[DFBeam] = []
11146
for brep in i_breps:
112-
beam = DFBeam.from_brep(brep)
47+
beam = DFBeam.from_brep_face(brep)
11348
beams.append(beam)
11449

11550
# assembly
@@ -122,8 +57,8 @@ def RunScript(self,
12257
o_xml = xml
12358

12459
# show the joint/side faces
125-
o_joints = [jf.to_brep() for jf in assembly1.all_joint_faces]
126-
o_sides = [sf.to_brep() for sf in assembly1.all_side_faces]
60+
o_joints = [jf.to_brep_face() for jf in assembly1.all_joint_faces]
61+
o_sides = [sf.to_brep_face() for sf in assembly1.all_side_faces]
12762

12863
return o_xml, o_joints, o_sides, o_debug
12964

src/gh/diffCheck/diffCheck/df_geometries.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import Rhino
88
import Rhino.Geometry as rg
99

10+
from Grasshopper.Kernel import GH_RuntimeMessageLevel as RML
11+
1012
import xml.etree.ElementTree as ET
1113
from xml.dom.minidom import parseString
1214

@@ -77,6 +79,11 @@ def __post_init__(self):
7779
self.__is_joint = False
7880
self.__id = uuid.uuid4().int
7981

82+
# if df_face is created from a rhino brep face, we store the rhino brep face
83+
self._rh_brepface = None
84+
85+
self.is_cylinder = False
86+
8087
def __repr__(self):
8188
return f"Face id: {len(self.id)}, IsJoint: {self.is_joint} Loops: {len(self.all_loops)}"
8289

@@ -93,11 +100,12 @@ def __hash__(self):
93100

94101
def __eq__(self, other):
95102
if isinstance(other, DFFace):
103+
# check if
96104
return self.all_loops == other.all_loops
97105
return False
98106

99107
@classmethod
100-
def from_brep(cls, brep_face: rg.BrepFace, joint_id: int = None):
108+
def from_brep_face(cls, brep_face: rg.BrepFace, joint_id: int = None):
101109
"""
102110
Create a DFFace from a Rhino Brep face
103111
@@ -107,6 +115,11 @@ def from_brep(cls, brep_face: rg.BrepFace, joint_id: int = None):
107115
"""
108116
all_loops = []
109117

118+
if brep_face.IsCylinder():
119+
cls.is_cylinder = True
120+
df_face._rh_brepface = brep_face
121+
return df_face
122+
110123
for idx, loop in enumerate(brep_face.Loops):
111124
loop_trims = loop.Trims
112125
loop_curve = loop.To3dCurve()
@@ -119,16 +132,24 @@ def from_brep(cls, brep_face: rg.BrepFace, joint_id: int = None):
119132
all_loops.append(loop)
120133

121134
df_face = cls(all_loops, joint_id)
122-
df_face._brepface = brep_face
135+
df_face._rh_brepface = brep_face
123136

124137
return df_face
125138

126-
def to_brep(self):
139+
def to_brep_face(self):
127140
"""
128141
Convert the face to a Rhino Brep planar face
129142
130143
:return brep_face: The Rhino Brep planar face
131144
"""
145+
if self._rh_brepface is not None:
146+
return self._rh_brepface
147+
148+
if self.is_cylinder:
149+
ghenv.Component.AddRuntimeMessage(
150+
RML.Warning, "The DFFace was a cylinder created from scratch \n \
151+
, it cannot convert to brep.")
152+
132153
brep_curves = []
133154

134155
for loop in self.all_loops:
@@ -151,7 +172,15 @@ def to_mesh(self):
151172
152173
:return mesh: The Rhino Mesh object
153174
"""
154-
mesh = rg.Mesh.CreateFromBrep(self.to_brep())[0]
175+
mesh = Rhino.Geometry.Mesh()
176+
mesh_parts = Rhino.Geometry.Mesh.CreateFromBrep(
177+
self.to_brep_face().ToBrep(),
178+
Rhino.Geometry.MeshingParameters.Coarse)
179+
for mesh_part in mesh_parts: mesh.Append(mesh_part)
180+
mesh.Compact()
181+
182+
183+
# mesh = rg.Mesh.CreateFromBrep(self.to_brep_face())[0]
155184
return mesh
156185

157186
@property
@@ -185,15 +214,15 @@ def __post_init__(self):
185214
self.__id = uuid.uuid4().int
186215

187216
@classmethod
188-
def from_brep(cls, brep):
217+
def from_brep_face(cls, brep):
189218
"""
190219
Create a DFBeam from a RhinoBrep object.
191220
It also removes duplicates and creates a list of unique faces.
192221
"""
193222
faces : typing.List[DFFace] = []
194223
data_faces = diffCheck.df_joint_detector.JointDetector(brep).run()
195224
for data in data_faces:
196-
face = DFFace.from_brep(data[0], data[1])
225+
face = DFFace.from_brep_face(data[0], data[1])
197226
faces.append(face)
198227
beam = cls("Beam", faces)
199228
return beam
Lines changed: 42 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import Rhino
32
import scriptcontext as sc
43
import Rhino.Geometry as rg
@@ -9,8 +8,6 @@
98
import diffCheck.df_util
109
import diffCheck.df_transformations
1110

12-
from Grasshopper.Kernel import GH_RuntimeMessageLevel as RML
13-
1411
import numpy as np
1512

1613

@@ -19,31 +16,39 @@ class JointDetector:
1916
"""
2017
This class is responsible for detecting joints in a brep
2118
"""
22-
brep : Rhino.Geometry.Brep
19+
brep: Rhino.Geometry.Brep
20+
2321
def __post_init__(self):
24-
self.brep = self.brep or None
25-
# list of straight cuts
26-
self._cuts : typing.List[rg.Brep] = []
27-
# list of holes
28-
self._holes : typing.List[rg.Brep] = []
29-
# list of mixed joints (cuts+holes)
30-
self._mix : typing.List[rg.Brep]= []
31-
32-
# list of DFFaces from joints and sides
3322
self._faces = []
3423

35-
def _compute_mass_center(self, b_face: rg.BrepFace) -> rg.Point3d:
36-
"""
37-
Compute the mass center of a brep face
38-
:param b_face: The brep face to compute the mass center from
39-
:return mass_center: The mass center of the brep face
40-
"""
41-
amp = rg.AreaMassProperties.Compute(b_face)
42-
if amp:
43-
return amp.Centroid
44-
return None
24+
def _assign_ids(self, joint_face_ids):
25+
""" Return the extended joint ids for each face in the brep """
26+
joint_ids_is_found = [False] * len(joint_face_ids)
27+
joint_ids = [None] * len(joint_face_ids)
28+
id_counter = 0
29+
30+
for idx_1, joint_face_id_1 in enumerate(joint_face_ids):
31+
if joint_ids_is_found[idx_1]:
32+
continue
33+
34+
joint_ids_is_found[idx_1] = True
35+
joint_ids[idx_1] = id_counter
4536

46-
def run(self) :
37+
for idx_2, joint_face_id_2 in enumerate(joint_face_ids):
38+
if any(item in joint_face_id_1 for item in joint_face_id_2):
39+
joint_ids_is_found[idx_2] = True
40+
joint_ids[idx_2] = id_counter
41+
42+
id_counter += 1
43+
44+
extended_ids = [None] * self.brep.Faces.Count
45+
for idx, joint_id in enumerate(joint_ids):
46+
for joint_face_id in joint_face_ids[idx]:
47+
extended_ids[joint_face_id] = joint_id
48+
49+
return extended_ids
50+
51+
def run(self):
4752
"""
4853
Run the joint detector. We use a dictionary to store the faces of the cuts based wethear they are cuts or holes.
4954
- for cuts: If it is a cut we return the face, and the id of the joint the faces belongs to.
@@ -53,59 +58,35 @@ def run(self) :
5358
"""
5459
# brep vertices to cloud
5560
df_cloud = diffCheck.diffcheck_bindings.dfb_geometry.DFPointCloud()
56-
brep_vertices = []
57-
for vertex in self.brep.Vertices:
58-
brep_vertices.append(np.array([vertex.Location.X, vertex.Location.Y, vertex.Location.Z]).reshape(3, 1))
59-
df_cloud.points = brep_vertices
61+
df_cloud.points = [np.array([vertex.Location.X, vertex.Location.Y, vertex.Location.Z]).reshape(3, 1) for vertex in self.brep.Vertices]
6062

61-
df_OBB = df_cloud.get_tight_bounding_box()
62-
rh_OBB = diffCheck.df_cvt_bindings.cvt_dfOBB_2_rhbrep(df_OBB)
63+
rh_OBB = diffCheck.df_cvt_bindings.cvt_dfOBB_2_rhbrep(df_cloud.get_tight_bounding_box())
6364

6465
# scale the box in the longest edge direction by 1.5 from center on both directions
6566
rh_OBB_center = rh_OBB.GetBoundingBox(True).Center
6667
edges = rh_OBB.Edges
6768
edge_lengths = [edge.GetLength() for edge in edges]
6869
longest_edge = edges[edge_lengths.index(max(edge_lengths))]
69-
shortest_edge = edges[edge_lengths.index(min(edge_lengths))]
7070

7171
rh_OBB_zaxis = rg.Vector3d(longest_edge.PointAt(1) - longest_edge.PointAt(0))
7272
rh_OBB_plane = rg.Plane(rh_OBB_center, rh_OBB_zaxis)
7373
scale_factor = 0.09
7474
xform = rg.Transform.Scale(
7575
rh_OBB_plane,
76-
1-scale_factor,
77-
1-scale_factor,
78-
1+scale_factor
76+
1 - scale_factor,
77+
1 - scale_factor,
78+
1 + scale_factor
7979
)
8080
rh_OBB.Transform(xform)
8181

8282
# check if face's centers are inside the OBB
83-
faces = {}
84-
for idx, face in enumerate(self.brep.Faces):
85-
face_center = rg.AreaMassProperties.Compute(face).Centroid
86-
if rh_OBB.IsPointInside(face_center, sc.doc.ModelAbsoluteTolerance, True):
87-
faces[idx] = (face, True)
88-
else:
89-
faces[idx] = (face, False)
90-
91-
face_jointid = {} # face : joint id (int) or None
92-
joint_counter = 0
93-
for key, value in faces.items():
94-
if value[1]:
95-
face_jointid[key] = joint_counter
96-
adjacent_faces = value[0].AdjacentFaces()
97-
for adj_face in adjacent_faces:
98-
if faces[adj_face][1]:
99-
face_jointid[value] = joint_counter
100-
joint_counter += 1
101-
else:
102-
face_jointid[value] = None
103-
104-
o_sides = [faces[key][0] for key, value in faces.items() if not value[1]]
105-
o_joints = [faces[key][0] for key, value in faces.items() if value[1]]
106-
107-
# create the faces
108-
# self._faces = [(face, face_jointid[idx]) for idx, face in faces.items()]
109-
# self._faces = [DFFace.from_brep(face, face_jointid[idx]) for idx, face in faces.items()]
83+
faces = {idx: (face, rh_OBB.IsPointInside(rg.AreaMassProperties.Compute(face).Centroid, sc.doc.ModelAbsoluteTolerance, True)) for idx, face in enumerate(self.brep.Faces)}
84+
85+
# get the proximity faces of the joint faces
86+
joint_face_ids = [[key] + [adj_face for adj_face in value[0].AdjacentFaces() if faces[adj_face][1] and adj_face != key] for key, value in faces.items() if value[1]]
87+
88+
face_ids = self._assign_ids(joint_face_ids)
89+
90+
self._faces = [(face, face_ids[idx]) for idx, face in enumerate(self.brep.Faces)]
11091

11192
return self._faces

0 commit comments

Comments
 (0)