WIP port reassign and unassign class to partial editing. See #1222.

This commit is contained in:
Dion Moult
2021-01-04 13:07:29 +11:00
parent 0c0ffce908
commit 6387c03dbc
10 changed files with 184 additions and 50 deletions
@@ -1,10 +1,13 @@
import bpy
from . import operator
from . import ui, operator
classes = (
operator.EnableReassignClass,
operator.DisableReassignClass,
operator.ReassignClass,
operator.AssignClass,
operator.UnassignClass,
ui.BIM_PT_class,
)
@@ -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)
cls.products[product_id] = {
"type": product.is_a(),
"PredefinedType": product.PredefinedType if hasattr(product, "PredefinedType") else None,
"ObjectType": product.ObjectType or None
}
@@ -1,7 +1,9 @@
import bpy
import numpy as np
import ifcopenshell
import blenderbim.bim.module.root.assign_class as assign_class
import blenderbim.bim.module.root.create_product as create_product
import blenderbim.bim.module.root.remove_product as remove_product
import blenderbim.bim.module.root.reassign_class as reassign_class
import blenderbim.bim.module.geometry.add_representation as add_representation
import blenderbim.bim.module.geometry.assign_styles as assign_styles
import blenderbim.bim.module.geometry.assign_representation as assign_representation
@@ -11,9 +13,9 @@ from blenderbim.bim.ifc import IfcStore
# from blenderbim.bim.module.geometry.data import Data
class ReassignClass(bpy.types.Operator):
bl_idname = "bim.reassign_class"
bl_label = "Reassign IFC Class"
class EnableReassignClass(bpy.types.Operator):
bl_idname = "bim.enable_reassign_class"
bl_label = "Enable Reassign IFC Class"
def execute(self, context):
obj = bpy.context.active_object
@@ -40,6 +42,40 @@ class ReassignClass(bpy.types.Operator):
return {"FINISHED"}
class DisableReassignClass(bpy.types.Operator):
bl_idname = "bim.disable_reassign_class"
bl_label = "Disable Reassign IFC Class"
def execute(self, context):
bpy.context.active_object.BIMObjectProperties.is_reassigning_class = False
return {"FINISHED"}
class ReassignClass(bpy.types.Operator):
bl_idname = "bim.reassign_class"
bl_label = "Reassign IFC Class"
def execute(self, context):
obj = bpy.context.active_object
self.file = IfcStore.get_file()
predefined_type = bpy.context.scene.BIMProperties.ifc_predefined_type
if predefined_type == "USERDEFINED":
predefined_type = bpy.context.scene.BIMProperties.ifc_userdefined_type
usecase = reassign_class.Usecase(
self.file,
{
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
"ifc_class": bpy.context.scene.BIMProperties.ifc_class,
"predefined_type": predefined_type,
},
)
product = usecase.execute()
obj.name = "{}/{}".format(product.is_a(), "/".join(obj.name.split("/")[1:]))
obj.BIMObjectProperties.ifc_definition_id = int(product.id())
bpy.context.active_object.BIMObjectProperties.is_reassigning_class = False
return {"FINISHED"}
class AssignClass(bpy.types.Operator):
bl_idname = "bim.assign_class"
bl_label = "Assign IFC Class"
@@ -51,11 +87,14 @@ class AssignClass(bpy.types.Operator):
for obj in objects:
if obj.BIMObjectProperties.ifc_definition_id:
continue
usecase = assign_class.Usecase(
predefined_type = bpy.context.scene.BIMProperties.ifc_predefined_type
if predefined_type == "USERDEFINED":
predefined_type = bpy.context.scene.BIMProperties.ifc_userdefined_type
usecase = create_product.Usecase(
self.file,
{
"ifc_class": bpy.context.scene.BIMProperties.ifc_class,
"predefined_type": bpy.context.scene.BIMProperties.ifc_predefined_type,
"predefined_type": predefined_type,
"name": obj.name,
},
)
@@ -124,12 +163,20 @@ class UnassignClass(bpy.types.Operator):
object_name: bpy.props.StringProperty()
def execute(self, context):
self.file = IfcStore.get_file()
if self.object_name:
objects = [bpy.data.objects.get(self.object_name)]
else:
objects = bpy.context.selected_objects
for obj in objects:
existing_class = None
if not obj.BIMObjectProperties.ifc_definition_id:
continue
usecase = remove_product.Usecase(
self.file,
{"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)},
)
usecase.execute()
obj.BIMObjectProperties.ifc_definition_id = 0
if "/" in obj.name and obj.name[0:3] == "Ifc":
obj.name = "/".join(obj.name.split("/")[1:])
return {"FINISHED"}
@@ -0,0 +1,26 @@
import ifcopenshell
import ifcopenshell.util.schema
class Usecase:
def __init__(self, file, settings=None):
self.file = file
self.settings = {
"product": None,
"ifc_class": "IfcBuildingElementProxy",
"predefined_type": None,
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
element = ifcopenshell.util.schema.reassign_class(
self.file, self.settings["product"], self.settings["ifc_class"]
)
if self.settings["predefined_type"] and hasattr(element, "PredefinedType"):
try:
element.PredefinedType = self.settings["predefined_type"]
except:
element.PredefinedType = "USERDEFINED"
element.ObjectType = self.settings["predefined_type"]
return element
@@ -0,0 +1,11 @@
class Usecase:
def __init__(self, file, settings=None):
self.file = file
self.settings = {
"product": None
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
self.file.remove(self.settings["product"])
@@ -0,0 +1,51 @@
import bpy
from bpy.types import Panel
from blenderbim.bim.module.root.data import Data
class BIM_PT_class(Panel):
bl_label = "IFC Class"
bl_idname = "BIM_PT_class"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "object"
def draw(self, context):
props = context.active_object.BIMObjectProperties
if props.ifc_definition_id:
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="")
else:
data = Data.products[props.ifc_definition_id]
name = data["type"]
if data["PredefinedType"] and data["PredefinedType"] == "USERDEFINED":
name += "[{}]".format(data["ObjectType"])
elif data["PredefinedType"]:
name += "[{}]".format(data["PredefinedType"])
row = self.layout.row(align=True)
row.label(text=name)
row.operator("bim.enable_reassign_class", icon="GREASEPENCIL", text="")
op = row.operator("bim.unassign_class", icon="X", text="")
op.object_name = context.active_object.name
else:
self.draw_class_dropdowns()
row = self.layout.row(align=True)
op = row.operator("bim.assign_class")
op.object_name = context.active_object.name
def draw_class_dropdowns(self):
props = bpy.context.scene.BIMProperties
row = self.layout.row()
row.prop(props, "ifc_product")
row = self.layout.row()
row.prop(props, "ifc_class")
if props.ifc_predefined_type:
row = self.layout.row()
row.prop(props, "ifc_predefined_type")
if props.ifc_predefined_type == "USERDEFINED":
row = self.layout.row()
row.prop(props, "ifc_userdefined_type")
-23
View File
@@ -23,29 +23,6 @@ class BIM_PT_object(Panel):
props = context.active_object.BIMObjectProperties
bim_properties = context.scene.BIMProperties
if props.is_reassigning_class or "/" not in context.active_object.name:
row = layout.row()
row.prop(bim_properties, "ifc_product")
row = layout.row()
row.prop(bim_properties, "ifc_class")
if bim_properties.ifc_predefined_type:
row = layout.row()
row.prop(bim_properties, "ifc_predefined_type")
if bim_properties.ifc_predefined_type == "USERDEFINED":
row = layout.row()
row.prop(bim_properties, "ifc_userdefined_type")
row = layout.row(align=True)
if "Ifc" not in context.active_object.name:
op = row.operator("bim.assign_class")
else:
op = row.operator("bim.assign_class")
op.object_name = context.active_object.name
op = row.operator("bim.unassign_class", icon="X", text="")
op.object_name = context.active_object.name
else:
row = layout.row()
row.operator("bim.reassign_class", text="Reassign IFC Class")
if "Ifc" not in context.active_object.name:
return
+2 -19
View File
@@ -4,6 +4,7 @@
import ifcopenshell
import ifcopenshell.util.selector
import ifcopenshell.util.element
import ifcopenshell.util.schema
import csv
import lark
import argparse
@@ -13,7 +14,7 @@ class IfcAttributeExtractor:
@staticmethod
def set_element_key(ifc_file, element, key, value):
if key == "type" and element.is_a() != value:
return IfcAttributeExtractor.change_ifc_class(ifc_file, element, value)
return ifcopenshell.util.schema.reassign_class(ifc_file, element, value)
if hasattr(element, key):
setattr(element, key, value)
return element
@@ -32,24 +33,6 @@ class IfcAttributeExtractor:
return element
return element
@staticmethod
def change_ifc_class(ifc_file, element, new_class):
try:
new_element = ifc_file.create_entity(new_class)
except:
print(f"Class of {element} could not be changed to {new_class}")
return element
new_attributes = [new_element.attribute_name(i) for i, attribute in enumerate(new_element)]
for i, attribute in enumerate(element):
try:
new_element[new_attributes.index(element.attribute_name(i))] = attribute
except:
continue
for inverse in ifc_file.get_inverse(element):
ifcopenshell.util.element.replace_attribute(inverse, element, new_element)
ifc_file.remove(element)
return new_element
@staticmethod
def get_element_qto(element, name):
for relationship in element.IsDefinedBy:
@@ -18,6 +18,25 @@ def is_a(entity, ifc_class):
return False
def reassign_class(ifc_file, element, new_class):
try:
new_element = ifc_file.create_entity(new_class)
except:
print(f"Class of {element} could not be changed to {new_class}")
return element
new_attributes = [new_element.attribute_name(i) for i, attribute in enumerate(new_element)]
for i, attribute in enumerate(element):
try:
new_element[new_attributes.index(element.attribute_name(i))] = attribute
except:
continue
for inverse in ifc_file.get_inverse(element):
ifcopenshell.util.element.replace_attribute(inverse, element, new_element)
ifc_file.remove(element)
return new_element
class Migrator:
def __init__(self):
self.migrated_ids = {}