From 373b8333da7e804033d5cc53c314f592db71095e Mon Sep 17 00:00:00 2001 From: DamienGilliard <127743632+DamienGilliard@users.noreply.github.com> Date: Sun, 8 Mar 2026 17:40:56 +0100 Subject: [PATCH 01/10] feat: create compute_oriented_bounding_box function in utils --- src/gh/diffCheck/diffCheck/df_geometries.py | 9 ++++++-- src/gh/diffCheck/diffCheck/df_util.py | 25 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/gh/diffCheck/diffCheck/df_geometries.py b/src/gh/diffCheck/diffCheck/df_geometries.py index 99d4c531..da348dc3 100644 --- a/src/gh/diffCheck/diffCheck/df_geometries.py +++ b/src/gh/diffCheck/diffCheck/df_geometries.py @@ -521,13 +521,18 @@ def compute_plane(self) -> rg.Plane: :return plane: The plane of the beam """ - beam_direction = self.axis.Direction + bounding_geometry = diffCheck.df_util.compute_oriented_bounding_box(self.to_brep()) + center = Rhino.Geometry.AreaMassProperties.Compute(bounding_geometry).Centroid + edge_lengths = [edge.GetLength() for edge in bounding_geometry.Edges] + longest_edge = bounding_geometry.Edges[edge_lengths.index(max(edge_lengths))] + z_axis = rg.Vector3d(longest_edge.PointAt(1) - longest_edge.PointAt(0)) + df_faces = [face for face in self.faces] sorted_df_faces = sorted(df_faces, key=lambda face: Rhino.Geometry.AreaMassProperties.Compute(face._rh_brepface).Area if face._rh_brepface else 0, reverse=True) largest_side_face_normal = sorted_df_faces[0].normal rh_largest_side_face_normal = rg.Vector3d(largest_side_face_normal[0], largest_side_face_normal[1], largest_side_face_normal[2]) - return rg.Plane(self.center, rg.Vector3d.CrossProduct(beam_direction, rh_largest_side_face_normal), rh_largest_side_face_normal) + return rg.Plane(center, rg.Vector3d.CrossProduct(z_axis, rh_largest_side_face_normal), rh_largest_side_face_normal) def compute_joint_distances_to_midpoint(self) -> typing.List[float]: """ diff --git a/src/gh/diffCheck/diffCheck/df_util.py b/src/gh/diffCheck/diffCheck/df_util.py index ba35f5e4..ce079f27 100644 --- a/src/gh/diffCheck/diffCheck/df_util.py +++ b/src/gh/diffCheck/diffCheck/df_util.py @@ -2,6 +2,10 @@ import Rhino.Geometry as rg import scriptcontext as sc +import diffCheck.diffcheck_bindings +import diffCheck.df_cvt_bindings +import numpy as np + import typing @@ -180,3 +184,24 @@ def merge_shared_indexes(original_dict): if not intersection_found: new_dict[key] = (face, indexes) return new_dict + +def compute_oriented_bounding_box(brep): + """ + Computes the oriented bounding box of a brep. + We use the point cloud of the vertices of the brep's 4 largest faces to compute the bounding box. + + :param brep: the brep to compute the bounding box of + :return: the oriented bounding box of the brep + """ + df_cloud = diffCheck.diffcheck_bindings.dfb_geometry.DFPointCloud() + sorted_faces = sorted(brep.Faces, key=lambda f : Rhino.Geometry.AreaMassProperties.Compute(f.ToBrep()).Area, reverse = True) + if len(sorted_faces) > 4: + largest_faces = sorted_faces[:4] + else: + largest_faces = sorted_faces + bb_vertices = [] + for face in largest_faces: + for v in face.ToBrep().Vertices: + bb_vertices.append(Rhino.Geometry.Point3d(v.Location.X, v.Location.Y, v.Location.Z)) + df_cloud.points = [np.array([vertex.X, vertex.Y, vertex.Z]).reshape(3, 1) for vertex in bb_vertices] + return diffCheck.df_cvt_bindings.cvt_dfOBB_2_rhbrep(df_cloud.get_tight_bounding_box()) From 4e581a234a055e91efadea8c0df85782527c3470 Mon Sep 17 00:00:00 2001 From: DamienGilliard <127743632+DamienGilliard@users.noreply.github.com> Date: Sun, 8 Mar 2026 18:05:51 +0100 Subject: [PATCH 02/10] fix: exclude poits out of face from brep face loop in DFFace.from_brep_face method --- src/gh/diffCheck/diffCheck/df_geometries.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/gh/diffCheck/diffCheck/df_geometries.py b/src/gh/diffCheck/diffCheck/df_geometries.py index da348dc3..9240e815 100644 --- a/src/gh/diffCheck/diffCheck/df_geometries.py +++ b/src/gh/diffCheck/diffCheck/df_geometries.py @@ -178,8 +178,17 @@ def from_brep_face(cls, loop_vertices = loop_curve.Points loop = [] for l_v in loop_vertices: - vertex = DFVertex(l_v.X, l_v.Y, l_v.Z) - loop.append(vertex) + rg_pt = rg.Point3d(l_v.X, l_v.Y, l_v.Z) + res = loop_curve.ClosestPoint(rg_pt) + if res: + t = res[1] + else: + t = 0 # this is a fallback, but it should not happen since the point is on the curve + point_on_curve = loop_curve.PointAt(t) + distance = rg.Point3d.DistanceTo(rg_pt, point_on_curve) + if distance < 10 * Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance: + vertex = DFVertex(l_v.X, l_v.Y, l_v.Z) + loop.append(vertex) all_loops.append(loop) df_face = cls(all_loops, joint_id) From 2325233c231329472a666e9c2dbc8c359501e2e5 Mon Sep 17 00:00:00 2001 From: DamienGilliard <127743632+DamienGilliard@users.noreply.github.com> Date: Sun, 8 Mar 2026 18:35:32 +0100 Subject: [PATCH 03/10] fix: slight refactor of .run method in JointDetector --- src/gh/diffCheck/diffCheck/df_joint_detector.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/gh/diffCheck/diffCheck/df_joint_detector.py b/src/gh/diffCheck/diffCheck/df_joint_detector.py index b8fa4678..dee4e94e 100644 --- a/src/gh/diffCheck/diffCheck/df_joint_detector.py +++ b/src/gh/diffCheck/diffCheck/df_joint_detector.py @@ -7,8 +7,6 @@ import diffCheck.df_util import diffCheck.df_transformations -import numpy as np - @dataclass class JointDetector: @@ -140,24 +138,21 @@ def run(self): :return: a list of faces from joins and faces """ - - # brep vertices to cloud - df_cloud = diffCheck.diffcheck_bindings.dfb_geometry.DFPointCloud() - df_cloud.points = [np.array([vertex.Location.X, vertex.Location.Y, vertex.Location.Z]).reshape(3, 1) for vertex in self.brep.Vertices] if self.is_roundwood: bounding_geometry = self._find_largest_cylinder() else: - bounding_geometry = diffCheck.df_cvt_bindings.cvt_dfOBB_2_rhbrep(df_cloud.get_tight_bounding_box()) + bounding_geometry = diffCheck.df_util.compute_oriented_bounding_box(self.brep) # scale the bounding geometry in the longest edge direction by 1.5 from center on both directions - rh_Bounding_geometry_center = bounding_geometry.GetBoundingBox(True).Center + rh_Bounding_geometry_center = Rhino.Geometry.AreaMassProperties.Compute(bounding_geometry).Centroid edges = bounding_geometry.Edges edge_lengths = [edge.GetLength() for edge in edges] longest_edge = edges[edge_lengths.index(max(edge_lengths))] rh_Bounding_geometry_zaxis = rg.Vector3d(longest_edge.PointAt(1) - longest_edge.PointAt(0)) + self.boudning_geometry_z_axis = rh_Bounding_geometry_zaxis rh_Bounding_geometry_plane = rg.Plane(rh_Bounding_geometry_center, rh_Bounding_geometry_zaxis) - scale_factor = 0.1 + scale_factor = 0.15 xform = rg.Transform.Scale( rh_Bounding_geometry_plane, 1 - scale_factor, From 5f0cf7ad8a7a409aa8200258f38e2da983d46faf Mon Sep 17 00:00:00 2001 From: DamienGilliard <127743632+DamienGilliard@users.noreply.github.com> Date: Sun, 8 Mar 2026 21:48:51 +0100 Subject: [PATCH 04/10] feat: add allow_curved_joint_faces parameter in joint detector and DFBeam constructor --- src/gh/diffCheck/diffCheck/df_geometries.py | 4 ++-- src/gh/diffCheck/diffCheck/df_joint_detector.py | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/gh/diffCheck/diffCheck/df_geometries.py b/src/gh/diffCheck/diffCheck/df_geometries.py index 9240e815..ef1a342f 100644 --- a/src/gh/diffCheck/diffCheck/df_geometries.py +++ b/src/gh/diffCheck/diffCheck/df_geometries.py @@ -604,13 +604,13 @@ def compute_joint_angles(self) -> typing.List[float]: return jointface_angles @classmethod - def from_brep_face(cls, brep, is_roundwood=False): + def from_brep_face(cls, brep, is_roundwood=False, allow_curved_joint_faces=False): """ Create a DFBeam from a RhinoBrep object. It also removes duplicates and creates a list of unique faces. """ faces : typing.List[DFFace] = [] - data_faces = diffCheck.df_joint_detector.JointDetector(brep, is_roundwood).run() + data_faces = diffCheck.df_joint_detector.JointDetector(brep, is_roundwood).run(allow_curved_joint_faces) for data in data_faces: face = DFFace.from_brep_face(data[0], data[1]) faces.append(face) diff --git a/src/gh/diffCheck/diffCheck/df_joint_detector.py b/src/gh/diffCheck/diffCheck/df_joint_detector.py index dee4e94e..93a1d454 100644 --- a/src/gh/diffCheck/diffCheck/df_joint_detector.py +++ b/src/gh/diffCheck/diffCheck/df_joint_detector.py @@ -76,7 +76,7 @@ def _find_largest_cylinder(self): return largest_cylinder - def _find_joint_faces(self, bounding_geometry): + def _find_joint_faces(self, bounding_geometry, allow_curved_joint_faces=False): """ Finds the brep faces that are joint faces. @@ -98,7 +98,11 @@ def _find_joint_faces(self, bounding_geometry): face_centroid = rg.AreaMassProperties.Compute(face).Centroid coord = face.ClosestPoint(face_centroid) projected_centroid = face.PointAt(coord[1], coord[2]) - faces[idx] = (face, + if allow_curved_joint_faces: + faces[idx] = (face, + bounding_geometry.IsPointInside(projected_centroid, sc.doc.ModelAbsoluteTolerance, True)) + else: + faces[idx] = (face, bounding_geometry.IsPointInside(projected_centroid, sc.doc.ModelAbsoluteTolerance, True) * face.IsPlanar(1 * sc.doc.ModelAbsoluteTolerance)) @@ -130,7 +134,7 @@ def _compute_adjacency_of_faces(self, faces): return adjacency_of_faces - def run(self): + def run(self, allow_curved_joint_faces=False): """ Run the joint detector. We use a dictionary to store the faces of the cuts based wethear they are cuts or holes. - for cuts: If it is a cut we return the face, and the id of the joint the faces belongs to. @@ -150,7 +154,6 @@ def run(self): longest_edge = edges[edge_lengths.index(max(edge_lengths))] rh_Bounding_geometry_zaxis = rg.Vector3d(longest_edge.PointAt(1) - longest_edge.PointAt(0)) - self.boudning_geometry_z_axis = rh_Bounding_geometry_zaxis rh_Bounding_geometry_plane = rg.Plane(rh_Bounding_geometry_center, rh_Bounding_geometry_zaxis) scale_factor = 0.15 xform = rg.Transform.Scale( @@ -161,7 +164,7 @@ def run(self): ) bounding_geometry.Transform(xform) - faces = self._find_joint_faces(bounding_geometry) + faces = self._find_joint_faces(bounding_geometry, allow_curved_joint_faces) adjacency_of_faces = self._compute_adjacency_of_faces(faces) adjacency_of_faces = diffCheck.df_util.merge_shared_indexes(adjacency_of_faces) joint_face_ids = [[key] + value[1] for key, value in adjacency_of_faces.items()] From f458f69982f904e78bedfc6935b6cb4cb22be9a9 Mon Sep 17 00:00:00 2001 From: DamienGilliard <127743632+DamienGilliard@users.noreply.github.com> Date: Sun, 8 Mar 2026 21:51:25 +0100 Subject: [PATCH 05/10] feat: add allow_curved_joint_faces parameter in DF_build_assembly component --- src/gh/components/DF_build_assembly/code.py | 8 ++++++-- src/gh/components/DF_build_assembly/metadata.json | 12 ++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/gh/components/DF_build_assembly/code.py b/src/gh/components/DF_build_assembly/code.py index 0be4fa94..df54156f 100644 --- a/src/gh/components/DF_build_assembly/code.py +++ b/src/gh/components/DF_build_assembly/code.py @@ -14,7 +14,8 @@ class DFBuildAssembly(component): def RunScript(self, i_assembly_name, i_breps : System.Collections.Generic.IList[Rhino.Geometry.Brep], - i_is_roundwood : bool): + i_is_roundwood : bool, + i_allow_curved_joint_faces : bool): beams: typing.List[DFBeam] = [] if i_assembly_name is None or i_breps is None: @@ -23,8 +24,11 @@ def RunScript(self, if i_is_roundwood is None: i_is_roundwood = False + if i_allow_curved_joint_faces is None: + i_allow_curved_joint_faces = False + for brep in i_breps: - beam = DFBeam.from_brep_face(brep, i_is_roundwood) + beam = DFBeam.from_brep_face(brep, i_is_roundwood, i_allow_curved_joint_faces) beams.append(beam) o_assembly = DFAssembly(beams, i_assembly_name) diff --git a/src/gh/components/DF_build_assembly/metadata.json b/src/gh/components/DF_build_assembly/metadata.json index 18c7a446..b8f31106 100644 --- a/src/gh/components/DF_build_assembly/metadata.json +++ b/src/gh/components/DF_build_assembly/metadata.json @@ -48,6 +48,18 @@ "wireDisplay": "default", "sourceCount": 0, "typeHintID": "bool" + }, + { + "name": "i_allow_curved_joint_faces", + "nickname": "i_allow_curved_joint_faces", + "description": "Whether to allow curved faces as joint faces.", + "optional": true, + "allowTreeAccess": false, + "showTypeHints": true, + "scriptParamAccess": "item", + "wireDisplay": "default", + "sourceCount": 0, + "typeHintID": "bool" } ], "outputParameters": [ From e87984ac57f8f91cab4eefe46a1c90c9bfd3c08c Mon Sep 17 00:00:00 2001 From: DamienGilliard <127743632+DamienGilliard@users.noreply.github.com> Date: Sun, 8 Mar 2026 22:22:36 +0100 Subject: [PATCH 06/10] feat: align detected pose vector to DFBeam's (no vector reversing) --- src/gh/diffCheck/diffCheck/df_poses.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/gh/diffCheck/diffCheck/df_poses.py b/src/gh/diffCheck/diffCheck/df_poses.py index 98f836c4..6080c532 100644 --- a/src/gh/diffCheck/diffCheck/df_poses.py +++ b/src/gh/diffCheck/diffCheck/df_poses.py @@ -132,25 +132,23 @@ def select_vectors(vectors, previous_xDirection, previous_yDirection): if previous_xDirection is not None and previous_yDirection is not None: sorted_vectors_by_alignment = sorted(vectors, key=lambda v: abs(compute_dot_product(v, previous_xDirection)), reverse=True) new_xDirection = sorted_vectors_by_alignment[0] + else: new_xDirection = vectors[0] - - condidates_for_yDirection = [] - for v in vectors: - if compute_dot_product(v, new_xDirection) ** 2 < 0.5: - condidates_for_yDirection.append(v) - - if not condidates_for_yDirection: - return new_xDirection, None - + new_xDirection.Unitize() if previous_xDirection is not None and previous_yDirection is not None: - sorted_vectors_by_perpendicularity = sorted(condidates_for_yDirection, key=lambda v: abs(compute_dot_product(v, previous_yDirection)), reverse=True) - new_xDirection = sorted_vectors_by_alignment[0] + sorted_vectors_by_perpendicularity = sorted(vectors, key=lambda v: abs(compute_dot_product(v, previous_xDirection))) new_yDirection = sorted_vectors_by_perpendicularity[0] - compute_dot_product(sorted_vectors_by_perpendicularity[0], new_xDirection) * new_xDirection + if compute_dot_product(new_xDirection, previous_xDirection) < 0: + new_xDirection = -sorted_vectors_by_alignment[0] + if compute_dot_product(new_yDirection, previous_yDirection) < 0: + new_yDirection = -new_yDirection new_yDirection.Unitize() else: - sorted_vectors = sorted(vectors[1:], key=lambda v: compute_dot_product(v, new_xDirection)**2) + sorted_vectors = sorted(vectors[1:], key=lambda v: abs(compute_dot_product(v, new_xDirection))) new_yDirection = sorted_vectors[0] - compute_dot_product(sorted_vectors[0], new_xDirection) * new_xDirection + if previous_yDirection is not None and compute_dot_product(new_yDirection, previous_yDirection) < 0: + new_yDirection = -new_yDirection new_yDirection.Unitize() return new_xDirection, new_yDirection From 6aae7c5819a0025bd976d3078518c473e5e76fa5 Mon Sep 17 00:00:00 2001 From: DamienGilliard <127743632+DamienGilliard@users.noreply.github.com> Date: Sun, 8 Mar 2026 22:23:46 +0100 Subject: [PATCH 07/10] fix: coherent spacing fix (cleanup) --- src/gh/diffCheck/diffCheck/df_poses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gh/diffCheck/diffCheck/df_poses.py b/src/gh/diffCheck/diffCheck/df_poses.py index 6080c532..eee7a694 100644 --- a/src/gh/diffCheck/diffCheck/df_poses.py +++ b/src/gh/diffCheck/diffCheck/df_poses.py @@ -132,10 +132,10 @@ def select_vectors(vectors, previous_xDirection, previous_yDirection): if previous_xDirection is not None and previous_yDirection is not None: sorted_vectors_by_alignment = sorted(vectors, key=lambda v: abs(compute_dot_product(v, previous_xDirection)), reverse=True) new_xDirection = sorted_vectors_by_alignment[0] - else: new_xDirection = vectors[0] new_xDirection.Unitize() + if previous_xDirection is not None and previous_yDirection is not None: sorted_vectors_by_perpendicularity = sorted(vectors, key=lambda v: abs(compute_dot_product(v, previous_xDirection))) new_yDirection = sorted_vectors_by_perpendicularity[0] - compute_dot_product(sorted_vectors_by_perpendicularity[0], new_xDirection) * new_xDirection @@ -145,10 +145,10 @@ def select_vectors(vectors, previous_xDirection, previous_yDirection): new_yDirection = -new_yDirection new_yDirection.Unitize() else: - sorted_vectors = sorted(vectors[1:], key=lambda v: abs(compute_dot_product(v, new_xDirection))) new_yDirection = sorted_vectors[0] - compute_dot_product(sorted_vectors[0], new_xDirection) * new_xDirection if previous_yDirection is not None and compute_dot_product(new_yDirection, previous_yDirection) < 0: new_yDirection = -new_yDirection new_yDirection.Unitize() + return new_xDirection, new_yDirection From 9a74d41614d302905c1162dd8d6399314a4f464d Mon Sep 17 00:00:00 2001 From: DamienGilliard <127743632+DamienGilliard@users.noreply.github.com> Date: Sun, 8 Mar 2026 22:25:09 +0100 Subject: [PATCH 08/10] fix: reversed x-y order in variable passing --- src/gh/components/DF_pose_estimation/code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gh/components/DF_pose_estimation/code.py b/src/gh/components/DF_pose_estimation/code.py index 60af0e56..7db7703b 100644 --- a/src/gh/components/DF_pose_estimation/code.py +++ b/src/gh/components/DF_pose_estimation/code.py @@ -52,7 +52,7 @@ def RunScript(self, rh_tentative_bb_centroid = Rhino.Geometry.Point3d(df_bb_centroid[0], df_bb_centroid[1], df_bb_centroid[2]) new_xDirection, new_yDirection = df_poses.select_vectors(rh_face_normals, i_assembly.beams[i].plane.XAxis, i_assembly.beams[i].plane.YAxis) - rh_tentative_plane = Rhino.Geometry.Plane(rh_tentative_bb_centroid, new_yDirection, new_xDirection) + rh_tentative_plane = Rhino.Geometry.Plane(rh_tentative_bb_centroid, new_xDirection, new_yDirection) rh_beam_cloud = Rhino.Geometry.PointCloud() for face_cloud in face_clouds: From a999efee1047927e9f987550f387ccfc99f7b9bf Mon Sep 17 00:00:00 2001 From: DamienGilliard <127743632+DamienGilliard@users.noreply.github.com> Date: Sun, 8 Mar 2026 22:31:23 +0100 Subject: [PATCH 09/10] feat: point association a bit more logical and simple --- src/diffCheck/segmentation/DFSegmentation.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/diffCheck/segmentation/DFSegmentation.cc b/src/diffCheck/segmentation/DFSegmentation.cc index d79cba5b..1b9572e8 100644 --- a/src/diffCheck/segmentation/DFSegmentation.cc +++ b/src/diffCheck/segmentation/DFSegmentation.cc @@ -258,22 +258,21 @@ namespace diffCheck::segmentation Eigen::Vector3d segmentCenter; Eigen::Vector3d segmentNormal; - for (auto point : segment->Points){segmentCenter += point;} - if (segment->GetNumPoints() > 0) - { - segmentCenter /= segment->GetNumPoints(); - } - else + if (segment->GetNumPoints() == 0) { DIFFCHECK_WARN("Empty segment. Skipping the segment."); continue; } + segmentCenter = segment->GetAxixAlignedBoundingBox()[0] + (segment->GetAxixAlignedBoundingBox()[1] - segment->GetAxixAlignedBoundingBox()[0])/2.0; + for (auto normal : segment->Normals){segmentNormal += normal;} segmentNormal.normalize(); double currentDistance = (faceCenter - segmentCenter).norm(); double currentDitanceOrthogonalToFace = std::abs((faceCenter - segmentCenter).dot(faceNormal)); double currentAngle = std::abs(sin(acos(faceNormal.dot(faceCenter - segmentCenter)))); - if (std::abs(sin(acos(faceNormal.dot(segmentNormal)))) < angleThreshold && currentDitanceOrthogonalToFace < maximumFaceSegmentDistance && currentDitanceOrthogonalToFace < faceDistance) + if (std::abs(sin(acos(faceNormal.dot(segmentNormal)))) < angleThreshold + && currentDitanceOrthogonalToFace < maximumFaceSegmentDistance + && currentDitanceOrthogonalToFace < faceDistance) { correspondingSegment = segment; faceDistance = currentDitanceOrthogonalToFace; @@ -435,7 +434,9 @@ namespace diffCheck::segmentation double currentDistance = (center - clusterCenter).norm() ; double adaptedDistance = currentDistance * std::abs(dotProduct); - if (std::abs(dotProduct) < angleThreshold && adaptedDistance < distance && currentDistance < (max - min).norm()*associationThreshold) + if (std::abs(dotProduct) < angleThreshold + && adaptedDistance < distance + && currentDistance < (max - min).norm()*associationThreshold) { goodMeshIndex = meshIndex; goodFaceIndex = faceIndex; From 08d0b8dd660ce140f470ed0c53edb85df9049e9c Mon Sep 17 00:00:00 2001 From: DamienGilliard <127743632+DamienGilliard@users.noreply.github.com> Date: Mon, 9 Mar 2026 12:26:45 +0100 Subject: [PATCH 10/10] feat-fix: add extremely important brep.Faces.ShrinkFaces() in components code --- src/gh/components/DF_build_assembly/code.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gh/components/DF_build_assembly/code.py b/src/gh/components/DF_build_assembly/code.py index df54156f..9b554b4f 100644 --- a/src/gh/components/DF_build_assembly/code.py +++ b/src/gh/components/DF_build_assembly/code.py @@ -28,6 +28,7 @@ def RunScript(self, i_allow_curved_joint_faces = False for brep in i_breps: + brep.Faces.ShrinkFaces() beam = DFBeam.from_brep_face(brep, i_is_roundwood, i_allow_curved_joint_faces) beams.append(beam)