mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-28 11:18:18 +00:00
WIP migrate attribute management to partial editing with 4 new features! See #1222.
New features include: - New clarity between null and empty string attributes - Attribute editing now shows appropriate UI widgets depending on data type - Attribute editing for enumerations now show a dropdown - Attribute editing is now schema sensitive
This commit is contained in:
@@ -6,6 +6,7 @@ bpy = sys.modules.get("bpy")
|
|||||||
if bpy is not None:
|
if bpy is not None:
|
||||||
import bpy
|
import bpy
|
||||||
import blenderbim.bim.module.root as module_root
|
import blenderbim.bim.module.root as module_root
|
||||||
|
import blenderbim.bim.module.attribute as module_attribute
|
||||||
import blenderbim.bim.module.bcf as module_bcf
|
import blenderbim.bim.module.bcf as module_bcf
|
||||||
import blenderbim.bim.module.context as module_context
|
import blenderbim.bim.module.context as module_context
|
||||||
import blenderbim.bim.module.covetool as module_covetool
|
import blenderbim.bim.module.covetool as module_covetool
|
||||||
@@ -87,8 +88,6 @@ if bpy is not None:
|
|||||||
operator.UnassignDocumentReference,
|
operator.UnassignDocumentReference,
|
||||||
operator.RemoveObjectDocumentReference,
|
operator.RemoveObjectDocumentReference,
|
||||||
operator.GenerateGlobalId,
|
operator.GenerateGlobalId,
|
||||||
operator.AddAttribute,
|
|
||||||
operator.RemoveAttribute,
|
|
||||||
operator.AddMaterialAttribute,
|
operator.AddMaterialAttribute,
|
||||||
operator.RemoveMaterialAttribute,
|
operator.RemoveMaterialAttribute,
|
||||||
operator.QuickProjectSetup,
|
operator.QuickProjectSetup,
|
||||||
@@ -312,6 +311,7 @@ if bpy is not None:
|
|||||||
]
|
]
|
||||||
|
|
||||||
classes.extend(module_root.classes)
|
classes.extend(module_root.classes)
|
||||||
|
classes.extend(module_attribute.classes)
|
||||||
classes.extend(module_bcf.classes)
|
classes.extend(module_bcf.classes)
|
||||||
classes.extend(module_context.classes)
|
classes.extend(module_context.classes)
|
||||||
classes.extend(module_covetool.classes)
|
classes.extend(module_covetool.classes)
|
||||||
@@ -350,6 +350,7 @@ if bpy is not None:
|
|||||||
bpy.types.TextCurve.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties)
|
bpy.types.TextCurve.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties)
|
||||||
bpy.types.SCENE_PT_unit.append(ui.ifc_units)
|
bpy.types.SCENE_PT_unit.append(ui.ifc_units)
|
||||||
module_root.register()
|
module_root.register()
|
||||||
|
module_attribute.register()
|
||||||
module_bcf.register()
|
module_bcf.register()
|
||||||
module_context.register()
|
module_context.register()
|
||||||
module_covetool.register()
|
module_covetool.register()
|
||||||
@@ -382,5 +383,6 @@ if bpy is not None:
|
|||||||
module_covetool.unregister()
|
module_covetool.unregister()
|
||||||
module_context.unregister()
|
module_context.unregister()
|
||||||
module_bcf.unregister()
|
module_bcf.unregister()
|
||||||
|
module_attribute.register()
|
||||||
module_root.unregister()
|
module_root.unregister()
|
||||||
bpy.app.handlers.depsgraph_update_pre.remove(operator.depsgraph_update_pre_handler)
|
bpy.app.handlers.depsgraph_update_pre.remove(operator.depsgraph_update_pre_handler)
|
||||||
|
|||||||
@@ -847,7 +847,6 @@ class IfcImporter:
|
|||||||
obj = bpy.data.objects.new(self.get_name(element), mesh)
|
obj = bpy.data.objects.new(self.get_name(element), mesh)
|
||||||
obj.BIMObjectProperties.ifc_definition_id = element.id()
|
obj.BIMObjectProperties.ifc_definition_id = element.id()
|
||||||
self.material_creator.create(element, obj, mesh)
|
self.material_creator.create(element, obj, mesh)
|
||||||
self.add_element_attributes(element, obj.BIMObjectProperties)
|
|
||||||
self.add_element_classifications(element, obj)
|
self.add_element_classifications(element, obj)
|
||||||
self.add_element_document_relations(element, obj)
|
self.add_element_document_relations(element, obj)
|
||||||
self.add_type_product_psets(element, obj)
|
self.add_type_product_psets(element, obj)
|
||||||
@@ -975,7 +974,6 @@ class IfcImporter:
|
|||||||
obj.matrix_world = self.get_element_matrix(element)
|
obj.matrix_world = self.get_element_matrix(element)
|
||||||
|
|
||||||
self.add_element_representation_items(element, obj)
|
self.add_element_representation_items(element, obj)
|
||||||
self.add_element_attributes(element, obj.BIMObjectProperties)
|
|
||||||
self.add_element_classifications(element, obj)
|
self.add_element_classifications(element, obj)
|
||||||
self.add_element_document_relations(element, obj)
|
self.add_element_document_relations(element, obj)
|
||||||
self.add_defines_by_type_relation(element, obj)
|
self.add_defines_by_type_relation(element, obj)
|
||||||
@@ -1732,7 +1730,6 @@ class IfcImporter:
|
|||||||
obj.instance_type = "COLLECTION"
|
obj.instance_type = "COLLECTION"
|
||||||
obj.instance_collection = collection
|
obj.instance_collection = collection
|
||||||
self.place_object_in_spatial_tree(element, obj)
|
self.place_object_in_spatial_tree(element, obj)
|
||||||
self.add_element_attributes(element, obj.BIMObjectProperties)
|
|
||||||
self.add_element_classifications(element, obj)
|
self.add_element_classifications(element, obj)
|
||||||
self.add_element_document_relations(element, obj)
|
self.add_element_document_relations(element, obj)
|
||||||
self.add_defines_by_type_relation(element, obj)
|
self.add_defines_by_type_relation(element, obj)
|
||||||
@@ -1795,7 +1792,6 @@ class IfcImporter:
|
|||||||
obj.BIMObjectProperties.ifc_definition_id = element.id()
|
obj.BIMObjectProperties.ifc_definition_id = element.id()
|
||||||
self.material_creator.create(element, obj, mesh)
|
self.material_creator.create(element, obj, mesh)
|
||||||
obj.matrix_world = self.get_element_matrix(element, mesh_name)
|
obj.matrix_world = self.get_element_matrix(element, mesh_name)
|
||||||
self.add_element_attributes(element, obj.BIMObjectProperties)
|
|
||||||
self.add_element_classifications(element, obj)
|
self.add_element_classifications(element, obj)
|
||||||
self.add_element_document_relations(element, obj)
|
self.add_element_document_relations(element, obj)
|
||||||
self.add_defines_by_type_relation(element, obj)
|
self.add_defines_by_type_relation(element, obj)
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import bpy
|
||||||
|
from . import ui, operator
|
||||||
|
|
||||||
|
classes = (
|
||||||
|
operator.EnableEditingAttributes,
|
||||||
|
operator.DisableEditingAttributes,
|
||||||
|
operator.EditAttributes,
|
||||||
|
ui.BIM_PT_attributes,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def register():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
pass
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import ifcopenshell
|
||||||
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
|
||||||
|
|
||||||
|
class Data:
|
||||||
|
products = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls, product_id):
|
||||||
|
file = IfcStore.get_file()
|
||||||
|
if not file:
|
||||||
|
return
|
||||||
|
product = file.by_id(product_id)
|
||||||
|
cls.products[product_id] = []
|
||||||
|
attributes = product.get_info()
|
||||||
|
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(file.schema)
|
||||||
|
declaration = schema.declaration_by_name(product.is_a())
|
||||||
|
for attribute in declaration.all_attributes():
|
||||||
|
data_type = str(attribute.type_of_attribute())
|
||||||
|
value = getattr(product, attribute.name())
|
||||||
|
list_type = None
|
||||||
|
enum_items = ()
|
||||||
|
if "<entity" in data_type:
|
||||||
|
data_type = "entity"
|
||||||
|
value = None if value is None else str(value)
|
||||||
|
elif "<list" in data_type:
|
||||||
|
if "<entity" in data_type:
|
||||||
|
list_type = "entity"
|
||||||
|
elif "<string>" in data_type:
|
||||||
|
list_type = "string"
|
||||||
|
elif "<real>" in data_type:
|
||||||
|
list_type = "float"
|
||||||
|
elif "<integer>" in data_type:
|
||||||
|
list_type = "integer"
|
||||||
|
data_type = "list"
|
||||||
|
value = None if value is None else str(value)
|
||||||
|
elif "<string>" in data_type:
|
||||||
|
data_type = "string"
|
||||||
|
value = None if value is None else str(value)
|
||||||
|
elif "<real>" in data_type:
|
||||||
|
data_type = "float"
|
||||||
|
value = None if value is None else float(value)
|
||||||
|
elif "<integer>" in data_type:
|
||||||
|
data_type = "integer"
|
||||||
|
value = None if value is None else int(value)
|
||||||
|
elif "<enumeration" in data_type:
|
||||||
|
data_type = "enum"
|
||||||
|
value = None if value is None else str(value)
|
||||||
|
enum_items = attribute.type_of_attribute().declared_type().enumeration_items()
|
||||||
|
cls.products[product_id].append({
|
||||||
|
"name": attribute.name(),
|
||||||
|
"value": value,
|
||||||
|
"type": data_type,
|
||||||
|
"enum_items": enum_items,
|
||||||
|
"list_type": list_type,
|
||||||
|
"is_optional": attribute.optional(),
|
||||||
|
"is_null": getattr(product, attribute.name()) is None
|
||||||
|
})
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class Usecase():
|
||||||
|
def __init__(self, file, settings=None):
|
||||||
|
self.file = file
|
||||||
|
self.settings = {
|
||||||
|
"product": None,
|
||||||
|
"attributes": {}
|
||||||
|
}
|
||||||
|
for key, value in settings.items():
|
||||||
|
self.settings[key] = value
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
for name, value in self.settings["attributes"].items():
|
||||||
|
setattr(self.settings["product"], name, value)
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import bpy
|
||||||
|
import json
|
||||||
|
import blenderbim.bim.module.attribute.edit_attributes as edit_attributes
|
||||||
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
from blenderbim.bim.module.attribute.data import Data
|
||||||
|
|
||||||
|
|
||||||
|
class EnableEditingAttributes(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.enable_editing_attributes"
|
||||||
|
bl_label = "Enable Editing Attributes"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
obj = bpy.context.active_object
|
||||||
|
props = obj.BIMObjectProperties
|
||||||
|
while len(props.attributes) > 0:
|
||||||
|
props.attributes.remove(0)
|
||||||
|
for attribute in Data.products[props.ifc_definition_id]:
|
||||||
|
new = props.attributes.add()
|
||||||
|
if attribute["type"] == "entity":
|
||||||
|
continue
|
||||||
|
new.name = attribute["name"]
|
||||||
|
new.is_null = attribute["is_null"]
|
||||||
|
if attribute["type"] == "string" or attribute["type"] == "list":
|
||||||
|
new.string_value = attribute["value"] or ""
|
||||||
|
elif attribute["type"] == "integer":
|
||||||
|
new.int_value = attribute["value"] or 0
|
||||||
|
elif attribute["type"] == "float":
|
||||||
|
new.float_value = attribute["value"] or 0.
|
||||||
|
elif attribute["type"] == "enum":
|
||||||
|
new.enum_items = json.dumps(attribute["enum_items"])
|
||||||
|
if attribute["value"]:
|
||||||
|
new.enum_value = attribute["value"]
|
||||||
|
props.is_editing_attributes = True
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class DisableEditingAttributes(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.disable_editing_attributes"
|
||||||
|
bl_label = "Disable Editing Attributes"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
obj = bpy.context.active_object
|
||||||
|
props = obj.BIMObjectProperties
|
||||||
|
props.is_editing_attributes = False
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class EditAttributes(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.edit_attributes"
|
||||||
|
bl_label = "Edit Attributes"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
obj = bpy.context.active_object
|
||||||
|
props = obj.BIMObjectProperties
|
||||||
|
attributes = {}
|
||||||
|
for attribute in Data.products[props.ifc_definition_id]:
|
||||||
|
blender_attribute = props.attributes.get(attribute["name"])
|
||||||
|
if not blender_attribute:
|
||||||
|
continue
|
||||||
|
if blender_attribute.is_null:
|
||||||
|
attributes[attribute["name"]] = None
|
||||||
|
elif attribute["type"] == "string":
|
||||||
|
attributes[attribute["name"]] = blender_attribute.string_value
|
||||||
|
elif attribute["type"] == "list":
|
||||||
|
values = blender_attribute.string_value[1:-1].split(", ")
|
||||||
|
print(attribute["name"])
|
||||||
|
print(attribute["list_type"])
|
||||||
|
if attribute["list_type"] == "float":
|
||||||
|
values = [float(v) for v in values]
|
||||||
|
elif attribute["list_type"] == "integer":
|
||||||
|
values = [int(v) for v in values]
|
||||||
|
attributes[attribute["name"]] = values
|
||||||
|
elif attribute["type"] == "integer":
|
||||||
|
attributes[attribute["name"]] = blender_attribute.int_value
|
||||||
|
elif attribute["type"] == "float":
|
||||||
|
attributes[attribute["name"]] = blender_attribute.float_value
|
||||||
|
elif attribute["type"] == "enum":
|
||||||
|
attributes[attribute["name"]] = blender_attribute.enum_value
|
||||||
|
usecase = edit_attributes.Usecase(self.file, {
|
||||||
|
"product": self.file.by_id(props.ifc_definition_id),
|
||||||
|
"attributes": attributes
|
||||||
|
})
|
||||||
|
usecase.execute()
|
||||||
|
Data.load(props.ifc_definition_id)
|
||||||
|
bpy.ops.bim.disable_editing_attributes()
|
||||||
|
return {"FINISHED"}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
from bpy.types import Panel
|
||||||
|
from blenderbim.bim.module.attribute.data import Data
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_PT_attributes(Panel):
|
||||||
|
bl_label = "IFC Attributes"
|
||||||
|
bl_idname = "BIM_PT_attributes"
|
||||||
|
bl_space_type = "PROPERTIES"
|
||||||
|
bl_region_type = "WINDOW"
|
||||||
|
bl_context = "object"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return bool(context.active_object.BIMObjectProperties.ifc_definition_id)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
props = context.active_object.BIMObjectProperties
|
||||||
|
if not props.ifc_definition_id:
|
||||||
|
return
|
||||||
|
if props.ifc_definition_id not in Data.products:
|
||||||
|
Data.load(props.ifc_definition_id)
|
||||||
|
|
||||||
|
props = context.active_object.BIMObjectProperties
|
||||||
|
|
||||||
|
|
||||||
|
if props.is_editing_attributes:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.operator("bim.edit_attributes", icon="CHECKMARK", text="Save Attributes")
|
||||||
|
row.operator("bim.disable_editing_attributes", icon="X", text="")
|
||||||
|
|
||||||
|
for attribute in Data.products[props.ifc_definition_id]:
|
||||||
|
if attribute["type"] == "entity":
|
||||||
|
continue
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
blender_attribute = props.attributes.get(attribute["name"])
|
||||||
|
if attribute["type"] == "string" or attribute["type"] == "list":
|
||||||
|
row.prop(blender_attribute, "string_value", text=attribute["name"])
|
||||||
|
elif attribute["type"] == "integer":
|
||||||
|
row.prop(blender_attribute, "int_value", text=attribute["name"])
|
||||||
|
elif attribute["type"] == "float":
|
||||||
|
row.prop(blender_attribute, "float_value", text=attribute["name"])
|
||||||
|
elif attribute["type"] == "enum":
|
||||||
|
row.prop(blender_attribute, "enum_value", text=attribute["name"])
|
||||||
|
|
||||||
|
if attribute["name"] == "GlobalId":
|
||||||
|
row.operator("bim.generate_global_id", icon="FILE_REFRESH", text="")
|
||||||
|
if attribute["is_optional"]:
|
||||||
|
row.prop(blender_attribute, "is_null", icon="RADIOBUT_OFF" if blender_attribute.is_null else "RADIOBUT_ON", text="")
|
||||||
|
# TODO: reimplement, see #1222
|
||||||
|
#op = row.operator("bim.copy_attribute_to_selection", icon="COPYDOWN", text="")
|
||||||
|
#op.attribute_name = attribute.name
|
||||||
|
#op.attribute_value = attribute.string_value
|
||||||
|
else:
|
||||||
|
row = self.layout.row()
|
||||||
|
row.operator("bim.enable_editing_attributes", icon="GREASEPENCIL", text="Edit")
|
||||||
|
for attribute in Data.products[props.ifc_definition_id]:
|
||||||
|
if attribute["value"] is None or attribute["type"] == "entity":
|
||||||
|
continue
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.label(text=attribute["name"])
|
||||||
|
row.label(text=str(attribute["value"]))
|
||||||
|
|
||||||
|
# TODO: reimplement, see #1222
|
||||||
|
#if "IfcSite/" in context.active_object.name or "IfcBuilding/" in context.active_object.name:
|
||||||
|
# self.draw_addresses_ui()
|
||||||
|
|
||||||
|
def draw_addresses_ui(self):
|
||||||
|
self.layout.label(text="Address:")
|
||||||
|
address = bpy.context.active_object.BIMObjectProperties.address
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(address, "purpose")
|
||||||
|
if address.purpose == "USERDEFINED":
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(address, "user_defined_purpose")
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(address, "description")
|
||||||
|
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(address, "internal_location")
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(address, "address_lines")
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(address, "postal_box")
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(address, "town")
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(address, "region")
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(address, "postal_code")
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(address, "country")
|
||||||
|
|
||||||
@@ -13,5 +13,5 @@ class Data:
|
|||||||
cls.products[product_id] = {
|
cls.products[product_id] = {
|
||||||
"type": product.is_a(),
|
"type": product.is_a(),
|
||||||
"PredefinedType": product.PredefinedType if hasattr(product, "PredefinedType") else None,
|
"PredefinedType": product.PredefinedType if hasattr(product, "PredefinedType") else None,
|
||||||
"ObjectType": product.ObjectType or None
|
"ObjectType": product.ObjectType if hasattr(product, "ObjectType") else None
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ class Data:
|
|||||||
if not file:
|
if not file:
|
||||||
return
|
return
|
||||||
product = file.by_id(product_id)
|
product = file.by_id(product_id)
|
||||||
if product.ContainedInStructure:
|
if not hasattr(product, "ContainedInStructure"):
|
||||||
|
cls.products[product_id] = None
|
||||||
|
elif product.ContainedInStructure:
|
||||||
structure = product.ContainedInStructure[0].RelatingStructure
|
structure = product.ContainedInStructure[0].RelatingStructure
|
||||||
cls.products[product_id] = {"type": structure.is_a(), "Name": structure.Name, "id": int(structure.id())}
|
cls.products[product_id] = {"type": structure.is_a(), "Name": structure.Name, "id": int(structure.id())}
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -11,7 +11,14 @@ class BIM_PT_spatial(Panel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return bool(context.active_object.BIMObjectProperties.ifc_definition_id)
|
props = context.active_object.BIMObjectProperties
|
||||||
|
if not props.ifc_definition_id:
|
||||||
|
return False
|
||||||
|
if props.ifc_definition_id not in Data.products:
|
||||||
|
Data.load(props.ifc_definition_id)
|
||||||
|
if not Data.products[props.ifc_definition_id]:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
props = context.active_object.BIMObjectProperties
|
props = context.active_object.BIMObjectProperties
|
||||||
@@ -20,9 +27,6 @@ class BIM_PT_spatial(Panel):
|
|||||||
if props.ifc_definition_id not in Data.products:
|
if props.ifc_definition_id not in Data.products:
|
||||||
Data.load(props.ifc_definition_id)
|
Data.load(props.ifc_definition_id)
|
||||||
|
|
||||||
if "Ifc" not in context.active_object.name:
|
|
||||||
return
|
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
name = "{}/{}".format(
|
name = "{}/{}".format(
|
||||||
Data.products[props.ifc_definition_id]["type"], Data.products[props.ifc_definition_id]["Name"]
|
Data.products[props.ifc_definition_id]["type"], Data.products[props.ifc_definition_id]["Name"]
|
||||||
|
|||||||
@@ -910,28 +910,6 @@ class GenerateGlobalId(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class AddAttribute(bpy.types.Operator):
|
|
||||||
bl_idname = "bim.add_attribute"
|
|
||||||
bl_label = "Add Attribute"
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
if not bpy.context.active_object.BIMObjectProperties.applicable_attributes:
|
|
||||||
return {"FINISHED"}
|
|
||||||
name = bpy.context.active_object.BIMObjectProperties.applicable_attributes
|
|
||||||
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(bpy.context.scene.BIMProperties.export_schema)
|
|
||||||
for obj in bpy.context.selected_objects:
|
|
||||||
if "/" not in obj.name or obj.BIMObjectProperties.attributes.find(name) != -1:
|
|
||||||
continue
|
|
||||||
entity = schema.declaration_by_name(obj.name.split("/")[0])
|
|
||||||
if name not in [a.name() for a in entity.all_attributes()]:
|
|
||||||
continue
|
|
||||||
attribute = obj.BIMObjectProperties.attributes.add()
|
|
||||||
attribute.name = name
|
|
||||||
if attribute.name == "GlobalId":
|
|
||||||
attribute.string_value = ifcopenshell.guid.new()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class AddMaterialAttribute(bpy.types.Operator):
|
class AddMaterialAttribute(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_material_attribute"
|
bl_idname = "bim.add_material_attribute"
|
||||||
bl_label = "Add Material Attribute"
|
bl_label = "Add Material Attribute"
|
||||||
@@ -943,22 +921,6 @@ class AddMaterialAttribute(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class RemoveAttribute(bpy.types.Operator):
|
|
||||||
bl_idname = "bim.remove_attribute"
|
|
||||||
bl_label = "Remove Attribute"
|
|
||||||
attribute_index: bpy.props.IntProperty()
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
name = bpy.context.active_object.BIMObjectProperties.attributes[self.attribute_index].name
|
|
||||||
for obj in bpy.context.selected_objects:
|
|
||||||
if "/" not in obj.name:
|
|
||||||
continue
|
|
||||||
index = obj.BIMObjectProperties.attributes.find(name)
|
|
||||||
if index != -1:
|
|
||||||
obj.BIMObjectProperties.attributes.remove(index)
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveMaterialAttribute(bpy.types.Operator):
|
class RemoveMaterialAttribute(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_material_attribute"
|
bl_idname = "bim.remove_material_attribute"
|
||||||
bl_label = "Remove Material Attribute"
|
bl_label = "Remove Material Attribute"
|
||||||
|
|||||||
@@ -274,6 +274,10 @@ def getIfcClasses(self, context):
|
|||||||
return classes_enum
|
return classes_enum
|
||||||
|
|
||||||
|
|
||||||
|
def getAttributeEnumValues(self, context):
|
||||||
|
return [(e, e, "") for e in json.loads(self.enum_items)]
|
||||||
|
|
||||||
|
|
||||||
def getProfileDef(self, context):
|
def getProfileDef(self, context):
|
||||||
global profiledef_enum
|
global profiledef_enum
|
||||||
if len(profiledef_enum) < 1:
|
if len(profiledef_enum) < 1:
|
||||||
@@ -440,20 +444,6 @@ def getQtoNames(self, context):
|
|||||||
return qtonames_enum
|
return qtonames_enum
|
||||||
|
|
||||||
|
|
||||||
def getApplicableAttributes(self, context):
|
|
||||||
global attributes_enum
|
|
||||||
attributes_enum.clear()
|
|
||||||
if "/" in context.active_object.name and context.active_object.name.split("/")[0] in schema.ifc.elements:
|
|
||||||
attributes_enum.extend(
|
|
||||||
[
|
|
||||||
(a["name"], a["name"], "")
|
|
||||||
for a in schema.ifc.elements[context.active_object.name.split("/")[0]]["attributes"]
|
|
||||||
if self.attributes.find(a["name"]) == -1
|
|
||||||
]
|
|
||||||
)
|
|
||||||
return attributes_enum
|
|
||||||
|
|
||||||
|
|
||||||
def getApplicableMaterialAttributes(self, context):
|
def getApplicableMaterialAttributes(self, context):
|
||||||
global materialattributes_enum
|
global materialattributes_enum
|
||||||
materialattributes_enum.clear()
|
materialattributes_enum.clear()
|
||||||
@@ -548,6 +538,9 @@ class Attribute(PropertyGroup):
|
|||||||
bool_value: BoolProperty(name="Value")
|
bool_value: BoolProperty(name="Value")
|
||||||
int_value: IntProperty(name="Value")
|
int_value: IntProperty(name="Value")
|
||||||
float_value: FloatProperty(name="Value")
|
float_value: FloatProperty(name="Value")
|
||||||
|
is_null: BoolProperty(name="Is Null")
|
||||||
|
enum_items: StringProperty(name="Value")
|
||||||
|
enum_value: EnumProperty(items=getAttributeEnumValues, name="Value")
|
||||||
|
|
||||||
|
|
||||||
class MaterialLayer(PropertyGroup):
|
class MaterialLayer(PropertyGroup):
|
||||||
@@ -1467,11 +1460,11 @@ class BIMObjectProperties(PropertyGroup):
|
|||||||
is_reassigning_class: BoolProperty(name="Is Reassigning Class")
|
is_reassigning_class: BoolProperty(name="Is Reassigning Class")
|
||||||
global_ids: CollectionProperty(name="GlobalIds", type=GlobalId)
|
global_ids: CollectionProperty(name="GlobalIds", type=GlobalId)
|
||||||
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
||||||
|
is_editing_attributes: BoolProperty(name="Is Editing Attributes")
|
||||||
relating_type: PointerProperty(name="Type Product", type=bpy.types.Object)
|
relating_type: PointerProperty(name="Type Product", type=bpy.types.Object)
|
||||||
relating_structure: PointerProperty(name="Spatial Container", type=bpy.types.Object)
|
relating_structure: PointerProperty(name="Spatial Container", type=bpy.types.Object)
|
||||||
psets: CollectionProperty(name="Psets", type=PsetQto)
|
psets: CollectionProperty(name="Psets", type=PsetQto)
|
||||||
qtos: CollectionProperty(name="Qtos", type=PsetQto)
|
qtos: CollectionProperty(name="Qtos", type=PsetQto)
|
||||||
applicable_attributes: EnumProperty(items=getApplicableAttributes, name="Attribute Names")
|
|
||||||
document_references: CollectionProperty(name="Document References", type=DocumentReference)
|
document_references: CollectionProperty(name="Document References", type=DocumentReference)
|
||||||
active_document_reference_index: IntProperty(name="Active Document Reference Index")
|
active_document_reference_index: IntProperty(name="Active Document Reference Index")
|
||||||
constraints: CollectionProperty(name="Constraints", type=Constraint)
|
constraints: CollectionProperty(name="Constraints", type=Constraint)
|
||||||
|
|||||||
@@ -26,59 +26,10 @@ class BIM_PT_object(Panel):
|
|||||||
if "Ifc" not in context.active_object.name:
|
if "Ifc" not in context.active_object.name:
|
||||||
return
|
return
|
||||||
|
|
||||||
layout.label(text="Attributes:")
|
|
||||||
row = layout.row(align=True)
|
|
||||||
row.prop(props, "applicable_attributes", text="")
|
|
||||||
row.operator("bim.add_attribute")
|
|
||||||
|
|
||||||
for index, attribute in enumerate(props.attributes):
|
|
||||||
row = layout.row(align=True)
|
|
||||||
row.prop(attribute, "name", text="")
|
|
||||||
row.prop(attribute, "string_value", text="")
|
|
||||||
if attribute.name == "GlobalId":
|
|
||||||
row.operator("bim.generate_global_id", icon="FILE_REFRESH", text="")
|
|
||||||
op = row.operator("bim.copy_attribute_to_selection", icon="COPYDOWN", text="")
|
|
||||||
op.attribute_name = attribute.name
|
|
||||||
op.attribute_value = attribute.string_value
|
|
||||||
row.operator("bim.remove_attribute", icon="X", text="").attribute_index = index
|
|
||||||
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(props, "attributes")
|
|
||||||
|
|
||||||
if "IfcSite/" in context.active_object.name or "IfcBuilding/" in context.active_object.name:
|
|
||||||
self.draw_addresses_ui()
|
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.prop(props, "relating_type")
|
row.prop(props, "relating_type")
|
||||||
row.operator("bim.select_similar_type", icon="RESTRICT_SELECT_OFF", text="")
|
row.operator("bim.select_similar_type", icon="RESTRICT_SELECT_OFF", text="")
|
||||||
|
|
||||||
def draw_addresses_ui(self):
|
|
||||||
layout = self.layout
|
|
||||||
layout.label(text="Address:")
|
|
||||||
address = bpy.context.active_object.BIMObjectProperties.address
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(address, "purpose")
|
|
||||||
if address.purpose == "USERDEFINED":
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(address, "user_defined_purpose")
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(address, "description")
|
|
||||||
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(address, "internal_location")
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(address, "address_lines")
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(address, "postal_box")
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(address, "town")
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(address, "region")
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(address, "postal_code")
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(address, "country")
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_object_material(Panel):
|
class BIM_PT_object_material(Panel):
|
||||||
bl_label = "IFC Object Material"
|
bl_label = "IFC Object Material"
|
||||||
|
|||||||
Reference in New Issue
Block a user