mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 14:23:53 +00:00
Gets the pick list for bSDD properties with Allowed Values working
This commit is contained in:
@@ -170,7 +170,7 @@ class Bsdd(bonsai.core.tool.Bsdd):
|
||||
psets.setdefault(pset, {})
|
||||
|
||||
predefined_value = prop.get("predefinedValue")
|
||||
if predefined_value:
|
||||
if predefined_value and predefined_value != "None":
|
||||
possible_values = [predefined_value]
|
||||
else:
|
||||
possible_values = prop.get("allowedValues", []) or []
|
||||
@@ -369,7 +369,7 @@ class Bsdd(bonsai.core.tool.Bsdd):
|
||||
data = cls.bsdd_properties[bsdd_prop.uri]
|
||||
|
||||
predefined_value = data.get("predefinedValue")
|
||||
if predefined_value:
|
||||
if predefined_value and predefined_value != "None":
|
||||
possible_values = [predefined_value]
|
||||
else:
|
||||
possible_values = data.get("allowedValues", []) or []
|
||||
@@ -401,7 +401,13 @@ class Bsdd(bonsai.core.tool.Bsdd):
|
||||
uris.add(uri)
|
||||
psets = set()
|
||||
for uri in uris:
|
||||
if not (bsdd_class := cls.bsdd_classes.get(uri, None)):
|
||||
try:
|
||||
# Cache may not be populated yet (e.g. a fresh session that never
|
||||
# browsed this class), so fetch on a cache miss instead of skipping.
|
||||
bsdd_class = cls.get_bsdd_class(uri)
|
||||
except Exception:
|
||||
continue
|
||||
if not bsdd_class:
|
||||
continue
|
||||
for class_pset in bsdd_class.get("classProperties", []):
|
||||
if not (pset_name := class_pset.get("propertySet", None)):
|
||||
@@ -409,6 +415,37 @@ class Bsdd(bonsai.core.tool.Bsdd):
|
||||
psets.add((uri, bsdd_class["name"], pset_name))
|
||||
return psets
|
||||
|
||||
@classmethod
|
||||
def get_bsdd_pset_property_values(
|
||||
cls, element: ifcopenshell.entity_instance, pset_name: str
|
||||
) -> dict[str, list[str]]:
|
||||
"""Map bSDD property code -> allowed/predefined values for properties bSDD says
|
||||
are applicable to `element` (via its classification references) under `pset_name`.
|
||||
|
||||
Used to recognise a Pset property as bSDD-sourced even outside the dedicated
|
||||
bSDD add-property flow (e.g. a Pset created in a previous session), so it can
|
||||
still be edited as a picklist.
|
||||
"""
|
||||
result: dict[str, list[str]] = {}
|
||||
for uri, class_name, applicable_pset_name in cls.get_applicable_psets(element):
|
||||
if applicable_pset_name != pset_name:
|
||||
continue
|
||||
bsdd_class = cls.get_bsdd_class(uri)
|
||||
for class_prop in bsdd_class.get("classProperties", []):
|
||||
if class_prop.get("propertySet") != pset_name:
|
||||
continue
|
||||
code = class_prop.get("propertyCode")
|
||||
if not code or code in result:
|
||||
continue
|
||||
predefined_value = class_prop.get("predefinedValue")
|
||||
if predefined_value and predefined_value != "None":
|
||||
result[code] = [predefined_value]
|
||||
continue
|
||||
allowed_values = class_prop.get("allowedValues", []) or []
|
||||
if allowed_values:
|
||||
result[code] = [v["value"] for v in allowed_values]
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def is_applicable(cls, pset_uri: str, element: ifcopenshell.entity_instance) -> bool:
|
||||
uris = set()
|
||||
|
||||
@@ -223,6 +223,18 @@ class Pset(bonsai.core.tool.Pset):
|
||||
elif pset.is_a("IfcMaterialProperties") or pset.is_a("IfcProfileProperties"):
|
||||
pset_props = pset.Properties
|
||||
|
||||
# If this Pset's owning element is classified against a bSDD class that defines
|
||||
# this Pset, recognise properties matching bSDD property codes as picklists,
|
||||
# even though the Pset wasn't necessarily created through the bSDD add-property UI.
|
||||
bsdd_allowed_values: dict[str, list[str]] = {}
|
||||
if pset.is_a("IfcPropertySet"):
|
||||
elements = ifcopenshell.util.element.get_elements_by_pset(pset)
|
||||
if elements:
|
||||
try:
|
||||
bsdd_allowed_values = tool.Bsdd.get_bsdd_pset_property_values(next(iter(elements)), pset.Name)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
prop_templates: dict[str, ifcopenshell.entity_instance] = {}
|
||||
if pset_template:
|
||||
prop_templates = {prop.Name: prop for prop in pset_template.HasPropertyTemplates}
|
||||
@@ -286,6 +298,17 @@ class Pset(bonsai.core.tool.Pset):
|
||||
metadata.set_value(metadata.get_value_default() if metadata.is_null else value)
|
||||
process_prop_description(metadata)
|
||||
|
||||
if prop.is_a("IfcPropertySingleValue") and (possible_values := bsdd_allowed_values.get(prop.Name)):
|
||||
str_value = None if value is None else str(value)
|
||||
if str_value is not None and str_value not in possible_values:
|
||||
# Preserve a legacy/imported value that doesn't match the current
|
||||
# bSDD enumeration instead of silently dropping it.
|
||||
possible_values = [*possible_values, str_value]
|
||||
metadata.enum_items = json.dumps(possible_values)
|
||||
metadata.data_type = "enum"
|
||||
if str_value is not None:
|
||||
metadata.enum_value = str_value
|
||||
|
||||
@classmethod
|
||||
def get_prop_template_primitive_type(cls, prop_template: ifcopenshell.entity_instance) -> str:
|
||||
if prop_template.TemplateType in ["Q_LENGTH", "Q_AREA", "Q_VOLUME", "Q_WEIGHT", "Q_TIME"]:
|
||||
|
||||
+1
-1
@@ -1026,7 +1026,7 @@ def apply_ifc_classification_properties(
|
||||
psets = ifcopenshell.util.element.get_psets(element)
|
||||
for prop in classificationProperties:
|
||||
predefinedValue = prop.get("predefinedValue")
|
||||
if not predefinedValue or prop.get("propertyDomainName") != "IFC":
|
||||
if not predefinedValue or predefinedValue == "None" or prop.get("propertyDomainName") != "IFC":
|
||||
continue
|
||||
pset = psets.get(prop["propertySet"])
|
||||
if pset:
|
||||
|
||||
Reference in New Issue
Block a user