Fix #971. New utility function to query which psets/qtos apply to a class.

This commit is contained in:
Dion Moult
2020-11-03 09:53:03 +11:00
parent 96b8bc638b
commit 67baad5182
6 changed files with 78 additions and 61 deletions
@@ -6,12 +6,13 @@ import datetime
import os import os
import zipfile import zipfile
import tempfile import tempfile
import ifcopenshell
import ifcopenshell.util.pset
from pathlib import Path from pathlib import Path
from mathutils import Vector, Matrix from mathutils import Vector, Matrix
from .helper import SIUnitHelper, get_representation_elements from .helper import SIUnitHelper, get_representation_elements
from . import schema from . import schema
from . import ifc from . import ifc
import ifcopenshell
import addon_utils import addon_utils
@@ -466,10 +467,10 @@ class IfcParser:
return return
qto_names = self.get_applicable_qtos(ifc_class) qto_names = self.get_applicable_qtos(ifc_class)
for name in qto_names: for name in qto_names:
if name not in schema.ifc.qtos: if name not in ifcopenshell.util.pset.qtos:
continue continue
has_automatic_value = False has_automatic_value = False
props = schema.ifc.qtos[name]["HasPropertyTemplates"].keys() props = ifcopenshell.util.pset.qtos[name]["HasPropertyTemplates"].keys()
guessed_values = {} guessed_values = {}
for prop_name in props: for prop_name in props:
value = self.qto_calculator.guess_quantity(prop_name, props, obj) value = self.qto_calculator.guess_quantity(prop_name, props, obj)
@@ -1666,12 +1667,12 @@ class IfcExporter:
) )
def create_qto_properties(self, qto): def create_qto_properties(self, qto):
if qto["attributes"]["Name"] in schema.ifc.qtos: if qto["attributes"]["Name"] in ifcopenshell.util.pset.qtos:
return self.create_templated_qto_properties(qto) return self.create_templated_qto_properties(qto)
return self.create_custom_qto_properties(qto) return self.create_custom_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 ifcopenshell.util.pset.psets:
return self.create_templated_pset_properties(pset) return self.create_templated_pset_properties(pset)
return self.create_custom_pset_properties(pset) return self.create_custom_pset_properties(pset)
@@ -1704,7 +1705,7 @@ class IfcExporter:
def create_templated_pset_properties(self, pset): def create_templated_pset_properties(self, pset):
properties = [] properties = []
templates = schema.ifc.psets[pset["attributes"]["Name"]]["HasPropertyTemplates"] templates = ifcopenshell.util.pset.psets[pset["attributes"]["Name"]]["HasPropertyTemplates"]
for name, data in templates.items(): for name, data in templates.items():
if name not in pset["raw"]: if name not in pset["raw"]:
continue continue
@@ -1731,7 +1732,7 @@ class IfcExporter:
def create_templated_qto_properties(self, qto): def create_templated_qto_properties(self, qto):
properties = [] properties = []
templates = schema.ifc.qtos[qto["attributes"]["Name"]]["HasPropertyTemplates"] templates = ifcopenshell.util.pset.qtos[qto["attributes"]["Name"]]["HasPropertyTemplates"]
for name, data in templates.items(): for name, data in templates.items():
if name not in qto["raw"]: if name not in qto["raw"]:
continue continue
@@ -3157,10 +3158,7 @@ class IfcExporter:
) )
def relate_spaces_to_boundary_elements(self): def relate_spaces_to_boundary_elements(self):
for ( for (relating_space_index, relationships,) in self.ifc_parser.rel_space_boundaries.items():
relating_space_index,
relationships,
) in self.ifc_parser.rel_space_boundaries.items():
for relationship in relationships: for relationship in relationships:
relationship["attributes"]["GlobalId"] = ifcopenshell.guid.new() relationship["attributes"]["GlobalId"] = ifcopenshell.guid.new()
relationship["attributes"]["RelatedBuildingElement"] = self.ifc_parser.products[ relationship["attributes"]["RelatedBuildingElement"] = self.ifc_parser.products[
@@ -3,6 +3,7 @@ import ifcopenshell.geom
import ifcopenshell.util.geolocation import ifcopenshell.util.geolocation
import ifcopenshell.util.selector import ifcopenshell.util.selector
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.pset
import bpy import bpy
import bmesh import bmesh
import os import os
@@ -206,8 +207,8 @@ class MaterialCreator:
def add_pset(self, pset, obj): def add_pset(self, pset, obj):
new_pset = obj.BIMMaterialProperties.psets.add() new_pset = obj.BIMMaterialProperties.psets.add()
new_pset.name = pset.Name new_pset.name = pset.Name
if new_pset.name in schema.ifc.psets: if new_pset.name in ifcopenshell.util.pset.psets:
for prop_name in schema.ifc.psets[new_pset.name]["HasPropertyTemplates"].keys(): for prop_name in ifcopenshell.util.pset.psets[new_pset.name]["HasPropertyTemplates"].keys():
prop = new_pset.properties.add() prop = new_pset.properties.add()
prop.name = prop_name prop.name = prop_name
for prop in pset.Properties: for prop in pset.Properties:
@@ -1338,8 +1339,8 @@ class IfcImporter:
def add_pset(self, pset, obj): def add_pset(self, pset, obj):
new_pset = obj.BIMObjectProperties.psets.add() new_pset = obj.BIMObjectProperties.psets.add()
new_pset.name = pset.Name new_pset.name = pset.Name
if new_pset.name in schema.ifc.psets: if new_pset.name in ifcopenshell.util.pset.psets:
for prop_name in schema.ifc.psets[new_pset.name]["HasPropertyTemplates"].keys(): for prop_name in ifcopenshell.util.pset.psets[new_pset.name]["HasPropertyTemplates"].keys():
prop = new_pset.properties.add() prop = new_pset.properties.add()
prop.name = prop_name prop.name = prop_name
# Invalid IFC, but some vendors like Solidworks do this so we accomodate it # Invalid IFC, but some vendors like Solidworks do this so we accomodate it
@@ -1358,8 +1359,8 @@ class IfcImporter:
def add_qto(self, qto, obj): def add_qto(self, qto, obj):
new_qto = obj.BIMObjectProperties.qtos.add() new_qto = obj.BIMObjectProperties.qtos.add()
new_qto.name = str(qto.Name) new_qto.name = str(qto.Name)
if new_qto.name in schema.ifc.qtos: if new_qto.name in ifcopenshell.util.pset.qtos:
for prop_name in schema.ifc.qtos[new_qto.name]["HasPropertyTemplates"].keys(): for prop_name in ifcopenshell.util.pset.qtos[new_qto.name]["HasPropertyTemplates"].keys():
prop = new_qto.properties.add() prop = new_qto.properties.add()
prop.name = prop_name prop.name = prop_name
for prop in qto.Quantities: for prop in qto.Quantities:
+11 -15
View File
@@ -9,6 +9,7 @@ import subprocess
import ifcopenshell import ifcopenshell
import ifcopenshell.util.selector import ifcopenshell.util.selector
import ifcopenshell.util.geolocation import ifcopenshell.util.geolocation
import ifcopenshell.util.pset
import tempfile import tempfile
from . import export_ifc from . import export_ifc
from . import import_ifc from . import import_ifc
@@ -836,11 +837,11 @@ class AddQto(bpy.types.Operator):
def execute(self, context): def execute(self, context):
name = bpy.context.active_object.BIMObjectProperties.qto_name name = bpy.context.active_object.BIMObjectProperties.qto_name
if name not in schema.ifc.qtos: if name not in ifcopenshell.util.pset.qtos:
return {"FINISHED"} return {"FINISHED"}
qto = bpy.context.active_object.BIMObjectProperties.qtos.add() qto = bpy.context.active_object.BIMObjectProperties.qtos.add()
qto.name = name qto.name = name
for prop_name in schema.ifc.qtos[name]["HasPropertyTemplates"].keys(): for prop_name in ifcopenshell.util.pset.qtos[name]["HasPropertyTemplates"].keys():
prop = qto.properties.add() prop = qto.properties.add()
prop.name = prop_name prop.name = prop_name
return {"FINISHED"} return {"FINISHED"}
@@ -852,11 +853,11 @@ class AddPset(bpy.types.Operator):
def execute(self, context): def execute(self, context):
pset_name = bpy.context.active_object.BIMObjectProperties.pset_name pset_name = bpy.context.active_object.BIMObjectProperties.pset_name
if pset_name not in schema.ifc.psets: if pset_name not in ifcopenshell.util.pset.psets:
return {"FINISHED"} return {"FINISHED"}
pset = bpy.context.active_object.BIMObjectProperties.psets.add() pset = bpy.context.active_object.BIMObjectProperties.psets.add()
pset.name = pset_name pset.name = pset_name
for prop_name in schema.ifc.psets[pset_name]["HasPropertyTemplates"].keys(): for prop_name in ifcopenshell.util.pset.psets[pset_name]["HasPropertyTemplates"].keys():
prop = pset.properties.add() prop = pset.properties.add()
prop.name = prop_name prop.name = prop_name
return {"FINISHED"} return {"FINISHED"}
@@ -2729,7 +2730,6 @@ class CopyPropertyToSelection(bpy.types.Operator):
def execute(self, context): def execute(self, context):
self.applicable_psets_cache = {} self.applicable_psets_cache = {}
self.empty = ifcopenshell.file()
for obj in bpy.context.selected_objects: for obj in bpy.context.selected_objects:
if "/" not in obj.name: if "/" not in obj.name:
continue continue
@@ -2740,7 +2740,7 @@ class CopyPropertyToSelection(bpy.types.Operator):
continue continue
pset = obj.BIMObjectProperties.psets.add() pset = obj.BIMObjectProperties.psets.add()
pset.name = self.pset_name pset.name = self.pset_name
for template_prop_name in schema.ifc.psets[self.pset_name]["HasPropertyTemplates"].keys(): for template_prop_name in ifcopenshell.util.pset.psets[self.pset_name]["HasPropertyTemplates"].keys():
prop = pset.properties.add() prop = pset.properties.add()
prop.name = template_prop_name prop.name = template_prop_name
prop = pset.properties.get(self.prop_name) prop = pset.properties.get(self.prop_name)
@@ -2748,15 +2748,11 @@ class CopyPropertyToSelection(bpy.types.Operator):
prop.string_value = self.prop_value prop.string_value = self.prop_value
return {"FINISHED"} return {"FINISHED"}
# TODO: move into util module. See bug #971
def get_applicable_psets(self, element_class): def get_applicable_psets(self, element_class):
if element_class not in self.applicable_psets_cache: if element_class not in self.applicable_psets_cache:
element = self.empty.create_entity(element_class) self.applicable_psets_cache[element_class] = ifcopenshell.util.pset.get_applicable_psetqtos(
applicable_psets = [] bpy.context.scene.BIMProperties.export_schema, element_class, is_pset=True
for ifc_class, pset_names in schema.ifc.applicable_psets.items(): )
if element.is_a(ifc_class):
applicable_psets.extend(pset_names)
self.applicable_psets_cache[element_class] = applicable_psets
return self.applicable_psets_cache[element_class] return self.applicable_psets_cache[element_class]
@@ -3604,11 +3600,11 @@ class GuessQuantity(bpy.types.Operator):
prop.string_value = str(round(quantity, 3)) prop.string_value = str(round(quantity, 3))
def add_qto(self, obj, name): def add_qto(self, obj, name):
if name not in schema.ifc.qtos: if name not in ifcopenshell.util.pset.qtos:
return return
qto = obj.BIMObjectProperties.qtos.add() qto = obj.BIMObjectProperties.qtos.add()
qto.name = name qto.name = name
for prop_name in schema.ifc.qtos[name]["HasPropertyTemplates"].keys(): for prop_name in ifcopenshell.util.pset.qtos[name]["HasPropertyTemplates"].keys():
prop = qto.properties.add() prop = qto.properties.add()
prop.name = prop_name prop.name = prop_name
return qto return qto
+9 -12
View File
@@ -2,6 +2,7 @@ import json
import os import os
import csv import csv
import ifcopenshell import ifcopenshell
import ifcopenshell.util.pset
from pathlib import Path from pathlib import Path
from . import export_ifc from . import export_ifc
from . import schema from . import schema
@@ -429,29 +430,25 @@ def refreshReferences(self, context):
context.scene.BIMProperties.classification_references.root = "" context.scene.BIMProperties.classification_references.root = ""
# TODO: move into util module. See bug #971
def getPsetNames(self, context): def getPsetNames(self, context):
global psetnames_enum global psetnames_enum
psetnames_enum.clear() psetnames_enum.clear()
if "/" in context.active_object.name and context.active_object.name.split("/")[0] in schema.ifc.elements: if "/" in context.active_object.name and context.active_object.name.split("/")[0] in schema.ifc.elements:
empty = ifcopenshell.file() pset_names = ifcopenshell.util.pset.get_applicable_psetqtos(
element = empty.create_entity(context.active_object.name.split("/")[0]) bpy.context.scene.BIMProperties.export_schema, context.active_object.name.split("/")[0], is_pset=True
for ifc_class, pset_names in schema.ifc.applicable_psets.items(): )
if element.is_a(ifc_class): psetnames_enum.extend([(p, p, "") for p in pset_names])
psetnames_enum.extend([(p, p, "") for p in pset_names])
return psetnames_enum return psetnames_enum
# TODO: move into util module. See bug #971
def getQtoNames(self, context): def getQtoNames(self, context):
global qtonames_enum global qtonames_enum
qtonames_enum.clear() qtonames_enum.clear()
if "/" in context.active_object.name and context.active_object.name.split("/")[0] in schema.ifc.elements: if "/" in context.active_object.name and context.active_object.name.split("/")[0] in schema.ifc.elements:
empty = ifcopenshell.file() qto_names = ifcopenshell.util.pset.get_applicable_psetqtos(
element = empty.create_entity(context.active_object.name.split("/")[0]) bpy.context.scene.BIMProperties.export_schema, context.active_object.name.split("/")[0], is_qto=True
for ifc_class, qto_names in schema.ifc.applicable_qtos.items(): )
if element.is_a(ifc_class): qtonames_enum.extend([(q, q, "") for q in qto_names])
qtonames_enum.extend([(q, q, "") for q in qto_names])
return qtonames_enum return qtonames_enum
+3 -17
View File
@@ -1,6 +1,7 @@
import os import os
import json import json
import ifcopenshell import ifcopenshell
import ifcopenshell.util.pset
import bpy import bpy
from pathlib import Path from pathlib import Path
@@ -30,14 +31,10 @@ class IfcSchema:
self.property_files = [] self.property_files = []
property_paths = Path(os.path.join(self.data_dir, "pset")).glob("*.ifc") property_paths = Path(os.path.join(self.data_dir, "pset")).glob("*.ifc")
for path in property_paths: for path in property_paths:
self.property_files.append(ifcopenshell.open(path)) ifcopenshell.util.pset.load_property_set_template(path)
self.property_files.append(ifcopenshell.open(os.path.join(self.schema_dir, "Pset_IFC4_ADD2.ifc"))) ifcopenshell.util.pset.load_property_set_template(os.path.join(self.schema_dir, "Pset_IFC4_ADD2.ifc"))
self.classification_files = {} self.classification_files = {}
self.psets = {}
self.qtos = {}
self.applicable_psets = {}
self.applicable_qtos = {}
self.classifications = {} self.classifications = {}
self.load() self.load()
@@ -50,17 +47,6 @@ class IfcSchema:
with open(os.path.join(self.schema_dir, "ifc_types_IFC4.json")) as f: with open(os.path.join(self.schema_dir, "ifc_types_IFC4.json")) as f:
self.type_map = json.load(f) self.type_map = json.load(f)
for property_file in self.property_files:
for prop in property_file.by_type("IfcPropertySetTemplate"):
if prop.Name[0:4] == "Qto_":
self.qtos[prop.Name] = {"HasPropertyTemplates": {p.Name: p for p in prop.HasPropertyTemplates}}
entity = prop.ApplicableEntity if prop.ApplicableEntity else "IfcRoot"
self.applicable_qtos.setdefault(entity, []).append(prop.Name)
else:
self.psets[prop.Name] = {"HasPropertyTemplates": {p.Name: p for p in prop.HasPropertyTemplates}}
entity = prop.ApplicableEntity if prop.ApplicableEntity else "IfcRoot"
self.applicable_psets.setdefault(entity, []).append(prop.Name)
def load_classification(self, name, classification_index=None): def load_classification(self, name, classification_index=None):
if name not in self.classifications: if name not in self.classifications:
if classification_index is not None: if classification_index is not None:
@@ -0,0 +1,39 @@
import ifcopenshell
property_set_template_files = []
psets = {}
qtos = {}
applicable_psets = {}
applicable_qtos = {}
def load_property_set_template(path):
property_set_template_files.append(ifcopenshell.open(path))
for prop in property_set_template_files[-1].by_type("IfcPropertySetTemplate"):
if prop.Name[0:4] == "Qto_":
qtos[prop.Name] = {"HasPropertyTemplates": {p.Name: p for p in prop.HasPropertyTemplates}}
entity = prop.ApplicableEntity if prop.ApplicableEntity else "IfcRoot"
applicable_qtos.setdefault(entity, []).append(prop.Name)
else:
psets[prop.Name] = {"HasPropertyTemplates": {p.Name: p for p in prop.HasPropertyTemplates}}
entity = prop.ApplicableEntity if prop.ApplicableEntity else "IfcRoot"
applicable_psets.setdefault(entity, []).append(prop.Name)
def get_applicable_psetqtos(schema_version, ifc_class, is_pset=False, is_qto=False):
def is_a(entity, ifc_class):
if entity.name() == ifc_class:
return True
return is_a(entity.supertype(), ifc_class) if entity.supertype() else False
results = []
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(schema_version)
entity = schema.declaration_by_name(ifc_class)
if is_pset:
search_items = applicable_psets.items()
elif is_qto:
search_items = applicable_qtos.items()
for ifc_class, pset_names in search_items:
if is_a(entity, ifc_class):
results.extend(pset_names)
return results