Add polyline tool for slabs.

No preview yet.
This commit is contained in:
Bruno Perdigão
2024-10-22 17:39:19 -03:00
parent ffe8d4fad2
commit 0c0225543b
4 changed files with 134 additions and 3 deletions
@@ -100,6 +100,7 @@ classes = (
roof.GenerateHippedRoof,
slab.DisableEditingExtrusionProfile,
slab.DisableEditingSketchExtrusionProfile,
slab.DrawPolylineSlab,
slab.EditExtrusionProfile,
slab.EditSketchExtrusionProfile,
slab.EnableEditingExtrusionProfile,
+124 -3
View File
@@ -32,7 +32,8 @@ import bonsai.core.root
import bonsai.tool as tool
from mathutils import Vector, Matrix
from bonsai.bim.module.geometry.helper import Helper
from bonsai.bim.module.model.decorator import ProfileDecorator
from bonsai.bim.module.model.decorator import ProfileDecorator, PolylineDecorator, ProductDecorator
from bonsai.bim.module.model.polyline import PolylineOperator
from typing import Optional
@@ -40,7 +41,7 @@ class DumbSlabGenerator:
def __init__(self, relating_type: ifcopenshell.entity_instance):
self.relating_type = relating_type
def generate(self):
def generate(self, draw_from_polyline=False):
self.file = tool.Ifc.get()
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
thicknesses = []
@@ -60,6 +61,7 @@ class DumbSlabGenerator:
props = bpy.context.scene.BIMModelProperties
self.polyline = None
self.container = None
self.container_obj = None
if container := tool.Root.get_default_container():
@@ -72,7 +74,26 @@ class DumbSlabGenerator:
self.rotation = 0
self.location = Vector((0, 0, 0))
self.x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else props.x_angle
return self.derive_from_cursor()
if draw_from_polyline:
return self.derive_from_polyline()
else:
return self.derive_from_cursor()
def derive_from_polyline(self):
polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline
polyline_points = polyline_data[0].polyline_points if polyline_data else []
self.location = Vector((polyline_points[0].x, polyline_points[0].y, self.container_obj.location.z))
self.polyline = [Vector((p.x, p.y, 0.0)) - self.location for p in polyline_points]
if len(self.polyline) <= 2:
return
# Always assume a closed polyline
if self.polyline[0] != self.polyline[-1]:
self.polyline.append(self.polyline[0])
return self.create_slab()
def derive_from_cursor(self):
self.location = bpy.context.scene.cursor.location
@@ -112,6 +133,7 @@ class DumbSlabGenerator:
context=self.body_context,
depth=self.depth,
x_angle=self.x_angle,
polyline=self.polyline,
)
ifcopenshell.api.run(
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=representation
@@ -700,3 +722,102 @@ class SetArcIndex(bpy.types.Operator):
group.add(selected_vertices, 1, "REPLACE")
bpy.ops.object.mode_set(mode="EDIT")
return {"FINISHED"}
class DrawPolylineSlab(bpy.types.Operator, PolylineOperator):
bl_idname = "bim.draw_polyline_slab"
bl_label = "Draw Polyline Slab"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.space_data.type == "VIEW_3D"
def __init__(self):
super().__init__()
self.relating_type = None
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))
def create_slab_from_polyline(self, context):
if not self.relating_type:
return {"FINISHED"}
DumbSlabGenerator(self.relating_type).generate(True)
def modal(self, context, event):
if not self.relating_type:
self.report({"WARNING"}, "You need to select a slab type.")
PolylineDecorator.uninstall()
tool.Blender.update_viewport()
return {"FINISHED"}
PolylineDecorator.update(event, self.tool_state, self.input_ui, self.snapping_points[0])
tool.Blender.update_viewport()
self.handle_lock_axis(context, event)
if event.type in {"MIDDLEMOUSE", "WHEELUPMOUSE", "WHEELDOWNMOUSE"}:
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 == "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
# slab_config = f"""Direction: {props.direction_sense}
# Offset Type: {props.offset_type}
# Offset Value: {props.offset}
# """
self.handle_instructions(context)
self.handle_mouse_move(context, event, should_round=True)
self.choose_axis(event)
self.handle_snap_selection(context, event)
if (
not self.tool_state.is_input_on
and event.value == "RELEASE"
and event.type in {"RET", "NUMPAD_ENTER", "RIGHTMOUSE"}
):
self.create_slab_from_polyline(context)
context.workspace.status_text_set(text=None)
ProductDecorator.uninstall()
PolylineDecorator.uninstall()
tool.Polyline.clear_polyline()
tool.Blender.update_viewport()
return {"FINISHED"}
self.handle_keyboard_input(context, event)
self.handle_inserting_polyline(context, event)
cancel = self.handle_cancelation(context, event)
if cancel is not None:
ProductDecorator.uninstall()
return cancel
return {"RUNNING_MODAL"}
def invoke(self, context, event):
super().invoke(context, event)
ProductDecorator.install(context)
self.tool_state.use_default_container = True
self.tool_state.plane_method = "XY"
return {"RUNNING_MODAL"}
@@ -935,6 +935,10 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
relating_type_id := tool.Blender.get_enum_safe(props, "relating_type_id")
) and tool.Model.get_usage_type(tool.Ifc.get().by_id(int(relating_type_id))) == "LAYER2":
bpy.ops.bim.draw_polyline_wall("INVOKE_DEFAULT")
elif (
relating_type_id := tool.Blender.get_enum_safe(props, "relating_type_id")
) and tool.Model.get_usage_type(tool.Ifc.get().by_id(int(relating_type_id))) == "LAYER3":
bpy.ops.bim.draw_polyline_slab("INVOKE_DEFAULT")
else:
bpy.ops.bim.add_occurrence("INVOKE_DEFAULT")
@@ -19,6 +19,7 @@
import ifcopenshell.util.unit
from ifcopenshell.util.data import Clipping
from math import sin, cos
from mathutils import Vector
from typing import Any, Optional, Union
@@ -34,6 +35,7 @@ def add_slab_representation(
# Planes are defined either by Clipping objects
# or by dictionaries of arguments for `Clipping.parse`
clippings: Optional[list[Union[Clipping, dict[str, Any]]]] = None,
polyline: Optional[list[Vector]] = None,
) -> ifcopenshell.entity_instance:
usecase = Usecase()
usecase.file = file
@@ -42,6 +44,7 @@ def add_slab_representation(
"depth": depth,
"x_angle": x_angle,
"clippings": clippings if clippings is not None else [],
"polyline": polyline,
}
return usecase.execute()
@@ -59,6 +62,8 @@ class Usecase:
def create_item(self):
size = self.convert_si_to_unit(1)
points = ((0.0, 0.0), (size, 0.0), (size, size), (0.0, size), (0.0, 0.0))
if self.settings["polyline"]:
points = [(self.convert_si_to_unit(p[0]), self.convert_si_to_unit(p[1])) for p in self.settings["polyline"]]
if self.file.schema == "IFC2X3":
curve = self.file.createIfcPolyline([self.file.createIfcCartesianPoint(p) for p in points])
else: