diff --git a/src/bonsai/bonsai/bim/module/model/polyline.py b/src/bonsai/bonsai/bim/module/model/polyline.py index fb4940918e..4c1b06b0f6 100644 --- a/src/bonsai/bonsai/bim/module/model/polyline.py +++ b/src/bonsai/bonsai/bim/module/model/polyline.py @@ -187,10 +187,23 @@ def get_wall_preview_data(context, relating_type): def get_slab_preview_data(context, relating_type): props = context.scene.BIMModelProperties x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else props.x_angle + model_props = context.scene.BIMModelProperties + direction_sense = model_props.direction_sense + direction = 1 + if direction_sense == "NEGATIVE": + direction = -1 + layers = tool.Model.get_material_layer_parameters(relating_type) if not layers["thickness"]: return thickness = layers["thickness"] + thickness *= direction + + offset_type = model_props.offset_type_horizontal + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) + offset = model_props.offset * unit_scale + offset *= direction + data = {} data["verts"] = [] # Verts @@ -209,6 +222,8 @@ def get_slab_preview_data(context, relating_type): transformed_vertices = [Vector((v.x, v.y * (1 / cos(x_angle)), v.z)) for v in local_vertices] # Convert back to world origin polyline_vertices = [v + Vector(polyline_vertices[0]) for v in transformed_vertices] + if offset != 0: + polyline_vertices = [v + Vector((0, 0, offset)) for v in polyline_vertices] is_closed = True if ( polyline_vertices[0].x == polyline_vertices[-1].x @@ -891,6 +906,26 @@ class PolylineOperator: t = props.tris.add() t.value_3d = tri + def set_offset(self, context: bpy.types.Context, relating_type: ifcopenshell.entity_instance) -> None: + props = bpy.context.scene.BIMModelProperties + if tool.Model.get_usage_type(relating_type) == "LAYER2": + offset_type = "offset_type_vertical" + elif tool.Model.get_usage_type(relating_type) == "LAYER3": + offset_type = "offset_type_horizontal" + else: + return + + layers = tool.Model.get_material_layer_parameters(relating_type) + thickness = layers["thickness"] + self.offset = 0 + if getattr(props, offset_type) == "CENTER": + self.offset = -thickness / 2 + elif getattr(props, offset_type) in {"INTERIOR", "TOP"}: + self.offset = -thickness + + props.offset = self.offset / self.unit_scale + tool.Blender.update_viewport() + def modal(self, context: bpy.types.Context, event: bpy.types.Event) -> Union[set[str], None]: PolylineDecorator.update(event, self.tool_state, self.input_ui, self.snapping_points[0]) tool.Blender.update_viewport() diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index 7038447574..76c0cd9db2 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -206,6 +206,12 @@ class BIMModelProperties(PropertyGroup): default="EXTERIOR", description="It's a convention that affects the offset to reference line", ) + offset_type_horizontal: bpy.props.EnumProperty( + items=[("TOP", "Top", ""), ("CENTER", "Center", ""), ("BOTTOM", "Bottom", "")], + name="Horizontal Layer Offset Type", + default="TOP", + 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") show_wall_axis: bpy.props.BoolProperty( name="Show Wall Axis", diff --git a/src/bonsai/bonsai/bim/module/model/slab.py b/src/bonsai/bonsai/bim/module/model/slab.py index 43db73b3c6..1a0cf97399 100644 --- a/src/bonsai/bonsai/bim/module/model/slab.py +++ b/src/bonsai/bonsai/bim/module/model/slab.py @@ -30,6 +30,7 @@ import bonsai.core.type import bonsai.core.geometry import bonsai.core.root import bonsai.tool as tool +from bonsai.bim.ifc import IfcStore from math import cos, radians from mathutils import Vector, Matrix from bonsai.bim.module.geometry.helper import Helper @@ -290,6 +291,14 @@ class DumbSlabPlaner: if material.LayerSetDirection == "AXIS3": self.change_thickness(related_object, new_thickness) + def regenerate_from_occurence(self, element, material_set_usage): + self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) + layer_set = material_set_usage.ForLayerSet + total_thickness = sum([l.LayerThickness for l in layer_set.MaterialLayers]) + if not total_thickness: + return + self.change_thickness(element, total_thickness) + def change_thickness(self, element: ifcopenshell.entity_instance, thickness: float) -> None: layer_params = tool.Model.get_material_layer_parameters(element) body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW") @@ -863,7 +872,25 @@ class DrawPolylineSlab(bpy.types.Operator, PolylineOperator): if not self.relating_type: return {"FINISHED"} - DumbSlabGenerator(self.relating_type).generate("POLYLINE") + slab = DumbSlabGenerator(self.relating_type).generate("POLYLINE") + + model_props = context.scene.BIMModelProperties + direction_sense = model_props.direction_sense + offset = model_props.offset + model = IfcStore.get_file() + element = tool.Ifc.get_entity(slab) + material = ifcopenshell.util.element.get_material(element) + material_set_usage = model.by_id(material.id()) + if not getattr(material_set_usage, "ForLayerSet", False): + return + attributes = {"OffsetFromReferenceLine": offset, "DirectionSense": direction_sense} + ifcopenshell.api.run( + "material.edit_layer_usage", + model, + **{"usage": material_set_usage, "attributes": attributes}, + ) + DumbSlabPlaner().regenerate_from_occurence(element, material_set_usage) + def modal(self, context, event): if not self.relating_type: @@ -881,27 +908,31 @@ class DrawPolylineSlab(bpy.types.Operator, PolylineOperator): self.handle_mouse_move(context, event) return {"PASS_THROUGH"} - # TODO Slab 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" - # ) + 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" + ) - # 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)] + props = bpy.context.scene.BIMModelProperties + if event.value == "RELEASE" and event.type == "O": + items = ["TOP", "CENTER", "BOTTOM"] + index = items.index(props.offset_type_horizontal) + size = len(items) + props.offset_type_horizontal = items[((index + 1) % size)] + self.set_offset(context, self.relating_type) - # props = bpy.context.scene.BIMModelProperties - # slab_config = f"""Direction: {props.direction_sense} - # Offset Type: {props.offset_type} - # Offset Value: {props.offset} - # """ + custom_instructions = { + 'Choose Axis': {'icons':True, 'keys': ['EVENT_X', 'EVENT_Y']} + } - self.handle_instructions(context) + slab_config = [ + f"Direction: {props.direction_sense}", + f"Offset Type: {props.offset_type_horizontal}", + f"Offset Value: {tool.Polyline.format_input_ui_units(props.offset * self.unit_scale)}", + ] + + self.handle_instructions(context, custom_instructions, slab_config) self.handle_mouse_move(context, event, should_round=True) @@ -940,6 +971,7 @@ class DrawPolylineSlab(bpy.types.Operator, PolylineOperator): ProductDecorator.install(context) self.tool_state.use_default_container = True self.tool_state.plane_method = "XY" + self.set_offset(context, self.relating_type) return {"RUNNING_MODAL"}