Ifc4x3 - entity-types mapping

- added mapping entity-types mapping based on iso release of ifc4x3

- added some manual corrections for `generate_util_type_json.py` if someone would regenerate the map for ifc4.

- manual correction in ifc4x3 mapping for IfcCivilElement. It could be removed in the future releases of IFC if https://github.com/buildingSMART/IFC4.3.x-development/issues/583 is resolved

If curious to look what were the changes for mapping between ifc4 and ifc4x3:
https://github.com/IfcOpenShell/IfcOpenShell/commit/da51253fb0a9d08aa93f5fe3c074d3592b3aa997#diff-98f525c91bb47b9820e603fba61cc015d3e6ae7261593d727c51114e3ff73aa7
This commit is contained in:
Andrej730
2023-02-17 15:29:10 +05:00
parent 743bd2c48f
commit d52618277e
3 changed files with 506 additions and 90 deletions
+109 -80
View File
@@ -1,5 +1,5 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
# Copyright (C) 2020, 2021, 2023 Dion Moult <dion@thinkmoult.com>, @Andrej730
#
# This file is part of BlenderBIM Add-on.
#
@@ -22,101 +22,130 @@ import ifcopenshell
import ifcopenshell.util.schema
filepath = "IFC4.exp"
schema2x3 = ifcopenshell.ifcopenshell_wrapper.schema_by_name("IFC2X3")
schema4 = ifcopenshell.ifcopenshell_wrapper.schema_by_name("IFC4")
def generate_ifc4_entity_map(filepath, schema_name, manual_corrections={}):
filepath = filepath
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(schema_name)
entity_to_type_map = {}
entity_to_type_map = {}
entity = None
is_in_where_rule = False
entity = None
is_in_where_rule = False
with open(filepath) as fp:
line = fp.readline()
while line:
if "ENTITY " in line:
entity = line[len("ENTITY ") : -1]
elif "END_ENTITY" in line:
is_in_where_rule = False
elif entity and ("CorrectTypeAssigned" in line or "CorrectStyleAssigned" in line):
is_in_where_rule = True
elif entity and is_in_where_rule and "IN TYPEOF" in line and "RelatingType" in line:
type_class = line.split("'")[1].split(".")[1]
if type_class == "IFCTRANFORMERTYPE":
# Fix typo in schema
type_class = "IFCTRANSFORMERTYPE"
type_class = schema4.declaration_by_name(type_class).name()
entity_to_type_map.setdefault(entity, []).append(type_class)
with open(filepath) as fp:
line = fp.readline()
while line:
if "ENTITY " in line:
entity = line[len("ENTITY ") : -1]
elif "END_ENTITY" in line:
is_in_where_rule = False
elif entity and ("CorrectTypeAssigned" in line or "CorrectStyleAssigned" in line):
is_in_where_rule = True
elif entity and is_in_where_rule and "IN TYPEOF" in line and "RelatingType" in line:
type_class = line.split("'")[1].split(".")[1]
if type_class == "IFCTRANFORMERTYPE":
# Fix typo in schema
type_class = "IFCTRANSFORMERTYPE"
type_class = schema.declaration_by_name(type_class).name()
entity_to_type_map.setdefault(entity, []).append(type_class)
line = fp.readline()
# This type of hacky express parsing doesn't accommodate subtypes, so...
for entity in manual_corrections:
for ifc_type in manual_corrections[entity]:
entity_to_type_map.setdefault(entity, []).append(ifc_type)
# This type of hacky express parsing doesn't accommodate subtypes, so...
def get_inherited_map(declaration):
if not ifcopenshell.util.schema.is_a(declaration, "IfcObject"):
return
if declaration.supertype().name() in entity_to_type_map:
return entity_to_type_map[declaration.supertype().name()]
return get_inherited_map(declaration.supertype())
def get_inherited_map(declaration):
if not ifcopenshell.util.schema.is_a(declaration, "IfcObject"):
return
if declaration.supertype().name() in entity_to_type_map:
return entity_to_type_map[declaration.supertype().name()]
return get_inherited_map(declaration.supertype())
for declaration in schema.declarations():
if not hasattr(declaration, "supertype"):
continue
if not ifcopenshell.util.schema.is_a(declaration, "IfcObject"):
continue
if declaration.is_abstract():
continue
if declaration.name() in entity_to_type_map:
continue
inherited_map = get_inherited_map(declaration)
if inherited_map:
entity_to_type_map[declaration.name()] = inherited_map
type_to_entity_map = {value: [key] for key in entity_to_type_map for value in entity_to_type_map[key]}
for declaration in schema4.declarations():
if not hasattr(declaration, "supertype"):
continue
if not ifcopenshell.util.schema.is_a(declaration, "IfcObject"):
continue
if declaration.is_abstract():
continue
if declaration.name() in entity_to_type_map:
continue
inherited_map = get_inherited_map(declaration)
if inherited_map:
entity_to_type_map[declaration.name()] = inherited_map
schema_version = schema_name.lower().strip("ifc")
with open(f"src/ifcopenshell-python/ifcopenshell/util/entity_to_type_map_{schema_version}.json", "w") as f:
json.dump(entity_to_type_map, f, indent=4)
return entity_to_type_map
type_to_entity_map = {value: [key] for key in entity_to_type_map for value in entity_to_type_map[key]}
# IFC2X3 doesn't seem to define this in EXPRESS, so let's just guess
# TODO: do we need some other way to validate 2x3 mapping?
def generate_ifc2x3_entity_map():
entity_to_type_map = {}
schema2x3 = ifcopenshell.ifcopenshell_wrapper.schema_by_name("IFC2X3")
entity_to_type_map2x3 = {}
def guess_type_declaration(declaration):
if not ifcopenshell.util.schema.is_a(declaration, "IfcObject"):
return
try:
type_declaration = schema2x3.declaration_by_name(declaration.name() + "Type")
return type_declaration
except:
pass
try:
type_declaration = schema2x3.declaration_by_name(declaration.name() + "Style")
return type_declaration
except:
pass
return guess_type_declaration(declaration.supertype())
for declaration in schema2x3.declarations():
if not hasattr(declaration, "supertype"):
continue
type_declaration = guess_type_declaration(declaration)
if not type_declaration:
continue
if not type_declaration.is_abstract():
entity_to_type_map.setdefault(declaration.name(), []).append(type_declaration.name())
for subtype in type_declaration.subtypes():
if not subtype.is_abstract():
entity_to_type_map.setdefault(declaration.name(), []).append(subtype.name())
type_to_entity_map2x3 = {value: [key] for key in entity_to_type_map for value in entity_to_type_map[key]}
with open("src/ifcopenshell-python/ifcopenshell/util/entity_to_type_map_2x3.json", "w") as f:
json.dump(entity_to_type_map, f, indent=4)
return entity_to_type_map
def guess_type_declaration(declaration):
if not ifcopenshell.util.schema.is_a(declaration, "IfcObject"):
return
# specs: https://technical.buildingsmart.org/standards/ifc/ifc-schema-specifications
# ifc4x3 - https://github.com/buildingSMART/IFC4.3-html/releases/tag/sep-13-release (inside .zip)
# ifc4 - https://standards.buildingsmart.org/IFC/RELEASE/IFC4/FINAL/EXPRESS/IFC4.exp
try:
type_declaration = schema2x3.declaration_by_name(declaration.name() + "Type")
return type_declaration
except:
pass
# IfcCivilElement correction could be removed in the future releases of IFC
# if https://github.com/buildingSMART/IFC4.3.x-development/issues/583 is solved
try:
type_declaration = schema2x3.declaration_by_name(declaration.name() + "Style")
return type_declaration
except:
pass
ifc4x3_corrections = {
"IfcCivilElement": ["IfcCivilElementType"],
}
entity_to_type_map4x3 = generate_ifc4_entity_map("IFC4X3_TC1.exp", "ifc4x3", ifc4x3_corrections)
return guess_type_declaration(declaration.supertype())
# some manual IFC4 corrections (more details in entity_to_type_map_4.json commits history)
ifc4_corrections = {
"IfcDoor": ["IfcDoorStyle"], # also will apply change to IfcDoorStandardCase
"IfcWindow": ["IfcWindowStyle"], # also will aply change to IfcWindowStandardCase
"IfcCivilElement": ["IfcCivilElementType"],
}
#
entity_to_type_map4 = generate_ifc4_entity_map("IFC4.exp", "ifc4", ifc4_corrections)
for declaration in schema2x3.declarations():
if not hasattr(declaration, "supertype"):
continue
type_declaration = guess_type_declaration(declaration)
if not type_declaration:
continue
if not type_declaration.is_abstract():
entity_to_type_map2x3.setdefault(declaration.name(), []).append(type_declaration.name())
for subtype in type_declaration.subtypes():
if not subtype.is_abstract():
entity_to_type_map2x3.setdefault(declaration.name(), []).append(subtype.name())
type_to_entity_map2x3 = {value: [key] for key in entity_to_type_map2x3 for value in entity_to_type_map2x3[key]}
with open("entity_to_type_map_4.json", "w") as f:
json.dump(entity_to_type_map, f, indent=4)
with open("entity_to_type_map_2x3.json", "w") as f:
json.dump(entity_to_type_map2x3, f, indent=4)
entity_to_type_map2x3 = generate_ifc2x3_entity_map()
@@ -0,0 +1,380 @@
{
"IfcActuator": [
"IfcActuatorType"
],
"IfcAirTerminal": [
"IfcAirTerminalType"
],
"IfcAirTerminalBox": [
"IfcAirTerminalBoxType"
],
"IfcAirToAirHeatRecovery": [
"IfcAirToAirHeatRecoveryType"
],
"IfcAlarm": [
"IfcAlarmType"
],
"IfcAudioVisualAppliance": [
"IfcAudioVisualApplianceType"
],
"IfcBeam": [
"IfcBeamType"
],
"IfcBearing": [
"IfcBearingType"
],
"IfcBoiler": [
"IfcBoilerType"
],
"IfcBuildingElementPart": [
"IfcBuildingElementPartType"
],
"IfcBuildingElementProxy": [
"IfcBuildingElementProxyType"
],
"IfcBurner": [
"IfcBurnerType"
],
"IfcCableCarrierFitting": [
"IfcCableCarrierFittingType"
],
"IfcCableCarrierSegment": [
"IfcCableCarrierSegmentType"
],
"IfcCableFitting": [
"IfcCableFittingType"
],
"IfcCableSegment": [
"IfcCableSegmentType"
],
"IfcCaissonFoundation": [
"IfcCaissonFoundationType"
],
"IfcChiller": [
"IfcChillerType"
],
"IfcChimney": [
"IfcChimneyType"
],
"IfcCoil": [
"IfcCoilType"
],
"IfcColumn": [
"IfcColumnType"
],
"IfcCommunicationsAppliance": [
"IfcCommunicationsApplianceType"
],
"IfcCompressor": [
"IfcCompressorType"
],
"IfcCondenser": [
"IfcCondenserType"
],
"IfcController": [
"IfcControllerType"
],
"IfcConveyorSegment": [
"IfcConveyorSegmentType"
],
"IfcCooledBeam": [
"IfcCooledBeamType"
],
"IfcCoolingTower": [
"IfcCoolingTowerType"
],
"IfcCourse": [
"IfcCourseType"
],
"IfcCovering": [
"IfcCoveringType"
],
"IfcCurtainWall": [
"IfcCurtainWallType"
],
"IfcDamper": [
"IfcDamperType"
],
"IfcDeepFoundation": [
"IfcDeepFoundationType"
],
"IfcDiscreteAccessory": [
"IfcDiscreteAccessoryType"
],
"IfcDistributionBoard": [
"IfcDistributionBoardType"
],
"IfcDistributionChamberElement": [
"IfcDistributionChamberElementType"
],
"IfcDoor": [
"IfcDoorType"
],
"IfcDuctFitting": [
"IfcDuctFittingType"
],
"IfcDuctSegment": [
"IfcDuctSegmentType"
],
"IfcDuctSilencer": [
"IfcDuctSilencerType"
],
"IfcElectricAppliance": [
"IfcElectricApplianceType"
],
"IfcElectricDistributionBoard": [
"IfcElectricDistributionBoardType"
],
"IfcElectricFlowStorageDevice": [
"IfcElectricFlowStorageDeviceType"
],
"IfcElectricFlowTreatmentDevice": [
"IfcElectricFlowTreatmentDeviceType"
],
"IfcElectricGenerator": [
"IfcElectricGeneratorType"
],
"IfcElectricMotor": [
"IfcElectricMotorType"
],
"IfcElectricTimeControl": [
"IfcElectricTimeControlType"
],
"IfcElementAssembly": [
"IfcElementAssemblyType"
],
"IfcEngine": [
"IfcEngineType"
],
"IfcEvaporativeCooler": [
"IfcEvaporativeCoolerType"
],
"IfcEvaporator": [
"IfcEvaporatorType"
],
"IfcFan": [
"IfcFanType"
],
"IfcFastener": [
"IfcFastenerType"
],
"IfcFilter": [
"IfcFilterType"
],
"IfcFireSuppressionTerminal": [
"IfcFireSuppressionTerminalType"
],
"IfcFlowInstrument": [
"IfcFlowInstrumentType"
],
"IfcFlowMeter": [
"IfcFlowMeterType"
],
"IfcFooting": [
"IfcFootingType"
],
"IfcFurniture": [
"IfcFurnitureType"
],
"IfcGeographicElement": [
"IfcGeographicElementType"
],
"IfcHeatExchanger": [
"IfcHeatExchangerType"
],
"IfcHumidifier": [
"IfcHumidifierType"
],
"IfcImpactProtectionDevice": [
"IfcImpactProtectionDeviceType"
],
"IfcInterceptor": [
"IfcInterceptorType"
],
"IfcJunctionBox": [
"IfcJunctionBoxType"
],
"IfcKerb": [
"IfcKerbType"
],
"IfcLamp": [
"IfcLampType"
],
"IfcLightFixture": [
"IfcLightFixtureType"
],
"IfcLiquidTerminal": [
"IfcLiquidTerminalType"
],
"IfcMechanicalFastener": [
"IfcMechanicalFastenerType"
],
"IfcMedicalDevice": [
"IfcMedicalDeviceType"
],
"IfcMember": [
"IfcMemberType"
],
"IfcMobileTelecommunicationsAppliance": [
"IfcMobileTelecommunicationsApplianceType"
],
"IfcMooringDevice": [
"IfcMooringDeviceType"
],
"IfcMotorConnection": [
"IfcMotorConnectionType"
],
"IfcNavigationElement": [
"IfcNavigationElementType"
],
"IfcOutlet": [
"IfcOutletType"
],
"IfcPavement": [
"IfcPavementType"
],
"IfcPile": [
"IfcPileType"
],
"IfcPipeFitting": [
"IfcPipeFittingType"
],
"IfcPipeSegment": [
"IfcPipeSegmentType"
],
"IfcPlate": [
"IfcPlateType"
],
"IfcProtectiveDevice": [
"IfcProtectiveDeviceType"
],
"IfcProtectiveDeviceTrippingUnit": [
"IfcProtectiveDeviceTrippingUnitType"
],
"IfcPump": [
"IfcPumpType"
],
"IfcRail": [
"IfcRailType"
],
"IfcRailing": [
"IfcRailingType"
],
"IfcRamp": [
"IfcRampType"
],
"IfcRampFlight": [
"IfcRampFlightType"
],
"IfcReinforcingBar": [
"IfcReinforcingBarType"
],
"IfcReinforcingMesh": [
"IfcReinforcingMeshType"
],
"IfcRoof": [
"IfcRoofType"
],
"IfcSanitaryTerminal": [
"IfcSanitaryTerminalType"
],
"IfcSensor": [
"IfcSensorType"
],
"IfcShadingDevice": [
"IfcShadingDeviceType"
],
"IfcSign": [
"IfcSignType"
],
"IfcSignal": [
"IfcSignalType"
],
"IfcSlab": [
"IfcSlabType"
],
"IfcSolarDevice": [
"IfcSolarDeviceType"
],
"IfcSpace": [
"IfcSpaceType"
],
"IfcSpaceHeater": [
"IfcSpaceHeaterType"
],
"IfcSpatialZone": [
"IfcSpatialZoneType"
],
"IfcStackTerminal": [
"IfcStackTerminalType"
],
"IfcStair": [
"IfcStairType"
],
"IfcStairFlight": [
"IfcStairFlightType"
],
"IfcSwitchingDevice": [
"IfcSwitchingDeviceType"
],
"IfcSystemFurnitureElement": [
"IfcSystemFurnitureElementType"
],
"IfcTank": [
"IfcTankType"
],
"IfcTendon": [
"IfcTendonType"
],
"IfcTendonAnchor": [
"IfcTendonAnchorType"
],
"IfcTendonConduit": [
"IfcTendonConduitType"
],
"IfcTrackElement": [
"IfcTrackElementType"
],
"IfcTransformer": [
"IfcTransformerType"
],
"IfcTransportElement": [
"IfcTransportElementType"
],
"IfcTubeBundle": [
"IfcTubeBundleType"
],
"IfcUnitaryControlElement": [
"IfcUnitaryControlElementType"
],
"IfcUnitaryEquipment": [
"IfcUnitaryEquipmentType"
],
"IfcValve": [
"IfcValveType"
],
"IfcVehicle": [
"IfcVehicleType"
],
"IfcVibrationDamper": [
"IfcVibrationDamperType"
],
"IfcVibrationIsolator": [
"IfcVibrationIsolatorType"
],
"IfcWall": [
"IfcWallType"
],
"IfcWasteTerminal": [
"IfcWasteTerminalType"
],
"IfcWindow": [
"IfcWindowType"
],
"IfcCivilElement": [
"IfcCivilElementType"
],
"IfcWallStandardCase": [
"IfcWallType"
]
}
@@ -1,5 +1,5 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
# Copyright (C) 2021, 2023 Dion Moult <dion@thinkmoult.com>, @Andrej730
#
# This file is part of IfcOpenShell.
#
@@ -24,28 +24,35 @@ cwd = os.path.dirname(os.path.realpath(__file__))
entity_to_type_map = {}
type_to_entity_map = {}
with open(os.path.join(cwd, "entity_to_type_map_2x3.json")) as f:
entity_to_type_map["IFC2X3"] = json.load(f)
mapped_schemas = {
"IFC2X3": "entity_to_type_map_2x3.json",
"IFC4": "entity_to_type_map_4.json",
"IFC4x3": "entity_to_type_map_4x3.json",
}
for schema in mapped_schemas:
# load entity maps from json
schema_path = os.path.join(cwd, mapped_schemas[schema])
with open(schema_path) as f:
entity_to_type_map[schema] = json.load(f)
with open(os.path.join(cwd, "entity_to_type_map_4.json")) as f:
entity_to_type_map["IFC4"] = json.load(f)
for schema in ["IFC2X3", "IFC4"]:
# create type_to_entity map
type_to_entity_map[schema] = {}
for element, element_types in entity_to_type_map[schema].items():
for element_type in element_types:
type_to_entity_map[schema].setdefault(element_type, []).append(element)
if schema == "IFC2X3":
# There is no official mapping for IFC2X3 but this method gets us something that looks correct
for element_type, elements in type_to_entity_map[schema].items():
guessed_element = element_type[0:-len("Type")]
# need to take both Type (4 symbols) and Style (5 symbols) into account
guessed_element = element_type[:-5] if element_type.endswith("Style") else element_type[:-4]
if guessed_element in elements:
type_to_entity_map[schema][element_type] = [e for e in elements if guessed_element in e]
def get_applicable_types(ifc_class, schema="IFC4"):
return entity_to_type_map[schema].get(ifc_class, [])
return entity_to_type_map[schema.upper()].get(ifc_class, [])
def get_applicable_entities(ifc_type_class, schema="IFC4"):
return type_to_entity_map[schema].get(ifc_type_class, [])
return type_to_entity_map[schema.upper()].get(ifc_type_class, [])