mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 10:11:46 +00:00
WIP port reassign and unassign class to partial editing. See #1222.
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from . import operator
|
from . import ui, operator
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
|
operator.EnableReassignClass,
|
||||||
|
operator.DisableReassignClass,
|
||||||
operator.ReassignClass,
|
operator.ReassignClass,
|
||||||
operator.AssignClass,
|
operator.AssignClass,
|
||||||
operator.UnassignClass,
|
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 bpy
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import ifcopenshell
|
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.add_representation as add_representation
|
||||||
import blenderbim.bim.module.geometry.assign_styles as assign_styles
|
import blenderbim.bim.module.geometry.assign_styles as assign_styles
|
||||||
import blenderbim.bim.module.geometry.assign_representation as assign_representation
|
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
|
# from blenderbim.bim.module.geometry.data import Data
|
||||||
|
|
||||||
|
|
||||||
class ReassignClass(bpy.types.Operator):
|
class EnableReassignClass(bpy.types.Operator):
|
||||||
bl_idname = "bim.reassign_class"
|
bl_idname = "bim.enable_reassign_class"
|
||||||
bl_label = "Reassign IFC Class"
|
bl_label = "Enable Reassign IFC Class"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
obj = bpy.context.active_object
|
obj = bpy.context.active_object
|
||||||
@@ -40,6 +42,40 @@ class ReassignClass(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
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):
|
class AssignClass(bpy.types.Operator):
|
||||||
bl_idname = "bim.assign_class"
|
bl_idname = "bim.assign_class"
|
||||||
bl_label = "Assign IFC Class"
|
bl_label = "Assign IFC Class"
|
||||||
@@ -51,11 +87,14 @@ class AssignClass(bpy.types.Operator):
|
|||||||
for obj in objects:
|
for obj in objects:
|
||||||
if obj.BIMObjectProperties.ifc_definition_id:
|
if obj.BIMObjectProperties.ifc_definition_id:
|
||||||
continue
|
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,
|
self.file,
|
||||||
{
|
{
|
||||||
"ifc_class": bpy.context.scene.BIMProperties.ifc_class,
|
"ifc_class": bpy.context.scene.BIMProperties.ifc_class,
|
||||||
"predefined_type": bpy.context.scene.BIMProperties.ifc_predefined_type,
|
"predefined_type": predefined_type,
|
||||||
"name": obj.name,
|
"name": obj.name,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -124,12 +163,20 @@ class UnassignClass(bpy.types.Operator):
|
|||||||
object_name: bpy.props.StringProperty()
|
object_name: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
if self.object_name:
|
if self.object_name:
|
||||||
objects = [bpy.data.objects.get(self.object_name)]
|
objects = [bpy.data.objects.get(self.object_name)]
|
||||||
else:
|
else:
|
||||||
objects = bpy.context.selected_objects
|
objects = bpy.context.selected_objects
|
||||||
for obj in 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":
|
if "/" in obj.name and obj.name[0:3] == "Ifc":
|
||||||
obj.name = "/".join(obj.name.split("/")[1:])
|
obj.name = "/".join(obj.name.split("/")[1:])
|
||||||
return {"FINISHED"}
|
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,29 +23,6 @@ class BIM_PT_object(Panel):
|
|||||||
props = context.active_object.BIMObjectProperties
|
props = context.active_object.BIMObjectProperties
|
||||||
bim_properties = context.scene.BIMProperties
|
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:
|
if "Ifc" not in context.active_object.name:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
+2
-19
@@ -4,6 +4,7 @@
|
|||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.selector
|
import ifcopenshell.util.selector
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
|
import ifcopenshell.util.schema
|
||||||
import csv
|
import csv
|
||||||
import lark
|
import lark
|
||||||
import argparse
|
import argparse
|
||||||
@@ -13,7 +14,7 @@ class IfcAttributeExtractor:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def set_element_key(ifc_file, element, key, value):
|
def set_element_key(ifc_file, element, key, value):
|
||||||
if key == "type" and element.is_a() != 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):
|
if hasattr(element, key):
|
||||||
setattr(element, key, value)
|
setattr(element, key, value)
|
||||||
return element
|
return element
|
||||||
@@ -32,24 +33,6 @@ class IfcAttributeExtractor:
|
|||||||
return element
|
return element
|
||||||
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
|
@staticmethod
|
||||||
def get_element_qto(element, name):
|
def get_element_qto(element, name):
|
||||||
for relationship in element.IsDefinedBy:
|
for relationship in element.IsDefinedBy:
|
||||||
|
|||||||
@@ -18,6 +18,25 @@ def is_a(entity, ifc_class):
|
|||||||
return False
|
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:
|
class Migrator:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.migrated_ids = {}
|
self.migrated_ids = {}
|
||||||
|
|||||||
Reference in New Issue
Block a user