Create UI to add/remove material attributes

This commit is contained in:
Dion Moult
2020-01-14 15:38:22 +11:00
parent ef919ab431
commit 2dbcd6712e
8 changed files with 451 additions and 35 deletions
@@ -68,6 +68,8 @@ if bpy is not None:
operator.GenerateGlobalId,
operator.AddAttribute,
operator.RemoveAttribute,
operator.AddMaterialAttribute,
operator.RemoveMaterialAttribute,
operator.QuickProjectSetup,
operator.SelectGlobalId,
operator.CreateAggregate,
+23 -30
View File
@@ -772,26 +772,18 @@ class IfcParser():
continue
results[slot.material.name] = {
'ifc': None,
'layer_ifc': None,
'constituent_ifc': None,
'part_ifc': None,
'raw': slot.material,
'material_type': obj.BIMObjectProperties.material_type,
'attributes': {'Name': slot.material.name},
# TODO: turn into non-custom attributes
'layer_attributes': {
key[3:]: slot.material[key]
for key in slot.material.keys()
if key[0:3] == 'Ifc'
},
# TODO: turn into non-custom attributes
'constituent_attributes': {
key[3:]: slot.material[key]
for key in slot.material.keys()
if key[0:3] == 'Ifc'
}
'attributes': self.get_material_attributes(slot.material)
}
return results
def get_material_attributes(self, material):
attributes = {'Name': material.name}
attributes.update({a.name: a.string_value for a in material.BIMMaterialProperties.attributes})
return attributes
def get_styled_items(self):
results = []
if not self.ifc_export_settings.has_representations:
@@ -1451,14 +1443,19 @@ class IfcExporter():
self.create_material_psets(material)
self.file.createIfcMaterialDefinitionRepresentation(
material['raw'].name, None, [styled_representation], material['ifc'])
if material['material_type'] == 'IfcMaterialLayerSet':
material['layer_attributes']['Material'] = material['ifc']
material['layer_ifc'] = self.file.create_entity('IfcMaterialLayer',
**material['layer_attributes'])
elif material['material_type'] == 'IfcMaterialConstituentSet':
material['constituent_attributes']['Material'] = material['ifc']
material['constituent_ifc'] = self.file.create_entity('IfcMaterialConstituent',
**material['constituent_attributes'])
if material['material_type'] != 'IfcMaterial':
material_type = material['material_type'][0:-3]
self.cast_attributes(material_type, material['attributes'])
material['attributes']['Material'] = material['ifc']
material['part_ifc'] = self.file.create_entity(material_type,
**material['attributes'])
def cast_attributes(self, ifc_class, attributes):
for key, value in attributes.items():
var_type = self.get_product_attribute_type(ifc_class, key)
if var_type is None:
continue
attributes[key] = self.cast_to_base_type(var_type, value)
def create_surface_style_rendering(self, styled_item):
surface_colour = self.create_colour_rgb(styled_item['raw'].diffuse_color)
@@ -1527,11 +1524,7 @@ class IfcExporter():
'Representation': self.get_product_shape(product)
})
for key, value in product['attributes'].items():
var_type = self.get_product_attribute_type(product['class'], key)
if var_type is None:
continue
product['attributes'][key] = self.cast_to_base_type(var_type, value)
self.cast_attributes(product['class'], product['attributes'])
try:
product['ifc'] = self.file.create_entity(product['class'], **product['attributes'])
@@ -2070,7 +2063,7 @@ class IfcExporter():
return
for product_index, related_materials in self.ifc_parser.rel_associates_material_layer_set.items():
material_layer_set = self.file.create_entity('IfcMaterialLayerSet', **{
'MaterialLayers': [self.ifc_parser.materials[m]['layer_ifc'] for m in related_materials]
'MaterialLayers': [self.ifc_parser.materials[m]['part_ifc'] for m in related_materials]
})
self.file.createIfcRelAssociatesMaterial(
ifcopenshell.guid.new(), self.owner_history, None, None,
@@ -2082,7 +2075,7 @@ class IfcExporter():
return
for product_index, related_materials in self.ifc_parser.rel_associates_material_constituent_set.items():
material_constituent_set = self.file.create_entity('IfcMaterialConstituentSet', **{
'MaterialConstituents': [self.ifc_parser.materials[m]['constituent_ifc'] for m in related_materials]
'MaterialConstituents': [self.ifc_parser.materials[m]['part_ifc'] for m in related_materials]
})
self.file.createIfcRelAssociatesMaterial(
ifcopenshell.guid.new(), self.owner_history, None, None,
@@ -386,6 +386,18 @@ class AddAttribute(bpy.types.Operator):
attribute.name = bpy.context.active_object.BIMObjectProperties.applicable_attributes
return {'FINISHED'}
class AddMaterialAttribute(bpy.types.Operator):
bl_idname = 'bim.add_material_attribute'
bl_label = 'Add Material Attribute'
def execute(self, context):
if bpy.context.active_object.active_material.BIMMaterialProperties.applicable_attributes:
attribute = bpy.context.active_object.active_material.BIMMaterialProperties.attributes.add()
attribute.name = bpy.context.active_object.active_material.BIMMaterialProperties.applicable_attributes
return {'FINISHED'}
class RemoveAttribute(bpy.types.Operator):
bl_idname = 'bim.remove_attribute'
bl_label = 'Remove Attribute'
@@ -395,6 +407,17 @@ class RemoveAttribute(bpy.types.Operator):
bpy.context.active_object.BIMObjectProperties.attributes.remove(self.attribute_index)
return {'FINISHED'}
class RemoveMaterialAttribute(bpy.types.Operator):
bl_idname = 'bim.remove_material_attribute'
bl_label = 'Remove Material Attribute'
attribute_index: bpy.props.IntProperty()
def execute(self, context):
bpy.context.active_object.active_material.BIMMaterialProperties.attributes.remove(self.attribute_index)
return {'FINISHED'}
class AddSweptSolid(bpy.types.Operator):
bl_idname = 'bim.add_swept_solid'
bl_label = 'Add Swept Solid'
+18 -1
View File
@@ -30,6 +30,7 @@ psetfiles_enum = []
classification_enum = []
reference_enum = []
attributes_enum = []
materialattributes_enum = []
documents_enum = []
materialtypes_enum = []
contexts_enum = []
@@ -197,13 +198,27 @@ def getApplicableAttributes(self, context):
global attributes_enum
attributes_enum.clear()
if '/' in context.active_object.name \
and context.active_object.name.split('/')[0] in ifc_schema.elements:
and context.active_object.name.split('/')[0] in ifc_schema.elements:
attributes_enum.extend([(a['name'], a['name'], '') for a in
ifc_schema.elements[context.active_object.name.split('/')[0]]['attributes']
if self.attributes.find(a['name']) == -1])
return attributes_enum
def getApplicableMaterialAttributes(self, context):
global materialattributes_enum
materialattributes_enum.clear()
if '/' in context.active_object.name \
and context.active_object.name.split('/')[0] in ifc_schema.elements:
material_type = context.active_object.BIMObjectProperties.material_type
if material_type[-3:] == 'Set':
material_type = material_type[0:-3]
materialattributes_enum.extend([(a['name'], a['name'], '') for a in
ifc_schema.IfcMaterialDefinition[material_type]['attributes']
if self.attributes.find(a['name']) == -1])
return materialattributes_enum
def getApplicableDocuments(self, context):
global documents_enum
documents_enum.clear()
@@ -384,6 +399,8 @@ class BIMMaterialProperties(PropertyGroup):
name: StringProperty(name="Name")
available_material_psets: EnumProperty(items=getAvailableMaterialPsets, name="Material Pset")
psets: CollectionProperty(name="Psets", type=Pset)
attributes: CollectionProperty(name="Attributes", type=Attribute)
applicable_attributes: EnumProperty(items=getApplicableMaterialAttributes, name="Attribute Names")
class SweptSolid(PropertyGroup):
+1 -2
View File
@@ -7,9 +7,8 @@ cwd = os.path.dirname(os.path.realpath(__file__))
class IfcSchema():
def __init__(self):
self.schema_dir = os.path.join(cwd, 'schema') # TODO: make configurable
self.products = ['IfcElement', 'IfcSpatialStructureElement', 'IfcStructural']
self.products = ['IfcElement', 'IfcSpatialStructureElement', 'IfcStructural', 'IfcMaterialDefinition']
self.elements = {}
print(os.path.join(self.schema_dir, 'IFC4_ADD2.ifc'))
self.property_file = ifcopenshell.open(os.path.join(self.schema_dir, 'IFC4_ADD2.ifc'))
self.psets = {}
self.qtos = {}
@@ -0,0 +1,366 @@
{
"IfcMaterial": {
"attributes": [
{
"enum_values": [],
"type": "IfcLabel",
"name": "Name",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcText",
"name": "Description",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcLabel",
"name": "Category",
"is_enum": false
}
],
"is_abstract": false,
"complex_attributes": [
{
"type": "IfcMaterialProperties",
"name": "HasProperties"
},
{
"type": "IfcMaterialDefinitionRepresentation",
"name": "HasRepresentation"
}
],
"parent": "IfcMaterialDefinition"
},
"IfcMaterialConstituent": {
"attributes": [
{
"enum_values": [],
"type": "IfcLabel",
"name": "Name",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcText",
"name": "Description",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcNormalisedRatioMeasure",
"name": "Fraction",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcLabel",
"name": "Category",
"is_enum": false
}
],
"is_abstract": false,
"complex_attributes": [
{
"type": "IfcMaterialProperties",
"name": "HasProperties"
},
{
"type": "IfcMaterial",
"name": "Material"
}
],
"parent": "IfcMaterialDefinition"
},
"IfcMaterialConstituentSet": {
"attributes": [
{
"enum_values": [],
"type": "IfcLabel",
"name": "Name",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcText",
"name": "Description",
"is_enum": false
}
],
"is_abstract": false,
"complex_attributes": [
{
"type": "IfcMaterialProperties",
"name": "HasProperties"
},
{
"type": "IfcMaterialConstituent",
"name": "MaterialConstituents"
}
],
"parent": "IfcMaterialDefinition"
},
"IfcMaterialLayer": {
"attributes": [
{
"enum_values": [],
"type": "IfcNonNegativeLengthMeasure",
"name": "LayerThickness",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcLogical",
"name": "IsVentilated",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcLabel",
"name": "Name",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcText",
"name": "Description",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcLabel",
"name": "Category",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcInteger",
"name": "Priority",
"is_enum": false
}
],
"is_abstract": false,
"complex_attributes": [
{
"type": "IfcMaterialProperties",
"name": "HasProperties"
},
{
"type": "IfcMaterial",
"name": "Material"
}
],
"parent": "IfcMaterialDefinition"
},
"IfcMaterialLayerSet": {
"attributes": [
{
"enum_values": [],
"type": "IfcLabel",
"name": "LayerSetName",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcText",
"name": "Description",
"is_enum": false
}
],
"is_abstract": false,
"complex_attributes": [
{
"type": "IfcMaterialProperties",
"name": "HasProperties"
},
{
"type": "IfcMaterialLayer",
"name": "MaterialLayers"
}
],
"parent": "IfcMaterialDefinition"
},
"IfcMaterialLayerWithOffsets": {
"attributes": [
{
"enum_values": [],
"type": "IfcNonNegativeLengthMeasure",
"name": "LayerThickness",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcLogical",
"name": "IsVentilated",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcLabel",
"name": "Name",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcText",
"name": "Description",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcLabel",
"name": "Category",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcInteger",
"name": "Priority",
"is_enum": false
},
{
"enum_values": [
"AXIS1",
"AXIS2",
"AXIS3"
],
"type": "IfcLayerSetDirectionEnum",
"name": "OffsetDirection",
"is_enum": true
}
],
"is_abstract": false,
"complex_attributes": [
{
"type": "IfcMaterialProperties",
"name": "HasProperties"
},
{
"type": "IfcMaterial",
"name": "Material"
}
],
"parent": "IfcMaterialLayer"
},
"IfcMaterialProfile": {
"attributes": [
{
"enum_values": [],
"type": "IfcLabel",
"name": "Name",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcText",
"name": "Description",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcInteger",
"name": "Priority",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcLabel",
"name": "Category",
"is_enum": false
}
],
"is_abstract": false,
"complex_attributes": [
{
"type": "IfcMaterialProperties",
"name": "HasProperties"
},
{
"type": "IfcMaterial",
"name": "Material"
},
{
"type": "IfcProfileDef",
"name": "Profile"
}
],
"parent": "IfcMaterialDefinition"
},
"IfcMaterialProfileSet": {
"attributes": [
{
"enum_values": [],
"type": "IfcLabel",
"name": "Name",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcText",
"name": "Description",
"is_enum": false
}
],
"is_abstract": false,
"complex_attributes": [
{
"type": "IfcMaterialProperties",
"name": "HasProperties"
},
{
"type": "IfcMaterialProfile",
"name": "MaterialProfiles"
},
{
"type": "IfcCompositeProfileDef",
"name": "CompositeProfile"
}
],
"parent": "IfcMaterialDefinition"
},
"IfcMaterialProfileWithOffsets": {
"attributes": [
{
"enum_values": [],
"type": "IfcLabel",
"name": "Name",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcText",
"name": "Description",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcInteger",
"name": "Priority",
"is_enum": false
},
{
"enum_values": [],
"type": "IfcLabel",
"name": "Category",
"is_enum": false
}
],
"is_abstract": false,
"complex_attributes": [
{
"type": "IfcMaterialProperties",
"name": "HasProperties"
},
{
"type": "IfcMaterial",
"name": "Material"
},
{
"type": "IfcProfileDef",
"name": "Profile"
}
],
"parent": "IfcMaterialProfile"
}
}
+14
View File
@@ -164,6 +164,20 @@ class BIM_PT_material(Panel):
row = layout.row()
row.operator('bim.fetch_external_material')
layout.label(text="Attributes:")
row = layout.row(align=True)
row.prop(props, 'applicable_attributes', text='')
row.operator('bim.add_material_attribute')
for index, attribute in enumerate(props.attributes):
row = layout.row(align=True)
row.prop(attribute, 'name', text='')
row.prop(attribute, 'string_value', text='')
row.operator('bim.remove_material_attribute', icon='X', text='').attribute_index = index
row = layout.row()
row.prop(props, 'attributes')
layout.label(text="Property Sets:")
row = layout.row(align=True)
row.prop(props, 'available_material_psets', text='')
+4 -2
View File
@@ -14,12 +14,14 @@ class IFC4Extractor:
#self.filters = ['IfcBuildingElement']
#self.filters = ['IfcElement']
#self.filters = ['IfcSpatialStructureElement']
self.filters = ['IfcStructuralActivity', 'IfcStructuralItem']
#self.filters = ['IfcStructuralActivity', 'IfcStructuralItem']
self.filters = ['IfcMaterialDefinition']
self.filtered_elements = {}
def extract(self):
for element in self.root.findall("xs:element", self.ns):
if self.is_descendant_from_class(element, "IfcRoot"):
#if self.is_descendant_from_class(element, "IfcRoot"):
if self.is_descendant_from_class(element, "IfcMaterialDefinition"):
print('Processing {}'.format(element.attrib['name']))
data = {
'is_abstract': self.is_abstract(element),