diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index eaf4c356be..972ac5d1b6 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -1297,6 +1297,51 @@ class DumbWallGenerator: walls.append(self.create_wall_from_2_points(coords)) return walls, is_polyline_closed + def _curve_has_arc_segments(self, curve: ifcopenshell.entity_instance) -> bool: + if not curve.is_a("IfcIndexedPolyCurve"): + return False + segments = getattr(curve, "Segments", None) or () + for segment in segments: + if (hasattr(segment, "is_a") and segment.is_a("IfcArcIndex")) or len(segment[0]) == 3: + return True + return False + + def _world_xy_point(self, slab_obj: bpy.types.Object, elevation: float, coord: Any) -> Vector: + return slab_obj.matrix_world @ Vector((coord[0] * self.unit_scale, coord[1] * self.unit_scale, elevation)) + + def _derive_points_from_arc_segments( + self, slab_obj: bpy.types.Object, elevation: float, curve: ifcopenshell.entity_instance + ) -> list[Vector]: + points: list[Vector] = [] + coord_list = curve.Points.CoordList + arc_resolution = 24 + precision = 1e-6 + + def append_point(point: Vector) -> None: + if points and (points[-1] - point).length < precision: + return + points.append(point) + + for segment in curve.Segments: + segment_indices = [i - 1 for i in segment[0]] + if len(segment_indices) == 3: + p1 = self._world_xy_point(slab_obj, elevation, coord_list[segment_indices[0]]) + p2 = self._world_xy_point(slab_obj, elevation, coord_list[segment_indices[1]]) + p3 = self._world_xy_point(slab_obj, elevation, coord_list[segment_indices[2]]) + arc_points, _ = tool.Cad.create_arc_segments([p1, p2, p3], num_verts=arc_resolution + 1) + arc_points = [Vector(arc_point) for arc_point in arc_points] + if arc_points and (arc_points[0] - p1).length > (arc_points[-1] - p1).length: + arc_points.reverse() + for arc_point in arc_points: + append_point(arc_point) + elif len(segment_indices) >= 2: + append_point(self._world_xy_point(slab_obj, elevation, coord_list[segment_indices[0]])) + append_point(self._world_xy_point(slab_obj, elevation, coord_list[segment_indices[1]])) + + if points and (points[0] - points[-1]).length >= precision: + points.append(points[0].copy()) + return points + def derive_from_slab(self): slab_obj = bpy.context.active_object slab = tool.Ifc.get_entity(slab_obj) @@ -1305,10 +1350,17 @@ class DumbWallGenerator: elevation = self.container_obj.location.z representation = ifcopenshell.util.representation.get_representation(slab, "Model", "Body", "MODEL_VIEW") extrusion = tool.Model.get_extrusion(representation) - builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get()) - polyline_points = builder.get_polyline_coords(extrusion.SweptArea.OuterCurve) - polyline_points = [[(v * self.unit_scale) for v in p] for p in polyline_points] - polyline_points = [slab_obj.matrix_world @ Vector((p[0], p[1], elevation)) for p in polyline_points] + outer_curve = extrusion.SweptArea.OuterCurve + if self._curve_has_arc_segments(outer_curve): + polyline_points = self._derive_points_from_arc_segments(slab_obj, elevation, outer_curve) + else: + builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get()) + polyline_points = builder.get_polyline_coords(outer_curve) + polyline_points = [[(v * self.unit_scale) for v in p] for p in polyline_points] + polyline_points = [slab_obj.matrix_world @ Vector((p[0], p[1], elevation)) for p in polyline_points] + + if len(polyline_points) < 3: + return [] if not tool.Cad.is_counter_clockwise_order(polyline_points[0], polyline_points[1], polyline_points[2]): polyline_points = polyline_points[::-1] walls = []