Basic editing of item attributes implemented

This commit is contained in:
Dion Moult
2024-09-21 14:27:17 +10:00
parent ef412c36c6
commit 2a8d43c42c
7 changed files with 87 additions and 93 deletions
@@ -322,10 +322,10 @@ def add_header_apply_button(layout, text, apply_operator, cancel_operator, ui_co
)
row = layout.row(align=True)
row.operator(apply_operator, text="Apply" if ui_context!="TOOL_HEADER" else "", icon="CHECKMARK")
row.label(text="", icon="EVENT_TAB") if ui_context!="TOOL_HEADER" else row
row = layout.row(align=True) if ui_context!="TOOL_HEADER" else row
row.operator(cancel_operator, text="Cancel" if ui_context!="TOOL_HEADER" else "", icon="CANCEL")
row.operator(apply_operator, text="Apply" if ui_context != "TOOL_HEADER" else "", icon="CHECKMARK")
row.label(text="", icon="EVENT_TAB") if ui_context != "TOOL_HEADER" else row
row = layout.row(align=True) if ui_context != "TOOL_HEADER" else row
row.operator(cancel_operator, text="Cancel" if ui_context != "TOOL_HEADER" else "", icon="CANCEL")
row = layout.row(align=True)
row.label(text="Tools")
@@ -58,6 +58,7 @@ classes = (
operator.SelectConnection,
operator.SwitchRepresentation,
operator.UnassignRepresentationItemStyle,
operator.UpdateItemAttributes,
operator.UpdateParametricRepresentation,
operator.UpdateRepresentation,
prop.RepresentationItem,
@@ -1780,7 +1780,7 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator):
tool.Geometry.reload_representation(bpy.context.scene.BIMGeometryProperties.representation_obj)
return
else:
self.reload_item(obj)
tool.Geometry.import_item(obj)
return
elif item.is_a("IfcSweptAreaSolid"):
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
@@ -1866,15 +1866,6 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator):
context.scene.BIMGeometryProperties.mode = "EDIT"
context.scene.BIMGeometryProperties.is_changing_mode = False
def reload_item(self, obj):
tool.Loader.settings.contexts = ifcopenshell.util.representation.get_prioritised_contexts(tool.Ifc.get())
tool.Loader.settings.context_settings = tool.Loader.create_settings()
tool.Loader.settings.gross_context_settings = tool.Loader.create_settings(is_gross=True)
item = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
geometry = tool.Loader.create_generic_shape(item)
obj.data.clear_geometry()
tool.Loader.convert_geometry_to_mesh(geometry, obj.data)
def invoke(self, context, event):
return IfcStore.execute_ifc_operator(self, context, is_invoke=True)
@@ -2388,27 +2379,33 @@ class ImportRepresentationItems(bpy.types.Operator, tool.Ifc.Operator):
item = tool.Ifc.get().by_id(item_id)
item_mesh = bpy.data.meshes.new(f"Item/{item.is_a()}/{item_id}")
item_mesh.BIMMeshProperties.ifc_definition_id = item_id
geometry = tool.Loader.create_generic_shape(item)
tool.Loader.convert_geometry_to_mesh(geometry, item_mesh)
item_obj = bpy.data.objects.new(f"Item/{item.is_a()}/{item_id}", item_mesh)
item_obj.matrix_world = obj.matrix_world
item_obj.show_in_front = True
bpy.context.collection.objects.link(item_obj)
if tool.Geometry.is_meshlike_item(item):
tool.Geometry.lock_object(item_obj)
new = props.item_objs.add()
new.obj = item_obj
if item.is_a("IfcSweptAreaSolid"):
tool.Geometry.record_object_position(item_obj)
if item.Position:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
position = Matrix(ifcopenshell.util.placement.get_axis2placement(item.Position).tolist())
position.translation *= unit_scale
position_i = position.inverted()
item_obj.matrix_world = item_obj.matrix_world @ position
for vert in item_obj.data.vertices:
vert.co = position_i @ vert.co
tool.Geometry.import_item(item_obj)
tool.Geometry.import_item_attributes(item_obj)
if tool.Geometry.is_meshlike_item(item):
tool.Geometry.lock_object(item_obj)
class UpdateItemAttributes(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.update_item_attributes"
bl_label = "Update Item Attributes"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
obj = context.active_object
props = obj.data.BIMMeshProperties
item = tool.Ifc.get().by_id(props.ifc_definition_id)
for attribute in props.item_attributes:
if attribute.name == "Depth":
item.Depth = attribute.float_value
tool.Geometry.reload_representation(bpy.context.scene.BIMGeometryProperties.representation_obj)
tool.Geometry.import_item(obj)
+25 -64
View File
@@ -105,12 +105,17 @@ class BimTool(WorkSpaceTool):
("bim.hotkey", {"type": "P", "value": "PRESS", "ctrl": True}, {"properties": [("hotkey", "C_P")]}),
("bim.hotkey", {"type": "P", "value": "PRESS", "alt": True}, {"properties": [("hotkey", "A_P")]}),
)
ifc_element_type = "all"
def draw_settings(context, layout, ws_tool):
@classmethod
def draw_settings(cls, context, layout, ws_tool):
# Unlike operators, Blender doesn't treat workspace tools as a class, so we'll create our own.
CreateObjectUI.draw(context, layout, ifc_element_type="all")
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout)
if context.scene.BIMGeometryProperties.mode == "ITEM":
EditItemUI.draw(context, layout)
else:
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
class WallTool(BimTool):
@@ -123,12 +128,6 @@ class WallTool(BimTool):
bl_widget = None
ifc_element_type = "IfcWallType"
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
class SlabTool(BimTool):
bl_space_type = "VIEW_3D"
@@ -140,12 +139,6 @@ class SlabTool(BimTool):
bl_widget = None
ifc_element_type = "IfcSlabType"
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
class DoorTool(BimTool):
bl_space_type = "VIEW_3D"
@@ -157,12 +150,6 @@ class DoorTool(BimTool):
bl_widget = None
ifc_element_type = "IfcDoorType"
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
class WindowTool(BimTool):
bl_space_type = "VIEW_3D"
@@ -174,12 +161,6 @@ class WindowTool(BimTool):
bl_widget = None
ifc_element_type = "IfcWindowType"
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
class ColumnTool(BimTool):
bl_space_type = "VIEW_3D"
@@ -191,12 +172,6 @@ class ColumnTool(BimTool):
bl_widget = None
ifc_element_type = "IfcColumnType"
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
class BeamTool(BimTool):
bl_space_type = "VIEW_3D"
@@ -208,12 +183,6 @@ class BeamTool(BimTool):
bl_widget = None
ifc_element_type = "IfcBeamType"
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
class DuctTool(BimTool):
bl_space_type = "VIEW_3D"
@@ -225,12 +194,6 @@ class DuctTool(BimTool):
bl_widget = None
ifc_element_type = "IfcDuctSegmentType"
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
class CableCarrierTool(BimTool):
bl_space_type = "VIEW_3D"
@@ -242,12 +205,6 @@ class CableCarrierTool(BimTool):
bl_widget = None
ifc_element_type = "IfcCableCarrierSegmentType"
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
class PipeTool(BimTool):
bl_space_type = "VIEW_3D"
@@ -259,12 +216,6 @@ class PipeTool(BimTool):
bl_widget = None
ifc_element_type = "IfcPipeSegmentType"
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
class CableTool(BimTool):
bl_space_type = "VIEW_3D"
@@ -276,12 +227,6 @@ class CableTool(BimTool):
bl_widget = None
ifc_element_type = "IfcCableSegmentType"
@classmethod
def draw_settings(cls, context, layout, ws_tool):
CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
if context.active_object and context.selected_objects:
EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
def add_layout_hotkey_operator(layout, text, hotkey, description, ui_context=""):
parts = hotkey.split("_") if hotkey else []
@@ -314,6 +259,22 @@ def format_ifc_camel_case(string):
return "".join(" " + char if char.isupper() else char for char in string).strip()
class EditItemUI:
@classmethod
def draw(cls, context, layout):
cls.layout = layout
row = cls.layout.row()
row.label(text="Item Mode", icon="MESH_DATA")
if not (obj := context.active_object) or not tool.Geometry.is_representation_item(obj):
return
for item_attribute in obj.data.BIMMeshProperties.item_attributes:
row = cls.layout.row()
row.prop(item_attribute, "float_value", text=item_attribute.name)
if len(obj.data.BIMMeshProperties.item_attributes):
row = cls.layout.row()
row.operator("bim.update_item_attributes", icon="FILE_REFRESH", text="")
class CreateObjectUI:
@classmethod
def draw(cls, context, layout, ifc_element_type=None):
+1
View File
@@ -508,6 +508,7 @@ class BIMMeshProperties(PropertyGroup):
subshape_type: StringProperty(name="Subshape Type")
ifc_definition: StringProperty(name="IFC Definition")
ifc_parameters: CollectionProperty(name="IFC Parameters", type=IfcParameter)
item_attributes: CollectionProperty(name="Item Attributes", type=Attribute)
material_checksum: StringProperty(name="Material Checksum", default="[]")
mesh_checksum: StringProperty(name="Mesh Checksum", default="")
replaced_mesh: PointerProperty(type=bpy.types.Mesh, description="Original mesh to revert section cutaway")
+33
View File
@@ -31,6 +31,7 @@ import ifcopenshell.guid
import ifcopenshell.util.element
import ifcopenshell.util.representation
import ifcopenshell.util.system
import ifcopenshell.util.placement
import bonsai.core.tool
import bonsai.core.drawing
import bonsai.core.geometry
@@ -1438,3 +1439,35 @@ class Geometry(bonsai.core.tool.Geometry):
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_position)
if has_changed:
cls.reload_representation(rep_obj)
@classmethod
def import_item_attributes(cls, obj: bpy.types.Object) -> None:
props = obj.data.BIMMeshProperties
props.item_attributes.clear()
item = tool.Ifc.get().by_id(props.ifc_definition_id)
if item.is_a("IfcExtrudedAreaSolid"):
new = props.item_attributes.add()
new.name = "Depth"
new.float_value = item.Depth
@classmethod
def import_item(cls, obj: bpy.types.Object) -> None:
props = bpy.context.scene.BIMGeometryProperties
tool.Loader.settings.contexts = ifcopenshell.util.representation.get_prioritised_contexts(tool.Ifc.get())
tool.Loader.settings.context_settings = tool.Loader.create_settings()
tool.Loader.settings.gross_context_settings = tool.Loader.create_settings(is_gross=True)
item = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
geometry = tool.Loader.create_generic_shape(item)
obj.data.clear_geometry()
tool.Loader.convert_geometry_to_mesh(geometry, obj.data)
if item.is_a("IfcSweptAreaSolid"):
cls.record_object_position(obj)
if item.Position:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
position = Matrix(ifcopenshell.util.placement.get_axis2placement(item.Position).tolist())
position.translation *= unit_scale
position_i = position.inverted()
obj.matrix_world = props.representation_obj.matrix_world @ position
for vert in obj.data.vertices:
vert.co = position_i @ vert.co
@@ -23,6 +23,7 @@ import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
from ifcopenshell.util.doc import get_predefined_type_doc
from ifcopenshell.util.element import get_psets
from ifcopenshell.util.unit import get_unit_symbol
arithmetic_operator_symbols = {"ADD": "+", "DIVIDE": "/", "MULTIPLY": "*", "SUBTRACT": "-"}
symbol_arithmetic_operators = {"+": "ADD", "/": "DIVIDE", "*": "MULTIPLY", "-": "SUBTRACT"}
FILTER_BY_TYPE = Literal["PRODUCT", "RESOURCE", "PROCESS"]