WIP create aggregation module to manipulate aggregations. See #1222.

This commit is contained in:
Dion Moult
2021-01-05 16:29:14 +11:00
parent 30b3090386
commit d74b344a95
11 changed files with 186 additions and 11 deletions
@@ -6,6 +6,7 @@ bpy = sys.modules.get("bpy")
if bpy is not None:
import bpy
import blenderbim.bim.module.root as module_root
import blenderbim.bim.module.aggregate as module_aggregate
import blenderbim.bim.module.attribute as module_attribute
import blenderbim.bim.module.bcf as module_bcf
import blenderbim.bim.module.context as module_context
@@ -311,6 +312,7 @@ if bpy is not None:
]
classes.extend(module_root.classes)
classes.extend(module_aggregate.classes)
classes.extend(module_attribute.classes)
classes.extend(module_bcf.classes)
classes.extend(module_context.classes)
@@ -350,6 +352,7 @@ if bpy is not None:
bpy.types.TextCurve.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties)
bpy.types.SCENE_PT_unit.append(ui.ifc_units)
module_root.register()
module_aggregate.register()
module_attribute.register()
module_bcf.register()
module_context.register()
@@ -384,5 +387,6 @@ if bpy is not None:
module_context.unregister()
module_bcf.unregister()
module_attribute.register()
module_aggregate.register()
module_root.unregister()
bpy.app.handlers.depsgraph_update_pre.remove(operator.depsgraph_update_pre_handler)
@@ -0,0 +1,17 @@
import bpy
from . import ui, operator
classes = (
operator.AssignObject,
operator.EnableEditingAggregate,
operator.DisableEditingAggregate,
ui.BIM_PT_aggregate,
)
def register():
pass
def unregister():
pass
@@ -0,0 +1,49 @@
import ifcopenshell
class Usecase:
def __init__(self, file, settings=None):
self.file = file
self.settings = {
"product": None,
"relating_object": None,
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
decomposes = None
if self.settings["product"].Decomposes:
decomposes = self.settings["product"].Decomposes[0]
is_decomposed_by = None
for rel in self.settings["relating_object"].IsDecomposedBy:
if rel.is_a("IfcRelAggregates"):
is_decomposed_by = rel
break
if decomposes and decomposes == is_decomposed_by:
return
if decomposes:
related_objects = list(decomposes.RelatedObjects)
related_objects.remove(self.settings["product"])
if related_objects:
decomposes.RelatedObjects = related_objects
else:
self.file.remove(decomposes)
if is_decomposed_by:
related_objects = list(is_decomposed_by.RelatedObjects)
related_objects.append(self.settings["product"])
is_decomposed_by.RelatedObjects = related_objects
else:
is_decomposed_by = self.file.create_entity(
"IfcRelAggregates",
**{
"GlobalId": ifcopenshell.guid.new(),
# TODO "OwnerHistory": None
"RelatedObjects": [self.settings["product"]],
"RelatingObject": self.settings["relating_object"],
}
)
@@ -0,0 +1,17 @@
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)
if product.Decomposes and product.Decomposes[0].is_a("IfcRelAggregates"):
obj = product.Decomposes[0].RelatingObject
cls.products[product_id] = {"type": obj.is_a(), "Name": obj.Name, "id": int(obj.id())}
else:
cls.products[product_id] = {"type": None, "Name": None, "id": None}
@@ -0,0 +1,47 @@
import bpy
import blenderbim.bim.module.aggregate.assign_object as assign_object
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.aggregate.data import Data
class AssignObject(bpy.types.Operator):
bl_idname = "bim.assign_object"
bl_label = "Assign Object"
def execute(self, context):
self.file = IfcStore.get_file()
obj = bpy.context.active_object
props = obj.BIMObjectProperties
relating_object = props.relating_object
if not relating_object or not relating_object.BIMObjectProperties.ifc_definition_id:
return {"FINISHED"}
usecase = assign_object.Usecase(
self.file,
{
"product": self.file.by_id(props.ifc_definition_id),
"relating_object": self.file.by_id(relating_object.BIMObjectProperties.ifc_definition_id),
},
)
usecase.execute()
Data.load(props.ifc_definition_id)
bpy.ops.bim.disable_editing_aggregate()
return {"FINISHED"}
class EnableEditingAggregate(bpy.types.Operator):
bl_idname = "bim.enable_editing_aggregate"
bl_label = "Enable Editing Aggregate"
def execute(self, context):
bpy.context.active_object.BIMObjectProperties.relating_object = None
bpy.context.active_object.BIMObjectProperties.is_editing_aggregate = True
return {"FINISHED"}
class DisableEditingAggregate(bpy.types.Operator):
bl_idname = "bim.disable_editing_aggregate"
bl_label = "Disable Editing Aggregate"
def execute(self, context):
bpy.context.active_object.BIMObjectProperties.is_editing_aggregate = False
return {"FINISHED"}
@@ -0,0 +1,43 @@
from bpy.types import Panel
from blenderbim.bim.module.aggregate.data import Data
class BIM_PT_aggregate(Panel):
bl_label = "IFC Aggregation"
bl_idname = "BIM_PT_aggregate"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "object"
@classmethod
def poll(cls, context):
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):
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)
if props.is_editing_aggregate:
row = self.layout.row(align=True)
row.prop(props, "relating_object", text="")
row.operator("bim.assign_object", icon="CHECKMARK", text="")
row.operator("bim.disable_editing_aggregate", icon="X", text="")
else:
row = self.layout.row(align=True)
name = "{}/{}".format(
Data.products[props.ifc_definition_id]["type"], Data.products[props.ifc_definition_id]["Name"]
)
if name == "None/None":
name = "This object is not part of an aggregation"
row.label(text=name)
row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="")
@@ -59,14 +59,12 @@ class EditAttributes(bpy.types.Operator):
blender_attribute = props.attributes.get(attribute["name"])
if not blender_attribute:
continue
if blender_attribute.is_null:
if attribute["is_optional"] and 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":
@@ -15,10 +15,10 @@ class BIM_PT_class(Panel):
if props.ifc_definition_id not in Data.products:
Data.load(props.ifc_definition_id)
if props.is_reassigning_class:
self.draw_class_dropdowns()
row = self.layout.row(align=True)
row.operator("bim.reassign_class", icon="CHECKMARK")
row.operator("bim.disable_reassign_class", icon="X", text="")
self.draw_class_dropdowns()
else:
data = Data.products[props.ifc_definition_id]
name = data["type"]
@@ -31,5 +31,7 @@ class BIM_PT_spatial(Panel):
name = "{}/{}".format(
Data.products[props.ifc_definition_id]["type"], Data.products[props.ifc_definition_id]["Name"]
)
if name == "None/None":
name = "This object is not spatially contained"
row.label(text=name)
row.operator("bim.assign_container", icon="FILE_REFRESH", text="")
@@ -3957,14 +3957,10 @@ class InspectFromObject(bpy.types.Operator):
bl_label = "Inspect From Object"
def execute(self, context):
global_id = bpy.context.active_object.BIMObjectProperties.attributes.get("GlobalId")
if not global_id:
ifc_definition_id = bpy.context.active_object.BIMObjectProperties.ifc_definition_id
if not ifc_definition_id:
return {"FINISHED"}
global_id = global_id.string_value
self.file = ifc.IfcStore.get_file()
element = self.file.by_guid(global_id)
if element:
bpy.ops.bim.inspect_from_step_id(step_id=element.id())
bpy.ops.bim.inspect_from_step_id(step_id=ifc_definition_id)
return {"FINISHED"}
@@ -1461,6 +1461,8 @@ class BIMObjectProperties(PropertyGroup):
global_ids: CollectionProperty(name="GlobalIds", type=GlobalId)
attributes: CollectionProperty(name="Attributes", type=Attribute)
is_editing_attributes: BoolProperty(name="Is Editing Attributes")
relating_object: PointerProperty(name="Aggregate", type=bpy.types.Object)
is_editing_aggregate: BoolProperty(name="Is Editing Aggregate")
relating_type: PointerProperty(name="Type Product", type=bpy.types.Object)
relating_structure: PointerProperty(name="Spatial Container", type=bpy.types.Object)
psets: CollectionProperty(name="Psets", type=PsetQto)