WIP assigning a class now ported over to partial editing and creates an IFC element. See #1222.

This commit is contained in:
Dion Moult
2021-01-04 11:08:15 +11:00
parent af5350bb9f
commit 0c0ffce908
8 changed files with 234 additions and 122 deletions
@@ -5,6 +5,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.bcf as module_bcf
import blenderbim.bim.module.context as module_context
import blenderbim.bim.module.covetool as module_covetool
@@ -13,9 +14,6 @@ if bpy is not None:
from . import ui, prop, operator
classes = [
operator.ReassignClass,
operator.AssignClass,
operator.UnassignClass,
operator.SelectClass,
operator.SelectType,
operator.OpenUri,
@@ -312,6 +310,7 @@ if bpy is not None:
ui.BIM_ADDON_preferences,
]
classes.extend(module_root.classes)
classes.extend(module_bcf.classes)
classes.extend(module_context.classes)
classes.extend(module_covetool.classes)
@@ -348,6 +347,7 @@ if bpy is not None:
bpy.types.Camera.BIMCameraProperties = bpy.props.PointerProperty(type=prop.BIMCameraProperties)
bpy.types.TextCurve.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties)
bpy.types.SCENE_PT_unit.append(ui.ifc_units)
module_root.register()
module_bcf.register()
module_context.register()
module_covetool.register()
@@ -378,4 +378,5 @@ if bpy is not None:
module_covetool.unregister()
module_context.unregister()
module_bcf.unregister()
module_root.unregister()
bpy.app.handlers.depsgraph_update_pre.remove(operator.depsgraph_update_pre_handler)
@@ -12,6 +12,7 @@ class Usecase:
definition = self.settings["product"].Representation
if not definition:
definition = self.file.createIfcProductDefinitionShape()
representations = list(definition.Representations)
self.settings["product"].Representation = definition
representations = list(definition.Representations) if definition.Representations else []
representations.append(self.settings["representation"])
definition.Representations = representations
@@ -6,6 +6,8 @@ class Usecase:
self.settings[key] = value
def execute(self):
if not self.settings["styles"]:
return []
self.results = []
for element in self.file.traverse(self.settings["shape_representation"]):
if not element.is_a("IfcShapeRepresentation"):
@@ -22,20 +22,35 @@ class AddRepresentation(bpy.types.Operator):
self.context_id = bpy.context.scene.BIMProperties.contexts
element = self.file.by_id(obj.data.BIMMeshProperties.ifc_definition_id)
usecase = add_representation.Usecase(self.file, {
"context": self.file.by_id(int(self.context_id)),
"geometry": obj.data,
"total_items": max(1, len(obj.material_slots)),
})
usecase = add_representation.Usecase(
self.file,
{
"context": self.file.by_id(int(self.context_id)),
"geometry": obj.data,
"total_items": max(1, len(obj.material_slots)),
},
)
result = usecase.execute()
if not result:
print("Failed to write shape representation")
return {"FINISHED"}
usecase = assign_representation.Usecase(self.file, {
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
"representation": result
})
usecase = assign_styles.Usecase(
self.file,
{
"shape_representation": result,
"styles": [
self.file.by_id(s.material.BIMMaterialProperties.ifc_style_id)
for s in obj.material_slots
if s.material
],
},
)
usecase.execute()
usecase = assign_representation.Usecase(
self.file, {"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), "representation": result}
)
usecase.execute()
existing_mesh = obj.data
@@ -116,27 +131,40 @@ class BakeParametricGeometry(bpy.types.Operator):
obj = bpy.context.active_object
self.file = IfcStore.get_file()
usecase = add_object_placement.Usecase(self.file, {
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
"matrix": np.array(obj.matrix_world)
})
usecase = add_object_placement.Usecase(
self.file,
{
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
"matrix": np.array(obj.matrix_world),
},
)
result = usecase.execute()
element = self.file.by_id(obj.data.BIMMeshProperties.ifc_definition_id)
usecase = add_representation.Usecase(self.file, {
"context": element.ContextOfItems,
"geometry": obj.data,
"total_items": max(1, len(obj.material_slots)),
})
usecase = add_representation.Usecase(
self.file,
{
"context": element.ContextOfItems,
"geometry": obj.data,
"total_items": max(1, len(obj.material_slots)),
},
)
result = usecase.execute()
if not result:
print("Failed to write shape representation")
return {"FINISHED"}
usecase = assign_styles.Usecase(self.file, {
"shape_representation": result,
"styles": [self.file.by_id(s.material.BIMMaterialProperties.ifc_style_id) for s in obj.material_slots if s.material]
})
usecase = assign_styles.Usecase(
self.file,
{
"shape_representation": result,
"styles": [
self.file.by_id(s.material.BIMMaterialProperties.ifc_style_id)
for s in obj.material_slots
if s.material
],
},
)
usecase.execute()
for inverse in self.file.get_inverse(element):
@@ -157,7 +185,7 @@ class UpdateIfcRepresentation(bpy.types.Operator):
props = obj.data.BIMMeshProperties
parameter = props.ifc_parameters[self.index]
element = IfcStore.get_file().by_id(parameter.step_id)[parameter.index] = parameter.value
bpy.ops.bim.switch_representation(ifc_definition_id = props.ifc_definition_id)
bpy.ops.bim.switch_representation(ifc_definition_id=props.ifc_definition_id)
return {"FINISHED"}
@@ -0,0 +1,16 @@
import bpy
from . import operator
classes = (
operator.ReassignClass,
operator.AssignClass,
operator.UnassignClass,
)
def register():
pass
def unregister():
pass
@@ -0,0 +1,24 @@
import ifcopenshell
class Usecase:
def __init__(self, file, settings=None):
self.file = file
self.settings = {
"ifc_class": "IfcBuildingElementProxy",
"predefined_type": None,
"name": None,
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
element = self.file.create_entity(self.settings["ifc_class"], **{"GlobalId": ifcopenshell.guid.new()})
element.Name = self.settings["name"] or None
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,135 @@
import bpy
import numpy as np
import ifcopenshell
import blenderbim.bim.module.root.assign_class as assign_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
import blenderbim.bim.module.geometry.add_object_placement as add_object_placement
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"
def execute(self, context):
obj = bpy.context.active_object
ifc_class = obj.name.split("/")[0]
ifc_schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(bpy.context.scene.BIMProperties.export_schema)
bpy.context.active_object.BIMObjectProperties.is_reassigning_class = True
ifc_products = [
"IfcElement",
"IfcElementType",
"IfcSpatialElement",
"IfcGroup",
"IfcStructural",
"IfcPositioningElement",
"IfcContext",
"IfcAnnotation",
]
for ifc_product in ifc_products:
if ifcopenshell.util.schema.is_a(ifc_schema.declaration_by_name(ifc_class), ifc_product):
bpy.context.scene.BIMProperties.ifc_product = ifc_product
bpy.context.scene.BIMProperties.ifc_class = obj.name.split("/")[0]
predefined_type = obj.BIMObjectProperties.attributes.get("PredefinedType")
if predefined_type:
bpy.context.scene.BIMProperties.ifc_predefined_type = predefined_type.string_value
return {"FINISHED"}
class AssignClass(bpy.types.Operator):
bl_idname = "bim.assign_class"
bl_label = "Assign IFC Class"
object_name: bpy.props.StringProperty()
def execute(self, context):
objects = [bpy.data.objects.get(self.object_name)] if self.object_name else bpy.context.selected_objects
self.file = IfcStore.get_file()
for obj in objects:
if obj.BIMObjectProperties.ifc_definition_id:
continue
usecase = assign_class.Usecase(
self.file,
{
"ifc_class": bpy.context.scene.BIMProperties.ifc_class,
"predefined_type": bpy.context.scene.BIMProperties.ifc_predefined_type,
"name": obj.name,
},
)
product = usecase.execute()
usecase = add_object_placement.Usecase(
self.file,
{
"product": product,
"matrix": np.array(obj.matrix_world),
},
)
result = usecase.execute()
if obj.data:
usecase = add_representation.Usecase(
self.file,
{
"context": self.file.by_id(int(bpy.context.scene.BIMProperties.contexts)),
"geometry": obj.data,
"total_items": max(1, len(obj.material_slots)),
},
)
representation = usecase.execute()
usecase = assign_styles.Usecase(
self.file,
{
"shape_representation": representation,
"styles": [
self.file.by_id(s.material.BIMMaterialProperties.ifc_style_id)
for s in obj.material_slots
if s.material
],
},
)
usecase.execute()
usecase = assign_representation.Usecase(
self.file, {"product": product, "representation": representation}
)
usecase.execute()
obj.name = "{}/{}".format(bpy.context.scene.BIMProperties.ifc_class, obj.name)
obj.BIMObjectProperties.ifc_definition_id = int(result.id())
if bpy.context.scene.BIMProperties.ifc_product == "IfcElementType":
self.place_in_types_collection(obj)
return {"FINISHED"}
def place_in_types_collection(self, obj):
for project in [c for c in bpy.context.view_layer.layer_collection.children if "IfcProject" in c.name]:
if not [c for c in project.children if "Types" in c.name]:
types = bpy.data.collections.new("Types")
project.collection.children.link(types)
for collection in [c for c in project.children if "Types" in c.name]:
for user_collection in obj.users_collection:
user_collection.objects.unlink(obj)
collection.collection.objects.link(obj)
break
break
class UnassignClass(bpy.types.Operator):
bl_idname = "bim.unassign_class"
bl_label = "Unassign IFC Class"
object_name: bpy.props.StringProperty()
def execute(self, context):
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 "/" in obj.name and obj.name[0:3] == "Ifc":
obj.name = "/".join(obj.name.split("/")[1:])
return {"FINISHED"}
@@ -229,101 +229,6 @@ class SelectPset(bpy.types.Operator):
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
ifc_class = obj.name.split("/")[0]
ifc_schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(bpy.context.scene.BIMProperties.export_schema)
bpy.context.active_object.BIMObjectProperties.is_reassigning_class = True
ifc_products = [
"IfcElement",
"IfcElementType",
"IfcSpatialElement",
"IfcGroup",
"IfcStructural",
"IfcPositioningElement",
"IfcContext",
"IfcAnnotation",
]
for ifc_product in ifc_products:
if ifcopenshell.util.schema.is_a(ifc_schema.declaration_by_name(ifc_class), ifc_product):
bpy.context.scene.BIMProperties.ifc_product = ifc_product
bpy.context.scene.BIMProperties.ifc_class = obj.name.split("/")[0]
predefined_type = obj.BIMObjectProperties.attributes.get("PredefinedType")
if predefined_type:
bpy.context.scene.BIMProperties.ifc_predefined_type = predefined_type.string_value
return {"FINISHED"}
class AssignClass(bpy.types.Operator):
bl_idname = "bim.assign_class"
bl_label = "Assign IFC Class"
object_name: bpy.props.StringProperty()
def execute(self, context):
if self.object_name:
objects = [bpy.data.objects.get(self.object_name)]
objects[0].BIMObjectProperties.is_reassigning_class = False
else:
objects = bpy.context.selected_objects
for obj in objects:
existing_class = None
if "/" in obj.name and obj.name[0:3] == "Ifc":
existing_class = obj.name.split("/")[0]
if existing_class:
obj.name = "{}/{}".format(bpy.context.scene.BIMProperties.ifc_class, obj.name.split("/")[1])
else:
obj.name = "{}/{}".format(bpy.context.scene.BIMProperties.ifc_class, obj.name)
predefined_type_index = obj.BIMObjectProperties.attributes.find("PredefinedType")
if predefined_type_index >= 0:
obj.BIMObjectProperties.attributes.remove(predefined_type_index)
object_type_index = obj.BIMObjectProperties.attributes.find("ObjectType")
if object_type_index >= 0:
obj.BIMObjectProperties.attributes.remove(object_type_index)
if bpy.context.scene.BIMProperties.ifc_predefined_type:
predefined_type = obj.BIMObjectProperties.attributes.add()
predefined_type.name = "PredefinedType"
predefined_type.string_value = (
bpy.context.scene.BIMProperties.ifc_predefined_type
) # TODO: make it an enum
if bpy.context.scene.BIMProperties.ifc_predefined_type == "USERDEFINED":
object_type = obj.BIMObjectProperties.attributes.add()
object_type.name = "ObjectType"
object_type.string_value = bpy.context.scene.BIMProperties.ifc_userdefined_type
if bpy.context.scene.BIMProperties.ifc_product == "IfcElementType":
for project in [c for c in bpy.context.view_layer.layer_collection.children if "IfcProject" in c.name]:
if not [c for c in project.children if "Types" in c.name]:
types = bpy.data.collections.new("Types")
project.collection.children.link(types)
for collection in [c for c in project.children if "Types" in c.name]:
for user_collection in obj.users_collection:
user_collection.objects.unlink(obj)
collection.collection.objects.link(obj)
break
break
return {"FINISHED"}
class UnassignClass(bpy.types.Operator):
bl_idname = "bim.unassign_class"
bl_label = "Unassign IFC Class"
object_name: bpy.props.StringProperty()
def execute(self, context):
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 "/" in obj.name and obj.name[0:3] == "Ifc":
obj.name = "/".join(obj.name.split("/")[1:])
return {"FINISHED"}
class SelectClass(bpy.types.Operator):
bl_idname = "bim.select_class"
bl_label = "Select IFC Class"