From 5180f40245af6d737f77200de928b093d3eee507 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Tue, 12 Sep 2023 09:40:14 +0500 Subject: [PATCH] MEP bends - support for circular profiles Demo - https://imgur.com/a/XQBOvGz --- .../blenderbim/bim/module/model/mep.py | 13 ++--- .../ifcopenshell/util/shape_builder.py | 54 ++++++++++++------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/mep.py b/src/blenderbim/blenderbim/bim/module/model/mep.py index 88d3e7a708..54e62e54cc 100644 --- a/src/blenderbim/blenderbim/bim/module/model/mep.py +++ b/src/blenderbim/blenderbim/bim/module/model/mep.py @@ -940,19 +940,16 @@ class MEPAddBend(bpy.types.Operator, tool.Ifc.Operator): if not types_check(): self.report( {"ERROR"}, - "Segments types do not match " "or one of the segments doesn't have type which is required for a bend.", + "Segments types do not match or one of the segments doesn't have type which is required for a bend.", ) return {"CANCELLED"} - # TODO: support circular profiles profile = tool.Model.get_flow_segment_profile(start_element) - if not profile.is_a("IfcRectangleProfileDef"): + if not profile.is_a("IfcRectangleProfileDef") and not profile.is_a("IfcCircleProfileDef"): self.report( - { - "ERROR", - "For now Only IfcRectangleProfileDef profiles supported for a bend, " - f"the segments are {profile.is_a()}", - } + {"ERROR"}, + "For now Only IfcRectangleProfileDef/IfcCircleProfileDef profiles supported for a bend, " + f"the segments are {profile.is_a()}", ) return {"CANCELLED"} diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index 7b8586a19b..a3e811dc1e 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -1321,6 +1321,7 @@ class ShapeBuilder: # TODO: test with 0 radius si_conversion = ifcopenshell.util.unit.calculate_unit_scale(self.file) profile = get_profile(segment) + is_circular_profile = profile.is_a("IfcCircleProfileDef") profile_dim = get_dim(profile, start_length) rounded_offset = round_vector_to_precision(profile_offset, si_conversion) @@ -1334,19 +1335,23 @@ class ShapeBuilder: # bend circle center O = V(0, 0, 0) O[lateral_axis] = (radius + profile_dim[lateral_axis]) * lateral_sign - theta = angle - def get_circle_extrusion(): - # get as much segment_length segments as possible - segment_length = pi / 20 - num_segments = ceil(theta / segment_length) - theta_segments = [i * segment_length for i in range(num_segments)] - if not is_x(theta_segments[-1], theta): - theta_segments.append(theta) + def get_bend_representation_item(): + if is_circular_profile: + theta_segments = [0, theta / 2, theta] + else: + # get as much segment_length segments as possible + segment_length = pi / 20 + num_segments = ceil(theta / segment_length) + theta_segments = [i * segment_length for i in range(num_segments)] + if not is_x(theta_segments[-1], theta): + theta_segments.append(theta) inner_points, outer_points = [], [] r = radius + if is_circular_profile: + r += profile_dim[lateral_axis] for cur_theta in theta_segments: cur_theta -= pi / 2 @@ -1356,24 +1361,33 @@ class ShapeBuilder: inner[lateral_axis] = lateral_sign * sin(cur_theta) * r inner_points.append(inner) - outer = V(0, 0, 0) - outer.z = z_sign * cos(cur_theta) * (r + 2 * profile_dim[lateral_axis]) - outer[lateral_axis] = lateral_sign * sin(cur_theta) * (r + 2 * profile_dim[lateral_axis]) - outer_points.append(outer) + if not is_circular_profile: + outer = V(0, 0, 0) + outer.z = z_sign * cos(cur_theta) * (r + 2 * profile_dim[lateral_axis]) + outer[lateral_axis] = lateral_sign * sin(cur_theta) * (r + 2 * profile_dim[lateral_axis]) + outer_points.append(outer) # fmt: on points = inner_points + outer_points[::-1] points = [p + O for p in points] offset = V(0, 0, 0) - offset[non_lateral_axis] = -profile_dim[non_lateral_axis] - extrusion_vector = V(0, 0, 0) - extrusion_vector[non_lateral_axis] = 1 - extrusion = self.extrude_face_set( - points, magnitude=profile_dim[non_lateral_axis] * 2, offset=offset, extrusion_vector=extrusion_vector - ) - return extrusion - rep_items.append(get_circle_extrusion()) + if is_circular_profile: + bend_path = self.polyline(points, closed=False, arc_points=[1]) + bend = self.create_swept_disk_solid(bend_path, profile_dim[lateral_axis]) + else: + offset[non_lateral_axis] = -profile_dim[non_lateral_axis] + extrusion_vector = V(0, 0, 0) + extrusion_vector[non_lateral_axis] = 1 + bend = self.extrude_face_set( + points, + magnitude=profile_dim[non_lateral_axis] * 2, + offset=offset, + extrusion_vector=extrusion_vector, + ) + return bend + + rep_items.append(get_bend_representation_item()) body = ifcopenshell.util.representation.get_context(self.file, "Model", "Body", "MODEL_VIEW") rep = self.get_representation(body, rep_items)