set_element_value - optimizations setting enum values

1) Identify from previous pset value whether prop was an enum (by checking if previous value is a list), instead of searching through prop templates

2) Compare previous and new enum values - if they match, skip editing IFC.
This commit is contained in:
Andrej730
2024-12-06 16:30:43 +05:00
parent c7af55183b
commit 2da5f2d61e
@@ -17,6 +17,7 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>. # along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import re import re
import types
import lark import lark
import numpy as np import numpy as np
import ifcopenshell.api.pset import ifcopenshell.api.pset
@@ -466,7 +467,12 @@ class SetElementValueException(Exception): ...
def set_element_value( def set_element_value(
ifc_file: ifcopenshell.file, ifc_file: ifcopenshell.file,
element: Union[ifcopenshell.entity_instance, Iterable[ifcopenshell.entity_instance], None], element: Union[
ifcopenshell.entity_instance,
dict[str, Any],
Iterable[ifcopenshell.entity_instance],
None,
],
query: Union[str, list[str]], query: Union[str, list[str]],
value: Any, value: Any,
*, *,
@@ -656,14 +662,30 @@ def set_element_value(
ifcopenshell.api.pset.edit_qto(ifc_file, qto=pset, properties={prop: float(value)}) ifcopenshell.api.pset.edit_qto(ifc_file, qto=pset, properties={prop: float(value)})
elif pset.is_a("IfcPropertySet") and element.get(key, None) != value: elif pset.is_a("IfcPropertySet") and element.get(key, None) != value:
def process_pset_prop_value(pset: ifcopenshell.entity_instance, prop: str, value: Any) -> Any: def process_pset_prop_value(
pset: ifcopenshell.entity_instance, prop: str, value: Any
) -> Union[Any, types.EllipsisType]:
"""Try to process value for edit_pset. """Try to process value for edit_pset.
`edit_pset` is expecting a sequence of values `edit_pset` is expecting a sequence of values
for enum properties, not just a string of some-symbol-separated values. for enum properties, not just a string of some-symbol-separated values.
Return `...` if property can be skipped as it has the same value.
""" """
if not isinstance(value, str): if not isinstance(value, str):
return value return value
current_value = element.get(key, ...)
# Check if previous value is a list as a fast way to identify enum properties.
if not isinstance(current_value, (types.EllipsisType, list)):
return value
if isinstance(current_value, list):
# Value won't change, safe to skip editing IFC.
enum_values = value.split(concat)
if len(enum_values) == len(current_value) and set(enum_values) == set(current_value):
return ...
template = ifcopenshell.util.pset.get_template(ifc_file.schema) template = ifcopenshell.util.pset.get_template(ifc_file.schema)
pset_template = template.get_by_name(pset.Name) pset_template = template.get_by_name(pset.Name)
if pset_template is None: if pset_template is None:
@@ -704,6 +726,8 @@ def set_element_value(
return value return value
value = process_pset_prop_value(pset, key, value) value = process_pset_prop_value(pset, key, value)
if value == ...:
return
ifcopenshell.api.pset.edit_pset(ifc_file, pset=pset, properties={key: value}) ifcopenshell.api.pset.edit_pset(ifc_file, pset=pset, properties={key: value})
elif pset.is_a("IfcElementQuantity"): elif pset.is_a("IfcElementQuantity"):
try: try: