diff --git a/src/blenderbim/blenderbim/bim/module/classification/operator.py b/src/blenderbim/blenderbim/bim/module/classification/operator.py index b1dd53b8fd..9163d3f06d 100644 --- a/src/blenderbim/blenderbim/bim/module/classification/operator.py +++ b/src/blenderbim/blenderbim/bim/module/classification/operator.py @@ -76,6 +76,7 @@ class EnableEditingClassification(bpy.types.Operator): new.name = attribute.name() new.is_null = classification_data[attribute.name()] is None new.is_optional = attribute.optional() + new.data_type = "string" if attribute.name() == "ReferenceTokens": new.string_value = "" if new.is_null else json.dumps(classification_data[attribute.name()]) else: @@ -162,6 +163,7 @@ class EnableEditingClassificationReference(bpy.types.Operator): new.name = attribute.name() new.is_null = reference_data[attribute.name()] is None new.is_optional = attribute.optional() + new.data_type = "string" new.string_value = "" if new.is_null else reference_data[attribute.name()] props.active_reference_id = self.reference return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/constraint/operator.py b/src/blenderbim/blenderbim/bim/module/constraint/operator.py index d7b409fa93..567d49b266 100644 --- a/src/blenderbim/blenderbim/bim/module/constraint/operator.py +++ b/src/blenderbim/blenderbim/bim/module/constraint/operator.py @@ -187,17 +187,21 @@ class AssignConstraint(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() - ifcopenshell.api.run( - "constraint.assign_constraint", - self.file, - **{ - "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), - "constraint": self.file.by_id(self.constraint), - } - ) - Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id) + objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects + for obj in objs: + obj_id = obj.BIMObjectProperties.ifc_definition_id + if not obj_id: + continue + ifcopenshell.api.run( + "constraint.assign_constraint", + self.file, + **{ + "product": self.file.by_id(obj_id), + "constraint": self.file.by_id(self.constraint), + } + ) + Data.load(self.file, obj_id) return {"FINISHED"} @@ -212,15 +216,19 @@ class UnassignConstraint(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() - ifcopenshell.api.run( - "constraint.unassign_constraint", - self.file, - **{ - "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), - "constraint": self.file.by_id(self.constraint), - } - ) - Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id) + objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects + for obj in objs: + obj_id = obj.BIMObjectProperties.ifc_definition_id + if not obj_id: + continue + ifcopenshell.api.run( + "constraint.unassign_constraint", + self.file, + **{ + "product": self.file.by_id(obj_id), + "constraint": self.file.by_id(self.constraint), + } + ) + Data.load(self.file, obj_id) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/document/operator.py b/src/blenderbim/blenderbim/bim/module/document/operator.py index 1d9ed2929d..ac13c55590 100644 --- a/src/blenderbim/blenderbim/bim/module/document/operator.py +++ b/src/blenderbim/blenderbim/bim/module/document/operator.py @@ -276,17 +276,21 @@ class AssignDocument(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() - ifcopenshell.api.run( - "document.assign_document", - self.file, - **{ - "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), - "document": self.file.by_id(self.document), - } - ) - Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id) + objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects + for obj in objs: + obj_id = obj.BIMObjectProperties.ifc_definition_id + if not obj_id: + continue + ifcopenshell.api.run( + "document.assign_document", + self.file, + **{ + "product": self.file.by_id(obj_id), + "document": self.file.by_id(self.document), + } + ) + Data.load(self.file, obj_id) return {"FINISHED"} @@ -301,15 +305,19 @@ class UnassignDocument(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() - ifcopenshell.api.run( - "document.unassign_document", - self.file, - **{ - "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), - "document": self.file.by_id(self.document), - } - ) - Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id) + objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects + for obj in objs: + obj_id = obj.BIMObjectProperties.ifc_definition_id + if not obj_id: + continue + ifcopenshell.api.run( + "document.unassign_document", + self.file, + **{ + "product": self.file.by_id(obj_id), + "document": self.file.by_id(self.document), + } + ) + Data.load(self.file, obj_id) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/georeference/operator.py b/src/blenderbim/blenderbim/bim/module/georeference/operator.py index 2026de99e4..8549912384 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/operator.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/operator.py @@ -39,7 +39,7 @@ class EnableEditingGeoreferencing(bpy.types.Operator): props = context.scene.BIMGeoreferenceProperties props.projected_crs.clear() - + for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes(): data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) if data_type == "entity": @@ -69,18 +69,9 @@ class EnableEditingGeoreferencing(bpy.types.Operator): props.map_unit_imperial = Data.projected_crs["MapUnit"]["Name"] props.map_conversion.clear() - - for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity" or data_type == "select": - continue - new = props.map_conversion.add() - new.name = attribute.name() - new.is_null = Data.map_conversion[attribute.name()] is None - new.is_optional = attribute.optional() - # Enforce a string data type to prevent data loss in single-precision Blender props - new.data_type = "string" - new.string_value = "" if new.is_null else str(Data.map_conversion[attribute.name()]) + blenderbim.bim.helper.import_attributes( + "IfcMapConversion", props.map_conversion, Data.map_conversion, self.import_map_conversion_attributes + ) props.has_true_north = bool(Data.true_north) if Data.true_north: @@ -90,6 +81,12 @@ class EnableEditingGeoreferencing(bpy.types.Operator): props.is_editing = True return {"FINISHED"} + def import_map_conversion_attributes(self, name, prop, data): + if name not in ["SourceCRS", "TargetCRS"]: + # Enforce a string data type to prevent data loss in single-precision Blender props + prop.data_type = "string" + prop.string_value = "" if prop.is_null else str(data[name]) + return True class DisableEditingGeoreferencing(bpy.types.Operator): bl_idname = "bim.disable_editing_georeferencing" diff --git a/src/blenderbim/blenderbim/bim/module/group/operator.py b/src/blenderbim/blenderbim/bim/module/group/operator.py index 0485249733..885df4c2ae 100644 --- a/src/blenderbim/blenderbim/bim/module/group/operator.py +++ b/src/blenderbim/blenderbim/bim/module/group/operator.py @@ -20,6 +20,7 @@ import bpy import ifcopenshell.util.attribute import ifcopenshell.api +import blenderbim.bim.helper from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.group.data import Data @@ -121,17 +122,8 @@ class EnableEditingGroup(bpy.types.Operator): props = context.scene.BIMGroupProperties props.group_attributes.clear() - data = Data.groups[self.group] + blenderbim.bim.helper.import_attributes("IfcGroup", props.group_attributes, Data.groups[self.group]) - for attribute in IfcStore.get_schema().declaration_by_name("IfcGroup").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity": - continue - new = props.group_attributes.add() - new.name = attribute.name() - new.is_null = data[attribute.name()] is None - new.is_optional = attribute.optional() - new.string_value = "" if new.is_null else data[attribute.name()] props.active_group_id = self.group return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/layer/operator.py b/src/blenderbim/blenderbim/bim/module/layer/operator.py index 2ebd391809..2e90fcc583 100644 --- a/src/blenderbim/blenderbim/bim/module/layer/operator.py +++ b/src/blenderbim/blenderbim/bim/module/layer/operator.py @@ -21,6 +21,7 @@ import bpy import json import ifcopenshell.util.attribute import ifcopenshell.api +import blenderbim.bim.helper from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.layer.data import Data @@ -63,17 +64,10 @@ class EnableEditingLayer(bpy.types.Operator): props = context.scene.BIMLayerProperties props.layer_attributes.clear() - data = Data.layers[self.layer] + blenderbim.bim.helper.import_attributes( + "IfcPresentationLayerAssignment", props.layer_attributes, Data.layers[self.layer] + ) - for attribute in IfcStore.get_schema().declaration_by_name("IfcPresentationLayerAssignment").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity" or data_type == "select": - continue - new = props.layer_attributes.add() - new.name = attribute.name() - new.is_null = data[attribute.name()] is None - new.is_optional = attribute.optional() - new.string_value = "" if new.is_null else data[attribute.name()] props.active_layer_id = self.layer return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/material/operator.py b/src/blenderbim/blenderbim/bim/module/material/operator.py index dfea986a57..b9212cf120 100644 --- a/src/blenderbim/blenderbim/bim/module/material/operator.py +++ b/src/blenderbim/blenderbim/bim/module/material/operator.py @@ -430,14 +430,7 @@ class EnableEditingAssignedMaterial(bpy.types.Operator): props.material_set_attributes.clear() - for attribute in IfcStore.get_schema().declaration_by_name(material_set_class).all_attributes(): - if "" not in str(attribute.type_of_attribute): - continue - if attribute.name() in material_set_data: - new = props.material_set_attributes.add() - new.name = attribute.name() - new.is_null = material_set_data[attribute.name()] is None - new.string_value = "" if new.is_null else material_set_data[attribute.name()] + blenderbim.bim.helper.import_attributes(material_set_class, props.material_set_attributes, material_set_data) return {"FINISHED"} def import_attributes(self, name, prop, data): @@ -509,10 +502,7 @@ class EditAssignedMaterial(bpy.types.Operator): return {"FINISHED"} material_set = self.file.by_id(self.material_set) - - attributes = {} - for attribute in props.material_set_attributes: - attributes[attribute.name] = None if attribute.is_null else attribute.string_value + attributes = blenderbim.bim.helper.export_attributes(props.material_set_attributes) ifcopenshell.api.run( "material.edit_assigned_material", self.file, diff --git a/src/blenderbim/blenderbim/bim/module/spatial/operator.py b/src/blenderbim/blenderbim/bim/module/spatial/operator.py index 7f8fe7b3aa..5c01b0c357 100644 --- a/src/blenderbim/blenderbim/bim/module/spatial/operator.py +++ b/src/blenderbim/blenderbim/bim/module/spatial/operator.py @@ -48,7 +48,9 @@ class AssignContainer(bpy.types.Operator): self.relating_structure or sprops.spatial_elements[sprops.active_spatial_element_index].ifc_definition_id ) for related_element in related_elements: - oprops = related_element.BIMObjectProperties + oprops = related_element.BIMObjectProperties + if not oprops.ifc_definition_id: + continue props = related_element.BIMObjectSpatialProperties ifcopenshell.api.run( @@ -134,25 +136,33 @@ class RemoveContainer(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - obj = bpy.data.objects.get(self.obj, context.active_object) - oprops = obj.BIMObjectProperties + active_object = context.active_object self.file = IfcStore.get_file() - ifcopenshell.api.run( - "spatial.remove_container", self.file, **{"product": self.file.by_id(oprops.ifc_definition_id)} - ) - Data.load(IfcStore.get_file(), oprops.ifc_definition_id) + objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects + for obj in objs: + obj_id = obj.BIMObjectProperties.ifc_definition_id + if not obj_id: + continue + ifcopenshell.api.run( + "spatial.remove_container", + self.file, + **{ + "product": self.file.by_id(obj_id) + } + ) + Data.load(self.file, obj_id) - aggregate_collection = bpy.data.collections.get(obj.name) - if aggregate_collection: - self.remove_collection(context.scene.collection, aggregate_collection) - for collection in bpy.data.collections: - self.remove_collection(collection, spatial_collection) - context.scene.collection.children.link(aggregate_collection) - else: - for collection in obj.users_collection: - collection.objects.unlink(obj) - context.scene.collection.objects.link(obj) - context.view_layer.objects.active = obj + aggregate_collection = bpy.data.collections.get(obj.name) + if aggregate_collection: + self.remove_collection(context.scene.collection, aggregate_collection) + for collection in bpy.data.collections: + self.remove_collection(collection, spatial_collection) + context.scene.collection.children.link(aggregate_collection) + else: + for collection in obj.users_collection: + collection.objects.unlink(obj) + context.scene.collection.objects.link(obj) + context.view_layer.objects.active = active_object return {"FINISHED"} def remove_collection(self, parent, child): diff --git a/src/blenderbim/blenderbim/bim/module/system/operator.py b/src/blenderbim/blenderbim/bim/module/system/operator.py index 23ce075299..e9824cf14d 100644 --- a/src/blenderbim/blenderbim/bim/module/system/operator.py +++ b/src/blenderbim/blenderbim/bim/module/system/operator.py @@ -20,6 +20,7 @@ import bpy import ifcopenshell.util.attribute import ifcopenshell.api +import blenderbim.bim.helper from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.system.data import Data @@ -121,17 +122,7 @@ class EnableEditingSystem(bpy.types.Operator): props = context.scene.BIMSystemProperties props.system_attributes.clear() - data = Data.systems[self.system] - - for attribute in IfcStore.get_schema().declaration_by_name("IfcSystem").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity": - continue - new = props.system_attributes.add() - new.name = attribute.name() - new.is_null = data[attribute.name()] is None - new.is_optional = attribute.optional() - new.string_value = "" if new.is_null else data[attribute.name()] + blenderbim.bim.helper.import_attributes("IfcSystem", props.system_attributes, Data.systems[self.system]) props.active_system_id = self.system return {"FINISHED"}