mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 21:42:19 +00:00
model/wall.py - poll messages
This commit is contained in:
@@ -54,7 +54,10 @@ class UnjoinWalls(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.selected_objects
|
if not tool.Model.has_selected_ifc_objects():
|
||||||
|
cls.poll_message_set("No IFC objects selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
core.unjoin_walls(tool.Ifc, tool.Blender, tool.Geometry, DumbWallJoiner(), tool.Model)
|
core.unjoin_walls(tool.Ifc, tool.Blender, tool.Geometry, DumbWallJoiner(), tool.Model)
|
||||||
@@ -139,11 +142,17 @@ class AlignWall(bpy.types.Operator):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
selected_valid_objects = [o for o in context.selected_objects if o.data and hasattr(o.data, "transform")]
|
if not context.active_object:
|
||||||
return context.active_object and len(selected_valid_objects) > 1
|
cls.poll_message_set("No active object selected.")
|
||||||
|
return False
|
||||||
|
selected_valid_objects = tool.Model.get_selected_mesh_objects()
|
||||||
|
if len(selected_valid_objects) < 2:
|
||||||
|
cls.poll_message_set("Please select at least two mesh objects.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
selected_objects = [o for o in context.selected_objects if o.data and hasattr(o.data, "transform")]
|
selected_objects = tool.Model.get_selected_mesh_objects()
|
||||||
for obj in selected_objects:
|
for obj in selected_objects:
|
||||||
if obj == context.active_object:
|
if obj == context.active_object:
|
||||||
continue
|
continue
|
||||||
@@ -167,10 +176,13 @@ class FlipWall(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.selected_objects
|
if not tool.Model.has_selected_ifc_objects():
|
||||||
|
cls.poll_message_set("No IFC objects selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
selected_objs = [o for o in context.selected_objects if o.data and hasattr(o.data, "transform")]
|
selected_objs = tool.Model.get_selected_mesh_objects()
|
||||||
joiner = DumbWallJoiner()
|
joiner = DumbWallJoiner()
|
||||||
for obj in selected_objs:
|
for obj in selected_objs:
|
||||||
joiner.flip(obj)
|
joiner.flip(obj)
|
||||||
@@ -187,10 +199,13 @@ class SplitWall(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.selected_objects
|
if not tool.Model.has_selected_ifc_objects():
|
||||||
|
cls.poll_message_set("No IFC objects selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
selected_objs = [o for o in context.selected_objects if o.data and hasattr(o.data, "transform")]
|
selected_objs = tool.Model.get_selected_mesh_objects()
|
||||||
for obj in selected_objs:
|
for obj in selected_objs:
|
||||||
DumbWallJoiner().split(obj, context.scene.cursor.location)
|
DumbWallJoiner().split(obj, context.scene.cursor.location)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -204,12 +219,23 @@ class MergeWall(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.selected_objects
|
if not context.active_object:
|
||||||
|
cls.poll_message_set("No active object selected.")
|
||||||
|
return False
|
||||||
|
elif not tool.Model.has_selected_ifc_objects():
|
||||||
|
cls.poll_message_set("No mesh IFC objects selected.")
|
||||||
|
return False
|
||||||
|
mesh_objects = [o for o in tool.Model.get_selected_ifc_objects() if o.type == "MESH"]
|
||||||
|
if len(mesh_objects) != 2:
|
||||||
|
cls.poll_message_set("Please select exactly two mesh IFC objects.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
selected_objs = [o for o in context.selected_objects if o.data and hasattr(o.data, "transform")]
|
active_obj = context.active_object
|
||||||
if len(selected_objs) == 2:
|
assert active_obj
|
||||||
DumbWallJoiner().merge([o for o in selected_objs if o != context.active_object][0], context.active_object)
|
selected_objs = tool.Model.get_selected_mesh_objects()
|
||||||
|
DumbWallJoiner().merge(next(o for o in selected_objs if o != active_obj), active_obj)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -220,50 +246,59 @@ class RecalculateWall(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.selected_objects
|
if not tool.Model.has_selected_mesh_ifc_objects():
|
||||||
|
cls.poll_message_set("No mesh IFC objects selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
DumbWallRecalculator().recalculate(context.selected_objects)
|
objects = tool.Model.get_selected_mesh_ifc_objects()
|
||||||
|
DumbWallRecalculator().recalculate(objects)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class ChangeExtrusionDepth(bpy.types.Operator, tool.Ifc.Operator):
|
class ChangeExtrusionDepth(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.change_extrusion_depth"
|
bl_idname = "bim.change_extrusion_depth"
|
||||||
bl_label = "Update"
|
bl_label = "Update"
|
||||||
bl_description = "Update Height"
|
bl_description = "Update height for the selected objects."
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
depth: bpy.props.FloatProperty()
|
depth: bpy.props.FloatProperty()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.selected_objects
|
if not tool.Model.has_selected_mesh_ifc_objects():
|
||||||
|
cls.poll_message_set("No mesh IFC objects selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
layer2_objs = []
|
layer2_objs: list[bpy.types.Object] = []
|
||||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
ifc_file = tool.Ifc.get()
|
||||||
for obj in context.selected_objects:
|
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||||
|
selected_objs = tool.Model.get_selected_mesh_ifc_objects()
|
||||||
|
|
||||||
|
for obj in selected_objs:
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
if not element:
|
assert element
|
||||||
return
|
|
||||||
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
if not representation:
|
if not representation:
|
||||||
return
|
continue
|
||||||
extrusion = tool.Model.get_extrusion(representation)
|
extrusion = tool.Model.get_extrusion(representation)
|
||||||
if not extrusion:
|
if not extrusion:
|
||||||
return
|
continue
|
||||||
x, y, z = extrusion.ExtrudedDirection.DirectionRatios
|
x, y, z = extrusion.ExtrudedDirection.DirectionRatios
|
||||||
x_angle = Vector((0, 1)).angle_signed(Vector((y, z)))
|
x_angle = Vector((0, 1)).angle_signed(Vector((y, z)))
|
||||||
extrusion.Depth = self.depth / si_conversion * (1 / cos(x_angle))
|
extrusion.Depth = self.depth / si_conversion * (1 / cos(x_angle))
|
||||||
if tool.Model.get_usage_type(element) == "LAYER2":
|
if tool.Model.get_usage_type(element) == "LAYER2":
|
||||||
for rel in element.ConnectedFrom:
|
for rel in element.ConnectedFrom:
|
||||||
if rel.is_a() == "IfcRelConnectsElements":
|
if rel.is_a() == "IfcRelConnectsElements":
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.geometry.disconnect_element(
|
||||||
"geometry.disconnect_element",
|
ifc_file,
|
||||||
tool.Ifc.get(),
|
|
||||||
relating_element=rel.RelatingElement,
|
relating_element=rel.RelatingElement,
|
||||||
related_element=element,
|
related_element=element,
|
||||||
)
|
)
|
||||||
layer2_objs.append(obj)
|
layer2_objs.append(obj)
|
||||||
|
|
||||||
if layer2_objs:
|
if layer2_objs:
|
||||||
DumbWallRecalculator().recalculate(layer2_objs)
|
DumbWallRecalculator().recalculate(layer2_objs)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -272,30 +307,33 @@ class ChangeExtrusionDepth(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
class ChangeExtrusionXAngle(bpy.types.Operator, tool.Ifc.Operator):
|
class ChangeExtrusionXAngle(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.change_extrusion_x_angle"
|
bl_idname = "bim.change_extrusion_x_angle"
|
||||||
bl_label = "Update"
|
bl_label = "Update"
|
||||||
bl_description = "Update Angle"
|
bl_description = "Update angle for the selected objects."
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
x_angle: bpy.props.FloatProperty(name="X Angle", default=0, subtype="ANGLE")
|
x_angle: bpy.props.FloatProperty(name="X Angle", default=0, subtype="ANGLE")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.selected_objects
|
if not tool.Model.has_selected_mesh_ifc_objects():
|
||||||
|
cls.poll_message_set("No mesh IFC objects selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
layer2_objs = []
|
layer2_objs: list[bpy.types.Object] = []
|
||||||
other_objs = []
|
|
||||||
x_angle = 0 if tool.Cad.is_x(self.x_angle, 0, tolerance=0.001) else self.x_angle
|
x_angle = 0 if tool.Cad.is_x(self.x_angle, 0, tolerance=0.001) else self.x_angle
|
||||||
x_angle = 0 if tool.Cad.is_x(self.x_angle, pi, tolerance=0.001) else self.x_angle
|
x_angle = 0 if tool.Cad.is_x(self.x_angle, pi, tolerance=0.001) else self.x_angle
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||||
for obj in context.selected_objects:
|
selected_objs = tool.Model.get_selected_mesh_ifc_objects()
|
||||||
|
|
||||||
|
for obj in selected_objs:
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
if not element:
|
assert element
|
||||||
return
|
|
||||||
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
if not representation:
|
if not representation:
|
||||||
return
|
continue
|
||||||
extrusion = tool.Model.get_extrusion(representation)
|
extrusion = tool.Model.get_extrusion(representation)
|
||||||
if not extrusion:
|
if not extrusion:
|
||||||
return
|
continue
|
||||||
existing_x_angle = tool.Model.get_existing_x_angle(extrusion)
|
existing_x_angle = tool.Model.get_existing_x_angle(extrusion)
|
||||||
existing_x_angle = 0 if tool.Cad.is_x(existing_x_angle, 0, tolerance=0.001) else existing_x_angle
|
existing_x_angle = 0 if tool.Cad.is_x(existing_x_angle, 0, tolerance=0.001) else existing_x_angle
|
||||||
existing_x_angle = 0 if tool.Cad.is_x(existing_x_angle, pi, tolerance=0.001) else existing_x_angle
|
existing_x_angle = 0 if tool.Cad.is_x(existing_x_angle, pi, tolerance=0.001) else existing_x_angle
|
||||||
@@ -382,17 +420,21 @@ class ChangeExtrusionXAngle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
class ChangeLayerLength(bpy.types.Operator, tool.Ifc.Operator):
|
class ChangeLayerLength(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.change_layer_length"
|
bl_idname = "bim.change_layer_length"
|
||||||
bl_label = "Update"
|
bl_label = "Update"
|
||||||
bl_description = "Update Length"
|
bl_description = "Update length for the selected objects."
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
length: bpy.props.FloatProperty()
|
length: bpy.props.FloatProperty()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.selected_objects
|
if not tool.Model.has_selected_mesh_ifc_objects():
|
||||||
|
cls.poll_message_set("No mesh IFC objects selected.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
joiner = DumbWallJoiner()
|
joiner = DumbWallJoiner()
|
||||||
for obj in context.selected_objects:
|
selected_objs = tool.Model.get_selected_mesh_ifc_objects()
|
||||||
|
for obj in selected_objs:
|
||||||
joiner.set_length(obj, self.length)
|
joiner.set_length(obj, self.length)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -1080,7 +1122,7 @@ class DumbWallJoiner:
|
|||||||
)
|
)
|
||||||
self.recreate_wall(element1, wall1)
|
self.recreate_wall(element1, wall1)
|
||||||
|
|
||||||
def merge(self, wall1, wall2):
|
def merge(self, wall1: bpy.types.Object, wall2: bpy.types.Object) -> None:
|
||||||
if tool.Ifc.is_moved(wall1):
|
if tool.Ifc.is_moved(wall1):
|
||||||
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=wall1)
|
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=wall1)
|
||||||
if tool.Ifc.is_moved(wall2):
|
if tool.Ifc.is_moved(wall2):
|
||||||
@@ -1088,6 +1130,7 @@ class DumbWallJoiner:
|
|||||||
|
|
||||||
element1 = tool.Ifc.get_entity(wall1)
|
element1 = tool.Ifc.get_entity(wall1)
|
||||||
element2 = tool.Ifc.get_entity(wall2)
|
element2 = tool.Ifc.get_entity(wall2)
|
||||||
|
assert element1 and element2
|
||||||
|
|
||||||
p1, p2 = ifcopenshell.util.representation.get_reference_line(element1)
|
p1, p2 = ifcopenshell.util.representation.get_reference_line(element1)
|
||||||
p3, p4 = ifcopenshell.util.representation.get_reference_line(element2)
|
p3, p4 = ifcopenshell.util.representation.get_reference_line(element2)
|
||||||
@@ -1196,8 +1239,7 @@ class DumbWallJoiner:
|
|||||||
|
|
||||||
def set_length(self, wall1: bpy.types.Object, si_length: float) -> None:
|
def set_length(self, wall1: bpy.types.Object, si_length: float) -> None:
|
||||||
element1 = tool.Ifc.get_entity(wall1)
|
element1 = tool.Ifc.get_entity(wall1)
|
||||||
if not element1:
|
assert element1
|
||||||
return
|
|
||||||
if tool.Ifc.is_moved(wall1):
|
if tool.Ifc.is_moved(wall1):
|
||||||
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=wall1)
|
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=wall1)
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ if TYPE_CHECKING:
|
|||||||
def unjoin_walls(
|
def unjoin_walls(
|
||||||
ifc: tool.Ifc, blender: tool.Blender, geometry: tool.Geometry, joiner: DumbWallJoiner, model: tool.Model
|
ifc: tool.Ifc, blender: tool.Blender, geometry: tool.Geometry, joiner: DumbWallJoiner, model: tool.Model
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""Unjoin selected walls."""
|
||||||
for obj in blender.get_selected_objects():
|
for obj in blender.get_selected_objects():
|
||||||
if not (element := ifc.get_entity(obj)) or model.get_usage_type(element) != "LAYER2":
|
if not (element := ifc.get_entity(obj)) or model.get_usage_type(element) != "LAYER2":
|
||||||
continue
|
continue
|
||||||
@@ -48,6 +49,7 @@ def extend_walls(
|
|||||||
model: tool.Model,
|
model: tool.Model,
|
||||||
target: Vector,
|
target: Vector,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""Extend selected walls to the target."""
|
||||||
for obj in blender.get_selected_objects():
|
for obj in blender.get_selected_objects():
|
||||||
if not (element := ifc.get_entity(obj)) or model.get_usage_type(element) != "LAYER2":
|
if not (element := ifc.get_entity(obj)) or model.get_usage_type(element) != "LAYER2":
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -1138,6 +1138,27 @@ class Model(bonsai.core.tool.Model):
|
|||||||
|
|
||||||
AuthoringData.type_thumbnails[element.id()] = obj.preview.icon_id
|
AuthoringData.type_thumbnails[element.id()] = obj.preview.icon_id
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_selected_ifc_objects(cls) -> list[bpy.types.Object]:
|
||||||
|
return [obj for obj in tool.Blender.get_selected_objects() if tool.Ifc.get_entity(obj)]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def has_selected_ifc_objects(cls) -> bool:
|
||||||
|
return any(tool.Ifc.get_entity(obj) for obj in tool.Blender.get_selected_objects())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_selected_mesh_objects(cls) -> list[bpy.types.Object]:
|
||||||
|
objects = tool.Blender.get_selected_objects()
|
||||||
|
return [obj for obj in objects if obj.type == "MESH"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_selected_mesh_ifc_objects(cls) -> list[bpy.types.Object]:
|
||||||
|
return [obj for obj in tool.Model.get_selected_mesh_objects() if tool.Ifc.get_entity(obj)]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def has_selected_mesh_ifc_objects(cls) -> bool:
|
||||||
|
return any(tool.Ifc.get_entity(obj) for obj in tool.Model.get_selected_mesh_objects())
|
||||||
|
|
||||||
BBIM_PARAMETRIC_PSETS = (
|
BBIM_PARAMETRIC_PSETS = (
|
||||||
"BBIM_Window",
|
"BBIM_Window",
|
||||||
"BBIM_Door",
|
"BBIM_Door",
|
||||||
|
|||||||
Reference in New Issue
Block a user