endofday 1207

240pm 14/07

draft version

cleanup
This commit is contained in:
Vukas Pajic
2022-07-11 16:33:24 +02:00
parent 1586c85314
commit e3d9dd747d
5 changed files with 458 additions and 29 deletions
@@ -20,6 +20,7 @@ import bpy
from . import ui, prop, operator
classes = (
operator.EditBlenderCollection,
operator.ActivateIfcClassFilter,
operator.ActivateIfcBuildingStoreyFilter,
operator.ColourByAttribute,
@@ -31,18 +32,30 @@ classes = (
operator.SelectGlobalId,
operator.SelectIfcClass,
operator.SelectPset,
operator.Reset3dView,
operator.FilterModelElements,
prop.BIMFilterClasses,
prop.BIMFilterBuildingStoreys,
prop.BIMSearchProperties,
prop.SearchCollection,
prop.SearchQueryFilter,
prop.SearchQuery,
prop.SearchQueryGroup,
prop.IfcSelectorProperties,
ui.BIM_PT_search,
ui.BIM_UL_ifc_class_filter,
ui.BIM_UL_ifc_building_storey_filter,
ui.BIM_PT_IFCSelector
)
def register():
bpy.types.Scene.BIMSearchProperties = bpy.props.PointerProperty(type=prop.BIMSearchProperties)
bpy.types.Scene.BIMSearchProperties = bpy.props.PointerProperty(
type=prop.BIMSearchProperties)
bpy.types.Scene.IfcSelectorProperties = bpy.props.PointerProperty(
type=prop.IfcSelectorProperties)
def unregister():
del bpy.types.Scene.BIMSearchProperties
del bpy.types.Scene.IfcSelectorProperties
@@ -20,6 +20,7 @@ import re
import bpy
import ifcopenshell
import ifcopenshell.util.element
from ifcopenshell.util.selector import Selector
import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore
from itertools import cycle
@@ -54,6 +55,23 @@ def does_keyword_exist(pattern, string, context):
return True
class EditBlenderCollection(bpy.types.Operator):
bl_idname = "bim.edit_blender_collection"
bl_label = "Add or Remove blender collection item"
bl_options = {"REGISTER", "UNDO"}
option: bpy.props.StringProperty()
collection: bpy.props.StringProperty()
index: bpy.props.IntProperty()
def execute(self, context):
if self.option == "add":
getattr(context.bim_prop_group, self.collection).add()
else:
getattr(context.bim_prop_group, self.collection).remove(self.index)
return {"FINISHED"}
class SelectGlobalId(bpy.types.Operator):
"""Click to select the objects that match with the given Global ID"""
@@ -86,7 +104,8 @@ class SelectIfcClass(bpy.types.Operator):
for obj in context.visible_objects:
if not obj.BIMObjectProperties.ifc_definition_id or obj.is_library_indirect:
continue
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
element = self.file.by_id(
obj.BIMObjectProperties.ifc_definition_id)
if does_keyword_exist(self.ifc_class, element.is_a(), context):
obj.select_set(True)
return {"FINISHED"}
@@ -107,10 +126,12 @@ class SelectAttribute(bpy.types.Operator):
for obj in context.visible_objects:
if not obj.BIMObjectProperties.ifc_definition_id:
continue
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
element = self.file.by_id(
obj.BIMObjectProperties.ifc_definition_id)
if context.scene.BIMSearchProperties.should_ignorecase:
data = element.get_info()
value = next((v for k, v in data.items() if k.lower() == attribute_name.lower()), None)
value = next((v for k, v in data.items()
if k.lower() == attribute_name.lower()), None)
else:
value = getattr(element, attribute_name, None)
if does_keyword_exist(pattern, value, context):
@@ -134,7 +155,8 @@ class SelectPset(bpy.types.Operator):
for obj in context.visible_objects:
if not obj.BIMObjectProperties.ifc_definition_id:
continue
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
element = self.file.by_id(
obj.BIMObjectProperties.ifc_definition_id)
psets = ifcopenshell.util.element.get_psets(element)
if search_pset_name == "":
props = {}
@@ -142,8 +164,10 @@ class SelectPset(bpy.types.Operator):
else:
props = None
if context.scene.BIMSearchProperties.should_ignorecase:
props = props or next((v for k, v in psets.items() if k.lower() == search_pset_name.lower()), {})
value = str(next((v for k, v in props.items() if k.lower() == search_prop_name.lower()), None))
props = props or next(
(v for k, v in psets.items() if k.lower() == search_pset_name.lower()), {})
value = str(next((v for k, v in props.items()
if k.lower() == search_prop_name.lower()), None))
else:
props = props or psets.get(search_pset_name, {})
value = props.get(search_prop_name, None)
@@ -175,10 +199,12 @@ class ColourByAttribute(bpy.types.Operator):
for obj in context.visible_objects:
if not obj.BIMObjectProperties.ifc_definition_id:
continue
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
element = self.file.by_id(
obj.BIMObjectProperties.ifc_definition_id)
if context.scene.BIMSearchProperties.should_ignorecase:
data = element.get_info()
value = next((v for k, v in data.items() if k.lower() == attribute_name.lower()), None)
value = next((v for k, v in data.items()
if k.lower() == attribute_name.lower()), None)
else:
value = getattr(element, attribute_name, None)
if value not in values:
@@ -192,7 +218,8 @@ class ColourByAttribute(bpy.types.Operator):
def store_state(self, context):
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
if areas:
self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
self.transaction_data = {
"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
def rollback(self, data):
if data:
@@ -227,7 +254,8 @@ class ColourByPset(bpy.types.Operator):
for obj in context.visible_objects:
if not obj.BIMObjectProperties.ifc_definition_id:
continue
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
element = self.file.by_id(
obj.BIMObjectProperties.ifc_definition_id)
psets = ifcopenshell.util.element.get_psets(element)
if search_pset_name == "":
props = {}
@@ -235,8 +263,10 @@ class ColourByPset(bpy.types.Operator):
else:
props = None
if context.scene.BIMSearchProperties.should_ignorecase:
props = props or next((v for k, v in psets.items() if k.lower() == search_pset_name.lower()), {})
value = str(next((v for k, v in props.items() if k.lower() == search_prop_name.lower()), None))
props = props or next(
(v for k, v in psets.items() if k.lower() == search_pset_name.lower()), {})
value = str(next((v for k, v in props.items()
if k.lower() == search_prop_name.lower()), None))
else:
props = props or psets.get(search_pset_name, {})
value = str(props.get(search_prop_name, None))
@@ -251,7 +281,8 @@ class ColourByPset(bpy.types.Operator):
def store_state(self, context):
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
if areas:
self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
self.transaction_data = {
"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
def rollback(self, data):
if data:
@@ -284,7 +315,8 @@ class ColourByClass(bpy.types.Operator):
for obj in context.visible_objects:
if not obj.BIMObjectProperties.ifc_definition_id:
continue
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
element = self.file.by_id(
obj.BIMObjectProperties.ifc_definition_id)
ifc_class = element.is_a()
if ifc_class not in ifc_classes:
ifc_classes[ifc_class] = next(colours)
@@ -297,7 +329,8 @@ class ColourByClass(bpy.types.Operator):
def store_state(self, context):
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
if areas:
self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
self.transaction_data = {
"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
def rollback(self, data):
if data:
@@ -324,7 +357,8 @@ class ToggleFilterSelection(bpy.types.Operator):
"Click to select/deselect current selection"
bl_idname = "bim.toggle_filter_selection"
bl_label = "Toggle Filter Selection"
action: bpy.props.EnumProperty(items=(("SELECT", "Select", ""), ("DESELECT", "Deselect", "")))
action: bpy.props.EnumProperty(
items=(("SELECT", "Select", ""), ("DESELECT", "Deselect", "")))
def execute(self, context):
props = bpy.context.scene.BIMSearchProperties
@@ -383,8 +417,10 @@ class ActivateIfcClassFilter(bpy.types.Operator):
else len(bpy.context.scene.BIMSearchProperties.filter_classes),
)
row = self.layout.row(align=True)
row.operator("bim.toggle_filter_selection", text="Select All").action = "SELECT"
row.operator("bim.toggle_filter_selection", text="Deselect All").action = "DESELECT"
row.operator("bim.toggle_filter_selection",
text="Select All").action = "SELECT"
row.operator("bim.toggle_filter_selection",
text="Deselect All").action = "DESELECT"
class ActivateIfcBuildingStoreyFilter(bpy.types.Operator):
@@ -431,5 +467,102 @@ class ActivateIfcBuildingStoreyFilter(bpy.types.Operator):
else len(bpy.context.scene.BIMSearchProperties.filter_building_storeys),
)
row = self.layout.row(align=True)
row.operator("bim.toggle_filter_selection", text="Select All").action = "SELECT"
row.operator("bim.toggle_filter_selection", text="Deselect All").action = "DESELECT"
row.operator("bim.toggle_filter_selection",
text="Select All").action = "SELECT"
row.operator("bim.toggle_filter_selection",
text="Deselect All").action = "DESELECT"
class Reset3dView(bpy.types.Operator):
"""Filter model elements based on selection"""
bl_idname = "bim.reset_3d_view"
bl_label = "Reset 3D View"
def execute(self, context):
for obj in bpy.data.scenes["Scene"].objects:
obj.hide_set(False)
return {"FINISHED"}
class FilterModelElements(bpy.types.Operator):
"""Filter model elements based on selection"""
bl_idname = "bim.filter_model_elements"
bl_label = "Filter Model Elements"
option: bpy.props.StringProperty("select|isolate|hide")
def execute(self, context):
selector = context.scene.IfcSelectorProperties
selection = self.add_groups(selector)
selector.selector_query_syntax = selection
self.update_model_view(context, selection)
return {"FINISHED"}
def add_groups(self, selector):
selection = ''
for group_index, group in enumerate(selector.groups):
if group_index != 0:
selection += " | "
selection += "(" if len(selector.groups) >1 else ""
selection = self.add_queries(selection, group)
selection += ")" if len(selector.groups) >1 else ""
return selection
def add_queries(self, selection, group):
for query_index, query in enumerate(group.queries):
if query_index != 0:
selection += " & " if query.and_or == "and" else " | "
if query.selector == "IFC Class":
active_option = query.active_option.split(": ")[1]
selection += f".{active_option}"
selection = self.add_filters(selection, query)
elif query.selector == "GlobalId":
selection += f"#{query.global_id}"
elif query.selector == "IfcElementType":
index = int(query.active_sub_option.split(":")[0])
selection += f"* #{query.sub_options[index].global_id}"
elif query.selector == "IfcSpatialElement":
index = int(query.active_sub_option.split(":")[0])
selection += f"@ #{query.sub_options[index].global_id}"
return selection
def add_filters(self, selection, query):
for f_index, f in enumerate(query.filters):
if f_index !=0:
selection += " & " if f.and_or == "and" else " | "
selection += f".{query.active_option}"
selection += "["
if f.selector == "Pset-Property":
selection += f'{f.active_option}.{f.active_sub_option} {"!" if f.negation else ""} ="{f.value}"'
elif f.selector == "Attribute":
selection += f'{f.attribute} {"!" if f.negation else ""}= "{f.value}"'
selection += "]"
return selection
def update_model_view(self, context, selection):
query = Selector.parse(IfcStore.file, selection)
sel_element_ids = [e.id() for e in query]
bpy.ops.object.select_all(action='DESELECT')
for obj in bpy.data.scenes["Scene"].objects:
obj.hide_set(False) # reset 3d view
if self.option == "select":
if obj.BIMObjectProperties.ifc_definition_id in sel_element_ids:
obj.select_set(True)
elif self.option == "isolate":
if obj.BIMObjectProperties.ifc_definition_id not in sel_element_ids:
obj.hide_set(True)
elif self.option == "hide":
if obj.BIMObjectProperties.ifc_definition_id in sel_element_ids:
obj.hide_set(True)
@@ -16,10 +16,13 @@
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
from ifcopenshell import util
from ifcopenshell.util.selector import Selector
import blenderbim.tool as tool
from blenderbim.bim.prop import ObjProperty
from blenderbim.bim.prop import ObjProperty, StrProperty
from blenderbim.bim.ifc import IfcStore
from bpy.types import PropertyGroup
from blenderbim.tool.ifc import Ifc
from . import ui, prop, operator
from bpy.props import (
PointerProperty,
@@ -90,3 +93,149 @@ class BIMSearchProperties(PropertyGroup):
filter_classes_index: IntProperty(name="Filter Classes Index")
filter_building_storeys: CollectionProperty(type=BIMFilterBuildingStoreys, name="Filter Level")
filter_building_storeys_index: IntProperty(name="Filter Level Index")
def get_classes(self, ifc_product):
declaration = tool.Ifc.schema().declaration_by_name(ifc_product)
declarations = util.schema.get_subtypes(declaration)
names = [d.name() for d in declarations]
return [(c, c, "") for c in sorted(names)]
def load_sub_options(self, context):
if self.selector not in ["IfcClass"]:
self.load_option = "sub_options"
load_selection_options(self, context)
def load_selection_options(self, context):
ifc = IfcStore.file
load_option = self.load_option
op = getattr(self, load_option)
op.clear()
options = []
if load_option == "options":
self.sub_options.clear()
if self.selector == "IFC Class":
options = get_classes(self, "IfcElement")
options.append(("IfcSpace", "IfcSpace",""))
elif self.selector == "IfcSpatialElement":
options = get_classes(self, "IfcSpatialElement")
elif self.selector == "IfcElementType":
options = get_classes(self, "IfcElementType")
elif self.selector == "GlobalId":
return
elif self.selector == "IfcPropertySet":
psets = Selector.parse(ifc, ".IfcPropertySet")
options = set([o.Name for o in psets])
elif load_option == "sub_options":
if self.selector in ["IfcSpatialElement", "IfcElementType"]:
active_option = self.active_option.split(": ")[1]
options = Selector.parse(ifc, f".{active_option}")
elif self.selector == "IfcPropertySet":
options = set()
active_pset = self.active_option.split(": ")[1]
psets_in_file = Selector.parse(ifc, f'.IfcPropertySet[Name="{active_pset}"]')
for pset in psets_in_file:
for prop in pset.HasProperties:
options.add(prop.Name)
for index, option in enumerate(options):
new = op.add()
if self.selector in ["IfcSpatialElement", "IfcElementType"]:
if self.load_option == "sub_options":
new.name = f"{index}: {option.Name}"
new.global_id = option.GlobalId
else:
new.name = f"{index}: {option[0]}"
elif self.selector == "IfcPropertySet":
new.name = f"{index}: {option}"
else:
new.name = f"{index}: {option[0]}"
self.load_option = "options"
def load_spatial_elements(self, context):
ifc = IfcStore.file
col_items = Selector.parse(ifc, f".{self.selected_spatial_element}")
collection = getattr(self, "sub_spatial_elements", None)
collection.clear()
for index, c in enumerate(col_items):
new = collection.add()
new.name = f"{index}-{c.Name}"
class SearchCollection(PropertyGroup):
name: StringProperty()
long_name: StringProperty()
global_id: StringProperty()
class IfcSelector:
and_or: EnumProperty(
items=[(i, i, i) for i in ["and", "or"]],
)
negation: BoolProperty(name="not")
comparison: EnumProperty(
items=[
("=", "equal to", ""),
("*=", "contains", ""),
(">=", "greater than or equal to", ""),
("<=", "lesser than or equal to", ""),
(">", "greater than", ""),
("<", "less than", ""),
],
)
load_option: StringProperty(default="options")
options: CollectionProperty(type=SearchCollection)
active_option: StringProperty(update=load_sub_options)
sub_options: CollectionProperty(type=SearchCollection)
active_sub_option: StringProperty()
value: StringProperty()
class SearchQueryFilter(PropertyGroup, IfcSelector):
selector: EnumProperty(
items=[(i, i, i) for i in ["-", "IfcPropertySet", "Attribute"]],
name="Filter selection by",
update=load_selection_options,
default="-",
)
attribute: EnumProperty(
items=[(i, i, i) for i in ["GlobalId", "Name", "Description", "ObjectType", "Tag", "PredefinedType"]],
name="Filter selection by",
update=load_selection_options,
)
# property_sets: CollectionProperty(type=StrProperty)
# selected_property_set: StringProperty(update=load_selection_options)
# prop_names: CollectionProperty(type=StrProperty)
# selected_prop: StringProperty()
# prop_value: StringProperty()
class SearchQuery(PropertyGroup, IfcSelector):
filters: CollectionProperty(type=SearchQueryFilter)
selector: EnumProperty(
items=[(i, i, i) for i in ["-", "IFC Class", "IfcSpatialElement", "IfcElementType", "GlobalId"]],
name="Selector type",
update=load_selection_options,
default="-",
)
class SearchQueryGroup(PropertyGroup, IfcSelector):
queries: CollectionProperty(type=SearchQuery)
class IfcSelectorProperties(PropertyGroup, IfcSelector):
groups: CollectionProperty(type=SearchQueryGroup)
selector_query_syntax: StringProperty()
@@ -102,3 +102,136 @@ class BIM_UL_ifc_building_storey_filter(bpy.types.UIList):
split = split.column()
split.scale_x = 0.5
split.label(text=str(item.total))
class BIM_PT_IFCSelector(Panel):
bl_label = "IFC Selector"
bl_idname = "BIM_PT_ifc_selector"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_collaboration"
@classmethod
def poll(cls, context):
return IfcStore.get_file()
def draw(self, context):
ifc_selector = context.scene.IfcSelectorProperties
layout = self.layout
row = layout.row()
row.context_pointer_set(name="bim_prop_group", data=ifc_selector)
op = row.operator("bim.edit_blender_collection", text="Add selection group")
op.option = "add"
op.collection = "groups"
layout.separator()
self.draw_query_group_ui(ifc_selector, layout)
if len(ifc_selector.groups) != 0:
row = layout.row()
row.alignment = "CENTER"
select = row.operator("bim.filter_model_elements", text="select")
select.option = "select"
isolate = row.operator("bim.filter_model_elements", text="isolate")
isolate.option = "isolate"
hide = row.operator("bim.filter_model_elements", text="hide")
hide.option = "hide"
reset = row.operator("bim.reset_3d_view", text="reset 3d view")
row = layout.row()
row.prop(ifc_selector, "selector_query_syntax", text="Query Syntax")
def draw_query_group_ui(self, ifc_selector, layout):
for index, group in enumerate(ifc_selector.groups):
row = layout.row()
row.alignment = "CENTER"
row.label(text="or") if index !=0 else None
box = layout.box()
row = box.row(align=True)
row.alignment = "CENTER"
row.label(text=f"Group #{str(index+1)}")
row.context_pointer_set(name="bim_prop_group", data=group)
op = row.operator("bim.edit_blender_collection", text="Add query", icon="PLUS")
op.option = "add"
op.collection = "queries"
row.context_pointer_set(name="bim_prop_group", data=ifc_selector)
op = row.operator("bim.edit_blender_collection", text="Remove selection group")
op.option = "remove"
op.collection = "groups"
op.index = index
self.draw_query_ui(group, box)
def draw_query_ui(self, group, box):
for index, query in enumerate(group.queries):
row = box.row()
row.alignment = "LEFT"
row.prop(query, "and_or", text="") if index != 0 else None
if query.and_or == "or":
row=box.row()
row.alignment = "LEFT"
row.prop(query, "selector", text="")
if query.selector in ["IFC Class", "IfcSpatialElement", "IfcElementType"]:
row.label(text="Equals")
row.prop_search(query, "active_option", query, "options", text="")
row.prop_search(query, "active_sub_option", query, "sub_options", text="") if len(query.sub_options) != 0 else None
self.draw_filter_ui(index, box, query)
elif query.selector in ["GlobalId", "Attribute"]:
row.prop(query, "negation", text="")
row.prop(query, "comparison", text="")
row.prop(query, "value", text="")
row.context_pointer_set(name="bim_prop_group", data=group)
op = row.operator("bim.edit_blender_collection", icon="REMOVE", text="")
op.option = "remove"
op.collection = "queries"
op.index = index
row.context_pointer_set(name="bim_prop_group", data=query)
op = (
row.operator("bim.edit_blender_collection", text="Add filter")
if query.selector == "IFC Class"
else None
)
if op:
op.option = "add"
op.collection = "filters"
def draw_filter_ui(self, index, box, query):
for filter_index, f in enumerate(query.filters):
row = box.row()
row.alignment = "LEFT"
row.label(text="")
row.prop(f, "and_or", text="") if filter_index != 0 else None
if f.and_or == "or":
row=box.row()
row.alignment = "LEFT"
row.label(text="")
row.prop(f, "selector", text="")
if f.selector == "Attribute":
row.prop(f, "attribute", text="")
row.prop(f, "negation",)
row.prop(f, "comparison", text="")
row.prop(f, "value", text="")
elif f.selector == "IfcPropertySet":
row.prop_search(f, "active_option", f, "options", text="")
row.prop_search(f, "active_sub_option", f, "sub_options", text="")
row.prop(f, "negation")
row.prop(f, "comparison", text="")
row.prop(f, "value", text="")
row.context_pointer_set(name="bim_prop_group", data=query)
op = row.operator("bim.edit_blender_collection", icon="REMOVE", text="")
op.option = "remove"
op.collection = "filters"
op.index = filter_index
@@ -21,13 +21,11 @@ import ifcopenshell.util.fm
import ifcopenshell.util.element
import lark
class Selector:
@classmethod
def parse(cls, ifc_file, query, elements=None):
cls.file = ifc_file
cls.elements = elements
l = lark.Lark(
"""start: query (lfunction query)*
query: selector | group
@@ -38,7 +36,7 @@ class Selector:
filter: "[" filter_key (comparison filter_value)? "]"
filter_key: WORD | pset_or_qto
filter_value: ESCAPED_STRING | SIGNED_FLOAT | SIGNED_INT | BOOLEAN | NULL
pset_or_qto: /[A-Za-z0-9_]+/ "." /[A-Za-z0-9_]+/
pset_or_qto: /[^.= ][^.=]*[^.= ]/ "." /[^.= ][^.=]*[^.= ](?= +\W+")/
lfunction: and | or
inverse_relationship: types | decomposed_by | bounded_by
types: "*"
@@ -143,7 +141,8 @@ class Selector:
elif hasattr(element, "ObjectTypeOf") and element.ObjectTypeOf:
results.extend(element.ObjectTypeOf[0].RelatedObjects)
elif inverse_relationship == "decomposed_by":
results.extend(ifcopenshell.util.element.get_decomposition(element))
results.extend(
ifcopenshell.util.element.get_decomposition(element))
elif inverse_relationship == "bounded_by" and hasattr(element, "BoundedBy"):
for relationship in element.BoundedBy:
results.append(relationship.RelatedBuildingElement)
@@ -161,7 +160,8 @@ class Selector:
if cls.elements is None:
elements = cls.file.by_type(class_selector.children[0])
else:
elements = [e for e in cls.elements if e.is_a(class_selector.children[0])]
elements = [e for e in cls.elements if e.is_a(
class_selector.children[0])]
if len(class_selector.children) > 1 and class_selector.children[1].data == "filter":
return cls.filter_elements(elements, class_selector.children[1])
return elements
@@ -210,7 +210,8 @@ class Selector:
key = ".".join(key.split(".")[1:])
elif "." in key and key.split(".")[0] == "material":
try:
element = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
element = ifcopenshell.util.element.get_material(
element, should_skip_usage=True)
if not element:
return None
except: