Refactor getting primitive data type into util

This commit is contained in:
Dion Moult
2021-03-24 16:09:29 +11:00
parent 41a694d0dc
commit 09bf5b85aa
10 changed files with 133 additions and 125 deletions
@@ -1,4 +1,5 @@
import ifcopenshell
import ifcopenshell.util.attribute
from blenderbim.bim.ifc import IfcStore
@@ -18,37 +19,25 @@ class Data:
cls.products[product_id] = []
declaration = IfcStore.get_schema().declaration_by_name(product.is_a())
for attribute in declaration.all_attributes():
data_type = str(attribute.type_of_attribute())
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
value = getattr(product, attribute.name())
list_type = None
enum_items = ()
if "<entity" in data_type:
data_type = "entity"
if isinstance(data_type, tuple):
list_type = data_type[1]
data_type = data_type[0]
if data_type in ["entity", "list", "string", "enum"]:
value = None if value is None else str(value)
elif "<list" in data_type:
if "<entity" in data_type:
list_type = "entity"
elif "<string>" in data_type:
list_type = "string"
elif "<real>" in data_type:
list_type = "float"
elif "<integer>" in data_type:
list_type = "integer"
data_type = "list"
value = None if value is None else str(value)
elif "<string>" in data_type:
data_type = "string"
value = None if value is None else str(value)
elif "<real>" in data_type:
data_type = "float"
elif data_type == "float":
value = None if value is None else float(value)
elif "<integer>" in data_type:
data_type = "integer"
elif data_type == "integer":
value = None if value is None else int(value)
elif "<enumeration" in data_type:
data_type = "enum"
value = None if value is None else str(value)
enum_items = attribute.type_of_attribute().declared_type().enumeration_items()
if data_type == "enum":
enum_items = ifcopenshell.util.attribute.get_enum_items(attribute)
cls.products[product_id].append({
"name": attribute.name(),
"value": value,
@@ -1,5 +1,6 @@
import bpy
import json
import ifcopenshell.util.attribute
import blenderbim.bim.module.constraint.add_objective as add_objective
import blenderbim.bim.module.constraint.edit_objective as edit_objective
import blenderbim.bim.module.constraint.remove_constraint as remove_constraint
@@ -50,19 +51,18 @@ class EnableEditingConstraint(bpy.types.Operator):
data = Data.objectives[self.constraint]
for attribute in IfcStore.get_schema().declaration_by_name(props.is_editing).all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.constraint_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
if "<string>" in data_type:
new.data_type = data_type
if data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
new.data_type = "string"
elif "<enumeration" in data_type:
new.enum_items = json.dumps(attribute.type_of_attribute().declared_type().enumeration_items())
new.data_type = "enum"
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
props.active_constraint_id = self.constraint
@@ -1,5 +1,6 @@
import bpy
import json
import ifcopenshell.util.attribute
import blenderbim.bim.module.document.add_information as add_information
import blenderbim.bim.module.document.add_reference as add_reference
import blenderbim.bim.module.document.edit_information as edit_information
@@ -83,19 +84,18 @@ class EnableEditingDocument(bpy.types.Operator):
ifc_class = "IfcDocumentReference"
for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.document_attributes.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
if "<string>" in data_type:
new.data_type = data_type
if data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
new.data_type = "string"
elif "<enumeration" in data_type:
new.enum_items = json.dumps(attribute.type_of_attribute().declared_type().enumeration_items())
new.data_type = "enum"
elif data_type == "enum":
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
if data[attribute.name()]:
new.enum_value = data[attribute.name()]
props.active_document_id = self.document
@@ -2,6 +2,7 @@ import bpy
import json
import ifcopenshell
import ifcopenshell.util.unit
import ifcopenshell.util.attribute
import blenderbim.bim.module.georeference.add_georeferencing as add_georeferencing
import blenderbim.bim.module.georeference.edit_georeferencing as edit_georeferencing
import blenderbim.bim.module.georeference.remove_georeferencing as remove_georeferencing
@@ -22,49 +23,43 @@ class EnableEditingGeoreferencing(bpy.types.Operator):
props.map_conversion.remove(0)
for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.map_conversion.add()
new.name = attribute.name()
new.is_null = Data.map_conversion[attribute.name()] is None
new.is_optional = attribute.optional()
if "<string>" in data_type:
new.data_type = data_type
if data_type == "string":
new.string_value = "" if new.is_null else Data.map_conversion[attribute.name()]
new.data_type = "string"
elif "<real>" in data_type:
elif data_type == "float":
new.float_value = 0.0 if new.is_null else Data.map_conversion[attribute.name()]
new.data_type = "float"
elif "<integer>" in data_type:
elif data_type == "integer":
new.int_value = 0 if new.is_null else Data.map_conversion[attribute.name()]
new.data_type = "integer"
elif "<boolean>" in data_type or "<logical>" in data_type:
elif data_type == "boolean":
new.bool_value = False if new.is_null else Data.map_conversion[attribute.name()]
new.data_type = "boolean"
while len(props.projected_crs) > 0:
props.projected_crs.remove(0)
for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.projected_crs.add()
new.name = attribute.name()
new.is_null = Data.projected_crs[attribute.name()] is None
new.is_optional = attribute.optional()
if "<string>" in data_type:
new.data_type = data_type
if data_type == "string":
new.string_value = "" if new.is_null else Data.projected_crs[attribute.name()]
new.data_type = "string"
elif "<real>" in data_type:
elif data_type == "float":
new.float_value = 0.0 if new.is_null else Data.projected_crs[attribute.name()]
new.data_type = "float"
elif "<integer>" in data_type:
elif data_type == "integer":
new.int_value = 0 if new.is_null else Data.projected_crs[attribute.name()]
new.data_type = "integer"
elif "<boolean>" in data_type or "<logical>" in data_type:
elif data_type == "boolean":
new.bool_value = False if new.is_null else Data.projected_crs[attribute.name()]
new.data_type = "boolean"
props.is_map_unit_null = Data.projected_crs["MapUnit"] is None
if not props.is_map_unit_null:
@@ -100,8 +95,8 @@ class EditGeoreferencing(bpy.types.Operator):
map_conversion = {}
for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
blender_attribute = props.map_conversion.get(attribute.name())
if blender_attribute.is_null:
@@ -117,8 +112,8 @@ class EditGeoreferencing(bpy.types.Operator):
projected_crs = {}
for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
blender_attribute = props.projected_crs.get(attribute.name())
if blender_attribute.is_null:
@@ -1,4 +1,5 @@
import bpy
import ifcopenshell.util.attribute
import blenderbim.bim.module.group.add_group as add_group
import blenderbim.bim.module.group.edit_group as edit_group
import blenderbim.bim.module.group.remove_group as remove_group
@@ -94,8 +95,8 @@ class EnableEditingGroup(bpy.types.Operator):
data = Data.groups[self.group]
for attribute in IfcStore.get_schema().declaration_by_name("IfcGroup").all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.group_attributes.add()
new.name = attribute.name()
@@ -1,5 +1,6 @@
import bpy
import json
import ifcopenshell.util.attribute
import blenderbim.bim.module.layer.add_layer as add_layer
import blenderbim.bim.module.layer.edit_layer as edit_layer
import blenderbim.bim.module.layer.remove_layer as remove_layer
@@ -49,8 +50,8 @@ class EnableEditingLayer(bpy.types.Operator):
data = Data.layers[self.layer]
for attribute in IfcStore.get_schema().declaration_by_name("IfcPresentationLayerAssignment").all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
new = props.layer_attributes.add()
new.name = attribute.name()
@@ -1,4 +1,5 @@
import bpy
import ifcopenshell.util.attribute
import blenderbim.bim.module.material.add_material as add_material
import blenderbim.bim.module.material.remove_material as remove_material
import blenderbim.bim.module.material.assign_material as assign_material
@@ -351,25 +352,22 @@ class EnableEditingMaterialSetItem(bpy.types.Operator):
props.material_set_item_attributes.remove(0)
for attribute in IfcStore.get_schema().declaration_by_name(material_set_item.is_a()).all_attributes():
data_type = str(attribute.type_of_attribute)
if "<entity" in data_type:
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
if data_type == "entity":
continue
if attribute.name() in material_set_item_data:
new = props.material_set_item_attributes.add()
new.name = attribute.name()
new.is_null = material_set_item_data[attribute.name()] is None
if "<string>" in data_type:
new.data_type = data_type
if data_type == "string":
new.string_value = "" if new.is_null else material_set_item_data[attribute.name()]
new.data_type = "string"
elif "<real>" in data_type:
elif data_type == "float":
new.float_value = 0.0 if new.is_null else material_set_item_data[attribute.name()]
new.data_type = "float"
elif "<integer>" in data_type:
elif data_type == "integer":
new.int_value = 0 if new.is_null else material_set_item_data[attribute.name()]
new.data_type = "integer"
elif "<boolean>" in data_type or "<logical>" in data_type:
elif data_type == "boolean":
new.bool_value = False if new.is_null else material_set_item_data[attribute.name()]
new.data_type = "boolean"
return {"FINISHED"}
@@ -1,5 +1,6 @@
import ifcopenshell
import blenderbim.bim.schema # TODO: refactor elsewhere
import ifcopenshell.util.attribute
import blenderbim.bim.schema # TODO: refactor elsewhere
from blenderbim.bim.ifc import IfcStore
@@ -31,7 +32,7 @@ class Data:
@classmethod
def add_type_product_psets(cls, product, product_id):
if not hasattr(product, "HasPropertySets") or not product.HasPropertySets:
return # TODO
return # TODO
for definition in product.HasPropertySets:
if definition.is_a("IfcPropertySet"):
cls.add_pset(definition, product_id)
@@ -60,17 +61,17 @@ class Data:
new_pset = {
"Name": pset.Name,
"is_expanded": True,
"Properties": cls.get_properties_from_template(pset.Name) or []
"Properties": cls.get_properties_from_template(pset.Name) or [],
}
cls.products[product_id]["psets"].add(int(pset.id()))
cls.psets[int(pset.id())] = new_pset
try:
if hasattr(pset, "HasProperties"):
props = pset.HasProperties
elif hasattr(pset, "Properties"): # For IfcMaterialProperties
elif hasattr(pset, "Properties"): # For IfcMaterialProperties
props = pset.Properties
except:
return # I've seen ArchiCAD produce invalid IFCs with empty data
return # I've seen ArchiCAD produce invalid IFCs with empty data
# Invalid IFC, but some vendors like Solidworks do this so we accomodate it
if not props:
return
@@ -107,20 +108,22 @@ class Data:
else:
data_type = "string"
value = str(value)
new_pset["Properties"].append({
"Name": prop.Name,
"value": value,
"type": data_type,
"enum_items": [],
"is_null": prop.NominalValue.wrappedValue is None
})
new_pset["Properties"].append(
{
"Name": prop.Name,
"value": value,
"type": data_type,
"enum_items": [],
"is_null": prop.NominalValue.wrappedValue is None,
}
)
@classmethod
def add_qto(cls, qto, product_id):
new_qto = {
"Name": qto.Name,
"is_expanded": True,
"Properties": cls.get_properties_from_template(qto.Name) or []
"Properties": cls.get_properties_from_template(qto.Name) or [],
}
cls.products[product_id]["qtos"].add(int(qto.id()))
cls.qtos[int(qto.id())] = new_qto
@@ -135,13 +138,15 @@ class Data:
has_existing_prop = True
break
if not has_existing_prop:
new_qto["Properties"].append({
"Name": prop.Name,
"value": float(value),
"type": "float",
"enum_items": [],
"is_null": value is None
})
new_qto["Properties"].append(
{
"Name": prop.Name,
"value": float(value),
"type": "float",
"enum_items": [],
"is_null": value is None,
}
)
@classmethod
def get_properties_from_template(cls, name):
@@ -151,12 +156,14 @@ class Data:
properties = []
for prop_template in template.HasPropertyTemplates:
if not prop_template.is_a("IfcSimplePropertyTemplate"):
continue # Other types not yet supported
continue # Other types not yet supported
enum_items = []
if prop_template.TemplateType == "P_SINGLEVALUE":
try:
data_type = str(IfcStore.get_schema().declaration_by_name(prop_template.PrimaryMeasureType or "IfcLabel"))
data_type = ifcopenshell.util.attribute.get_primitive_type(
IfcStore.get_schema().declaration_by_name(prop_template.PrimaryMeasureType or "IfcLabel")
)
except:
# TODO: Occurs if the data type is something that exists in IFC4 and not in IFC2X3. To fully fix
# this we need to generate the IFC2X3 pset template definitions.
@@ -169,26 +176,15 @@ class Data:
elif prop_template.TemplateType == "Q_COUNT":
data_type = "integer"
else:
continue # Other types not yet supported
continue # Other types not yet supported
if "<string>" in data_type:
data_type = "string"
elif "<real>" in data_type:
data_type = "float"
elif "<number>" in data_type:
data_type = "integer"
elif "<integer>" in data_type:
data_type = "integer"
elif "<boolean>" in data_type or "<logical>" in data_type:
data_type = "boolean"
elif "<enumeration" in data_type:
data_type = "enum"
enum_items = attribute.type_of_attribute().declared_type().enumeration_items()
properties.append({
"Name": prop_template.Name,
"value": None,
"type": data_type,
"enum_items": enum_items,
"is_null": True
})
properties.append(
{
"Name": prop_template.Name,
"value": None,
"type": data_type,
"enum_items": enum_items,
"is_null": True,
}
)
return properties
@@ -53,13 +53,13 @@ class EnableEditingStructuralBoundaryCondition(bpy.types.Operator):
for attribute in IfcStore.get_schema().declaration_by_name(data["type"]).all_attributes():
value = data[attribute.name()]
data_type = str(attribute.type_of_attribute)
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
new = props.boundary_condition_attributes.add()
new.name = attribute.name()
new.is_null = value is None
new.is_optional = attribute.optional()
if "<select" in data_type:
enum_items = [s.name() for s in attribute.type_of_attribute().declared_type().select_list()]
if data_type == "select":
enum_items = [s.name() for s in ifcopenshell.get_select_items(attribute)]
new.enum_items = json.dumps(enum_items)
if isinstance(value, bool):
new.bool_value = False if new.is_null else data[attribute.name()]
@@ -69,9 +69,8 @@ class EnableEditingStructuralBoundaryCondition(bpy.types.Operator):
new.float_value = 0.0 if new.is_null else data[attribute.name()]
new.data_type = "float"
new.enum_value = [i for i in enum_items if i != "IfcBoolean"][0]
elif "<string>" in data_type:
elif data_type == "string":
new.string_value = "" if new.is_null else data[attribute.name()]
new.data_type = "string"
props.is_editing_boundary_condition = True
return {"FINISHED"}
@@ -0,0 +1,29 @@
def get_primitive_type(attribute_or_data_type):
if hasattr(attribute_or_data_type, "type_of_attribute"):
data_type = str(attribute_or_data_type.type_of_attribute())
else:
data_type = str(attribute_or_data_type)
if "<list" in data_type:
return ("list", get_primitive_type(data_type.replace("<list", "")))
elif "<entity" in data_type:
return "entity"
elif "<string>" in data_type:
return "string"
elif "<real>" in data_type:
return "float"
elif "<number>" in data_type or "<integer>" in data_type:
return "integer"
elif "<boolean>" in data_type or "<logical>" in data_type:
return "boolean"
elif "<enumeration" in data_type:
return "enum"
elif "<select" in data_type:
return "select"
def get_enum_items(attribute):
return attribute.type_of_attribute().declared_type().enumeration_items()
def get_select_items(attribute):
return attribute.type_of_attribute().declared_type().select_list()