mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-30 00:23:14 +00:00
181 lines
7.3 KiB
Python
181 lines
7.3 KiB
Python
|
|
import ifcopenshell
|
||
|
|
import ifcopenshell.util
|
||
|
|
import ifcopenshell.util.pset
|
||
|
|
import ifcopenshell.util.schema
|
||
|
|
import xml.etree.ElementTree as ET
|
||
|
|
from xmlschema.validators.exceptions import XMLSchemaValidationError
|
||
|
|
from ifctester.ids import Ids, IdsXmlValidationError, get_schema
|
||
|
|
|
||
|
|
# https://github.com/buildingSMART/IDS/blob/9914d568c7ac037acd97e58a0d16e9f93c3e3416/Schema/ids.xsd#L232
|
||
|
|
ifc_schemas = ["IFC2X3", "IFC4", "IFC4X3_ADD2"]
|
||
|
|
|
||
|
|
def get_predefined_types_for_entity(schema_name, entity_name):
|
||
|
|
"""Get a list of predefined types for a given entity."""
|
||
|
|
|
||
|
|
schema = ifcopenshell.schema_by_name(schema_name)
|
||
|
|
|
||
|
|
try:
|
||
|
|
entity = schema.declaration_by_name(entity_name)
|
||
|
|
except:
|
||
|
|
return []
|
||
|
|
|
||
|
|
if not entity or not entity.as_entity():
|
||
|
|
print(f"Entity {entity_name} not found")
|
||
|
|
return []
|
||
|
|
|
||
|
|
entity = entity.as_entity()
|
||
|
|
predefined_type_attr = None
|
||
|
|
|
||
|
|
# Check all attributes for "PredefinedType"
|
||
|
|
for attr in entity.all_attributes():
|
||
|
|
if attr.name() == "PredefinedType":
|
||
|
|
predefined_type_attr = attr
|
||
|
|
break
|
||
|
|
|
||
|
|
if not predefined_type_attr:
|
||
|
|
return []
|
||
|
|
|
||
|
|
param_type = predefined_type_attr.type_of_attribute()
|
||
|
|
|
||
|
|
if param_type.as_named_type():
|
||
|
|
enum_decl = param_type.as_named_type().declared_type()
|
||
|
|
if enum_decl.as_enumeration_type():
|
||
|
|
return enum_decl.as_enumeration_type().enumeration_items()
|
||
|
|
|
||
|
|
return []
|
||
|
|
|
||
|
|
def get_all_entity_classes(schema_name):
|
||
|
|
"""Get all IFC entity classes in the given schema."""
|
||
|
|
|
||
|
|
schema = ifcopenshell.schema_by_name(schema_name)
|
||
|
|
entities = []
|
||
|
|
|
||
|
|
for entity in schema.entities():
|
||
|
|
entities.append(entity.name())
|
||
|
|
|
||
|
|
# Sort alphabetically
|
||
|
|
entities.sort()
|
||
|
|
return entities
|
||
|
|
|
||
|
|
def get_all_data_types(schema_name):
|
||
|
|
"""Get all data types in the given schema."""
|
||
|
|
|
||
|
|
schema = ifcopenshell.schema_by_name(schema_name)
|
||
|
|
return {d.name(): ifcopenshell.util.attribute.get_primitive_type(d) for d in schema.declarations() if d.as_type_declaration()}
|
||
|
|
|
||
|
|
def get_entity_attributes(schema_name, entity_name):
|
||
|
|
"""Get all attributes for a given entity."""
|
||
|
|
|
||
|
|
schema = ifcopenshell.schema_by_name(schema_name)
|
||
|
|
|
||
|
|
try:
|
||
|
|
entity = schema.declaration_by_name(entity_name)
|
||
|
|
except:
|
||
|
|
return []
|
||
|
|
|
||
|
|
if not entity or not entity.as_entity():
|
||
|
|
print(f"Entity {entity_name} not found")
|
||
|
|
return []
|
||
|
|
|
||
|
|
entity = entity.as_entity()
|
||
|
|
attributes = []
|
||
|
|
for attr in entity.all_attributes():
|
||
|
|
attributes.append({
|
||
|
|
"name": attr.name(),
|
||
|
|
# "type": attr.type_of_attribute() # TODO Types of attribute
|
||
|
|
})
|
||
|
|
|
||
|
|
return attributes
|
||
|
|
|
||
|
|
def get_applicable_psets(schema_name, entity_name, predefined_type = ""):
|
||
|
|
"""Get all applicable property and quantity sets for a given entity."""
|
||
|
|
|
||
|
|
pset_qto = ifcopenshell.util.pset.PsetQto(schema_name)
|
||
|
|
pset_names = pset_qto.get_applicable_names(entity_name, predefined_type)
|
||
|
|
|
||
|
|
return pset_names
|
||
|
|
|
||
|
|
def get_all_psets(schema_name):
|
||
|
|
"""Get all property sets and quantity sets defined in an IFC schema"""
|
||
|
|
|
||
|
|
pset_qto = ifcopenshell.util.pset.PsetQto(schema_name)
|
||
|
|
result = {}
|
||
|
|
|
||
|
|
for template_file in pset_qto.templates:
|
||
|
|
for pset_template in template_file.by_type("IfcPropertySetTemplate"):
|
||
|
|
pset_name = pset_template.Name
|
||
|
|
properties = []
|
||
|
|
|
||
|
|
# Get property templates for this pset
|
||
|
|
if pset_template.HasPropertyTemplates:
|
||
|
|
for prop_template in pset_template.HasPropertyTemplates:
|
||
|
|
prop_info = {
|
||
|
|
"name": prop_template.Name,
|
||
|
|
# "description": prop_template.Description
|
||
|
|
}
|
||
|
|
|
||
|
|
# Extract type information
|
||
|
|
if prop_template.is_a("IfcSimplePropertyTemplate"):
|
||
|
|
if prop_template.PrimaryMeasureType:
|
||
|
|
prop_info["type"] = prop_template.PrimaryMeasureType
|
||
|
|
else:
|
||
|
|
prop_info["type"] = str(prop_template.TemplateType)
|
||
|
|
elif prop_template.is_a("IfcComplexPropertyTemplate"):
|
||
|
|
prop_info["type"] = None # Complex properties are not supported
|
||
|
|
else:
|
||
|
|
prop_info["type"] = None
|
||
|
|
|
||
|
|
properties.append(prop_info)
|
||
|
|
result[pset_name] = properties
|
||
|
|
|
||
|
|
return result
|
||
|
|
|
||
|
|
def get_material_categories():
|
||
|
|
return ['concrete', 'steel', 'aluminium', 'block', 'brick', 'stone', 'wood', 'glass', 'gypsum', 'plastic', 'earth']
|
||
|
|
|
||
|
|
def get_standard_classification_systems():
|
||
|
|
return {
|
||
|
|
'BB/SfB (3/4 cijfers)': {'source': 'Regie der Gebouwen', 'tokens': ['.']},
|
||
|
|
'BIMTypeCode': {'source': 'BIMStockholm', 'tokens': None},
|
||
|
|
'Common Arrangement of Work Sections (CAWS)': {'source': 'NBS', 'tokens': ['/']},
|
||
|
|
'CBI Classification - Level 2': {'source': 'Masterspec', 'tokens': None},
|
||
|
|
'CBI Classification - Level 4': {'source': 'Masterspec', 'tokens': None},
|
||
|
|
'Rumsfunktionskoder CC001 - 001': {'source': 'BIMAlliance', 'tokens': ['-']},
|
||
|
|
'CCS': {'source': 'Molio', 'tokens': None},
|
||
|
|
'CCTB': {'source': 'CCT-Bâtiments', 'tokens': ['.']},
|
||
|
|
'Funktionskoder Regionservice CD001 - 001': {'source': 'BIMAlliance', 'tokens': None},
|
||
|
|
'Rumsfunktion Blekinge CD002 - 001': {'source': 'BIMAlliance', 'tokens': None},
|
||
|
|
'EcoQuaestor Codetabel': {'source': 'EcoQuaestor', 'tokens': ['.', '-']},
|
||
|
|
'GuBIMclass CA': {'source': 'GuBIMClass', 'tokens': ['.']},
|
||
|
|
'GuBIMclass ES': {'source': 'GuBIMClass', 'tokens': ['.']},
|
||
|
|
'MasterFormat': {'source': 'CSI', 'tokens': [' ', '.']},
|
||
|
|
'NATSPEC Worksections': {'source': 'NATSPEC', 'tokens': None},
|
||
|
|
'NBS Create': {'source': 'NBS', 'tokens': ['_', '/']},
|
||
|
|
'NL/SfB (4 cijfers)': {'source': 'BIMLoket', 'tokens': ['.']},
|
||
|
|
'NS 3451 - Bygningsdelstabell': {'source': 'Standard Norge', 'tokens': None},
|
||
|
|
'OmniClass': {'source': 'OmniClass', 'tokens': ['-', ' ']},
|
||
|
|
'ÖNORM 6241-2': {'source': 'freeBIM 2', 'tokens': None},
|
||
|
|
'RICS NRM1': {'source': 'RICS', 'tokens': ['.']},
|
||
|
|
'RICS NRM3': {'source': 'RICS', 'tokens': ['.']},
|
||
|
|
'SFG20': {'source': 'SFG20', 'tokens': ['-']},
|
||
|
|
'SINAPI': {'source': 'Caixa', 'tokens': ['/']},
|
||
|
|
'STABU-Element': {'source': 'STABU', 'tokens': ['.']},
|
||
|
|
'TALO 2000 Building Component Classification': {'source': 'Rakennustieto', 'tokens': ['.']},
|
||
|
|
'TALO 2000 Hankenimikkeistö': {'source': 'Rakennustieto', 'tokens': ['.']},
|
||
|
|
'Uniclass': {'source': 'RIBA Enterprises Ltd', 'tokens': ['_']},
|
||
|
|
'Uniclass 2015': {'source': 'RIBA Enterprises Ltd', 'tokens': ['_']},
|
||
|
|
'UniFormat': {'source': 'UniFormat', 'tokens': ['.']},
|
||
|
|
'Uniformat': {'source': 'UniFormat', 'tokens': ['.']},
|
||
|
|
'VMSW': {'source': 'VMSW', 'tokens': ['.']}
|
||
|
|
}
|
||
|
|
|
||
|
|
def ids_from_xml_string(xml: str, validate: bool = False) -> Ids:
|
||
|
|
try:
|
||
|
|
decode = get_schema().decode(
|
||
|
|
xml, strip_namespaces=True, namespaces={
|
||
|
|
"": "http://standards.buildingsmart.org/IDS"
|
||
|
|
}
|
||
|
|
)
|
||
|
|
except XMLSchemaValidationError as e:
|
||
|
|
raise IdsXmlValidationError(e, "Provided XML appears to be invalid. See details above.")
|
||
|
|
return Ids().parse(decode)
|