From f8a0c4c66791198b035ee44e3aaa4b3a40d5a368 Mon Sep 17 00:00:00 2001 From: papachap Date: Fri, 9 Aug 2024 19:47:44 +0200 Subject: [PATCH] fully implement step and notch --- src/compas_timber/_fabrication/step_joint.py | 25 +- .../_fabrication/step_joint_notch.py | 316 ++-- tests/compas_timber/gh/test_step_joint.ghx | 1348 +++++++---------- 3 files changed, 702 insertions(+), 987 deletions(-) diff --git a/src/compas_timber/_fabrication/step_joint.py b/src/compas_timber/_fabrication/step_joint.py index 0f007ff68..b9c96c29a 100644 --- a/src/compas_timber/_fabrication/step_joint.py +++ b/src/compas_timber/_fabrication/step_joint.py @@ -1,13 +1,13 @@ import math +from compas.geometry import Box +from compas.geometry import Brep from compas.geometry import Frame from compas.geometry import Line from compas.geometry import Plane +from compas.geometry import Polyline from compas.geometry import Rotation from compas.geometry import Vector -from compas.geometry import Box -from compas.geometry import Brep -from compas.geometry import Polyline from compas.geometry import angle_vectors_signed from compas.geometry import distance_point_point from compas.geometry import intersection_line_plane @@ -428,6 +428,16 @@ def apply(self, beam): raise FeatureApplicationError( cutting_planes[0], tenon_volume, "Failed to trim tenon volume with cutting plane: {}".format(str(e)) ) + # trim tenon volume with second cutting plane if tenon height is greater than step depth + if self.tenon_height > self.step_depth: + try: + tenon_volume.trim(cutting_planes[1]) + except Exception as e: + raise FeatureApplicationError( + cutting_planes[1], + tenon_volume, + "Failed to trim tenon volume with second cutting plane: {}".format(str(e)), + ) # add tenon volume to geometry try: geometry += tenon_volume @@ -646,8 +656,13 @@ def tenon_volume_from_params_and_beam(self, beam): # convert to Brep and trim with ref_side and opp_side tenon_brep = Brep.from_box(tenon_box) - tenon_brep.trim(ref_side.to_plane()) - tenon_brep.trim(opp_side.to_plane()) + try: + tenon_brep.trim(ref_side.to_plane()) + tenon_brep.trim(opp_side.to_plane()) + except Exception as e: + raise FeatureApplicationError( + None, tenon_brep, "Failed to trim tenon volume with cutting planes: {}".format(str(e)) + ) return tenon_brep diff --git a/src/compas_timber/_fabrication/step_joint_notch.py b/src/compas_timber/_fabrication/step_joint_notch.py index 1a8628c9e..c9f944b8a 100644 --- a/src/compas_timber/_fabrication/step_joint_notch.py +++ b/src/compas_timber/_fabrication/step_joint_notch.py @@ -1,10 +1,10 @@ import math +from compas.geometry import Box from compas.geometry import Brep from compas.geometry import Frame from compas.geometry import Line from compas.geometry import Plane -from compas.geometry import Polyhedron from compas.geometry import Polyline from compas.geometry import Rotation from compas.geometry import Vector @@ -427,7 +427,7 @@ def _calculate_displacement_heel(heel_depth, strut_inclination, orientation): # Methods ######################################################################## - def apply(self, geometry, beam): + def apply(self, beam): """Apply the feature to the beam geometry. Parameters @@ -449,6 +449,11 @@ def apply(self, geometry, beam): """ # type: (Brep, Beam) -> Brep + + # compute the geometry of the beam as a Brep and get the reference side + geometry = beam.compute_geometry() + ref_side = beam.side_as_surface(self.ref_side_index) + # get cutting planes from params try: cutting_planes = self.planes_from_params_and_beam(beam) @@ -456,46 +461,87 @@ def apply(self, geometry, beam): raise FeatureApplicationError( None, geometry, "Failed to generate cutting planes from parameters and beam: {}".format(str(e)) ) - # create notch polyedron from planes - # add ref_side plane to create a polyhedron - # !: the beam's ref_side Plane might need to be offsetted to create a valid polyhedron when step_type is "double" - cutting_planes.append(Plane.from_frame(beam.ref_sides[self.ref_side_index])) - try: - notch_polyhedron = Polyhedron.from_planes(cutting_planes) - except Exception as e: - raise FeatureApplicationError( - cutting_planes, geometry, "Failed to create valid polyhedron from cutting planes: {}".format(str(e)) - ) - # convert polyhedron to mesh - try: - notch_mesh = notch_polyhedron.to_mesh() - except Exception as e: - raise FeatureApplicationError( - notch_polyhedron, geometry, "Failed to convert polyhedron to mesh: {}".format(str(e)) - ) - # convert mesh to brep - try: - notch_brep = Brep.from_mesh(notch_mesh) - except Exception as e: - raise FeatureApplicationError(notch_mesh, geometry, "Failed to convert mesh to Brep: {}".format(str(e))) - # apply boolean difference - try: - brep_with_notch = Brep.from_boolean_difference(geometry, notch_brep) - except Exception as e: - raise FeatureApplicationError( - notch_brep, geometry, "Boolean difference operation failed: {}".format(str(e)) - ) - # check if the notch is empty - if not brep_with_notch: - raise FeatureApplicationError( - notch_brep, geometry, "The cutting planes do not create a volume that intersects with beam geometry." - ) - if self.mortise: # !: implement mortise - # create mortise volume and subtract from brep_with_notch - pass + # get box volume for subtracting from geometry + corner_1 = ref_side.point_at(self.start_x, self.start_y) + corner_2 = ref_side.point_at(self.start_x + self.displacement_end, self.start_y + self.notch_width) + subtraction_box = Box.from_corner_corner_height(corner_1, corner_2, max(self.step_depth, self.heel_depth)) + subtraction_box.translate(-ref_side.frame.zaxis * max(self.step_depth, self.heel_depth)) + subtraction_volume = Brep.from_box(subtraction_box) + + if self.step_shape == StepShape.DOUBLE: + # trim geometry with first and last cutting plane + try: + for cutting_plane in [cutting_planes[-1], cutting_planes[0]]: + cutting_plane.normal = cutting_plane.normal * -1 + subtraction_volume.trim(cutting_plane) + except Exception as e: + raise FeatureApplicationError( + cutting_planes[-1], + subtraction_volume, + "Failed to trim geometry with cutting plane: {}".format(str(e)), + ) + # trim geometry with two middle cutting planes + trimmed_geometies = [] + for cutting_plane in cutting_planes[1:-1]: + cutting_plane.normal = cutting_plane.normal * -1 + try: + trimmed_geometies.append(subtraction_volume.trimmed(cutting_plane)) + except Exception as e: + raise FeatureApplicationError( + cutting_plane, + subtraction_volume, + "Failed to trim geometry with cutting plane: {}".format(str(e)), + ) + subtraction_volume = trimmed_geometies + + else: + for cutting_plane in cutting_planes: + cutting_plane.normal = cutting_plane.normal * -1 + try: + subtraction_volume.trim(cutting_plane) + except Exception as e: + raise FeatureApplicationError( + cutting_plane, + subtraction_volume, + "Failed to trim geometry with cutting planes: {}".format(str(e)), + ) + + if self.mortise and self.step_shape == StepShape.STEP: # TODO: check if mortise applies only to step in BTLx + # create mortise volume and subtract from brep + mortise_volume = self.mortise_volume_from_params_and_beam(beam) + # trim mortise volume with cutting plane + try: + mortise_volume.trim(cutting_planes[0]) + except Exception as e: + raise FeatureApplicationError( + cutting_planes[0], + mortise_volume, + "Failed to trim mortise volume with cutting plane: {}".format(str(e)), + ) + # subtract mortise volume from geometry + try: + geometry -= mortise_volume + except Exception as e: + raise FeatureApplicationError( + mortise_volume, + subtraction_volume, + "Failed to subtract mortise volume from geometry: {}".format(str(e)), + ) + + # subtract volume from geometry + if isinstance(subtraction_volume, list): + for sub_vol in subtraction_volume: + try: + geometry -= sub_vol + except Exception as e: + raise FeatureApplicationError( + sub_vol, geometry, "Failed to subtract volume from geometry: {}".format(str(e)) + ) + else: + geometry - subtraction_volume - return brep_with_notch + return geometry def add_mortise(self, mortise_width, mortise_height, beam): """Add a mortise to the existing StepJointNotch instance. @@ -510,7 +556,13 @@ def add_mortise(self, mortise_width, mortise_height, beam): self.mortise = True # self.mortise_width = beam.width / 4 # TODO: should this relate to the beam? typically 1/3 or 1/4 of beam.width self.mortise_width = mortise_width - self.mortise_height = beam.height if mortise_height > beam.height else mortise_height + + if mortise_height > beam.height: # TODO: should this be constrained? + self.mortise_height = beam.height + elif mortise_height < self.step_depth: + self.mortise_height = self.step_depth + else: + self.mortise_height = mortise_height def planes_from_params_and_beam(self, beam): """Calculates the cutting planes from the machining parameters in this instance and the given beam @@ -533,19 +585,16 @@ def planes_from_params_and_beam(self, beam): ref_side = beam.side_as_surface(self.ref_side_index) rot_axis = ref_side.frame.yaxis - # if self.orientation == OrientationType.END: - # rot_axis = -rot_axis # Negative rotation axis for the end cut - if self.step_shape == StepShape.STEP: - return self._calculate_step_planes(ref_side, rot_axis) + return self._calculate_step_planes(ref_side) elif self.step_shape == StepShape.HEEL: - return self._calculate_heel_planes(ref_side, rot_axis) + return self._calculate_heel_planes(ref_side) elif self.step_shape == StepShape.TAPERED_HEEL: - return self._calculate_tapered_heel_planes(ref_side, rot_axis) + return self._calculate_tapered_heel_planes(ref_side) elif self.step_shape == StepShape.DOUBLE: - return self._calculate_double_planes(ref_side, rot_axis) + return self._calculate_double_planes(ref_side) - def _calculate_step_planes(self, ref_side, rot_axis): + def _calculate_step_planes(self, ref_side): """Calculate cutting planes for a step notch.""" # Move the frames to the start and end of the notch to create the cuts if self.strut_inclination > 90: @@ -565,84 +614,66 @@ def _calculate_step_planes(self, ref_side, rot_axis): self.step_depth / (self.displacement_end - self.step_depth / math.tan(math.radians(self.strut_inclination / 2))) ) - rot_long_side = Rotation.from_axis_and_angle(rot_axis, angle_long_side, point=p_origin) + rot_long_side = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_long_side, point=p_origin) cutting_plane_origin.transform(rot_long_side) # Rotate second cutting plane at the end of the notch (short side of the step) angle_short_side = math.radians(180 - self.strut_inclination / 2) - rot_short_side = Rotation.from_axis_and_angle(rot_axis, angle_short_side, point=p_end) + rot_short_side = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_short_side, point=p_end) cutting_plane_end.transform(rot_short_side) else: # Rotate first cutting plane at the start of the notch (short side of the step) - angle_short_side = math.radians((180-self.strut_inclination)/2) - rot_short_side = Rotation.from_axis_and_angle(rot_axis, angle_short_side, point=p_origin) + angle_short_side = math.radians((180 - self.strut_inclination) / 2) + rot_short_side = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_short_side, point=p_origin) cutting_plane_origin.transform(rot_short_side) - #Rotate second cutting plane at the end of the notch (large side of the step) + # Rotate second cutting plane at the end of the notch (large side of the step) angle_long_side = math.atan( self.step_depth - / (self.displacement_end + (self.step_depth / math.tan(math.radians((180 - self.strut_inclination)/2)))) + / ( + self.displacement_end + + (self.step_depth / math.tan(math.radians((180 - self.strut_inclination) / 2))) + ) ) - rot_long_side = Rotation.from_axis_and_angle(rot_axis, angle_long_side, point=p_end) + rot_long_side = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_long_side, point=p_end) cutting_plane_end.transform(rot_long_side) return [Plane.from_frame(cutting_plane_origin), Plane.from_frame(cutting_plane_end)] - def _calculate_heel_planes(self, ref_side, rot_axis): + def _calculate_heel_planes(self, ref_side): """Calculate cutting planes for a heel notch.""" - # if self.strut_inclination > 90: # Move the frames to the start and end of the notch to create the cuts p_origin = ref_side.point_at(self.start_x, self.start_y) p_heel = ref_side.point_at(self.start_x + self.displacement_heel, self.start_y) - cutting_plane_end = Frame(p_origin, ref_side.frame.xaxis, ref_side.frame.yaxis) - cutting_plane_heel = Frame(p_heel, ref_side.frame.xaxis, ref_side.frame.yaxis) + cutting_plane_end = Frame(p_origin, ref_side.frame.xaxis, -ref_side.frame.yaxis) + cutting_plane_heel = Frame(p_heel, ref_side.frame.xaxis, -ref_side.frame.yaxis) # Calculate heel cutting planes angles # Rotate first cutting plane at the start of the notch (short side of the heel) angle_short_side = math.radians(180 - self.strut_inclination) - rot_short_side = Rotation.from_axis_and_angle(rot_axis, angle_short_side, point=p_origin) + rot_short_side = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_short_side, point=p_origin) cutting_plane_end.transform(rot_short_side) # Rotate second cutting plane at the end of the notch (long side of the heel) angle_long_side = math.radians(270 - self.strut_inclination) - rot_long_side = Rotation.from_axis_and_angle(rot_axis, angle_long_side, point=p_heel) + rot_long_side = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_long_side, point=p_heel) cutting_plane_heel.transform(rot_long_side) - # else: - # # Move the frames to the start and end of the notch to create the cuts - # p_end = ref_side.point_at(self.start_x, self.start_y) - # p_heel = ref_side.point_at(self.start_x + self.displacement_heel, self.start_y) - # cutting_plane_heel = Frame(p_heel, ref_side.frame.xaxis, -ref_side.frame.yaxis) - # cutting_plane_end = Frame(p_end, ref_side.frame.xaxis, -ref_side.frame.yaxis) - - # # Calculate heel cutting planes angles - # # Rotate first cutting plane at the displaced start of the notch (long side of the heel) - # angle_long_side = math.radians(90 - self.strut_inclination) - # rot_long_side = Rotation.from_axis_and_angle(rot_axis, angle_long_side, point=p_heel) - # cutting_plane_heel.transform(rot_long_side) - - # # Rotate second cutting plane at the end of the notch (short side of the heel) - # angle_short_side = math.radians(180 - self.strut_inclination) - # rot_short_side = Rotation.from_axis_and_angle(rot_axis, angle_short_side, point=p_end) - # cutting_plane_end.transform(rot_short_side) return [Plane.from_frame(cutting_plane_heel), Plane.from_frame(cutting_plane_end)] - def _calculate_tapered_heel_planes(self, ref_side, rot_axis): + def _calculate_tapered_heel_planes(self, ref_side): """Calculate cutting planes for a tapered heel notch.""" # Move the frames to the start and end of the notch to create the cuts p_origin = ref_side.point_at(self.start_x, self.start_y) p_end = ref_side.point_at(self.start_x + self.displacement_end, self.start_y) - cutting_plane_origin = Frame(p_origin, ref_side.frame.xaxis, ref_side.frame.yaxis) + cutting_plane_origin = Frame(p_origin, ref_side.frame.xaxis, -ref_side.frame.yaxis) cutting_plane_end = Frame(p_end, ref_side.frame.xaxis, ref_side.frame.yaxis) - # Calculate tapered heel cutting planes angles - # if self.strut_inclination > 90: # Rotate first cutting plane at the start of the notch (short side of the heel) angle_short_side = math.radians(180 - self.strut_inclination) - rot_short_side = Rotation.from_axis_and_angle(rot_axis, angle_short_side, point=p_origin) + rot_short_side = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_short_side, point=p_origin) cutting_plane_origin.transform(rot_short_side) # Rotate second cutting plane at the end of the notch (long side of the heel) - angle_long_side = math.atan( self.heel_depth / (abs(self.displacement_end) - abs(self.heel_depth / math.tan(math.radians(self.strut_inclination)))) @@ -651,45 +682,32 @@ def _calculate_tapered_heel_planes(self, ref_side, rot_axis): if self.strut_inclination > 90: angle_long_side = math.radians(180) - angle_long_side - rot_long_side = Rotation.from_axis_and_angle(rot_axis, angle_long_side, point=p_end) + rot_long_side = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_long_side, point=p_end) cutting_plane_end.transform(rot_long_side) - # else: - # # Rotate first cutting plane at the start of the notch (long side of the heel) - # angle_long_side = math.atan( - # self.heel_depth - # / (abs(self.displacement_end) - abs(self.heel_depth / math.tan(math.radians(self.strut_inclination)))) - # ) - # rot_long_side = Rotation.from_axis_and_angle(rot_axis, angle_long_side, point=p_origin) - # cutting_plane_origin.transform(rot_long_side) - - # # Rotate second cutting plane at the end of the notch (short side of the heel) - # angle_short_side = math.radians(180 - self.strut_inclination) - # rot_short_side = Rotation.from_axis_and_angle(rot_axis, angle_short_side, point=p_end) - # cutting_plane_end.transform(rot_short_side) return [Plane.from_frame(cutting_plane_origin), Plane.from_frame(cutting_plane_end)] - def _calculate_double_planes(self, ref_side, rot_axis): + def _calculate_double_planes(self, ref_side): """Calculate cutting planes for a double notch.""" # if self.strut_inclination > 90: # Move the frames to the start and end of the notch to create the cuts p_origin = ref_side.point_at(self.start_x, self.start_y) p_heel = ref_side.point_at(self.start_x + self.displacement_heel, self.start_y) p_end = ref_side.point_at(self.start_x + self.displacement_end, self.start_y) - cutting_plane_origin = Frame(p_origin, ref_side.frame.xaxis, ref_side.frame.yaxis) - cutting_plane_heel_heel = Frame(p_heel, ref_side.frame.xaxis, ref_side.frame.yaxis) + cutting_plane_origin = Frame(p_origin, ref_side.frame.xaxis, -ref_side.frame.yaxis) + cutting_plane_heel_heel = Frame(p_heel, ref_side.frame.xaxis, -ref_side.frame.yaxis) cutting_plane_heel_step = Frame(p_heel, ref_side.frame.xaxis, ref_side.frame.yaxis) - cutting_plane_end = Frame(p_end, ref_side.frame.xaxis, ref_side.frame.yaxis) + cutting_plane_end = Frame(p_end, ref_side.frame.xaxis, -ref_side.frame.yaxis) # Calculate heel cutting planes angles # Rotate first cutting plane at the start of the notch (short side of the heel) angle_short_side_heel = math.radians(180 - self.strut_inclination) - rot_short_side_heel = Rotation.from_axis_and_angle(rot_axis, angle_short_side_heel, point=p_origin) + rot_short_side_heel = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_short_side_heel, point=p_origin) cutting_plane_origin.transform(rot_short_side_heel) # Rotate second cutting plane at the end of the notch (long side of the heel) angle_long_side_heel = math.radians(270 - self.strut_inclination) - rot_long_side_heel = Rotation.from_axis_and_angle(rot_axis, angle_long_side_heel, point=p_heel) + rot_long_side_heel = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_long_side_heel, point=p_heel) cutting_plane_heel_heel.transform(rot_long_side_heel) # Calculate step cutting planes angles @@ -704,54 +722,23 @@ def _calculate_double_planes(self, ref_side, rot_axis): ) if self.strut_inclination < 90: - angle_long_side_step = math.atan(self.step_depth / (self.displacement_end - self.displacement_heel + (self.step_depth / math.tan(math.radians(90 - self.strut_inclination / 2))))) - rot_long_side_step = Rotation.from_axis_and_angle(rot_axis, angle_long_side_step, point=p_heel) + angle_long_side_step = math.atan( + self.step_depth + / ( + self.displacement_end + - self.displacement_heel + + (self.step_depth / math.tan(math.radians(90 - self.strut_inclination / 2))) + ) + ) + rot_long_side_step = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_long_side_step, point=p_heel) cutting_plane_heel_step.transform(rot_long_side_step) # Rotate second cutting plane at the end of the notch (short side of the step) angle_short_side_step = math.radians(180 - self.strut_inclination / 2) if self.strut_inclination < 90: angle_short_side_step = math.radians(90) + angle_short_side_step - rot_short_side_step = Rotation.from_axis_and_angle(rot_axis, angle_short_side_step, point=p_end) + rot_short_side_step = Rotation.from_axis_and_angle(ref_side.frame.yaxis, angle_short_side_step, point=p_end) cutting_plane_end.transform(rot_short_side_step) - # else: - # # Move the frames to the start and end of the notch to create the cuts - # p_origin = ref_side.point_at(self.start_x, self.start_y) - # p_heel = ref_side.point_at(self.start_x + (self.displacement_end - self.displacement_heel), self.start_y) - # p_end = ref_side.point_at(self.start_x + self.displacement_end, self.start_y) - # cutting_plane_origin = Frame(p_origin, ref_side.frame.xaxis, ref_side.frame.yaxis) - # cutting_plane_heel_heel = Frame(p_heel, ref_side.frame.xaxis, ref_side.frame.yaxis) - # cutting_plane_heel_step = Frame(p_heel, ref_side.frame.xaxis, ref_side.frame.yaxis) - # cutting_plane_end = Frame(p_end, ref_side.frame.xaxis, ref_side.frame.yaxis) - - # # Calculate step cutting planes angles - # # Rotate first cutting plane at the start of the notch (short side of the step) - # angle_short_side_step = math.radians(90 + self.strut_inclination / 2) - # rot_short_side_step = Rotation.from_axis_and_angle(rot_axis, angle_short_side_step, point=p_origin) - # cutting_plane_origin.transform(rot_short_side_step) - - # # Rotate second cutting plane at the end of the notch (large side of the step) - # angle_long_side_step = math.radians(180) - math.atan( - # self.step_depth - # / ( - # self.displacement_end - # - self.displacement_heel - # - self.step_depth / math.tan(math.radians(90 - self.strut_inclination / 2)) - # ) - # ) - # rot_long_side_step = Rotation.from_axis_and_angle(rot_axis, angle_long_side_step, point=p_heel) - # cutting_plane_heel_step.transform(rot_long_side_step) - - # # Calculate heel cutting planes angles - # # Rotate first cutting plane at the displaced start of the notch (long side of the heel) - # angle_long_side_heel = math.radians(90 - self.strut_inclination) - # rot_long_side_heel = Rotation.from_axis_and_angle(rot_axis, angle_long_side_heel, point=p_heel) - # cutting_plane_heel_heel.transform(rot_long_side_heel) - - # # Rotate second cutting plane at the end of the notch (short side of the heel) - # angle_short_side_heel = math.radians(180 - self.strut_inclination) - # rot_short_side_heel = Rotation.from_axis_and_angle(rot_axis, angle_short_side_heel, point=p_end) - # cutting_plane_end.transform(rot_short_side_heel) return [ Plane.from_frame(cutting_plane_origin), @@ -770,11 +757,11 @@ def mortise_volume_from_params_and_beam(self, beam): Returns ------- - :class:`compas.geometry.Polyhedron` + :class:`compas.geometry.Brep` The mortise volume. """ - # type: (Beam) -> Mesh + # type: (Beam) -> Brep assert self.strut_inclination is not None assert self.step_shape is not None @@ -793,7 +780,7 @@ def mortise_volume_from_params_and_beam(self, beam): start_y = self.start_y + (self.notch_width - self.mortise_width) / 2 displacement_y = self.mortise_width - step_cutting_planes = self._calculate_step_planes(ref_side, rot_axis) + step_cutting_planes = self._calculate_step_planes(ref_side) step_cutting_plane = step_cutting_planes[1] # the second cutting plane is the one at the end of the step if self.orientation == OrientationType.END: @@ -809,10 +796,10 @@ def mortise_volume_from_params_and_beam(self, beam): # construct polyline for the top face of the mortise mortise_polyline = Polyline([p_1, p_2, p_3, p_4, p_1]) - # calcutate the plane for the extrusion of the polyline - extr_plane = Plane(p_1, ref_side.frame.xaxis) + + # calcutate extrusion vector extr_vector_length = self.mortise_height / math.sin(math.radians(self.strut_inclination)) - extr_vector = extr_plane.normal * extr_vector_length + extr_vector = ref_side.frame.xaxis * extr_vector_length if self.strut_inclination > 90: vector_angle = math.radians(180 - self.strut_inclination) else: @@ -821,15 +808,26 @@ def mortise_volume_from_params_and_beam(self, beam): rot_vect = Rotation.from_axis_and_angle(rot_axis, vector_angle) extr_vector.transform(rot_vect) - + # translate the polyline to create the bottom face of the mortise mortise_polyline_extrusion = mortise_polyline.translated(extr_vector) - # extrude the polyline to create the mortise volume as a Brep - # mortise_volume = Brep.from_extrusion(mortise_polyline, extr_vector, cap_ends=True) - # trim brep with step cutting planes - # mortise_volume.trim(step_cutting_plane) # !: check if the trimming works correctly // add checks - # return mortise_volume - return mortise_polyline, mortise_polyline_extrusion + # create Box from mortise points # TODO: should create Brep directly by extruding the polyline + mortise_points = mortise_polyline.points + mortise_polyline_extrusion.points + mortise_box = Box.from_points(mortise_points) + + # convert to Brep and trim with cutting_planes + mortise_brep = Brep.from_box(mortise_box) + trimming_plane_start = Plane.from_point_and_two_vectors(p_1, extr_vector, ref_side.frame.yaxis) + trimming_plane_end = Plane.from_point_and_two_vectors(p_2, -extr_vector, ref_side.frame.yaxis) + try: + mortise_brep.trim(trimming_plane_start) + mortise_brep.trim(trimming_plane_end) + except Exception as e: + raise FeatureApplicationError( + mortise_brep, None, "Failed to trim mortise volume with cutting planes: {}".format(str(e)) + ) + + return mortise_brep class StepJointNotchParams(BTLxProcessParams): diff --git a/tests/compas_timber/gh/test_step_joint.ghx b/tests/compas_timber/gh/test_step_joint.ghx index 4e2bcd73b..7c11ad7dc 100644 --- a/tests/compas_timber/gh/test_step_joint.ghx +++ b/tests/compas_timber/gh/test_step_joint.ghx @@ -48,10 +48,10 @@ - 78 - 222 + 207 + 153 - 0.151132 + 0.2460933 @@ -95,9 +95,9 @@ - 68 + 70 - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 @@ -264,7 +264,7 @@ from compas_timber.fabrication import BTLx from compas_rhino import unload_modules from compas.scene import SceneObject -from compas_rhino.conversions import frame_to_rhino, plane_to_rhino, surface_to_rhino, polyline_to_rhino +from compas_rhino.conversions import frame_to_rhino, plane_to_rhino, surface_to_rhino, polyline_to_rhino, brep_to_rhino import Rhino.Geometry as rg unload_modules("compas_timber") @@ -277,19 +277,17 @@ plane = main_beam.ref_sides[index] step_joint_notch = StepJointNotch.from_surface_and_beam(plane, beam, notch_limited=False, step_depth=step, heel_depth=heel, strut_height=100.0, tapered_heel=tapered, ref_side_index=ref_side_index) cutting_planes = step_joint_notch.planes_from_params_and_beam(beam) -#print("Orientation: ", step_joint_notch.orientation) -#print("StartX: ", step_joint_notch.start_x) -#print("StrutInclination: ", step_joint_notch.strut_inclination) - +print("Orientation: ", step_joint_notch.orientation) +print("StrutInclination: ", step_joint_notch.strut_inclination) #add mortise if mortise_height > 0: step_joint_notch.add_mortise(beam.width/4, mortise_height, beam) - mortise_polylines = step_joint_notch.mortise_volume_from_params_and_beam(beam) - rg_mortise_polylines = [polyline_to_rhino(polyline) for polyline in mortise_polylines] + mortise_brep = step_joint_notch.mortise_volume_from_params_and_beam(beam) -##apply geometric features -#step_joint_notch.apply(brep, beam) +#apply geometric features +geometry = step_joint_notch.apply(beam) +rg_geometry = brep_to_rhino(geometry) #get btlx params step_joint_notch_params = StepJointNotchParams(step_joint_notch).as_dict() @@ -309,8 +307,8 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) GhPython provides a Python script component - 154 - 194 + 247 + 383 1232 @@ -331,13 +329,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2259 - 368 - 222 + 380 + 203 164 2355 - 450 + 462 @@ -381,13 +379,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2261 - 370 + 382 79 20 2302 - 380 + 392 @@ -412,13 +410,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2261 - 390 + 402 79 20 2302 - 400 + 412 @@ -443,13 +441,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2261 - 410 + 422 79 20 2302 - 420 + 432 @@ -474,13 +472,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2261 - 430 + 442 79 20 2302 - 440 + 452 @@ -505,13 +503,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2261 - 450 + 462 79 20 2302 - 460 + 472 @@ -536,13 +534,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2261 - 470 + 482 79 20 2302 - 480 + 492 @@ -567,13 +565,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2261 - 490 + 502 79 20 2302 - 500 + 512 @@ -598,13 +596,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2261 - 510 + 522 79 20 2302 - 520 + 532 @@ -624,13 +622,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2370 - 370 - 109 + 382 + 90 22 - 2424.5 - 381.4286 + 2415 + 393.4286 @@ -650,13 +648,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2370 - 392 - 109 + 404 + 90 23 - 2424.5 - 404.2857 + 2415 + 416.2857 @@ -676,13 +674,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2370 - 415 - 109 + 427 + 90 23 - 2424.5 - 427.1429 + 2415 + 439.1429 @@ -702,13 +700,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2370 - 438 - 109 + 450 + 90 23 - 2424.5 - 450 + 2415 + 462 @@ -728,13 +726,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2370 - 461 - 109 + 473 + 90 23 - 2424.5 - 472.8571 + 2415 + 484.8571 @@ -742,10 +740,10 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - Script output rg_mortise_polylines. - 1a4781d4-bfe8-4573-86bb-90d0f0ffc197 - rg_mortise_polylines - rg_mortise_polylines + Script output rg_geometry. + b10f1b85-d84a-4d8b-84d3-f956ea4e2805 + rg_geometry + rg_geometry false 0 @@ -754,13 +752,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2370 - 484 - 109 + 496 + 90 23 - 2424.5 - 495.7143 + 2415 + 507.7143 @@ -780,13 +778,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2370 - 507 - 109 - 23 + 519 + 90 + 22 - 2424.5 - 518.5714 + 2415 + 530.5714 @@ -852,207 +850,6 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - - f31d8d7a-7536-4ac8-9c96-fde6ecda4d0a - Cluster - - - - - - 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 - - Contains a cluster of Grasshopper components - true - a5869824-14fc-400f-a69e-f5050392632f - Cluster - Cluster - false - - - - - 5 - 3f3af581-d64e-4909-91e4-3576cf2e9e86 - 4c2588f5-9e63-4ce5-a5e7-50f44fb19cb9 - d28e1b27-74ad-41ab-b017-540fa9111876 - ebd18bdb-78c3-4d40-8a69-e1af30a53c27 - fd03a9d4-272c-4590-9595-4d3107dc0fdc - 3c631e1e-b12f-4297-9535-87b4fdc7b45e - 5d665740-a9cc-4f15-8a38-0dc75e214ae2 - 5d32325d-62cf-40bd-93fe-74af56a2c91e - b360d350-2b53-401b-9420-d9402019cb30 - 796ac502-faba-4bb6-a612-7e3dfb448d98 - - - - - - 2653 - 429 - 72 - 84 - - - 2692 - 471 - - - - - - 4 - 919e146f-30ae-4aae-be34-4d72f555e7da - 4f8984c4-7c7a-4d69-b0a2-183cbb330d20 - 4f8984c4-7c7a-4d69-b0a2-183cbb330d20 - d5967b9f-e8ee-436b-a8ad-29fdcecf32d5 - 1 - 919e146f-30ae-4aae-be34-4d72f555e7da - - - - - Brep to split - ebd18bdb-78c3-4d40-8a69-e1af30a53c27 - Brep - B - true - b0a6568e-06d8-4c68-b393-d8274f661640 - 1 - - - - - - 2655 - 431 - 22 - 20 - - - 2667.5 - 441 - - - - - - - - Contains a collection of three-dimensional axis-systems - d28e1b27-74ad-41ab-b017-540fa9111876 - Plane - Pln - true - 16bc55f9-a035-4099-834e-e9dc0931b695 - 1 - - - - - - 2655 - 451 - 22 - 20 - - - 2667.5 - 461 - - - - - - - - Contains a collection of three-dimensional axis-systems - fd03a9d4-272c-4590-9595-4d3107dc0fdc - Plane - Pln - true - ddc1d959-4491-4f72-b7d5-a74d74b99385 - 1 - - - - - - 2655 - 471 - 22 - 20 - - - 2667.5 - 481 - - - - - - - - 1 - Section curves - 3f3af581-d64e-4909-91e4-3576cf2e9e86 - Curves - C - true - 1a4781d4-bfe8-4573-86bb-90d0f0ffc197 - 1 - - - - - - 2655 - 491 - 22 - 20 - - - 2667.5 - 501 - - - - - - - - 1 - Joined Breps - 4c2588f5-9e63-4ce5-a5e7-50f44fb19cb9 - Breps - B - false - 0 - - - - - - 2707 - 431 - 16 - 80 - - - 2715 - 471 - - - - - - - - - - - - 537b0419-bbc2-4ff4-bf08-afe526367b2c Custom Preview @@ -1062,7 +859,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) Allows for customized geometry previews true - false + true 9e4f0b21-759b-4c9a-8dfb-6654484027c5 Custom Preview Preview @@ -1073,13 +870,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2841 - 514 + 526 48 44 2875 - 536 + 548 @@ -1091,7 +888,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) Geometry G false - 4c2588f5-9e63-4ce5-a5e7-50f44fb19cb9 + 91868622-66e7-4d7d-a5a0-9480a9e4a02a 1 @@ -1099,13 +896,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2843 - 516 + 528 17 20 2853 - 526 + 538 @@ -1126,13 +923,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2843 - 536 + 548 17 20 2853 - 546 + 558 @@ -1172,7 +969,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 0148a65d-6f42-414a-9db7-9a9b2eb78437 Brep Edges @@ -1191,13 +988,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2741 - 439 + 419 72 64 2771 - 471 + 451 @@ -1208,7 +1005,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) Brep B false - 4c2588f5-9e63-4ce5-a5e7-50f44fb19cb9 + 91868622-66e7-4d7d-a5a0-9480a9e4a02a 1 @@ -1216,13 +1013,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2743 - 441 + 421 13 60 2751 - 471 + 451 @@ -1243,13 +1040,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2786 - 441 + 421 25 20 2798.5 - 451 + 431 @@ -1270,13 +1067,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2786 - 461 + 441 25 20 2798.5 - 471 + 451 @@ -1297,13 +1094,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2786 - 481 + 461 25 20 2798.5 - 491 + 471 @@ -1313,7 +1110,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 4f8984c4-7c7a-4d69-b0a2-183cbb330d20 Plane @@ -1335,13 +1132,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2839 - 377 + 371 50 24 2864.272 - 389.9877 + 383.8677 @@ -1349,7 +1146,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 4f8984c4-7c7a-4d69-b0a2-183cbb330d20 Plane @@ -1371,13 +1168,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2838 - 307 + 300 50 24 2863.631 - 319.0432 + 312.9232 @@ -1385,7 +1182,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 4f8984c4-7c7a-4d69-b0a2-183cbb330d20 Plane @@ -1407,13 +1204,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2837 - 242 + 236 50 24 2862.671 - 254.6153 + 248.4953 @@ -1421,7 +1218,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 59e0b89a-e487-49f8-bab8-b5bab16be14c Panel @@ -1444,16 +1241,16 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2261 - 285 - 221 + 293 + 201 85 0 0 0 - 2261.57 - 285.1643 + 2261.519 + 293.1643 @@ -1474,7 +1271,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -1499,7 +1296,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -1524,7 +1321,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + a77d0879-94c2-4101-be44-e4a616ffeb0c 5f86fa9f-c62b-50e8-157b-b454ef3e00fa @@ -1544,13 +1341,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2842 - 420 + 440 46 84 2874 - 462 + 482 @@ -1570,13 +1367,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2844 - 422 + 442 15 20 2853 - 432 + 452 @@ -1597,13 +1394,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2844 - 442 + 462 15 20 2853 - 452 + 472 @@ -1653,13 +1450,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2844 - 462 + 482 15 20 2853 - 472 + 492 @@ -1679,13 +1476,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2844 - 482 + 502 15 20 2853 - 492 + 512 @@ -1715,7 +1512,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -1740,7 +1537,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -1765,7 +1562,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 410755b1-224a-4c1e-a407-bf32fb45ea7e 00000000-0000-0000-0000-000000000000 @@ -1774,10 +1571,12 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - from compas_rhino.conversions import surface_to_rhino + import compas +from compas_rhino.conversions import surface_to_rhino from compas_timber._fabrication import StepJointNotch from compas_timber._fabrication import StepJointNotchParams from compas_timber._fabrication import StepJoint +from compas_timber._fabrication import StepJointParams from compas_timber.model import TimberModel from compas_timber.fabrication import BTLx @@ -1785,7 +1584,7 @@ from compas_timber.fabrication import BTLx from compas_rhino import unload_modules from compas.scene import SceneObject -from compas_rhino.conversions import frame_to_rhino, plane_to_rhino, surface_to_rhino, polyline_to_rhino +from compas_rhino.conversions import frame_to_rhino, plane_to_rhino, surface_to_rhino, polyline_to_rhino, brep_to_rhino, mesh_to_rhino import Rhino.Geometry as rg unload_modules("compas_timber") @@ -1797,44 +1596,35 @@ plane = cross_beam.ref_sides[index] #create step_joint step_joint = StepJoint.from_plane_and_beam(plane, beam, step, heel, tapered, ref_side_index) cutting_planes = step_joint.planes_from_params_and_beam(beam) -# -###create step_joint_notch -##step_joint_notch = StepJointNotch.from_surface_and_beam(plane, beam, notch_limited=False, step_depth=step, heel_depth=heel, strut_height=100.0, tapered_heel=tapered, ref_side_index=ref_side_index) -##cutting_planes = step_joint_notch.planes_from_params_and_beam(beam) -## -##print("Orientation: ", step_joint_notch.orientation) -##print("StartX: ", step_joint_notch.start_x) -##print("StrutInclination: ", step_joint_notch.strut_inclination) -## -## -###add mortise -##if mortise_height > 0: -## step_joint_notch.add_mortise(beam.width/4, mortise_height, beam) -## mortise_polylines = step_joint_notch.mortise_volume_from_params_and_beam(beam) -## -####apply geometric features -###step_joint_notch.apply(brep, beam) -## -###get btlx params -##step_joint_notch_params = StepJointNotchParams(step_joint_notch).as_dict() -##btlx_params = [] -##for key, value in step_joint_notch_params.items(): -## btlx_params.append("{0}: {1}".format(key, value)) -## -## -##vizualize in rhino +print("Orientation: ", step_joint.orientation) +print("StrutInclination: ", step_joint.strut_inclination) + +#add tenon +if tenon_height > 0: + step_joint.add_tenon(cross_beam.width/4, tenon_height) + tenon_volume = step_joint.tenon_volume_from_params_and_beam(beam) + +#apply geometric features +geometry = step_joint.apply(beam) +rg_geometry = brep_to_rhino(geometry) +rg_geometry.MergeCoplanarFaces(0.01) + +#get btlx params +step_joint_params = StepJointParams(step_joint).as_dict() +btlx_params = [] +for key, value in step_joint_params.items(): + btlx_params.append("{0}: {1}".format(key, value)) + +#vizualize in rhino rg_ref_side = frame_to_rhino(beam.ref_sides[ref_side_index]) rg_cutting_plane = frame_to_rhino(plane) rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) -## -##rg_mortise_polylines = [polyline_to_rhino(polyline) for polyline in mortise_polylines] - GhPython provides a Python script component - 248 - 94 + 278 + 159 1232 @@ -1854,19 +1644,19 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2256 - 1265 - 222 + 2258 + 1269 + 199 164 - 2352 - 1347 + 2350 + 1351 - + 8 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 @@ -1876,16 +1666,15 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 - 7 + 6 3ede854e-c753-40eb-84cb-b48008f14fd4 8ec86459-bf01-4409-baee-174d0d2b13d0 8ec86459-bf01-4409-baee-174d0d2b13d0 8ec86459-bf01-4409-baee-174d0d2b13d0 8ec86459-bf01-4409-baee-174d0d2b13d0 8ec86459-bf01-4409-baee-174d0d2b13d0 - 8ec86459-bf01-4409-baee-174d0d2b13d0 - + true @@ -1904,14 +1693,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2258 - 1267 - 79 + 2260 + 1271 + 75 20 2299 - 1277 + 1281 @@ -1935,14 +1724,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2258 - 1287 - 79 + 2260 + 1291 + 75 20 2299 - 1297 + 1301 @@ -1966,14 +1755,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2258 - 1307 - 79 + 2260 + 1311 + 75 20 2299 - 1317 + 1321 @@ -1997,14 +1786,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2258 - 1327 - 79 + 2260 + 1331 + 75 20 2299 - 1337 + 1341 @@ -2028,14 +1817,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2258 - 1347 - 79 + 2260 + 1351 + 75 20 2299 - 1357 + 1361 @@ -2059,14 +1848,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2258 - 1367 - 79 + 2260 + 1371 + 75 20 2299 - 1377 + 1381 @@ -2090,14 +1879,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2258 - 1387 - 79 + 2260 + 1391 + 75 20 2299 - 1397 + 1401 @@ -2106,10 +1895,10 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) true - Script input mortise_height. + Script input tenon_height. 74b917c7-fc1a-4dec-abae-860ed10a0b11 - mortise_height - mortise_height + tenon_height + tenon_height true 0 true @@ -2121,14 +1910,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2258 - 1407 - 79 + 2260 + 1411 + 75 20 2299 - 1417 + 1421 @@ -2147,46 +1936,20 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2367 - 1267 - 109 - 22 + 2365 + 1271 + 90 + 26 - 2421.5 - 1278.429 + 2410 + 1284.333 - - Script output surface. - 8579e7d8-c52b-4634-b03d-5bc56067fd74 - surface - surface - false - 0 - - - - - - 2367 - 1289 - 109 - 23 - - - 2421.5 - 1301.286 - - - - - - Script output rg_cutting_plane. 9fe4a86c-3c6e-4f70-8cbe-630b57b5a0b1 @@ -2199,20 +1962,20 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2367 - 1312 - 109 - 23 + 2365 + 1297 + 90 + 27 - 2421.5 - 1324.143 + 2410 + 1311 - + Script output rg_planes. 6270f634-eb6d-402e-a88f-24f478dcf237 @@ -2225,20 +1988,20 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2367 - 1335 - 109 - 23 + 2365 + 1324 + 90 + 27 - 2421.5 - 1347 + 2410 + 1337.667 - + Script output rg_ref_side. 9c129a89-24d5-45f5-bcea-890db46f3da4 @@ -2251,25 +2014,25 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2367 - 1358 - 109 - 23 + 2365 + 1351 + 90 + 26 - 2421.5 - 1369.857 + 2410 + 1364.333 - + - Script output rg_mortise_polylines. - 9ba6c2c7-77fe-4ea5-96f9-edfa7f161fb3 - rg_mortise_polylines - rg_mortise_polylines + Script output rg_geometry. + 441ff4ac-6060-44cf-965a-55428a9d4cc6 + rg_geometry + rg_geometry false 0 @@ -2277,20 +2040,20 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2367 - 1381 - 109 - 23 + 2365 + 1377 + 90 + 27 - 2421.5 - 1392.714 + 2410 + 1391 - + Script output btlx_params. 269c79e7-4269-4669-b62a-9869376ea11c @@ -2303,14 +2066,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2367 + 2365 1404 - 109 - 23 + 90 + 27 - 2421.5 - 1415.571 + 2410 + 1417.667 @@ -2322,7 +2085,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 57da07bd-ecab-415d-9d86-af36d7073abc Number Slider @@ -2343,7 +2106,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 1675 873 - 160 + 201 20 @@ -2367,7 +2130,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 57da07bd-ecab-415d-9d86-af36d7073abc Number Slider @@ -2412,7 +2175,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 59e0b89a-e487-49f8-bab8-b5bab16be14c Panel @@ -2465,7 +2228,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 57da07bd-ecab-415d-9d86-af36d7073abc Number Slider @@ -2510,7 +2273,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 57da07bd-ecab-415d-9d86-af36d7073abc Number Slider @@ -2555,7 +2318,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 2e78987b-9dfb-42a2-8b76-3923ac8bd91a Boolean Toggle @@ -2566,238 +2329,39 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) Boolean (true/false) toggle dec5089d-c452-417b-a948-4034d6df42ce Boolean Toggle - tapered_heel - false - 0 - true - - - - - - 1663 - 1006 - 133 - 22 - - - - - - - - - - f31d8d7a-7536-4ac8-9c96-fde6ecda4d0a - Cluster - - - - - - 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 - - Contains a cluster of Grasshopper components - true - 7154ee57-be53-4a07-8da4-9858a1faea73 - Cluster - Cluster - false - - - - - 5 - 065c8b93-533c-4d8c-b22d-d9bc535f688e - 6f553506-3c94-4dbc-b2ec-f549b4c30b0c - 8afe827d-4dab-4dde-aea7-476d34f57a1b - e7de4017-7053-4063-8078-ab0ab768ffd7 - fc6af981-1cbe-4ef5-aa1c-23484b153ef3 - 3c631e1e-b12f-4297-9535-87b4fdc7b45e - b360d350-2b53-401b-9420-d9402019cb30 - 5d32325d-62cf-40bd-93fe-74af56a2c91e - 5d665740-a9cc-4f15-8a38-0dc75e214ae2 - fc820447-d987-4fb0-931e-987ca527842b - - - - - - 2643 - 1326 - 79 - 84 - - - 2689 - 1368 - - - - - - 4 - 919e146f-30ae-4aae-be34-4d72f555e7da - 4f8984c4-7c7a-4d69-b0a2-183cbb330d20 - d5967b9f-e8ee-436b-a8ad-29fdcecf32d5 - cb95db89-6165-43b6-9c41-5702bc5bf137 - 1 - 919e146f-30ae-4aae-be34-4d72f555e7da - - - - - Brep to split - 6f553506-3c94-4dbc-b2ec-f549b4c30b0c - Brep - B - true - 55c66290-a177-4518-824a-6a531a1e8086 - 1 - - - - - - 2645 - 1328 - 29 - 20 - - - 2661 - 1338 - - - - - - - - Contains a collection of three-dimensional axis-systems - 8afe827d-4dab-4dde-aea7-476d34f57a1b - Plane - Pln - true - 6270f634-eb6d-402e-a88f-24f478dcf237 - 1 - - - - - - 2645 - 1348 - 29 - 20 - - - 2661 - 1358 - - - - - - - - 1 - Section curves - 065c8b93-533c-4d8c-b22d-d9bc535f688e - Curves - C - true - 9ba6c2c7-77fe-4ea5-96f9-edfa7f161fb3 - 1 - - - - - - 2645 - 1368 - 29 - 20 - - - 2661 - 1378 - - - - - - - - Contains a collection of boolean values - fc6af981-1cbe-4ef5-aa1c-23484b153ef3 - Boolean - Bool - true - 8af59bcf-e43d-4808-b965-440e7d003dfd - 1 - - - - - - 2645 - 1388 - 29 - 20 - - - 2661 - 1398 - - - - - - - - 1 - Joined Breps - e7de4017-7053-4063-8078-ab0ab768ffd7 - Breps - B - false - 0 - - - - - - 2704 - 1328 - 16 - 80 - - - 2712 - 1368 - - - - - - + tapered_heel + false + 0 + false + + + + + + 1663 + 1006 + 133 + 22 + + - + 537b0419-bbc2-4ff4-bf08-afe526367b2c Custom Preview - + Allows for customized geometry previews - false + true + true def048ab-0443-4189-81d6-03594953cdd1 + true Custom Preview Preview @@ -2807,25 +2371,26 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2840 - 1407 + 1423 48 44 2874 - 1429 + 1445 - + Geometry to preview true 977e596e-9c8a-4d5e-a490-c2c39fe7f008 + true Geometry G false - e7de4017-7053-4063-8078-ab0ab768ffd7 + b1d2aad0-ff8f-419b-9c56-f82b9b6378df 1 @@ -2833,39 +2398,41 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2842 - 1409 + 1425 17 20 2852 - 1419 + 1435 - + The material override 5f9e9e88-be8b-4453-b5f6-8e8fcf54697c + true Material M false - 0 + d0dd1043-724e-45c1-a8b5-6f7ff06d8073 + 1 2842 - 1429 + 1445 17 20 2852 - 1439 + 1455 @@ -2905,7 +2472,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 0148a65d-6f42-414a-9db7-9a9b2eb78437 Brep Edges @@ -2923,14 +2490,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2738 - 1336 + 2739 + 1313 72 64 - 2768 - 1368 + 2769 + 1345 @@ -2941,21 +2508,21 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) Brep B false - e7de4017-7053-4063-8078-ab0ab768ffd7 + b1d2aad0-ff8f-419b-9c56-f82b9b6378df 1 - 2740 - 1338 + 2741 + 1315 13 60 - 2748 - 1368 + 2749 + 1345 @@ -2975,14 +2542,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2783 - 1338 + 2784 + 1315 25 20 - 2795.5 - 1348 + 2796.5 + 1325 @@ -3002,14 +2569,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2783 - 1358 + 2784 + 1335 25 20 - 2795.5 - 1368 + 2796.5 + 1345 @@ -3029,14 +2596,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - 2783 - 1378 + 2784 + 1355 25 20 - 2795.5 - 1388 + 2796.5 + 1365 @@ -3046,7 +2613,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 4f8984c4-7c7a-4d69-b0a2-183cbb330d20 Plane @@ -3068,13 +2635,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2837 - 1275 + 1254 50 24 2862.183 - 1287.725 + 1266.925 @@ -3082,7 +2649,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 4f8984c4-7c7a-4d69-b0a2-183cbb330d20 Plane @@ -3104,13 +2671,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2836 - 1204 + 1185 50 24 2861.542 - 1216.78 + 1197.58 @@ -3118,7 +2685,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 4f8984c4-7c7a-4d69-b0a2-183cbb330d20 Plane @@ -3140,13 +2707,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2835 - 1136 + 1115 50 24 2860.975 - 1148.724 + 1127.124 @@ -3154,7 +2721,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 59e0b89a-e487-49f8-bab8-b5bab16be14c Panel @@ -3177,16 +2744,16 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2258 - 1180 - 220 - 85 + 1185 + 199 + 82 0 0 0 - 2258.007 - 1180.445 + 2258.006 + 1185.64 @@ -3207,7 +2774,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -3232,7 +2799,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -3257,7 +2824,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + a77d0879-94c2-4101-be44-e4a616ffeb0c 5f86fa9f-c62b-50e8-157b-b454ef3e00fa @@ -3277,13 +2844,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2839 - 1317 + 1333 46 84 2871 - 1359 + 1375 @@ -3303,13 +2870,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2841 - 1319 + 1335 15 20 2850 - 1329 + 1345 @@ -3329,13 +2896,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2841 - 1339 + 1355 15 20 2850 - 1349 + 1365 @@ -3385,13 +2952,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2841 - 1359 + 1375 15 20 2850 - 1369 + 1385 @@ -3411,13 +2978,13 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 2841 - 1379 + 1395 15 20 2850 - 1389 + 1405 @@ -3447,7 +3014,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -3472,7 +3039,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 57da07bd-ecab-415d-9d86-af36d7073abc Number Slider @@ -3510,14 +3077,14 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) 100 0 0 - 30 + 50 - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -3543,7 +3110,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -3570,7 +3137,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -3595,7 +3162,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -3620,7 +3187,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + d5967b9f-e8ee-436b-a8ad-29fdcecf32d5 Curve @@ -3679,7 +3246,7 @@ rg_planes = (plane_to_rhino(plane) for plane in cutting_planes) - + 410755b1-224a-4c1e-a407-bf32fb45ea7e 00000000-0000-0000-0000-000000000000 @@ -3792,7 +3359,7 @@ class Beam_fromCurve(component): true true - iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDQAACw0B7QfALAAAAhRJREFUSEulVLtKA0EUzSfkD3zlrUKMIcHGB6ghIj5QxEoDiiA2gtqGYBEfRRQiSRc7iXU6IWKZwh8Q/AI/wEcRr/cMmWUZ7ya7Whw2uXvvOTNnzqyPiP6Nob7+Q0bBQJ0xLQ64BRP4R6OxZ37Swf4+nRwdKyxmFyg4MEhcvxYH3YCH4+GhwHsqMd6+r9ep1WrRY7OpyGcmp2hvZxcCBXG4F3gQligykIIcIulkknJb26qGnXgW4AF/NBi6AzkIQAxcnl+AjAr5vFXzLMDN8ZFI9JXxfVMuW0RYMZ8D3dZqVs2zADeuRALBD3jbaDQUAZ74D2ib/iQwHI5UudHyFsNYLVaN5JjEGj0F+KUVQXisB+EzyO01CV0F+IUYwY21dZUUXXMCemGdKMBFMYIYgIDktx2wD0FAILBQO7FjBGGJveYE2Id5Jn8AH3g1uRhBHCLI7TUJ2BVCAHLuP9eLVgJc3GS/vyZSaboqldQWq5UKZeczyhYdSyfouCLGzLViJ9cCT1A2sbq03NNv7Ay7joXCLzzTb5JbAqa/mdm5XzfTRCeG1Dk35bcEUQAJchLArpAmkDMOJVI7PAkgrrgbuCM8F5cITbgWQFyHI9F2x29HS0y4EkBcuU/5LZF0Q1cB+I3fHMFP7stJBL3gKHBWLOoIvnGPK78lKAEQQkQjOZZQlnS+pq79lgABfNxw2UycSgPeQL4fsKzVEEQlKEcAAAAASUVORK5CYII= + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDAAACwwBP0AiyAAAAhRJREFUSEulVLtKA0EUzSfkD3zlrUKMIcHGB6ghIj5QxEoDiiA2gtqGYBEfRRQiSRc7iXU6IWKZwh8Q/AI/wEcRr/cMmWUZ7ya7Whw2uXvvOTNnzqyPiP6Nob7+Q0bBQJ0xLQ64BRP4R6OxZ37Swf4+nRwdKyxmFyg4MEhcvxYH3YCH4+GhwHsqMd6+r9ep1WrRY7OpyGcmp2hvZxcCBXG4F3gQligykIIcIulkknJb26qGnXgW4AF/NBi6AzkIQAxcnl+AjAr5vFXzLMDN8ZFI9JXxfVMuW0RYMZ8D3dZqVs2zADeuRALBD3jbaDQUAZ74D2ib/iQwHI5UudHyFsNYLVaN5JjEGj0F+KUVQXisB+EzyO01CV0F+IUYwY21dZUUXXMCemGdKMBFMYIYgIDktx2wD0FAILBQO7FjBGGJveYE2Id5Jn8AH3g1uRhBHCLI7TUJ2BVCAHLuP9eLVgJc3GS/vyZSaboqldQWq5UKZeczyhYdSyfouCLGzLViJ9cCT1A2sbq03NNv7Ay7joXCLzzTb5JbAqa/mdm5XzfTRCeG1Dk35bcEUQAJchLArpAmkDMOJVI7PAkgrrgbuCM8F5cITbgWQFyHI9F2x29HS0y4EkBcuU/5LZF0Q1cB+I3fHMFP7stJBL3gKHBWLOoIvnGPK78lKAEQQkQjOZZQlnS+pq79lgABfNxw2UycSgPeQL4fsKzVEEQlKEcAAAAASUVORK5CYII= false e28e26d5-b791-48bc-902c-a1929ace9685 @@ -4076,7 +3643,7 @@ class Beam_fromCurve(component): - + 57da07bd-ecab-415d-9d86-af36d7073abc Number Slider @@ -4121,7 +3688,7 @@ class Beam_fromCurve(component): - + d5967b9f-e8ee-436b-a8ad-29fdcecf32d5 Curve @@ -4180,7 +3747,7 @@ class Beam_fromCurve(component): - + 410755b1-224a-4c1e-a407-bf32fb45ea7e 00000000-0000-0000-0000-000000000000 @@ -4577,7 +4144,7 @@ class Beam_fromCurve(component): - + 57da07bd-ecab-415d-9d86-af36d7073abc Number Slider @@ -4622,7 +4189,7 @@ class Beam_fromCurve(component): - + 57da07bd-ecab-415d-9d86-af36d7073abc Number Slider @@ -4667,7 +4234,7 @@ class Beam_fromCurve(component): - + 22990b1f-9be6-477c-ad89-f775cd347105 Flip Curve @@ -4805,7 +4372,7 @@ class Beam_fromCurve(component): - + 11bbd48b-bb0a-4f1b-8167-fa297590390d End Points @@ -4917,7 +4484,7 @@ class Beam_fromCurve(component): - + e9eb1dcf-92f6-4d4d-84ae-96222d60f56b Move @@ -5081,7 +4648,7 @@ class Beam_fromCurve(component): - + 79f9fbb3-8f1d-4d9a-88a9-f7961b1012cd Unit X @@ -5187,7 +4754,7 @@ class Beam_fromCurve(component): - + 57da07bd-ecab-415d-9d86-af36d7073abc Number Slider @@ -5232,7 +4799,7 @@ class Beam_fromCurve(component): - + 4c4e56eb-2f04-43f9-95a3-cc46a14f495a Line @@ -5345,7 +4912,7 @@ class Beam_fromCurve(component): - + 9103c240-a6a9-4223-9b42-dbd19bf38e2b Unit Z @@ -5451,7 +5018,7 @@ class Beam_fromCurve(component): - + 57da07bd-ecab-415d-9d86-af36d7073abc Number Slider @@ -5496,7 +5063,7 @@ class Beam_fromCurve(component): - + a0d62394-a118-422d-abb3-6af115c75b25 Addition @@ -5620,7 +5187,7 @@ class Beam_fromCurve(component): - + 2e78987b-9dfb-42a2-8b76-3923ac8bd91a Boolean Toggle @@ -5634,7 +5201,7 @@ class Beam_fromCurve(component): FlipCurve false 0 - false + true @@ -5651,7 +5218,7 @@ class Beam_fromCurve(component): - + eeafc956-268e-461d-8e73-ee05c6f72c01 Stream Filter @@ -5802,7 +5369,7 @@ class Beam_fromCurve(component): 09fe95fb-9551-4690-abf6-4a0665002914 false Stream - S(0) + S(1) false 0 @@ -5829,7 +5396,7 @@ class Beam_fromCurve(component): - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5855,7 +5422,7 @@ class Beam_fromCurve(component): - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5883,7 +5450,7 @@ class Beam_fromCurve(component): - + 9c53bac0-ba66-40bd-8154-ce9829b9db1a Colour Swatch @@ -5906,44 +5473,13 @@ class Beam_fromCurve(component): 2737 - 544 + 557 88 20 2737.545 - 544.3754 - - - - - - - - - - 2e78987b-9dfb-42a2-8b76-3923ac8bd91a - Boolean Toggle - - - - - Boolean (true/false) toggle - 8af59bcf-e43d-4808-b965-440e7d003dfd - Boolean Toggle - Toggle - false - 0 - false - - - - - - 2526 - 1387 - 104 - 22 + 557.0914 @@ -5951,7 +5487,7 @@ class Beam_fromCurve(component): - + 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe Scribble @@ -6004,7 +5540,7 @@ class Beam_fromCurve(component): - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6029,7 +5565,7 @@ class Beam_fromCurve(component): - + 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe Scribble @@ -6043,11 +5579,11 @@ class Beam_fromCurve(component): 1060.245 - 2691.896 + 2691.895 1060.245 - 2691.896 + 2691.895 1107.584 @@ -6082,7 +5618,7 @@ class Beam_fromCurve(component): - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6107,7 +5643,7 @@ class Beam_fromCurve(component): - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6132,6 +5668,172 @@ class Beam_fromCurve(component): + + + 919e146f-30ae-4aae-be34-4d72f555e7da + Brep + + + + + Contains a collection of Breps (Boundary REPresentations) + true + b1d2aad0-ff8f-419b-9c56-f82b9b6378df + Brep + Brep + false + 441ff4ac-6060-44cf-965a-55428a9d4cc6 + 1 + + + + + + 2651 + 1378 + 50 + 24 + + + 2676.568 + 1390.515 + + + + + + + + + + 9c53bac0-ba66-40bd-8154-ce9829b9db1a + Colour Swatch + + + + + Colour (palette) swatch + d0dd1043-724e-45c1-a8b5-6f7ff06d8073 + Colour Swatch + Swatch + false + 0 + + 29;0;102;255 + + + + + + + 2728 + 1445 + 88 + 20 + + + 2728.811 + 1445.6 + + + + + + + + + + 919e146f-30ae-4aae-be34-4d72f555e7da + Brep + + + + + Contains a collection of Breps (Boundary REPresentations) + 91868622-66e7-4d7d-a5a0-9480a9e4a02a + Brep + Brep + false + b10f1b85-d84a-4d8b-84d3-f956ea4e2805 + 1 + + + + + + 2660 + 496 + 50 + 24 + + + 2685.648 + 508.1772 + + + + + + + + + + c552a431-af5b-46a9-a8a4-0fcbc27ef596 + Group + + + + + 1 + + 150;255;255;255 + + A group of Grasshopper objects + def048ab-0443-4189-81d6-03594953cdd1 + aa461d11-c653-411c-a341-b7900f1ccbd6 + 0cbceed4-3434-411c-b4d1-46985ef14dea + b1d2aad0-ff8f-419b-9c56-f82b9b6378df + d0dd1043-724e-45c1-a8b5-6f7ff06d8073 + 5 + 7dff34a0-670b-4fd3-8912-0a128d903453 + Group + GEOMETRY + + + + + + + + + + c552a431-af5b-46a9-a8a4-0fcbc27ef596 + Group + + + + + 1 + + 150;255;255;255 + + A group of Grasshopper objects + 9e4f0b21-759b-4c9a-8dfb-6654484027c5 + be8a15e2-8773-4720-9d61-dfdc10761646 + 56020ec2-ccb1-4ae9-a538-84dcb2857db9 + c0a53353-9802-4df7-a063-6228afad4537 + 91868622-66e7-4d7d-a5a0-9480a9e4a02a + 5 + 1994870e-f2d3-43af-9b16-274f462b9ef7 + Group + GEOMETRY + + + + + + + @@ -6139,7 +5841,7 @@ class Beam_fromCurve(component): - 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