WIP class dropdowns are now schema version specific and generated. See #1222.

This commit is contained in:
Dion Moult
2021-01-06 15:19:55 +11:00
parent cac635107e
commit d206dff9c0
6 changed files with 143 additions and 84 deletions
@@ -1,4 +1,5 @@
import bpy
import ifcopenshell.util.schema
import blenderbim.bim.module.aggregate.assign_object as assign_object
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.aggregate.data import Data
@@ -12,22 +13,44 @@ class AssignObject(bpy.types.Operator):
def execute(self, context):
self.file = IfcStore.get_file()
obj = bpy.data.objects.get(self.related_object) if self.related_object else bpy.context.active_object
props = obj.BIMObjectProperties
related_object = bpy.data.objects.get(self.related_object) if self.related_object else bpy.context.active_object
props = related_object.BIMObjectProperties
relating_object = bpy.data.objects.get(self.relating_object) if self.relating_object else props.relating_object
if not relating_object or not relating_object.BIMObjectProperties.ifc_definition_id:
return {"FINISHED"}
product = self.file.by_id(props.ifc_definition_id)
assign_object.Usecase(
self.file,
{
"product": self.file.by_id(props.ifc_definition_id),
"product": product,
"relating_object": self.file.by_id(relating_object.BIMObjectProperties.ifc_definition_id),
},
).execute()
Data.load(props.ifc_definition_id)
bpy.ops.bim.disable_editing_aggregate(obj=self.related_object)
bpy.ops.bim.disable_editing_aggregate(obj=related_object.name)
file = IfcStore.get_file()
ifc_schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(file.schema)
declaration = ifc_schema.declaration_by_name(product.is_a())
# TODO: we may not need this conditional if aggregates stop using collection instances
if ifcopenshell.util.schema.is_a(declaration, "IfcSpatialElement"):
related_collection = related_object.users_collection[0]
relating_collection = relating_object.users_collection[0]
self.remove_collection(bpy.context.scene.collection, related_collection)
for collection in bpy.data.collections:
if collection == relating_collection:
collection.children.link(related_collection)
continue
self.remove_collection(collection, related_collection)
return {"FINISHED"}
def remove_collection(self, parent, child):
try:
parent.children.unlink(child)
except:
pass
class EnableEditingAggregate(bpy.types.Operator):
bl_idname = "bim.enable_editing_aggregate"
@@ -119,6 +119,25 @@ class Usecase:
items,
)
def create_polygonal_face_set(self):
ifc_raw_items = [None] * self.settings["total_items"]
for i, value in enumerate(ifc_raw_items):
ifc_raw_items[i] = []
for polygon in self.settings["geometry"].polygons:
ifc_raw_items[polygon.material_index % self.settings["total_items"]].append(
self.file.createIfcIndexedPolygonalFace([v + 1 for v in polygon.vertices])
)
coordinates = self.file.createIfcCartesianPointList3D(
[self.convert_si_to_unit(v.co) for v in self.settings["geometry"].vertices]
)
items = [self.file.createIfcPolygonalFaceSet(coordinates, None, i) for i in ifc_raw_items if i]
return self.file.createIfcShapeRepresentation(
self.settings["context"],
self.settings["context"].ContextIdentifier,
"Tessellation",
items,
)
def create_vertices(self, is_2d=False):
if is_2d:
for v in self.settings["geometry"].vertices:
@@ -12,7 +12,7 @@ class Data:
return
cls.products[product_id] = []
product = file.by_id(product_id)
if not product.Representation:
if not hasattr(product, "Representation") or not product.Representation:
return
for representation in product.Representation.Representations:
c = representation.ContextOfItems
@@ -22,39 +22,30 @@ class CreateProject(bpy.types.Operator):
IfcStore.file = create_file.Usecase({"version": bpy.context.scene.BIMProperties.export_schema}).execute()
self.file = IfcStore.get_file()
project = bpy.data.collections.new("My Project")
site = bpy.data.collections.new("My Site")
building = bpy.data.collections.new("My Building")
building_storey = bpy.data.collections.new("Ground Floor")
project = bpy.data.objects.new("My Project", None)
site = bpy.data.objects.new("My Site", None)
building = bpy.data.objects.new("My Building", None)
building_storey = bpy.data.objects.new("Ground Floor", None)
project_obj = bpy.data.objects.new("My Project", None)
site_obj = bpy.data.objects.new("My Site", None)
building_obj = bpy.data.objects.new("My Building", None)
building_storey_obj = bpy.data.objects.new("Ground Floor", None)
bpy.context.scene.collection.children.link(project)
project.children.link(site)
site.children.link(building)
building.children.link(building_storey)
project.objects.link(project_obj)
site.objects.link(site_obj)
building.objects.link(building_obj)
building_storey.objects.link(building_storey_obj)
bpy.ops.bim.assign_class(obj=project_obj.name, ifc_class="IfcProject")
bpy.ops.bim.assign_class(obj=project.name, ifc_class="IfcProject")
bpy.ops.bim.assign_unit()
bpy.ops.bim.add_subcontext(context="Model")
bpy.ops.bim.add_subcontext(context="Model", subcontext="Body", target_view="MODEL_VIEW")
bpy.ops.bim.add_subcontext(context="Model", subcontext="Box", target_view="MODEL_VIEW")
bpy.ops.bim.add_subcontext(context="Plan")
bpy.ops.bim.add_subcontext(context="Plan", subcontext="Annotation", target_view="PLAN_VIEW")
bpy.ops.bim.assign_class(obj=site_obj.name, ifc_class="IfcSite")
bpy.ops.bim.assign_class(obj=building_obj.name, ifc_class="IfcBuilding")
bpy.ops.bim.assign_class(obj=building_storey_obj.name, ifc_class="IfcBuildingStorey")
bpy.ops.bim.assign_object(related_object=site_obj.name, relating_object=project_obj.name)
bpy.ops.bim.assign_object(related_object=building_obj.name, relating_object=site_obj.name)
bpy.ops.bim.assign_object(related_object=building_storey_obj.name, relating_object=building_obj.name)
for subcontext in self.file.by_type("IfcGeometricRepresentationSubContext"):
if subcontext.ContextIdentifier == "Body":
bpy.context.scene.BIMProperties.contexts = str(subcontext.id())
break
bpy.ops.bim.assign_class(obj=site.name, ifc_class="IfcSite")
bpy.ops.bim.assign_class(obj=building.name, ifc_class="IfcBuilding")
bpy.ops.bim.assign_class(obj=building_storey.name, ifc_class="IfcBuildingStorey")
bpy.ops.bim.assign_object(related_object=site.name, relating_object=project.name)
bpy.ops.bim.assign_object(related_object=building.name, relating_object=site.name)
bpy.ops.bim.assign_object(related_object=building_storey.name, relating_object=building.name)
# Data.load()
return {"FINISHED"}
@@ -1,6 +1,7 @@
import bpy
import numpy as np
import ifcopenshell
import ifcopenshell.util.schema
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
@@ -19,7 +20,8 @@ class EnableReassignClass(bpy.types.Operator):
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)
file = IfcStore.get_file()
ifc_schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(file.schema)
bpy.context.active_object.BIMObjectProperties.is_reassigning_class = True
ifc_products = [
"IfcElement",
@@ -85,49 +87,39 @@ class AssignClass(bpy.types.Operator):
def execute(self, context):
objects = [bpy.data.objects.get(self.obj)] if self.obj else bpy.context.selected_objects
self.file = IfcStore.get_file()
ifc_schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(self.file.schema)
self.declaration = ifc_schema.declaration_by_name(self.ifc_class)
if self.predefined_type == "USERDEFINED":
self.predefined_type = self.ifc_userdefined_type
elif self.predefined_type == "":
predefined_type = None
for obj in objects:
if obj.BIMObjectProperties.ifc_definition_id:
continue
if self.predefined_type == "USERDEFINED":
predefined_type = self.ifc_userdefined_type
elif self.predefined_type == "":
predefined_type = None
else:
predefined_type = self.predefined_type
product = create_product.Usecase(
self.file,
{
"ifc_class": self.ifc_class,
"predefined_type": predefined_type,
"name": obj.name,
},
).execute()
obj.name = "{}/{}".format(product.is_a(), obj.name)
obj.BIMObjectProperties.ifc_definition_id = int(product.id())
bpy.ops.bim.add_representation(obj=obj.name)
relating_structure = None
for collection in obj.users_collection:
if "Ifc" in collection.name:
relating_structure = self.file.by_id(
bpy.data.objects.get(collection.name).BIMObjectProperties.ifc_definition_id
)
break
if relating_structure:
assign_container.Usecase(
self.file,
{
"product": product,
"relating_structure": relating_structure,
},
).execute()
if bpy.context.scene.BIMProperties.ifc_product == "IfcElementType":
self.place_in_types_collection(obj)
self.assign_class(obj)
return {"FINISHED"}
def assign_class(self, obj):
if obj.BIMObjectProperties.ifc_definition_id:
return
product = create_product.Usecase(
self.file,
{
"ifc_class": self.ifc_class,
"predefined_type": self.predefined_type,
"name": obj.name,
},
).execute()
obj.name = "{}/{}".format(product.is_a(), obj.name)
obj.BIMObjectProperties.ifc_definition_id = int(product.id())
bpy.ops.bim.add_representation(obj=obj.name)
if ifcopenshell.util.schema.is_a(self.declaration, "IfcElementType"):
self.place_in_types_collection(obj)
elif ifcopenshell.util.schema.is_a(self.declaration, "IfcSpatialElement") or self.ifc_class == "IfcProject":
self.place_in_spatial_collection(obj)
else:
self.assign_potential_spatial_container(obj)
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]:
@@ -140,6 +132,29 @@ class AssignClass(bpy.types.Operator):
break
break
def place_in_spatial_collection(self, obj):
for collection in obj.users_collection:
if collection.name == obj.name:
return
parent_collection = None
for collection in obj.users_collection:
collection.objects.unlink(obj)
if "Ifc" in collection.name:
parent_collection = collection
collection = bpy.data.collections.new(obj.name)
collection.objects.link(obj)
if parent_collection:
parent_collection.children.link(collection)
else:
bpy.context.scene.collection.children.link(collection)
def assign_potential_spatial_container(self, obj):
for collection in obj.users_collection:
if "Ifc" not in collection.name:
continue
bpy.ops.bim.assign_container(relating_structure=collection.name, related_element=obj.name)
break
class UnassignClass(bpy.types.Operator):
bl_idname = "bim.unassign_class"
+23 -12
View File
@@ -8,6 +8,7 @@ from . import ifc
from . import annotation
from . import decoration
import bpy
from blenderbim.bim.ifc import IfcStore
from bpy.types import PropertyGroup
from bpy.app.handlers import persistent
from bpy.props import (
@@ -125,14 +126,14 @@ def setDefaultProperties(scene):
def getIfcPredefinedTypes(self, context):
global types_enum
if len(types_enum) < 1:
for name, data in schema.ifc.elements.items():
if name != self.ifc_class.strip():
continue
for attribute in data["attributes"]:
if attribute["name"] != "PredefinedType":
continue
types_enum.extend([(e, e, "") for e in attribute["enum_values"]])
file = IfcStore.get_file()
if len(types_enum) < 1 and file:
ifc_schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(file.schema)
declaration = ifc_schema.declaration_by_name(self.ifc_class)
for attribute in declaration.attributes():
if attribute.name() == "PredefinedType":
types_enum.extend([(e, e, "") for e in attribute.type_of_attribute().declared_type().enumeration_items()])
break
return types_enum
@@ -257,8 +258,7 @@ def getIfcProducts(self, context):
"IfcElementType",
"IfcSpatialElement",
"IfcGroup",
"IfcStructural",
"IfcPositioningElement",
"IfcStructuralItem",
"IfcContext",
"IfcAnnotation",
]
@@ -269,8 +269,19 @@ def getIfcProducts(self, context):
def getIfcClasses(self, context):
global classes_enum
if len(classes_enum) < 1:
classes_enum.extend([(e, e, "") for e in getattr(schema.ifc, self.ifc_product)])
file = IfcStore.get_file()
if len(classes_enum) < 1 and file:
ifc_schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(file.schema)
declaration = ifc_schema.declaration_by_name(self.ifc_product)
def get_classes(declaration):
results = []
if not declaration.is_abstract():
results.append(declaration.name())
for subtype in declaration.subtypes():
results.extend(get_classes(subtype))
return results
classes = get_classes(declaration)
classes_enum.extend([(c, c, "") for c in sorted(classes)])
return classes_enum