mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 18:21:59 +00:00
Add polyline tool for slabs.
No preview yet.
This commit is contained in:
@@ -100,6 +100,7 @@ classes = (
|
|||||||
roof.GenerateHippedRoof,
|
roof.GenerateHippedRoof,
|
||||||
slab.DisableEditingExtrusionProfile,
|
slab.DisableEditingExtrusionProfile,
|
||||||
slab.DisableEditingSketchExtrusionProfile,
|
slab.DisableEditingSketchExtrusionProfile,
|
||||||
|
slab.DrawPolylineSlab,
|
||||||
slab.EditExtrusionProfile,
|
slab.EditExtrusionProfile,
|
||||||
slab.EditSketchExtrusionProfile,
|
slab.EditSketchExtrusionProfile,
|
||||||
slab.EnableEditingExtrusionProfile,
|
slab.EnableEditingExtrusionProfile,
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ import bonsai.core.root
|
|||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
from bonsai.bim.module.geometry.helper import Helper
|
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
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ class DumbSlabGenerator:
|
|||||||
def __init__(self, relating_type: ifcopenshell.entity_instance):
|
def __init__(self, relating_type: ifcopenshell.entity_instance):
|
||||||
self.relating_type = relating_type
|
self.relating_type = relating_type
|
||||||
|
|
||||||
def generate(self):
|
def generate(self, draw_from_polyline=False):
|
||||||
self.file = tool.Ifc.get()
|
self.file = tool.Ifc.get()
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||||
thicknesses = []
|
thicknesses = []
|
||||||
@@ -60,6 +61,7 @@ class DumbSlabGenerator:
|
|||||||
|
|
||||||
props = bpy.context.scene.BIMModelProperties
|
props = bpy.context.scene.BIMModelProperties
|
||||||
|
|
||||||
|
self.polyline = None
|
||||||
self.container = None
|
self.container = None
|
||||||
self.container_obj = None
|
self.container_obj = None
|
||||||
if container := tool.Root.get_default_container():
|
if container := tool.Root.get_default_container():
|
||||||
@@ -72,7 +74,26 @@ class DumbSlabGenerator:
|
|||||||
self.rotation = 0
|
self.rotation = 0
|
||||||
self.location = Vector((0, 0, 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
|
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):
|
def derive_from_cursor(self):
|
||||||
self.location = bpy.context.scene.cursor.location
|
self.location = bpy.context.scene.cursor.location
|
||||||
@@ -112,6 +133,7 @@ class DumbSlabGenerator:
|
|||||||
context=self.body_context,
|
context=self.body_context,
|
||||||
depth=self.depth,
|
depth=self.depth,
|
||||||
x_angle=self.x_angle,
|
x_angle=self.x_angle,
|
||||||
|
polyline=self.polyline,
|
||||||
)
|
)
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=representation
|
"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")
|
group.add(selected_vertices, 1, "REPLACE")
|
||||||
bpy.ops.object.mode_set(mode="EDIT")
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
return {"FINISHED"}
|
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")
|
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":
|
) and tool.Model.get_usage_type(tool.Ifc.get().by_id(int(relating_type_id))) == "LAYER2":
|
||||||
bpy.ops.bim.draw_polyline_wall("INVOKE_DEFAULT")
|
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:
|
else:
|
||||||
bpy.ops.bim.add_occurrence("INVOKE_DEFAULT")
|
bpy.ops.bim.add_occurrence("INVOKE_DEFAULT")
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
from ifcopenshell.util.data import Clipping
|
from ifcopenshell.util.data import Clipping
|
||||||
from math import sin, cos
|
from math import sin, cos
|
||||||
|
from mathutils import Vector
|
||||||
from typing import Any, Optional, Union
|
from typing import Any, Optional, Union
|
||||||
|
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ def add_slab_representation(
|
|||||||
# Planes are defined either by Clipping objects
|
# Planes are defined either by Clipping objects
|
||||||
# or by dictionaries of arguments for `Clipping.parse`
|
# or by dictionaries of arguments for `Clipping.parse`
|
||||||
clippings: Optional[list[Union[Clipping, dict[str, Any]]]] = None,
|
clippings: Optional[list[Union[Clipping, dict[str, Any]]]] = None,
|
||||||
|
polyline: Optional[list[Vector]] = None,
|
||||||
) -> ifcopenshell.entity_instance:
|
) -> ifcopenshell.entity_instance:
|
||||||
usecase = Usecase()
|
usecase = Usecase()
|
||||||
usecase.file = file
|
usecase.file = file
|
||||||
@@ -42,6 +44,7 @@ def add_slab_representation(
|
|||||||
"depth": depth,
|
"depth": depth,
|
||||||
"x_angle": x_angle,
|
"x_angle": x_angle,
|
||||||
"clippings": clippings if clippings is not None else [],
|
"clippings": clippings if clippings is not None else [],
|
||||||
|
"polyline": polyline,
|
||||||
}
|
}
|
||||||
return usecase.execute()
|
return usecase.execute()
|
||||||
|
|
||||||
@@ -59,6 +62,8 @@ class Usecase:
|
|||||||
def create_item(self):
|
def create_item(self):
|
||||||
size = self.convert_si_to_unit(1)
|
size = self.convert_si_to_unit(1)
|
||||||
points = ((0.0, 0.0), (size, 0.0), (size, size), (0.0, size), (0.0, 0.0))
|
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":
|
if self.file.schema == "IFC2X3":
|
||||||
curve = self.file.createIfcPolyline([self.file.createIfcCartesianPoint(p) for p in points])
|
curve = self.file.createIfcPolyline([self.file.createIfcCartesianPoint(p) for p in points])
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user