mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 17:57:02 +00:00
Allow manually specified qto values to be exported
This commit is contained in:
@@ -66,6 +66,7 @@ if bpy is not None:
|
|||||||
operator.RemovePset,
|
operator.RemovePset,
|
||||||
operator.AddOverridePset,
|
operator.AddOverridePset,
|
||||||
operator.RemoveOverridePset,
|
operator.RemoveOverridePset,
|
||||||
|
operator.AddQto,
|
||||||
operator.RemoveQto,
|
operator.RemoveQto,
|
||||||
operator.AddMaterialPset,
|
operator.AddMaterialPset,
|
||||||
operator.RemoveMaterialPset,
|
operator.RemoveMaterialPset,
|
||||||
|
|||||||
@@ -141,7 +141,6 @@ class IfcParser():
|
|||||||
self.load_representations()
|
self.load_representations()
|
||||||
self.materials = self.get_materials()
|
self.materials = self.get_materials()
|
||||||
self.styled_items = self.get_styled_items()
|
self.styled_items = self.get_styled_items()
|
||||||
self.qtos = self.get_qtos()
|
|
||||||
self.spatial_structure_elements = self.get_spatial_structure_elements()
|
self.spatial_structure_elements = self.get_spatial_structure_elements()
|
||||||
self.structural_analysis_models = self.get_structural_analysis_models()
|
self.structural_analysis_models = self.get_structural_analysis_models()
|
||||||
|
|
||||||
@@ -448,17 +447,8 @@ class IfcParser():
|
|||||||
self.rel_defines_by_pset.setdefault(
|
self.rel_defines_by_pset.setdefault(
|
||||||
'{}/{}'.format(pset.name, pset.file), []).append(product)
|
'{}/{}'.format(pset.name, pset.file), []).append(product)
|
||||||
|
|
||||||
for pset in obj.BIMObjectProperties.override_psets:
|
self.get_product_psets_qtos(product, obj, is_pset=True)
|
||||||
pset_key = '{}/{}'.format(pset.name, obj.name)
|
self.get_product_psets_qtos(product, obj, is_qto=True)
|
||||||
raw = {p.name: p.string_value for p in pset.properties if p.string_value}
|
|
||||||
if not raw:
|
|
||||||
continue
|
|
||||||
self.psets[pset_key] = {
|
|
||||||
'ifc': None,
|
|
||||||
'raw': raw,
|
|
||||||
'attributes': { 'Name': pset.name }
|
|
||||||
}
|
|
||||||
self.rel_defines_by_pset.setdefault(pset_key, []).append(product)
|
|
||||||
|
|
||||||
for document in obj.BIMObjectProperties.documents:
|
for document in obj.BIMObjectProperties.documents:
|
||||||
self.rel_associates_document_object.setdefault(
|
self.rel_associates_document_object.setdefault(
|
||||||
@@ -490,6 +480,27 @@ class IfcParser():
|
|||||||
|
|
||||||
return product
|
return product
|
||||||
|
|
||||||
|
def get_product_psets_qtos(self, product, obj, is_pset=False, is_qto=False):
|
||||||
|
if is_pset:
|
||||||
|
psets_qtos = obj.BIMObjectProperties.override_psets
|
||||||
|
results = self.psets
|
||||||
|
relationships = self.rel_defines_by_pset
|
||||||
|
if is_qto:
|
||||||
|
psets_qtos = obj.BIMObjectProperties.qtos
|
||||||
|
results = self.qtos
|
||||||
|
relationships = self.rel_defines_by_qto
|
||||||
|
for item in psets_qtos:
|
||||||
|
item_key = '{}/{}'.format(item.name, obj.name)
|
||||||
|
raw = {p.name: p.string_value for p in item.properties if p.string_value}
|
||||||
|
if not raw:
|
||||||
|
continue
|
||||||
|
results[item_key] = {
|
||||||
|
'ifc': None,
|
||||||
|
'raw': raw,
|
||||||
|
'attributes': { 'Name': item.name }
|
||||||
|
}
|
||||||
|
relationships.setdefault(item_key, []).append(product)
|
||||||
|
|
||||||
def get_product_relating_structure(self, product, obj):
|
def get_product_relating_structure(self, product, obj):
|
||||||
relating_structure = obj.BIMObjectProperties.relating_structure
|
relating_structure = obj.BIMObjectProperties.relating_structure
|
||||||
if relating_structure:
|
if relating_structure:
|
||||||
@@ -918,28 +929,6 @@ class IfcParser():
|
|||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def get_qtos(self):
|
|
||||||
if not self.ifc_export_settings.has_quantities:
|
|
||||||
return {}
|
|
||||||
results = {}
|
|
||||||
for product in self.selected_products + self.type_products:
|
|
||||||
obj = product['raw']
|
|
||||||
if not obj.data:
|
|
||||||
continue
|
|
||||||
for property in obj.keys():
|
|
||||||
if property[0:4] != 'Qto_':
|
|
||||||
continue
|
|
||||||
results[obj.name] = {
|
|
||||||
'ifc': None,
|
|
||||||
'raw': obj,
|
|
||||||
'class': property,
|
|
||||||
'attributes': {
|
|
||||||
'Name': property,
|
|
||||||
'MethodOfMeasurement': obj[property]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results
|
|
||||||
|
|
||||||
def get_type_products(self):
|
def get_type_products(self):
|
||||||
results = []
|
results = []
|
||||||
index = 0
|
index = 0
|
||||||
@@ -1316,10 +1305,6 @@ class IfcExporter():
|
|||||||
for pset in self.ifc_parser.psets.values():
|
for pset in self.ifc_parser.psets.values():
|
||||||
properties = self.create_pset_properties(pset)
|
properties = self.create_pset_properties(pset)
|
||||||
if not properties:
|
if not properties:
|
||||||
self.ifc_export_settings.logger.error(
|
|
||||||
'No properties could be detected for the pset {}/{}'.format(
|
|
||||||
pset['attributes']['Name'],
|
|
||||||
pset['attributes']['Description']))
|
|
||||||
continue
|
continue
|
||||||
pset['attributes'].update({
|
pset['attributes'].update({
|
||||||
'GlobalId': ifcopenshell.guid.new(),
|
'GlobalId': ifcopenshell.guid.new(),
|
||||||
@@ -1338,6 +1323,10 @@ class IfcExporter():
|
|||||||
'Material': material['ifc']
|
'Material': material['ifc']
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def create_qto_properties(self, qto):
|
||||||
|
if qto['attributes']['Name'] in schema.ifc.qtos:
|
||||||
|
return self.create_templated_qto_properties(qto)
|
||||||
|
|
||||||
def create_pset_properties(self, pset):
|
def create_pset_properties(self, pset):
|
||||||
if pset['attributes']['Name'] in schema.ifc.psets:
|
if pset['attributes']['Name'] in schema.ifc.psets:
|
||||||
return self.create_templated_pset_properties(pset)
|
return self.create_templated_pset_properties(pset)
|
||||||
@@ -1382,6 +1371,30 @@ class IfcExporter():
|
|||||||
invalid_pset_keys))
|
invalid_pset_keys))
|
||||||
return properties
|
return properties
|
||||||
|
|
||||||
|
def create_templated_qto_properties(self, qto):
|
||||||
|
properties = []
|
||||||
|
templates = schema.ifc.qtos[qto['attributes']['Name']]['HasPropertyTemplates']
|
||||||
|
for name, data in templates.items():
|
||||||
|
if name not in qto['raw']:
|
||||||
|
continue
|
||||||
|
if data.TemplateType[0:2] == 'Q_':
|
||||||
|
value_basename = data.TemplateType[2:].title()
|
||||||
|
value_name = f'{value_basename}Value'
|
||||||
|
class_name = f'IfcQuantity{value_basename}'
|
||||||
|
properties.append(
|
||||||
|
self.file.create_entity(class_name, **{
|
||||||
|
'Name': name,
|
||||||
|
value_name: float(qto['raw'][name])
|
||||||
|
}))
|
||||||
|
invalid_qto_keys = [k for k in qto['raw'].keys() if k not in templates.keys()]
|
||||||
|
if invalid_qto_keys:
|
||||||
|
self.ifc_export_settings.logger.error(
|
||||||
|
'One or more properties were invalid in the qto {}/{}: {}'.format(
|
||||||
|
qto['attributes']['Name'],
|
||||||
|
qto['attributes']['Description'],
|
||||||
|
invalid_qto_keys))
|
||||||
|
return properties
|
||||||
|
|
||||||
def cast_to_base_type(self, var_type, value):
|
def cast_to_base_type(self, var_type, value):
|
||||||
if var_type not in schema.ifc.type_map:
|
if var_type not in schema.ifc.type_map:
|
||||||
return value
|
return value
|
||||||
@@ -1676,12 +1689,15 @@ class IfcExporter():
|
|||||||
self.create_product(product)
|
self.create_product(product)
|
||||||
|
|
||||||
def create_qtos(self):
|
def create_qtos(self):
|
||||||
for object_name, qto in self.ifc_parser.qtos.items():
|
# TODO: re-introduce calculated quantities
|
||||||
quantities = self.calculate_quantities(qto['class'], qto['raw'])
|
for qto in self.ifc_parser.qtos.values():
|
||||||
|
properties = self.create_qto_properties(qto)
|
||||||
|
if not properties:
|
||||||
|
continue
|
||||||
qto['attributes'].update({
|
qto['attributes'].update({
|
||||||
'GlobalId': ifcopenshell.guid.new(),
|
'GlobalId': ifcopenshell.guid.new(),
|
||||||
'OwnerHistory': self.owner_history,
|
'OwnerHistory': self.owner_history,
|
||||||
'Quantities': quantities
|
'Quantities': properties
|
||||||
})
|
})
|
||||||
qto['ifc'] = self.file.create_entity('IfcElementQuantity', **qto['attributes'])
|
qto['ifc'] = self.file.create_entity('IfcElementQuantity', **qto['attributes'])
|
||||||
|
|
||||||
|
|||||||
@@ -480,6 +480,22 @@ class RemovePset(bpy.types.Operator):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class AddQto(bpy.types.Operator):
|
||||||
|
bl_idname = 'bim.add_qto'
|
||||||
|
bl_label = 'Add Qto'
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
name = bpy.context.active_object.BIMObjectProperties.qto_name
|
||||||
|
if name not in schema.ifc.qtos:
|
||||||
|
return {'FINISHED'}
|
||||||
|
qto = bpy.context.active_object.BIMObjectProperties.qtos.add()
|
||||||
|
qto.name = name
|
||||||
|
for prop_name in schema.ifc.qtos[name]['HasPropertyTemplates'].keys():
|
||||||
|
prop = qto.properties.add()
|
||||||
|
prop.name = prop_name
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
class AddOverridePset(bpy.types.Operator):
|
class AddOverridePset(bpy.types.Operator):
|
||||||
bl_idname = 'bim.add_override_pset'
|
bl_idname = 'bim.add_override_pset'
|
||||||
bl_label = 'Add Override Pset'
|
bl_label = 'Add Override Pset'
|
||||||
|
|||||||
@@ -490,6 +490,7 @@ class BIMObjectProperties(PropertyGroup):
|
|||||||
material_type: EnumProperty(items=getMaterialTypes, name="Material Type")
|
material_type: EnumProperty(items=getMaterialTypes, name="Material Type")
|
||||||
override_psets: CollectionProperty(name="Override Psets", type=PsetQto)
|
override_psets: CollectionProperty(name="Override Psets", type=PsetQto)
|
||||||
override_pset_name: StringProperty(name="Override Pset Name")
|
override_pset_name: StringProperty(name="Override Pset Name")
|
||||||
|
qto_name: StringProperty(name="Qto Name")
|
||||||
has_boundary_condition: BoolProperty(name='Has Boundary Condition')
|
has_boundary_condition: BoolProperty(name='Has Boundary Condition')
|
||||||
boundary_condition: PointerProperty(name='Boundary Condition', type=BoundaryCondition)
|
boundary_condition: PointerProperty(name='Boundary Condition', type=BoundaryCondition)
|
||||||
structural_member_connection: PointerProperty(name='Structural Member Connection', type=bpy.types.Object)
|
structural_member_connection: PointerProperty(name='Structural Member Connection', type=bpy.types.Object)
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ class BIM_PT_object(Panel):
|
|||||||
|
|
||||||
layout.label(text="Quantities:")
|
layout.label(text="Quantities:")
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(props, 'qto_name', text='')
|
||||||
|
row.operator('bim.add_qto')
|
||||||
|
|
||||||
for index, qto in enumerate(props.qtos):
|
for index, qto in enumerate(props.qtos):
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.prop(qto, 'name', text='')
|
row.prop(qto, 'name', text='')
|
||||||
|
|||||||
Reference in New Issue
Block a user