mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-14 11:24:19 +00:00
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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user