mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 14:23:53 +00:00
Apply object operators to all selected objects (#1696)
* Remove container executes on all selected objects * Pass silently if assigning or removing container on non-bim object * Assign / Unassign Material executes on all selected objects * AddRepresentation executes on all selected objects * Assign / Unassign Constraint executes on all selected objects * Fix error when trying to assign representation to non-mesh object * Assign / Unassign Document executes on all selected objects * Code Cleanup & Consistency * Fix Attribute data type not being assigned when it makes sense * Revert changes to geometry operator * Revert "Fix Attribute data type not being assigned when it makes sense" This reverts commit1117c8670c. * Revert changes to material operator * Use attribute helper functions * Filter select entities in import_attributes * revert changes to attribute fetching * Revert "Filter select entities in import_attributes" This reverts commit7f84c2ea63. * Enforce new attribute data type to string * Restrict import_attributes usecase * Remove trailing spaces * Revert changes to IfcProjectedCRS attributes This is done prior to the planned unit refactor
This commit is contained in:
@@ -76,6 +76,7 @@ class EnableEditingClassification(bpy.types.Operator):
|
|||||||
new.name = attribute.name()
|
new.name = attribute.name()
|
||||||
new.is_null = classification_data[attribute.name()] is None
|
new.is_null = classification_data[attribute.name()] is None
|
||||||
new.is_optional = attribute.optional()
|
new.is_optional = attribute.optional()
|
||||||
|
new.data_type = "string"
|
||||||
if attribute.name() == "ReferenceTokens":
|
if attribute.name() == "ReferenceTokens":
|
||||||
new.string_value = "" if new.is_null else json.dumps(classification_data[attribute.name()])
|
new.string_value = "" if new.is_null else json.dumps(classification_data[attribute.name()])
|
||||||
else:
|
else:
|
||||||
@@ -162,6 +163,7 @@ class EnableEditingClassificationReference(bpy.types.Operator):
|
|||||||
new.name = attribute.name()
|
new.name = attribute.name()
|
||||||
new.is_null = reference_data[attribute.name()] is None
|
new.is_null = reference_data[attribute.name()] is None
|
||||||
new.is_optional = attribute.optional()
|
new.is_optional = attribute.optional()
|
||||||
|
new.data_type = "string"
|
||||||
new.string_value = "" if new.is_null else reference_data[attribute.name()]
|
new.string_value = "" if new.is_null else reference_data[attribute.name()]
|
||||||
props.active_reference_id = self.reference
|
props.active_reference_id = self.reference
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -187,17 +187,21 @@ class AssignConstraint(bpy.types.Operator):
|
|||||||
return IfcStore.execute_ifc_operator(self, context)
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
def _execute(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()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||||
"constraint.assign_constraint",
|
for obj in objs:
|
||||||
self.file,
|
obj_id = obj.BIMObjectProperties.ifc_definition_id
|
||||||
**{
|
if not obj_id:
|
||||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
continue
|
||||||
"constraint": self.file.by_id(self.constraint),
|
ifcopenshell.api.run(
|
||||||
}
|
"constraint.assign_constraint",
|
||||||
)
|
self.file,
|
||||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
**{
|
||||||
|
"product": self.file.by_id(obj_id),
|
||||||
|
"constraint": self.file.by_id(self.constraint),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Data.load(self.file, obj_id)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -212,15 +216,19 @@ class UnassignConstraint(bpy.types.Operator):
|
|||||||
return IfcStore.execute_ifc_operator(self, context)
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
def _execute(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()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||||
"constraint.unassign_constraint",
|
for obj in objs:
|
||||||
self.file,
|
obj_id = obj.BIMObjectProperties.ifc_definition_id
|
||||||
**{
|
if not obj_id:
|
||||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
continue
|
||||||
"constraint": self.file.by_id(self.constraint),
|
ifcopenshell.api.run(
|
||||||
}
|
"constraint.unassign_constraint",
|
||||||
)
|
self.file,
|
||||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
**{
|
||||||
|
"product": self.file.by_id(obj_id),
|
||||||
|
"constraint": self.file.by_id(self.constraint),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Data.load(self.file, obj_id)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -276,17 +276,21 @@ class AssignDocument(bpy.types.Operator):
|
|||||||
return IfcStore.execute_ifc_operator(self, context)
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
def _execute(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()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||||
"document.assign_document",
|
for obj in objs:
|
||||||
self.file,
|
obj_id = obj.BIMObjectProperties.ifc_definition_id
|
||||||
**{
|
if not obj_id:
|
||||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
continue
|
||||||
"document": self.file.by_id(self.document),
|
ifcopenshell.api.run(
|
||||||
}
|
"document.assign_document",
|
||||||
)
|
self.file,
|
||||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
**{
|
||||||
|
"product": self.file.by_id(obj_id),
|
||||||
|
"document": self.file.by_id(self.document),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Data.load(self.file, obj_id)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -301,15 +305,19 @@ class UnassignDocument(bpy.types.Operator):
|
|||||||
return IfcStore.execute_ifc_operator(self, context)
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
def _execute(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()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||||
"document.unassign_document",
|
for obj in objs:
|
||||||
self.file,
|
obj_id = obj.BIMObjectProperties.ifc_definition_id
|
||||||
**{
|
if not obj_id:
|
||||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
continue
|
||||||
"document": self.file.by_id(self.document),
|
ifcopenshell.api.run(
|
||||||
}
|
"document.unassign_document",
|
||||||
)
|
self.file,
|
||||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
**{
|
||||||
|
"product": self.file.by_id(obj_id),
|
||||||
|
"document": self.file.by_id(self.document),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Data.load(self.file, obj_id)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class EnableEditingGeoreferencing(bpy.types.Operator):
|
|||||||
props = context.scene.BIMGeoreferenceProperties
|
props = context.scene.BIMGeoreferenceProperties
|
||||||
|
|
||||||
props.projected_crs.clear()
|
props.projected_crs.clear()
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes():
|
for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes():
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||||
if data_type == "entity":
|
if data_type == "entity":
|
||||||
@@ -69,18 +69,9 @@ class EnableEditingGeoreferencing(bpy.types.Operator):
|
|||||||
props.map_unit_imperial = Data.projected_crs["MapUnit"]["Name"]
|
props.map_unit_imperial = Data.projected_crs["MapUnit"]["Name"]
|
||||||
|
|
||||||
props.map_conversion.clear()
|
props.map_conversion.clear()
|
||||||
|
blenderbim.bim.helper.import_attributes(
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes():
|
"IfcMapConversion", props.map_conversion, Data.map_conversion, self.import_map_conversion_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()])
|
|
||||||
|
|
||||||
props.has_true_north = bool(Data.true_north)
|
props.has_true_north = bool(Data.true_north)
|
||||||
if Data.true_north:
|
if Data.true_north:
|
||||||
@@ -90,6 +81,12 @@ class EnableEditingGeoreferencing(bpy.types.Operator):
|
|||||||
props.is_editing = True
|
props.is_editing = True
|
||||||
return {"FINISHED"}
|
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):
|
class DisableEditingGeoreferencing(bpy.types.Operator):
|
||||||
bl_idname = "bim.disable_editing_georeferencing"
|
bl_idname = "bim.disable_editing_georeferencing"
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import ifcopenshell.util.attribute
|
import ifcopenshell.util.attribute
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
import blenderbim.bim.helper
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.group.data import Data
|
from ifcopenshell.api.group.data import Data
|
||||||
|
|
||||||
@@ -121,17 +122,8 @@ class EnableEditingGroup(bpy.types.Operator):
|
|||||||
props = context.scene.BIMGroupProperties
|
props = context.scene.BIMGroupProperties
|
||||||
props.group_attributes.clear()
|
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
|
props.active_group_id = self.group
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import bpy
|
|||||||
import json
|
import json
|
||||||
import ifcopenshell.util.attribute
|
import ifcopenshell.util.attribute
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
import blenderbim.bim.helper
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.layer.data import Data
|
from ifcopenshell.api.layer.data import Data
|
||||||
|
|
||||||
@@ -63,17 +64,10 @@ class EnableEditingLayer(bpy.types.Operator):
|
|||||||
props = context.scene.BIMLayerProperties
|
props = context.scene.BIMLayerProperties
|
||||||
props.layer_attributes.clear()
|
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
|
props.active_layer_id = self.layer
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|||||||
@@ -430,14 +430,7 @@ class EnableEditingAssignedMaterial(bpy.types.Operator):
|
|||||||
|
|
||||||
props.material_set_attributes.clear()
|
props.material_set_attributes.clear()
|
||||||
|
|
||||||
for attribute in IfcStore.get_schema().declaration_by_name(material_set_class).all_attributes():
|
blenderbim.bim.helper.import_attributes(material_set_class, props.material_set_attributes, material_set_data)
|
||||||
if "<string>" 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()]
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def import_attributes(self, name, prop, data):
|
def import_attributes(self, name, prop, data):
|
||||||
@@ -509,10 +502,7 @@ class EditAssignedMaterial(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
material_set = self.file.by_id(self.material_set)
|
material_set = self.file.by_id(self.material_set)
|
||||||
|
attributes = blenderbim.bim.helper.export_attributes(props.material_set_attributes)
|
||||||
attributes = {}
|
|
||||||
for attribute in props.material_set_attributes:
|
|
||||||
attributes[attribute.name] = None if attribute.is_null else attribute.string_value
|
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"material.edit_assigned_material",
|
"material.edit_assigned_material",
|
||||||
self.file,
|
self.file,
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ class AssignContainer(bpy.types.Operator):
|
|||||||
self.relating_structure or sprops.spatial_elements[sprops.active_spatial_element_index].ifc_definition_id
|
self.relating_structure or sprops.spatial_elements[sprops.active_spatial_element_index].ifc_definition_id
|
||||||
)
|
)
|
||||||
for related_element in related_elements:
|
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
|
props = related_element.BIMObjectSpatialProperties
|
||||||
|
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
@@ -134,25 +136,33 @@ class RemoveContainer(bpy.types.Operator):
|
|||||||
return IfcStore.execute_ifc_operator(self, context)
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
obj = bpy.data.objects.get(self.obj, context.active_object)
|
active_object = context.active_object
|
||||||
oprops = obj.BIMObjectProperties
|
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
ifcopenshell.api.run(
|
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||||
"spatial.remove_container", self.file, **{"product": self.file.by_id(oprops.ifc_definition_id)}
|
for obj in objs:
|
||||||
)
|
obj_id = obj.BIMObjectProperties.ifc_definition_id
|
||||||
Data.load(IfcStore.get_file(), oprops.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)
|
aggregate_collection = bpy.data.collections.get(obj.name)
|
||||||
if aggregate_collection:
|
if aggregate_collection:
|
||||||
self.remove_collection(context.scene.collection, aggregate_collection)
|
self.remove_collection(context.scene.collection, aggregate_collection)
|
||||||
for collection in bpy.data.collections:
|
for collection in bpy.data.collections:
|
||||||
self.remove_collection(collection, spatial_collection)
|
self.remove_collection(collection, spatial_collection)
|
||||||
context.scene.collection.children.link(aggregate_collection)
|
context.scene.collection.children.link(aggregate_collection)
|
||||||
else:
|
else:
|
||||||
for collection in obj.users_collection:
|
for collection in obj.users_collection:
|
||||||
collection.objects.unlink(obj)
|
collection.objects.unlink(obj)
|
||||||
context.scene.collection.objects.link(obj)
|
context.scene.collection.objects.link(obj)
|
||||||
context.view_layer.objects.active = obj
|
context.view_layer.objects.active = active_object
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def remove_collection(self, parent, child):
|
def remove_collection(self, parent, child):
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import ifcopenshell.util.attribute
|
import ifcopenshell.util.attribute
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
import blenderbim.bim.helper
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.system.data import Data
|
from ifcopenshell.api.system.data import Data
|
||||||
|
|
||||||
@@ -121,17 +122,7 @@ class EnableEditingSystem(bpy.types.Operator):
|
|||||||
props = context.scene.BIMSystemProperties
|
props = context.scene.BIMSystemProperties
|
||||||
props.system_attributes.clear()
|
props.system_attributes.clear()
|
||||||
|
|
||||||
data = Data.systems[self.system]
|
blenderbim.bim.helper.import_attributes("IfcSystem", props.system_attributes, 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()]
|
|
||||||
props.active_system_id = self.system
|
props.active_system_id = self.system
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user