diff --git a/src/bonsai/bonsai/bim/module/model/polyline.py b/src/bonsai/bonsai/bim/module/model/polyline.py index 1afc147564..3f07752814 100644 --- a/src/bonsai/bonsai/bim/module/model/polyline.py +++ b/src/bonsai/bonsai/bim/module/model/polyline.py @@ -165,13 +165,13 @@ class PolylineOperator: self.tool_state.axis_method = None tool.Blender.update_viewport() - def handle_instructions(self, context): + def handle_instructions(self, context, custom_instructions): self.snap_info = f"""| Axis: {self.tool_state.axis_method} Plane: {self.tool_state.plane_method} Snap: {self.snapping_points[0][1]} """ - context.workspace.status_text_set(self.instructions + self.snap_info) + context.workspace.status_text_set(self.instructions + custom_instructions + self.snap_info) def handle_lock_axis(self, context, event): if event.value == "RELEASE" and event.type == "L": diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index 0d6b6220df..f44e6a01a8 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -149,6 +149,18 @@ class BIMModelProperties(PropertyGroup): type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page) type_name: bpy.props.StringProperty(name="Name", default="TYPEX") boundary_class: bpy.props.EnumProperty(items=get_boundary_class, name="Boundary Class") + direction_sense: bpy.props.EnumProperty( + items=[("POSITIVE", "Positive", ""), ("NEGATIVE", "Negative", "")], + name="Material Usage Direction Sense", + default="POSITIVE" + ) + offset_type: bpy.props.EnumProperty( + items=[("EXTERIOR", "Exterior", ""), ("CENTER", "Center", ""), ("INTERIOR", "Interior", "")], + name="Layer Offset Type", + default="EXTERIOR", + description="It's a convention that affects the offset to reference line" + ) + offset: bpy.props.FloatProperty(name="Offset", default=0.0, description="Material usage offset from reference line") class BIMArrayProperties(PropertyGroup): diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index aefb3af676..bfb97575c8 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -297,7 +297,8 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator): def __init__(self): super().__init__() self.relating_type = None - relating_type_id = bpy.context.scene.BIMModelProperties.relating_type_id + props = bpy.context.scene.BIMModelProperties + relating_type_id = props.relating_type_id if relating_type_id: self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) @@ -305,7 +306,25 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator): if not self.relating_type: return {"FINISHED"} + model_props = context.scene.BIMModelProperties + direction_sense = model_props.direction_sense + offset = model_props.offset + walls, is_polyline_closed = DumbWallGenerator(self.relating_type).generate(True) + for wall in walls: + model = IfcStore.get_file() + element = tool.Ifc.get_entity(wall["obj"]) + material = ifcopenshell.util.element.get_material(element) + material_set_usage = model.by_id(material.id()) + # if material.is_a("IfcMaterialLayerSetUsage"): + attributes = {"OffsetFromReferenceLine": offset, "DirectionSense": direction_sense} + ifcopenshell.api.run( + "material.edit_layer_usage", + model, + **{"usage": material_set_usage, "attributes": attributes}, + ) + DumbWallRecalculator().recalculate([wall["obj"]]) + if walls: if is_polyline_closed: for wall1, wall2 in zip(walls, walls[1:] + [walls[0]]): @@ -330,7 +349,28 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator): self.handle_mouse_move(context, event) return {"PASS_THROUGH"} - self.handle_instructions(context) + # Wall axis settings + if event.value == "RELEASE" and event.type == "F": + direction_sense = context.scene.BIMModelProperties.direction_sense + context.scene.BIMModelProperties.direction_sense = ( + "NEGATIVE" if direction_sense == "POSITIVE" else "POSITIVE" + ) + tool.Polyline.create_wall_preview_vertices(context, self.relating_type) + + if event.value == "RELEASE" and event.type == "O": + offset_type = context.scene.BIMModelProperties.offset_type + items = ["EXTERIOR", "CENTER", "INTERIOR"] + index = items.index(offset_type) + size = len(items) + context.scene.BIMModelProperties.offset_type = items[((index + 1) % size)] + tool.Polyline.create_wall_preview_vertices(context, self.relating_type) + + props = bpy.context.scene.BIMModelProperties + wall_config = f"""Direction: {props.direction_sense} + Offset Type: {props.offset_type} + Offset Value: {props.offset} + """ + self.handle_instructions(context, wall_config) self.handle_mouse_move(context, event, should_round=True) diff --git a/src/bonsai/bonsai/tool/polyline.py b/src/bonsai/bonsai/tool/polyline.py index 4a8aab457d..10f8cfc882 100644 --- a/src/bonsai/bonsai/tool/polyline.py +++ b/src/bonsai/bonsai/tool/polyline.py @@ -309,7 +309,7 @@ class Polyline(bonsai.core.tool.Polyline): def create_bmesh_from_vertices(vertices): bm = bmesh.new() - new_verts = [bm.verts.new(v) for v in base_vertices] + new_verts = [bm.verts.new(v) for v in polyline_vertices] if is_closed: new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)] new_edges.append( @@ -327,36 +327,61 @@ class Polyline(bonsai.core.tool.Polyline): if not layers["thickness"]: return thickness = layers["thickness"] + model_props = context.scene.BIMModelProperties + direction_sense = model_props.direction_sense + direction = 1 + if direction_sense == "NEGATIVE": + direction = -1 + offset_type = model_props.offset_type + offset = 0 + if offset_type == "CENTER": + offset = -thickness/2 + elif offset_type == "INTERIOR": + offset = -thickness - height = float(context.scene.BIMModelProperties.extrusion_depth) - rl = float(context.scene.BIMModelProperties.rl1) - x_angle = float(context.scene.BIMModelProperties.x_angle) + unit_system = tool.Drawing.get_unit_system() + factor = 1 + if unit_system == "IMPERIAL": + factor = 3.048 + if unit_system == "METRIC": + unit_length = bpy.context.scene.unit_settings.length_unit + if unit_length == "MILLIMETERS": + factor = 1000 + + # For the model properties, the offset value should just be converted + # However, for the wall preview logic that follows, offset and thickness must change direction + model_props.offset = offset * factor + thickness *= direction + offset *= direction + + height = float(model_props.extrusion_depth) + rl = float(model_props.rl1) + x_angle = float(model_props.x_angle) angle_distortion = height * tan(x_angle) - base_vertices = [] - top_vertices = [] + polyline_vertices = [] polyline_data = context.scene.BIMPolylineProperties.insertion_polyline polyline_points = polyline_data[0].polyline_points if polyline_data else [] if len(polyline_points) < 2: context.scene.BIMPolylineProperties.product_preview.clear() return for point in polyline_points: - base_vertices.append(Vector((point.x, point.y, point.z))) + polyline_vertices.append(Vector((point.x, point.y, point.z))) is_closed = False if ( - base_vertices[0].x == base_vertices[-1].x - and base_vertices[0].y == base_vertices[-1].y - and base_vertices[0].z == base_vertices[-1].z + polyline_vertices[0].x == polyline_vertices[-1].x + and polyline_vertices[0].y == polyline_vertices[-1].y + and polyline_vertices[0].z == polyline_vertices[-1].z ): is_closed = True - base_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed. + polyline_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed. - bm_base = create_bmesh_from_vertices(base_vertices) - - offset_base_verts = tool.Cad.offset_edges(bm_base, thickness) - top_vertices = tool.Cad.offset_edges(bm_base, angle_distortion) - offset_top_verts = tool.Cad.offset_edges(bm_base, angle_distortion + thickness) + bm_base = create_bmesh_from_vertices(polyline_vertices) + base_vertices = tool.Cad.offset_edges(bm_base, offset) + offset_base_verts = tool.Cad.offset_edges(bm_base, thickness + offset) + top_vertices = tool.Cad.offset_edges(bm_base, angle_distortion + offset) + offset_top_verts = tool.Cad.offset_edges(bm_base, angle_distortion + thickness + offset) if is_closed: base_vertices.append(base_vertices[0]) @@ -367,10 +392,11 @@ class Polyline(bonsai.core.tool.Polyline): if offset_base_verts is not None: context.scene.BIMPolylineProperties.product_preview.clear() for v in base_vertices: + new_v = Vector((v.co.x, v.co.y, v.co.z)) prop = context.scene.BIMPolylineProperties.product_preview.add() - prop.x = v.x - prop.y = v.y - prop.z = v.z + rl + prop.x = new_v.x + prop.y = new_v.y + prop.z = new_v.z + rl for v in offset_base_verts[::-1]: new_v = Vector((v.co.x, v.co.y, v.co.z))