mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 18:43:26 +00:00
Add UI for pset overrides without the need to create a CSV.
This commit is contained in:
@@ -61,6 +61,8 @@ if bpy is not None:
|
||||
operator.UnassignPset,
|
||||
operator.AddPset,
|
||||
operator.RemovePset,
|
||||
operator.AddOverridePset,
|
||||
operator.RemoveOverridePset,
|
||||
operator.AddMaterialPset,
|
||||
operator.RemoveMaterialPset,
|
||||
operator.AddDocument,
|
||||
|
||||
@@ -7,6 +7,7 @@ import os
|
||||
from pathlib import Path
|
||||
from mathutils import Vector, Matrix
|
||||
from .helper import SIUnitHelper
|
||||
from . import schema
|
||||
import ifcopenshell
|
||||
import addon_utils
|
||||
|
||||
@@ -408,6 +409,18 @@ class IfcParser():
|
||||
self.rel_defines_by_pset.setdefault(
|
||||
'{}/{}'.format(pset.name, pset.file), []).append(product)
|
||||
|
||||
for pset in obj.BIMObjectProperties.override_psets:
|
||||
pset_key = '{}/{}'.format(pset.name, obj.name)
|
||||
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:
|
||||
self.rel_associates_document_object.setdefault(
|
||||
document.file, []).append(product)
|
||||
@@ -943,10 +956,9 @@ class IfcParser():
|
||||
|
||||
|
||||
class IfcExporter():
|
||||
def __init__(self, ifc_export_settings, ifc_schema, ifc_parser, qto_calculator):
|
||||
def __init__(self, ifc_export_settings, ifc_parser, qto_calculator):
|
||||
self.template_file = '{}template.ifc'.format(ifc_export_settings.schema_dir)
|
||||
self.ifc_export_settings = ifc_export_settings
|
||||
self.ifc_schema = ifc_schema
|
||||
self.ifc_parser = ifc_parser
|
||||
self.qto_calculator = qto_calculator
|
||||
|
||||
@@ -1206,7 +1218,7 @@ class IfcExporter():
|
||||
})
|
||||
|
||||
def create_pset_properties(self, pset):
|
||||
if pset['attributes']['Name'] in self.ifc_schema.psets:
|
||||
if pset['attributes']['Name'] in schema.ifc.psets:
|
||||
return self.create_templated_pset_properties(pset)
|
||||
return self.create_custom_pset_properties(pset)
|
||||
|
||||
@@ -1222,7 +1234,7 @@ class IfcExporter():
|
||||
|
||||
def create_templated_pset_properties(self, pset):
|
||||
properties = []
|
||||
templates = self.ifc_schema.psets[pset['attributes']['Name']]['HasPropertyTemplates']
|
||||
templates = schema.ifc.psets[pset['attributes']['Name']]['HasPropertyTemplates']
|
||||
for name, data in templates.items():
|
||||
if name not in pset['raw']:
|
||||
continue
|
||||
@@ -1250,13 +1262,13 @@ class IfcExporter():
|
||||
return properties
|
||||
|
||||
def cast_to_base_type(self, var_type, value):
|
||||
if var_type not in self.ifc_schema.type_map:
|
||||
if var_type not in schema.ifc.type_map:
|
||||
return value
|
||||
elif self.ifc_schema.type_map[var_type] == 'float':
|
||||
elif schema.ifc.type_map[var_type] == 'float':
|
||||
return float(value)
|
||||
elif self.ifc_schema.type_map[var_type] == 'integer':
|
||||
elif schema.ifc.type_map[var_type] == 'integer':
|
||||
return int(value)
|
||||
elif self.ifc_schema.type_map[var_type] == 'bool':
|
||||
elif schema.ifc.type_map[var_type] == 'bool':
|
||||
return True if value.lower() in ['1', 't', 'true', 'yes', 'y', 'uh-huh'] else False
|
||||
return str(value)
|
||||
|
||||
@@ -1551,11 +1563,11 @@ class IfcExporter():
|
||||
)
|
||||
|
||||
def get_product_attribute_type(self, product_class, attribute_name):
|
||||
element_schema = self.ifc_schema.elements[product_class]
|
||||
element_schema = schema.ifc.elements[product_class]
|
||||
for a in element_schema['attributes']:
|
||||
if a['name'] == attribute_name:
|
||||
return a['type']
|
||||
if element_schema['parent'] in self.ifc_schema.elements:
|
||||
if element_schema['parent'] in schema.ifc.elements:
|
||||
return self.get_product_attribute_type(element_schema['parent'], attribute_name)
|
||||
return None
|
||||
|
||||
|
||||
@@ -7,9 +7,7 @@ import time
|
||||
import mathutils
|
||||
import multiprocessing
|
||||
from .helper import SIUnitHelper
|
||||
from .schema import IfcSchema
|
||||
|
||||
ifc_schema = IfcSchema()
|
||||
from . import schema
|
||||
|
||||
class MaterialCreator():
|
||||
def __init__(self, ifc_import_settings):
|
||||
@@ -402,8 +400,8 @@ class IfcImporter():
|
||||
|
||||
def add_element_attributes(self, element, obj):
|
||||
attributes = element.get_info()
|
||||
if element.is_a() in ifc_schema.elements:
|
||||
applicable_attributes = [a['name'] for a in ifc_schema.elements[element.is_a()]['attributes']]
|
||||
if element.is_a() in schema.ifc.elements:
|
||||
applicable_attributes = [a['name'] for a in schema.ifc.elements[element.is_a()]['attributes']]
|
||||
for key, value in attributes.items():
|
||||
if key not in applicable_attributes \
|
||||
or value is None:
|
||||
|
||||
@@ -8,10 +8,10 @@ from . import export_ifc
|
||||
from . import import_ifc
|
||||
from . import cut_ifc
|
||||
from . import sheeter
|
||||
from . import schema
|
||||
from bpy_extras.io_utils import ImportHelper
|
||||
from itertools import cycle
|
||||
from mathutils import Vector
|
||||
from .schema import IfcSchema
|
||||
|
||||
class ExportIFC(bpy.types.Operator):
|
||||
bl_idname = "export.ifc"
|
||||
@@ -54,9 +54,8 @@ class ExportIFC(bpy.types.Operator):
|
||||
]
|
||||
})
|
||||
ifc_parser = export_ifc.IfcParser(ifc_export_settings)
|
||||
ifc_schema = IfcSchema()
|
||||
qto_calculator = export_ifc.QtoCalculator()
|
||||
ifc_exporter = export_ifc.IfcExporter(ifc_export_settings, ifc_schema, ifc_parser, qto_calculator)
|
||||
ifc_exporter = export_ifc.IfcExporter(ifc_export_settings, ifc_parser, qto_calculator)
|
||||
ifc_exporter.export()
|
||||
ifc_export_settings.logger.info('Export finished in {:.2f} seconds'.format(time.time() - start))
|
||||
return {'FINISHED'}
|
||||
@@ -323,6 +322,32 @@ class RemovePset(bpy.types.Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class AddOverridePset(bpy.types.Operator):
|
||||
bl_idname = 'bim.add_override_pset'
|
||||
bl_label = 'Add Override Pset'
|
||||
|
||||
def execute(self, context):
|
||||
pset_name = bpy.context.active_object.BIMObjectProperties.override_pset_name
|
||||
if pset_name not in schema.ifc.psets:
|
||||
return {'FINISHED'}
|
||||
pset = bpy.context.active_object.BIMObjectProperties.override_psets.add()
|
||||
pset.name = pset_name
|
||||
for prop_name in schema.ifc.psets[pset_name]['HasPropertyTemplates'].keys():
|
||||
prop = pset.properties.add()
|
||||
prop.name = prop_name
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class RemoveOverridePset(bpy.types.Operator):
|
||||
bl_idname = 'bim.remove_override_pset'
|
||||
bl_label = 'Remove Override Pset'
|
||||
pset_index: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.active_object.BIMObjectProperties.override_psets.remove(self.pset_index)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class AddMaterialPset(bpy.types.Operator):
|
||||
bl_idname = 'bim.add_material_pset'
|
||||
bl_label = 'Add Material Pset'
|
||||
|
||||
@@ -3,7 +3,7 @@ import os
|
||||
import csv
|
||||
from pathlib import Path
|
||||
from . import export_ifc
|
||||
from .schema import IfcSchema
|
||||
from . import schema
|
||||
import bpy
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.app.handlers import persistent
|
||||
@@ -18,8 +18,6 @@ from bpy.props import (
|
||||
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
ifc_schema = IfcSchema()
|
||||
|
||||
diagram_scales_enum = []
|
||||
products_enum = []
|
||||
profiledef_enum = []
|
||||
@@ -53,7 +51,7 @@ def setDefaultProperties(scene):
|
||||
def getIfcPredefinedTypes(self, context):
|
||||
global types_enum
|
||||
if len(types_enum) < 1:
|
||||
for name, data in ifc_schema.elements.items():
|
||||
for name, data in schema.ifc.elements.items():
|
||||
if name != self.ifc_class.strip():
|
||||
continue
|
||||
for attribute in data['attributes']:
|
||||
@@ -106,14 +104,14 @@ 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(ifc_schema, self.ifc_product)])
|
||||
classes_enum.extend([(e, e, '') for e in getattr(schema.ifc, self.ifc_product)])
|
||||
return classes_enum
|
||||
|
||||
|
||||
def getProfileDef(self, context):
|
||||
global profiledef_enum
|
||||
if len(profiledef_enum) < 1:
|
||||
profiledef_enum.extend([(e, e, '') for e in getattr(ifc_schema, 'IfcParameterizedProfileDef')])
|
||||
profiledef_enum.extend([(e, e, '') for e in getattr(schema.ifc, 'IfcParameterizedProfileDef')])
|
||||
return profiledef_enum
|
||||
|
||||
|
||||
@@ -206,9 +204,9 @@ 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 schema.ifc.elements:
|
||||
attributes_enum.extend([(a['name'], a['name'], '') for a in
|
||||
ifc_schema.elements[context.active_object.name.split('/')[0]]['attributes']
|
||||
schema.ifc.elements[context.active_object.name.split('/')[0]]['attributes']
|
||||
if self.attributes.find(a['name']) == -1])
|
||||
return attributes_enum
|
||||
|
||||
@@ -217,12 +215,12 @@ 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:
|
||||
and context.active_object.name.split('/')[0] in schema.ifc.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']
|
||||
schema.ifc.IfcMaterialDefinition[material_type]['attributes']
|
||||
if self.attributes.find(a['name']) == -1])
|
||||
return materialattributes_enum
|
||||
|
||||
@@ -230,7 +228,7 @@ def getApplicableMaterialAttributes(self, context):
|
||||
def refreshProfileAttributes(self, context):
|
||||
while len(context.active_object.active_material.BIMMaterialProperties.profile_attributes) > 0:
|
||||
context.active_object.active_material.BIMMaterialProperties.profile_attributes.remove(0)
|
||||
for attribute in ifc_schema.IfcParameterizedProfileDef[self.profile_def]['attributes']:
|
||||
for attribute in schema.ifc.IfcParameterizedProfileDef[self.profile_def]['attributes']:
|
||||
profile_attribute = context.active_object.active_material.BIMMaterialProperties.profile_attributes.add()
|
||||
profile_attribute.name = attribute['name']
|
||||
|
||||
@@ -384,6 +382,7 @@ class Attribute(PropertyGroup):
|
||||
class Pset(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
file: StringProperty(name="File")
|
||||
properties: CollectionProperty(name="Properties", type=Attribute)
|
||||
|
||||
class Document(PropertyGroup):
|
||||
file: StringProperty(name="File")
|
||||
@@ -406,6 +405,8 @@ class BIMObjectProperties(PropertyGroup):
|
||||
applicable_documents: EnumProperty(items=getApplicableDocuments, name="Available Documents")
|
||||
classifications: CollectionProperty(name="Classifications", type=Classification)
|
||||
material_type: EnumProperty(items=getMaterialTypes, name="Material Type")
|
||||
override_psets: CollectionProperty(name="Override Psets", type=Pset)
|
||||
override_pset_name: StringProperty(name="Override Pset Name")
|
||||
|
||||
|
||||
class BIMMaterialProperties(PropertyGroup):
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
import json
|
||||
import ifcopenshell
|
||||
from pathlib import Path
|
||||
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
@@ -15,7 +16,10 @@ class IfcSchema():
|
||||
'IfcParameterizedProfileDef'
|
||||
]
|
||||
self.elements = {}
|
||||
self.property_file = ifcopenshell.open(os.path.join(self.schema_dir, 'IFC4_ADD2.ifc'))
|
||||
self.property_files = []
|
||||
property_paths = Path(self.schema_dir).glob('Pset_*.ifc')
|
||||
for path in property_paths:
|
||||
self.property_files.append(ifcopenshell.open(path))
|
||||
self.psets = {}
|
||||
self.qtos = {}
|
||||
self.load()
|
||||
@@ -29,10 +33,13 @@ class IfcSchema():
|
||||
with open(os.path.join(self.schema_dir, 'ifc_types_IFC4.json')) as f:
|
||||
self.type_map = json.load(f)
|
||||
|
||||
for property in self.property_file.by_type('IfcPropertySetTemplate'):
|
||||
if property.Name[0:4] == 'Qto_':
|
||||
# self.qtos.append({ })
|
||||
pass
|
||||
else:
|
||||
self.psets[property.Name] = {
|
||||
'HasPropertyTemplates': {p.Name: p for p in property.HasPropertyTemplates}}
|
||||
for property_file in self.property_files:
|
||||
for property in property_file.by_type('IfcPropertySetTemplate'):
|
||||
if property.Name[0:4] == 'Qto_':
|
||||
# self.qtos.append({ })
|
||||
pass
|
||||
else:
|
||||
self.psets[property.Name] = {
|
||||
'HasPropertyTemplates': {p.Name: p for p in property.HasPropertyTemplates}}
|
||||
|
||||
ifc = IfcSchema()
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION((),'2;1');
|
||||
FILE_NAME('Pset_Custom.ifc','2020-01-01T00:00:00',(),(),'Sample','Sample',$);
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
|
||||
DATA;
|
||||
#1= IFCPROPERTYSETTEMPLATE('05N2Dhepb9ouTCSmWBh22D',$,'Custom_Pset','An example custom pset.',.PSET_TYPEDRIVENOVERRIDE.,'IfcObject',(#2,#3));
|
||||
#2= IFCSIMPLEPROPERTYTEMPLATE('37EpTDq4v96gTZh196BBXQ',$,'NumericProperty','An example numeric property',.P_SINGLEVALUE.,'IfcCountMeasure','',$,$,$,$,.READWRITE.);
|
||||
#3= IFCSIMPLEPROPERTYTEMPLATE('22H7CzDvz1XfVHKkGWoYUK',$,'StringProperty','An example string property',.P_SINGLEVALUE.,'IfcLabel','',$,$,$,$,.READWRITE.);
|
||||
ENDSEC;
|
||||
|
||||
END-ISO-10303-21;
|
||||
@@ -54,6 +54,19 @@ class BIM_PT_object(Panel):
|
||||
row = layout.row()
|
||||
row.prop(props, 'psets')
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, 'override_pset_name', text='')
|
||||
row.operator('bim.add_override_pset')
|
||||
|
||||
for index, pset in enumerate(props.override_psets):
|
||||
row = layout.row(align=True)
|
||||
row.prop(pset, 'name', text='')
|
||||
row.operator('bim.remove_override_pset', icon='X', text='').pset_index = index
|
||||
for prop in pset.properties:
|
||||
row = layout.row(align=True)
|
||||
row.prop(prop, 'name', text='')
|
||||
row.prop(prop, 'string_value', text='')
|
||||
|
||||
layout.label(text="Documents:")
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, 'applicable_documents', text='')
|
||||
|
||||
Reference in New Issue
Block a user