mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 06:58:56 +00:00
Express rules: allow comparison of instances to instances and values
This commit is contained in:
@@ -25,6 +25,8 @@ import functools
|
|||||||
import importlib
|
import importlib
|
||||||
import numbers
|
import numbers
|
||||||
import itertools
|
import itertools
|
||||||
|
import operator
|
||||||
|
import functools
|
||||||
|
|
||||||
from . import ifcopenshell_wrapper
|
from . import ifcopenshell_wrapper
|
||||||
|
|
||||||
@@ -133,13 +135,18 @@ class entity_instance(object):
|
|||||||
self.wrapped_data.get_argument(idx), self.wrapped_data.file
|
self.wrapped_data.get_argument(idx), self.wrapped_data.file
|
||||||
)
|
)
|
||||||
elif attr_cat == INVERSE:
|
elif attr_cat == INVERSE:
|
||||||
return entity_instance.wrap_value(self.wrapped_data.get_inverse(name), self.wrapped_data.file)
|
return entity_instance.wrap_value(
|
||||||
|
self.wrapped_data.get_inverse(name), self.wrapped_data.file
|
||||||
|
)
|
||||||
|
|
||||||
# derived attribute perhaps?
|
# derived attribute perhaps?
|
||||||
schema_name = self.wrapped_data.is_a(True).split('.')[0]
|
schema_name = self.wrapped_data.is_a(True).split(".")[0]
|
||||||
rules = importlib.import_module(f"ifcopenshell.express.rules.{schema_name}")
|
rules = importlib.import_module(f"ifcopenshell.express.rules.{schema_name}")
|
||||||
|
|
||||||
def yield_supertypes():
|
def yield_supertypes():
|
||||||
decl = ifcopenshell_wrapper.schema_by_name(schema_name).declaration_by_name(self.is_a())
|
decl = ifcopenshell_wrapper.schema_by_name(schema_name).declaration_by_name(
|
||||||
|
self.is_a()
|
||||||
|
)
|
||||||
while decl:
|
while decl:
|
||||||
yield decl.name()
|
yield decl.name()
|
||||||
decl = decl.supertype()
|
decl = decl.supertype()
|
||||||
@@ -296,7 +303,9 @@ class entity_instance(object):
|
|||||||
elif None in (self.wrapped_data.file, other.wrapped_data.file):
|
elif None in (self.wrapped_data.file, other.wrapped_data.file):
|
||||||
# when not added to a file, we can only compare attribute values
|
# when not added to a file, we can only compare attribute values
|
||||||
# and we need this for where rule evaluation
|
# and we need this for where rule evaluation
|
||||||
return self.get_info(recursive=True, include_identifier=False) == other.get_info(recursive=True, include_identifier=False)
|
return self.get_info(
|
||||||
|
recursive=True, include_identifier=False
|
||||||
|
) == other.get_info(recursive=True, include_identifier=False)
|
||||||
else:
|
else:
|
||||||
# Proper entity instances have a stable identity by means of the numeric
|
# Proper entity instances have a stable identity by means of the numeric
|
||||||
# step id. Selected type instances (such as IfcPropertySingleValue.NominalValue
|
# step id. Selected type instances (such as IfcPropertySingleValue.NominalValue
|
||||||
@@ -310,6 +319,83 @@ class entity_instance(object):
|
|||||||
other.wrapped_data.file_pointer(),
|
other.wrapped_data.file_pointer(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def is_entity(self):
|
||||||
|
"""Tests whether the instance is an entity type as opposed to a simple data type.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the instance is an entity
|
||||||
|
"""
|
||||||
|
schema_name = self.wrapped_data.is_a(True).split(".")[0]
|
||||||
|
decl = ifcopenshell_wrapper.schema_by_name(schema_name).declaration_by_name(
|
||||||
|
self.is_a()
|
||||||
|
)
|
||||||
|
return isinstance(decl, ifcopenshell_wrapper.entity)
|
||||||
|
|
||||||
|
def compare(self, other, op, reverse=False):
|
||||||
|
"""Compares with another instance.
|
||||||
|
|
||||||
|
For simple types the declaration name is not taken into account:
|
||||||
|
|
||||||
|
>>> f = ifcopenshell.file()
|
||||||
|
>>> f.createIfcInteger(0) < f.createIfcPositiveInteger(1)
|
||||||
|
True
|
||||||
|
|
||||||
|
For entity types the declaration name is taken into account:
|
||||||
|
|
||||||
|
>>> f.createIfcWall('a') < f.createIfcWall('b')
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> f.createIfcWallStandardCase('a') < f.createIfcWall('b')
|
||||||
|
False
|
||||||
|
|
||||||
|
Comparing simple types with different underlying types throws an exception:
|
||||||
|
|
||||||
|
>>> f.createIfcInteger(0) < f.createIfcLabel('x')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
File "entity_instance.py", line 371, in compare
|
||||||
|
return op(a, b)
|
||||||
|
TypeError: '<' not supported between instances of 'int' and 'str'
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other (_type_): Right hand side (or lhs when reverse = True)
|
||||||
|
op (_type_): The comparison operator (likely from the operator module)
|
||||||
|
reverse (bool, optional): When true swaps lhs and rhs. Defaults to False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: The comparison predicate applied to self and other
|
||||||
|
"""
|
||||||
|
|
||||||
|
if isinstance(other, entity_instance):
|
||||||
|
a, b = map(tuple, (self, other))
|
||||||
|
if any(map(entity_instance.is_entity, (self, other))):
|
||||||
|
a = (self.is_a(),) + a
|
||||||
|
b = (other.is_a(),) + b
|
||||||
|
elif self.is_entity():
|
||||||
|
a = tuple(self)
|
||||||
|
b = other
|
||||||
|
if isinstance(b, list):
|
||||||
|
b = tuple(b)
|
||||||
|
if not isinstance(b, tuple):
|
||||||
|
b = (b,)
|
||||||
|
else:
|
||||||
|
a = self[0]
|
||||||
|
b = other
|
||||||
|
|
||||||
|
if reverse:
|
||||||
|
a, b = b, a
|
||||||
|
|
||||||
|
return op(a, b)
|
||||||
|
|
||||||
|
__le__ = functools.partialmethod(compare, op=operator.le)
|
||||||
|
__lt__ = functools.partialmethod(compare, op=operator.lt)
|
||||||
|
__ge__ = functools.partialmethod(compare, op=operator.ge)
|
||||||
|
__gt__ = functools.partialmethod(compare, op=operator.gt)
|
||||||
|
__rle__ = functools.partialmethod(compare, op=operator.le, reverse=True)
|
||||||
|
__rlt__ = functools.partialmethod(compare, op=operator.lt, reverse=True)
|
||||||
|
__rge__ = functools.partialmethod(compare, op=operator.ge, reverse=True)
|
||||||
|
__rgt__ = functools.partialmethod(compare, op=operator.gt, reverse=True)
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
# Proper entity instances have a stable identity by means of the numeric
|
# Proper entity instances have a stable identity by means of the numeric
|
||||||
# step id. Selected type instances (such as IfcPropertySingleValue.NominalValue
|
# step id. Selected type instances (such as IfcPropertySingleValue.NominalValue
|
||||||
|
|||||||
Reference in New Issue
Block a user