mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
Basic editing of item attributes implemented
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"]
|
||||
|
||||
Reference in New Issue
Block a user