mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 23:36:20 +00:00
Rework memory mngmt
This commit is contained in:
@@ -71,7 +71,7 @@ except Exception as e:
|
|||||||
|
|
||||||
from . import guid
|
from . import guid
|
||||||
from .file import file
|
from .file import file
|
||||||
from .entity_instance import entity_instance, register_schema_attributes
|
from .entity_instance import entity_instance
|
||||||
from .sql import sqlite, sqlite_entity
|
from .sql import sqlite, sqlite_entity
|
||||||
try:
|
try:
|
||||||
from .stream import stream, stream_entity
|
from .stream import stream, stream_entity
|
||||||
@@ -171,7 +171,7 @@ def create_entity(type, schema="IFC4", *args, **kwargs):
|
|||||||
model = ifcopenshell.file()
|
model = ifcopenshell.file()
|
||||||
model.add(person) # #1=IfcPerson($,$,$,$,$,$,$,$)
|
model.add(person) # #1=IfcPerson($,$,$,$,$,$,$,$)
|
||||||
"""
|
"""
|
||||||
e = entity_instance((schema, type))
|
e = ifcopenshell_wrapper.make_instance(schema, type)
|
||||||
attrs = list(enumerate(args)) + [(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
|
attrs = list(enumerate(args)) + [(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
|
||||||
for idx, arg in attrs:
|
for idx, arg in attrs:
|
||||||
e[idx] = arg
|
e[idx] = arg
|
||||||
@@ -195,7 +195,6 @@ def register_schema(schema):
|
|||||||
schema.schema.this.disown()
|
schema.schema.this.disown()
|
||||||
schema.disown()
|
schema.disown()
|
||||||
ifcopenshell_wrapper.register_schema(schema.schema)
|
ifcopenshell_wrapper.register_schema(schema.schema)
|
||||||
register_schema_attributes(schema.schema)
|
|
||||||
|
|
||||||
|
|
||||||
def schema_by_name(
|
def schema_by_name(
|
||||||
|
|||||||
@@ -42,66 +42,8 @@ except ImportError as e:
|
|||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
# poor man's enum
|
||||||
def set_derived_attribute(*args):
|
ATTR_INVALID, ATTR_FORWARD, ATTR_INVERSE, ATTR_FORWARD_DERIVED = range(4)
|
||||||
raise TypeError("Unable to set derived attribute")
|
|
||||||
|
|
||||||
|
|
||||||
def set_unsupported_attribute(*args):
|
|
||||||
raise TypeError("This is an unsupported attribute type")
|
|
||||||
|
|
||||||
|
|
||||||
# For every schema and its entities populate a list
|
|
||||||
# of functions for every entity attribute (including
|
|
||||||
# inherited attributes) to set that particular
|
|
||||||
# attribute by index.
|
|
||||||
# For example. IFC2X3.IfcWall with have a list of
|
|
||||||
# 9 methods. The first will point at
|
|
||||||
# ifcopenshell.ifcopenshell_wrapper.entity_instance.setArgumentAsString
|
|
||||||
# because the first attribute GlobalId ultimately
|
|
||||||
# is of type string.
|
|
||||||
# Previously, resolving the appropriate function was
|
|
||||||
# done for each invocation of __setitem__. Now this
|
|
||||||
# mapping is built once during initialization of the
|
|
||||||
# module.
|
|
||||||
_method_dict = {}
|
|
||||||
|
|
||||||
|
|
||||||
def register_schema_attributes(schema):
|
|
||||||
for decl in schema.declarations():
|
|
||||||
if hasattr(decl, "argument_types"):
|
|
||||||
fq_name = ".".join((schema.name(), decl.name()))
|
|
||||||
|
|
||||||
# get type strings as reported by IfcOpenShell C++
|
|
||||||
type_strs = decl.argument_types()
|
|
||||||
|
|
||||||
# convert case for setter function
|
|
||||||
type_strs = [x.title().replace(" ", "") for x in type_strs]
|
|
||||||
|
|
||||||
# binary and enumeration are passed from python as string as well
|
|
||||||
type_strs = [x.replace("Binary", "String") for x in type_strs]
|
|
||||||
type_strs = [x.replace("Enumeration", "String") for x in type_strs]
|
|
||||||
|
|
||||||
# prefix to get method names
|
|
||||||
fn_names = ["setArgumentAs" + x for x in type_strs]
|
|
||||||
|
|
||||||
# resolve to actual functions in wrapper
|
|
||||||
functions = [
|
|
||||||
set_derived_attribute
|
|
||||||
if mname == "setArgumentAsDerived"
|
|
||||||
else set_unsupported_attribute
|
|
||||||
if mname == "setArgumentAsUnknown"
|
|
||||||
else getattr(ifcopenshell_wrapper.entity_instance, mname)
|
|
||||||
for mname in fn_names
|
|
||||||
]
|
|
||||||
|
|
||||||
_method_dict[fq_name] = functions
|
|
||||||
|
|
||||||
|
|
||||||
for nm in ifcopenshell_wrapper.schema_names():
|
|
||||||
schema = ifcopenshell_wrapper.schema_by_name(nm)
|
|
||||||
register_schema_attributes(schema)
|
|
||||||
|
|
||||||
|
|
||||||
class entity_instance(object):
|
class entity_instance(object):
|
||||||
"""Base class for all IFC objects.
|
"""Base class for all IFC objects.
|
||||||
@@ -120,44 +62,22 @@ class entity_instance(object):
|
|||||||
>>> #423=IfcProductDefinitionShape($,$,(#409,#421))
|
>>> #423=IfcProductDefinitionShape($,$,(#409,#421))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
wrapped_data: ifcopenshell_wrapper.entity_instance
|
|
||||||
|
|
||||||
def __init__(self, e, file=None):
|
|
||||||
if isinstance(e, tuple):
|
|
||||||
e = ifcopenshell_wrapper.new_IfcBaseClass(*e)
|
|
||||||
super(entity_instance, self).__setattr__("wrapped_data", e)
|
|
||||||
super(entity_instance, self).__setattr__("method_list", None)
|
|
||||||
|
|
||||||
# Make sure the file is not gc'ed while we have live instances
|
|
||||||
self.wrapped_data.file = file
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
"""
|
|
||||||
#2471 while the precise chain of action is unclear, creating
|
|
||||||
instance references prevents file gc, even with all instance
|
|
||||||
refs deleted. This is a work-around for that.
|
|
||||||
"""
|
|
||||||
self.wrapped_data.file = None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def file(self):
|
def file(self):
|
||||||
# ugh circular imports, name collisions
|
# ugh circular imports, name collisions
|
||||||
from . import file
|
from . import file
|
||||||
|
|
||||||
return file.from_pointer(self.wrapped_data.file_pointer())
|
return file.from_pointer(self.file_pointer())
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
INVALID, FORWARD, INVERSE = range(3)
|
attr_cat = self.get_attribute_category(name)
|
||||||
attr_cat = self.wrapped_data.get_attribute_category(name)
|
if attr_cat == ATTR_FORWARD:
|
||||||
if attr_cat == FORWARD:
|
idx = self.get_argument_index(name)
|
||||||
idx = self.wrapped_data.get_argument_index(name)
|
return self.get_argument(idx)
|
||||||
if _method_dict[self.is_a(True)][idx] != set_derived_attribute:
|
elif attr_cat == ATTR_INVERSE:
|
||||||
# A bit ugly, but we fall through to derived attribute handling below
|
vs = self.get_inverse(name)
|
||||||
return entity_instance.wrap_value(self.wrapped_data.get_argument(idx), self.wrapped_data.file)
|
|
||||||
elif attr_cat == INVERSE:
|
|
||||||
vs = entity_instance.wrap_value(self.wrapped_data.get_inverse(name), self.wrapped_data.file)
|
|
||||||
if settings.unpack_non_aggregate_inverses:
|
if settings.unpack_non_aggregate_inverses:
|
||||||
schema_name = self.wrapped_data.is_a(True).split(".")[0]
|
schema_name = self.is_a(True).split(".")[0]
|
||||||
ent = ifcopenshell_wrapper.schema_by_name(schema_name).declaration_by_name(self.is_a())
|
ent = ifcopenshell_wrapper.schema_by_name(schema_name).declaration_by_name(self.is_a())
|
||||||
inv = [i for i in ent.all_inverse_attributes() if i.name() == name][0]
|
inv = [i for i in ent.all_inverse_attributes() if i.name() == name][0]
|
||||||
if (inv.bound1(), inv.bound2()) == (-1, -1):
|
if (inv.bound1(), inv.bound2()) == (-1, -1):
|
||||||
@@ -166,9 +86,9 @@ class entity_instance(object):
|
|||||||
else:
|
else:
|
||||||
vs = None
|
vs = None
|
||||||
return vs
|
return vs
|
||||||
|
|
||||||
# derived attribute perhaps?
|
# derived attribute perhaps?
|
||||||
schema_name = self.wrapped_data.is_a(True).split(".")[0]
|
schema_name = self.is_a(True).split(".")[0]
|
||||||
try:
|
try:
|
||||||
rules = importlib.import_module(f"ifcopenshell.express.rules.{schema_name}")
|
rules = importlib.import_module(f"ifcopenshell.express.rules.{schema_name}")
|
||||||
except:
|
except:
|
||||||
@@ -180,21 +100,21 @@ class entity_instance(object):
|
|||||||
subprocess.run([sys.executable, "-m", "ifcopenshell.express.rule_compiler", schema_path, fn], check=True)
|
subprocess.run([sys.executable, "-m", "ifcopenshell.express.rule_compiler", schema_path, fn], check=True)
|
||||||
time.sleep(1.)
|
time.sleep(1.)
|
||||||
rules = importlib.import_module(schema_name)
|
rules = importlib.import_module(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()
|
||||||
|
|
||||||
for sty in yield_supertypes():
|
for sty in yield_supertypes():
|
||||||
fn = getattr(rules, f"calc_{sty}_{name}", None)
|
fn = getattr(rules, f"calc_{sty}_{name}", None)
|
||||||
if fn:
|
if fn:
|
||||||
return fn(self)
|
return fn(self)
|
||||||
|
|
||||||
if attr_cat != FORWARD:
|
if attr_cat != FORWARD:
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
"entity instance of type '%s' has no attribute '%s'" % (self.wrapped_data.is_a(True), name)
|
"entity instance of type '%s' has no attribute '%s'" % (self.is_a(True), name)
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -235,26 +155,6 @@ class entity_instance(object):
|
|||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def wrap_value(v, file):
|
|
||||||
def wrap(e):
|
|
||||||
return entity_instance(e, file)
|
|
||||||
|
|
||||||
def is_instance(e):
|
|
||||||
return isinstance(e, ifcopenshell_wrapper.entity_instance)
|
|
||||||
|
|
||||||
return entity_instance.walk(is_instance, wrap, v)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def unwrap_value(v):
|
|
||||||
def unwrap(e):
|
|
||||||
return e.wrapped_data
|
|
||||||
|
|
||||||
def is_instance(e):
|
|
||||||
return isinstance(e, entity_instance)
|
|
||||||
|
|
||||||
return entity_instance.walk(is_instance, unwrap, v)
|
|
||||||
|
|
||||||
def attribute_type(self, attr: int) -> str:
|
def attribute_type(self, attr: int) -> str:
|
||||||
"""Return the data type of a positional attribute of the element
|
"""Return the data type of a positional attribute of the element
|
||||||
|
|
||||||
@@ -262,8 +162,8 @@ class entity_instance(object):
|
|||||||
:type attr: int
|
:type attr: int
|
||||||
:rtype: string
|
:rtype: string
|
||||||
"""
|
"""
|
||||||
attr_idx = attr if isinstance(attr, numbers.Integral) else self.wrapped_data.get_argument_index(attr)
|
attr_idx = attr if isinstance(attr, numbers.Integral) else self.get_argument_index(attr)
|
||||||
return self.wrapped_data.get_argument_type(attr_idx)
|
return self.get_argument_type(attr_idx)
|
||||||
|
|
||||||
def attribute_name(self, attr_idx: int) -> str:
|
def attribute_name(self, attr_idx: int) -> str:
|
||||||
"""Return the name of a positional attribute of the element
|
"""Return the name of a positional attribute of the element
|
||||||
@@ -272,37 +172,28 @@ class entity_instance(object):
|
|||||||
:type attr_idx: int
|
:type attr_idx: int
|
||||||
:rtype: string
|
:rtype: string
|
||||||
"""
|
"""
|
||||||
return self.wrapped_data.get_argument_name(attr_idx)
|
return self.get_argument_name(attr_idx)
|
||||||
|
|
||||||
def __setattr__(self, key: str, value: Any) -> None:
|
def __setattr__(self, key: str, value: Any) -> None:
|
||||||
index = self.wrapped_data.get_argument_index(key)
|
index = self.get_argument_index(key)
|
||||||
self[index] = value
|
self[index] = value
|
||||||
|
|
||||||
def __getitem__(self, key: int) -> Any:
|
def __getitem__(self, key: int) -> Any:
|
||||||
if key < 0 or key >= len(self):
|
if key < 0 or key >= len(self):
|
||||||
raise IndexError("Attribute index {} out of range for instance of type {}".format(key, self.is_a()))
|
raise IndexError("Attribute index {} out of range for instance of type {}".format(key, self.is_a()))
|
||||||
return entity_instance.wrap_value(self.wrapped_data.get_argument(key), self.wrapped_data.file)
|
return self.get_argument(key)
|
||||||
|
|
||||||
def __setitem__(self, idx: int, value: T) -> T:
|
def __setitem__(self, idx: int, value: T) -> T:
|
||||||
if self.wrapped_data.file and self.wrapped_data.file.transaction:
|
if self.file and self.file.transaction:
|
||||||
self.wrapped_data.file.transaction.store_edit(self, idx, value)
|
self.file.transaction.store_edit(self, idx, value)
|
||||||
|
|
||||||
if self.method_list is None:
|
self.setAttribute(idx, value)
|
||||||
super(entity_instance, self).__setattr__("method_list", _method_dict[self.is_a(True)])
|
|
||||||
|
|
||||||
method = self.method_list[idx]
|
|
||||||
|
|
||||||
if value is None:
|
|
||||||
if method is not set_derived_attribute:
|
|
||||||
self.wrapped_data.setArgumentAsNull(idx)
|
|
||||||
else:
|
|
||||||
self.method_list[idx](self.wrapped_data, idx, entity_instance.unwrap_value(value))
|
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.wrapped_data)
|
return len(self.wrapped_data)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return repr(self.wrapped_data)
|
return repr(self.wrapped_data)
|
||||||
|
|
||||||
@@ -315,7 +206,7 @@ class entity_instance(object):
|
|||||||
the specific control directives.
|
the specific control directives.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return self.wrapped_data.to_string(valid_spf)
|
return self.to_string(valid_spf)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def is_a(self) -> str: ...
|
def is_a(self) -> str: ...
|
||||||
@@ -348,19 +239,19 @@ class entity_instance(object):
|
|||||||
f.is_a('IfcPerson')
|
f.is_a('IfcPerson')
|
||||||
>>> True
|
>>> True
|
||||||
"""
|
"""
|
||||||
return self.wrapped_data.is_a(*args)
|
return self.is_a(*args)
|
||||||
|
|
||||||
def id(self) -> int:
|
def id(self) -> int:
|
||||||
"""Return the STEP numerical identifier
|
"""Return the STEP numerical identifier
|
||||||
|
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
return self.wrapped_data.id()
|
return self.id()
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if not isinstance(self, type(other)):
|
if not isinstance(self, type(other)):
|
||||||
return False
|
return False
|
||||||
elif None in (self.wrapped_data.file, other.wrapped_data.file):
|
elif None in (self.file, other.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(
|
return self.get_info(recursive=True, include_identifier=False) == other.get_info(
|
||||||
@@ -373,10 +264,10 @@ class entity_instance(object):
|
|||||||
if self.id():
|
if self.id():
|
||||||
return self.wrapped_data == other.wrapped_data
|
return self.wrapped_data == other.wrapped_data
|
||||||
else:
|
else:
|
||||||
return (self.is_a(), self[0], self.wrapped_data.file_pointer()) == (
|
return (self.is_a(), self[0], self.file_pointer()) == (
|
||||||
other.is_a(),
|
other.is_a(),
|
||||||
other[0],
|
other[0],
|
||||||
other.wrapped_data.file_pointer(),
|
other.file_pointer(),
|
||||||
)
|
)
|
||||||
|
|
||||||
def is_entity(self) -> bool:
|
def is_entity(self) -> bool:
|
||||||
@@ -385,7 +276,7 @@ class entity_instance(object):
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True if the instance is an entity
|
bool: True if the instance is an entity
|
||||||
"""
|
"""
|
||||||
schema_name = self.wrapped_data.is_a(True).split(".")[0]
|
schema_name = self.is_a(True).split(".")[0]
|
||||||
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())
|
||||||
return isinstance(decl, ifcopenshell_wrapper.entity)
|
return isinstance(decl, ifcopenshell_wrapper.entity)
|
||||||
|
|
||||||
@@ -459,17 +350,17 @@ class entity_instance(object):
|
|||||||
# step id. Selected type instances (such as IfcPropertySingleValue.NominalValue
|
# step id. Selected type instances (such as IfcPropertySingleValue.NominalValue
|
||||||
# always have id=0, so we hash <type, value, file pointer>
|
# always have id=0, so we hash <type, value, file pointer>
|
||||||
if self.id():
|
if self.id():
|
||||||
return hash((self.id(), self.wrapped_data.file_pointer()))
|
return hash((self.id(), self.file_pointer()))
|
||||||
else:
|
else:
|
||||||
return hash((self.is_a(), self[0], self.wrapped_data.file_pointer()))
|
return hash((self.is_a(), self[0], self.file_pointer()))
|
||||||
|
|
||||||
def __dir__(self):
|
def __dir__(self):
|
||||||
return sorted(
|
return sorted(
|
||||||
set(
|
set(
|
||||||
itertools.chain(
|
itertools.chain(
|
||||||
dir(type(self)),
|
dir(type(self)),
|
||||||
map(str, self.wrapped_data.get_attribute_names()),
|
map(str, self.get_attribute_names()),
|
||||||
map(str, self.wrapped_data.get_inverse_attribute_names()),
|
map(str, self.get_inverse_attribute_names()),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -513,7 +404,7 @@ class entity_instance(object):
|
|||||||
logging.exception("unhandled exception while getting id / type info on {}".format(self))
|
logging.exception("unhandled exception while getting id / type info on {}".format(self))
|
||||||
for i in range(len(self)):
|
for i in range(len(self)):
|
||||||
try:
|
try:
|
||||||
if self.wrapped_data.get_attribute_names()[i] in ignore:
|
if self.get_attribute_names()[i] in ignore:
|
||||||
continue
|
continue
|
||||||
attr_value = self[i]
|
attr_value = self[i]
|
||||||
|
|
||||||
@@ -548,7 +439,8 @@ class entity_instance(object):
|
|||||||
|
|
||||||
return return_type(_())
|
return return_type(_())
|
||||||
|
|
||||||
__dict__ = property(get_info)
|
# @todo this is no longer possible with the direct integration into the swig type
|
||||||
|
# __dict__ = property(get_info)
|
||||||
|
|
||||||
def get_info_2(self, include_identifier=True, recursive=False, return_type=dict, ignore=()):
|
def get_info_2(self, include_identifier=True, recursive=False, return_type=dict, ignore=()):
|
||||||
"""More perfomant version of `.get_info()` but with limited arguments values.\n
|
"""More perfomant version of `.get_info()` but with limited arguments values.\n
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ class file(object):
|
|||||||
"""
|
"""
|
||||||
eid = kwargs.pop("id", -1)
|
eid = kwargs.pop("id", -1)
|
||||||
|
|
||||||
e = entity_instance((self.schema_identifier, type), self)
|
e = ifcopenshell_wrapper.make_instance(self.schema_identifier, type)
|
||||||
|
|
||||||
# Create pairs of {attribute index, attribute value}.
|
# Create pairs of {attribute index, attribute value}.
|
||||||
# Keyword arguments are mapped to their corresponding
|
# Keyword arguments are mapped to their corresponding
|
||||||
@@ -337,7 +337,7 @@ class file(object):
|
|||||||
# @todo we should probably check that values for
|
# @todo we should probably check that values for
|
||||||
# attributes are not passed as duplicates using
|
# attributes are not passed as duplicates using
|
||||||
# both regular arguments and keyword arguments.
|
# both regular arguments and keyword arguments.
|
||||||
attrs = list(enumerate(args)) + [(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
|
attrs = list(enumerate(args)) + [(e.get_argument_index(name), arg) for name, arg in kwargs.items()]
|
||||||
|
|
||||||
# Don't store these attributes as transactions
|
# Don't store these attributes as transactions
|
||||||
# as the creation it self is already stored with
|
# as the creation it self is already stored with
|
||||||
@@ -353,14 +353,13 @@ class file(object):
|
|||||||
if attrs:
|
if attrs:
|
||||||
self.transaction = transaction
|
self.transaction = transaction
|
||||||
|
|
||||||
# Once the values are populated add the instance
|
# Once the values are populated move the instance
|
||||||
# to the file.
|
# to the file.
|
||||||
self.wrapped_data.add(e.wrapped_data, eid)
|
e = self.wrapped_data.add(e, eid)
|
||||||
|
|
||||||
# The file container now handles the lifetime of
|
# The file container now handles the lifetime of
|
||||||
# this instance. Tell SWIG that it is no longer
|
# this instance. Tell SWIG that it is no longer
|
||||||
# the owner.
|
# the owner.
|
||||||
e.wrapped_data.this.disown()
|
|
||||||
|
|
||||||
if self.transaction:
|
if self.transaction:
|
||||||
self.transaction.store_create(e)
|
self.transaction.store_create(e)
|
||||||
@@ -398,9 +397,9 @@ class file(object):
|
|||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
if isinstance(key, numbers.Integral):
|
if isinstance(key, numbers.Integral):
|
||||||
return entity_instance(self.wrapped_data.by_id(key), self)
|
return self.wrapped_data.by_id(key)
|
||||||
elif isinstance(key, basestring):
|
elif isinstance(key, basestring):
|
||||||
return entity_instance(self.wrapped_data.by_guid(str(key)), self)
|
return self.wrapped_data.by_guid(str(key))
|
||||||
|
|
||||||
def by_id(self, id: int) -> ifcopenshell.entity_instance:
|
def by_id(self, id: int) -> ifcopenshell.entity_instance:
|
||||||
"""Return an IFC entity instance filtered by IFC ID.
|
"""Return an IFC entity instance filtered by IFC ID.
|
||||||
@@ -441,8 +440,8 @@ class file(object):
|
|||||||
|
|
||||||
if self.transaction:
|
if self.transaction:
|
||||||
max_id = self.wrapped_data.getMaxId()
|
max_id = self.wrapped_data.getMaxId()
|
||||||
inst.wrapped_data.this.disown()
|
# inst.wrapped_data.this.disown()
|
||||||
result = entity_instance(self.wrapped_data.add(inst.wrapped_data, -1 if _id is None else _id), self)
|
result = self.wrapped_data.add(inst, -1 if _id is None else _id)
|
||||||
if self.transaction:
|
if self.transaction:
|
||||||
added_elements = [e for e in self.traverse(result) if e.id() > max_id]
|
added_elements = [e for e in self.traverse(result) if e.id() > max_id]
|
||||||
[self.transaction.store_create(e) for e in reversed(added_elements)]
|
[self.transaction.store_create(e) for e in reversed(added_elements)]
|
||||||
@@ -461,8 +460,8 @@ class file(object):
|
|||||||
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
||||||
"""
|
"""
|
||||||
if include_subtypes:
|
if include_subtypes:
|
||||||
return [entity_instance(e, self) for e in self.wrapped_data.by_type(type)]
|
return self.wrapped_data.by_type(type)
|
||||||
return [entity_instance(e, self) for e in self.wrapped_data.by_type_excl_subtypes(type)]
|
return self.wrapped_data.by_type_excl_subtypes(type)
|
||||||
|
|
||||||
def traverse(
|
def traverse(
|
||||||
self, inst: ifcopenshell.entity_instance, max_levels=None, breadth_first=False
|
self, inst: ifcopenshell.entity_instance, max_levels=None, breadth_first=False
|
||||||
@@ -486,7 +485,7 @@ class file(object):
|
|||||||
else:
|
else:
|
||||||
fn = self.wrapped_data.traverse
|
fn = self.wrapped_data.traverse
|
||||||
|
|
||||||
return [entity_instance(e, self) for e in fn(inst.wrapped_data, max_levels)]
|
return fn(inst, max_levels)
|
||||||
|
|
||||||
def get_inverse(
|
def get_inverse(
|
||||||
self, inst: ifcopenshell.entity_instance, allow_duplicate=False, with_attribute_indices=False
|
self, inst: ifcopenshell.entity_instance, allow_duplicate=False, with_attribute_indices=False
|
||||||
@@ -504,11 +503,11 @@ class file(object):
|
|||||||
if with_attribute_indices and not allow_duplicate:
|
if with_attribute_indices and not allow_duplicate:
|
||||||
raise ValueError("with_attribute_indices requires allow_duplicate to be True")
|
raise ValueError("with_attribute_indices requires allow_duplicate to be True")
|
||||||
|
|
||||||
inverses = [entity_instance(e, self) for e in self.wrapped_data.get_inverse(inst.wrapped_data)]
|
inverses = self.wrapped_data.get_inverse(inst)
|
||||||
|
|
||||||
if allow_duplicate:
|
if allow_duplicate:
|
||||||
if with_attribute_indices:
|
if with_attribute_indices:
|
||||||
idxs = self.wrapped_data.get_inverse_indices(inst.wrapped_data)
|
idxs = self.wrapped_data.get_inverse_indices(inst)
|
||||||
return list(zip(inverses, idxs))
|
return list(zip(inverses, idxs))
|
||||||
else:
|
else:
|
||||||
return inverses
|
return inverses
|
||||||
@@ -523,7 +522,7 @@ class file(object):
|
|||||||
:returns: The total number of references
|
:returns: The total number of references
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
return self.wrapped_data.get_total_inverses(inst.wrapped_data)
|
return self.wrapped_data.get_total_inverses(inst)
|
||||||
|
|
||||||
def remove(self, inst: ifcopenshell.entity_instance) -> None:
|
def remove(self, inst: ifcopenshell.entity_instance) -> None:
|
||||||
"""Deletes an IFC object in the file.
|
"""Deletes an IFC object in the file.
|
||||||
@@ -538,7 +537,7 @@ class file(object):
|
|||||||
"""
|
"""
|
||||||
if self.transaction:
|
if self.transaction:
|
||||||
self.transaction.store_delete(inst)
|
self.transaction.store_delete(inst)
|
||||||
return self.wrapped_data.remove(inst.wrapped_data)
|
return self.wrapped_data.remove(inst)
|
||||||
|
|
||||||
def batch(self):
|
def batch(self):
|
||||||
"""Low-level mechanism to speed up deletion of large subgraphs"""
|
"""Low-level mechanism to speed up deletion of large subgraphs"""
|
||||||
@@ -605,4 +604,4 @@ class file(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_pointer(v):
|
def from_pointer(v):
|
||||||
return file_dict.get(v)()
|
return file_dict.get(v)() if v else None
|
||||||
|
|||||||
@@ -1902,8 +1902,6 @@ IfcFile::instance_storage_type IfcFile::addEntity(IfcUtil::IfcBaseClass* entity,
|
|||||||
return mit->second;
|
return mit->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance_storage_type new_entity = instance_storage_type(entity);
|
|
||||||
|
|
||||||
// Obtain all forward references by a depth-first
|
// Obtain all forward references by a depth-first
|
||||||
// traversal and add them to the file.
|
// traversal and add them to the file.
|
||||||
if (parsing_complete_) {
|
if (parsing_complete_) {
|
||||||
@@ -1922,12 +1920,17 @@ IfcFile::instance_storage_type IfcFile::addEntity(IfcUtil::IfcBaseClass* entity,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instance_storage_type new_entity;
|
||||||
|
|
||||||
// See whether the instance is already part of a file
|
// See whether the instance is already part of a file
|
||||||
if (entity->data().file != 0) {
|
if (entity->data().file == 0) {
|
||||||
|
// We can simply wrap it into a new smart pointer
|
||||||
|
new_entity = instance_storage_type(entity);
|
||||||
|
} else {
|
||||||
if (entity->data().file == this) {
|
if (entity->data().file == this) {
|
||||||
if (entity->declaration().as_entity() == nullptr) {
|
if (entity->declaration().as_entity() == nullptr) {
|
||||||
// While not a mapping that can be queried, we do need to free the instance later on
|
// While not a mapping that can be queried, we do need to free the instance later on
|
||||||
byidentity_[new_entity->identity()] = new_entity;
|
byidentity_[entity->identity()] = instance_storage_type(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it is part of this file
|
// If it is part of this file
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS})
|
|||||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
SET(CMAKE_SWIG_FLAGS ${SWIG_DEFINES})
|
SET(CMAKE_SWIG_FLAGS ${SWIG_DEFINES})
|
||||||
|
|
||||||
|
# track file modifications to reinvoke swig wrapper code gen
|
||||||
|
set(USE_SWIG_DEPENDENCIES TRUE)
|
||||||
|
|
||||||
# NOTE Workaround for most likely missing debug Python libraries on Windows (requires Python built from the source).
|
# NOTE Workaround for most likely missing debug Python libraries on Windows (requires Python built from the source).
|
||||||
# Python 3.5 intaller and onwards will have an option to install the debug libraries too.
|
# Python 3.5 intaller and onwards will have an option to install the debug libraries too.
|
||||||
# NOTE PYTHON_DEBUG_LIBRARIES appears to be a deprecated variable
|
# NOTE PYTHON_DEBUG_LIBRARIES appears to be a deprecated variable
|
||||||
@@ -68,6 +72,15 @@ endif()
|
|||||||
# directory in which the wrapper can be installed.
|
# directory in which the wrapper can be installed.
|
||||||
FIND_PACKAGE(PythonInterp)
|
FIND_PACKAGE(PythonInterp)
|
||||||
IF((PYTHONINTERP_FOUND AND NOT "${PYTHON_EXECUTABLE}" STREQUAL "") OR PYTHON_MODULE_INSTALL_DIR)
|
IF((PYTHONINTERP_FOUND AND NOT "${PYTHON_EXECUTABLE}" STREQUAL "") OR PYTHON_MODULE_INSTALL_DIR)
|
||||||
|
# Find Python interpreter and get its version
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))"
|
||||||
|
OUTPUT_VARIABLE PYTHON_EXTENSION_SUFFIX
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(${SWIG_MODULE_ifcopenshell_wrapper_REAL_NAME} PROPERTIES SUFFIX ${PYTHON_EXTENSION_SUFFIX})
|
||||||
|
|
||||||
if (PYTHON_MODULE_INSTALL_DIR)
|
if (PYTHON_MODULE_INSTALL_DIR)
|
||||||
set(python_package_dir "${PYTHON_MODULE_INSTALL_DIR}")
|
set(python_package_dir "${PYTHON_MODULE_INSTALL_DIR}")
|
||||||
else()
|
else()
|
||||||
|
|||||||
@@ -587,13 +587,6 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
|||||||
%}
|
%}
|
||||||
};
|
};
|
||||||
|
|
||||||
%extend IfcGeom::Matrix {
|
|
||||||
%pythoncode %{
|
|
||||||
# Hide the getters with read-only property implementations
|
|
||||||
data = property(data)
|
|
||||||
%}
|
|
||||||
};
|
|
||||||
|
|
||||||
%{
|
%{
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::string to_locale_invariant_string(const T& t) {
|
std::string to_locale_invariant_string(const T& t) {
|
||||||
|
|||||||
+378
-231
@@ -50,10 +50,15 @@ private:
|
|||||||
%ignore IfcParse::IfcFile::instances_by_type;
|
%ignore IfcParse::IfcFile::instances_by_type;
|
||||||
%ignore IfcParse::IfcFile::instances_by_type_excl_subtypes;
|
%ignore IfcParse::IfcFile::instances_by_type_excl_subtypes;
|
||||||
|
|
||||||
%rename("file") IfcFile;
|
|
||||||
%ignore IfcParse::IfcFile::addEntity;
|
%ignore IfcParse::IfcFile::addEntity;
|
||||||
|
%ignore IfcParse::IfcFile::addEntities;
|
||||||
%ignore IfcParse::IfcFile::removeEntity;
|
%ignore IfcParse::IfcFile::removeEntity;
|
||||||
|
|
||||||
|
%ignore IfcParse::IfcFile;
|
||||||
|
%ignore IfcUtil::IfcBaseClass;
|
||||||
|
%ignore IfcUtil::IfcBaseEntity;
|
||||||
|
%ignore IfcUtil::IfcBaseInterface;
|
||||||
|
|
||||||
class attribute_value_derived {};
|
class attribute_value_derived {};
|
||||||
%{
|
%{
|
||||||
class attribute_value_derived {};
|
class attribute_value_derived {};
|
||||||
@@ -87,65 +92,190 @@ PyObject* get_feature(const std::string& x) {
|
|||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%ignore entity_instance::entity_instance;
|
||||||
|
|
||||||
%{
|
%{
|
||||||
class entity_instance;
|
class entity_instance;
|
||||||
const std::string& helper_fn_declaration_get_name(const IfcParse::declaration* decl);
|
const std::string& helper_fn_declaration_get_name(const IfcParse::declaration* decl);
|
||||||
IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsigned i);
|
IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsigned i);
|
||||||
|
bool check_aggregate_of_type(PyObject* aggregate, void* type_obj);
|
||||||
|
bool check_aggregate_of_aggregate_of_type(PyObject* aggregate, void* type_obj);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%pythoncode %{
|
||||||
|
### hack hack hack
|
||||||
|
### we trick swig into inheriting from our own extension class
|
||||||
|
### that way we do not constantly need to decorate/undecorate
|
||||||
|
# @todo is there no official way to do this?
|
||||||
|
_old_object = _object
|
||||||
|
from .entity_instance import entity_instance as custom_base
|
||||||
|
_object = custom_base
|
||||||
|
%}
|
||||||
|
|
||||||
|
%include "utils/type_conversion.i"
|
||||||
|
%include "utils/typemaps_in.i"
|
||||||
|
%include "utils/typemaps_out.i"
|
||||||
|
|
||||||
%inline %{
|
%inline %{
|
||||||
class entity_instance {
|
class entity_instance {
|
||||||
boost::variant<
|
boost::variant<
|
||||||
IfcParse::IfcFile::instance_storage_type,
|
IfcUtil::IfcBaseClass*,
|
||||||
std::weak_ptr<IfcUtil::IfcBaseClass>
|
std::weak_ptr<IfcUtil::IfcBaseClass>,
|
||||||
|
boost::blank
|
||||||
> data_;
|
> data_;
|
||||||
|
std::shared_ptr<IfcParse::IfcFile> file_;
|
||||||
|
|
||||||
struct visitor {
|
struct visitor {
|
||||||
IfcParse::IfcFile::instance_storage_type operator()(const IfcParse::IfcFile::instance_storage_type& t) {
|
const IfcUtil::IfcBaseClass* const operator()(const IfcUtil::IfcBaseClass* const & t) {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
IfcParse::IfcFile::instance_storage_type operator()(const std::weak_ptr<IfcUtil::IfcBaseClass>& t) {
|
const IfcUtil::IfcBaseClass* const operator()(const std::weak_ptr<IfcUtil::IfcBaseClass>& t) {
|
||||||
auto u = t.lock();
|
auto u = t.lock();
|
||||||
if (u) {
|
if (u) {
|
||||||
return u;
|
// @todo this is not really safe, nor ideal as we don't retain the scope
|
||||||
|
// until used.
|
||||||
|
return &*u;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("No longer availabe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IfcUtil::IfcBaseClass* operator()(boost::blank) {
|
||||||
|
throw std::runtime_error("No longer availabe");
|
||||||
|
}
|
||||||
|
IfcUtil::IfcBaseClass* operator()(IfcUtil::IfcBaseClass* & t) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
IfcUtil::IfcBaseClass* operator()(std::weak_ptr<IfcUtil::IfcBaseClass>& t) {
|
||||||
|
auto u = t.lock();
|
||||||
|
if (u) {
|
||||||
|
// @todo this is not really safe, nor ideal as we don't retain the scope
|
||||||
|
// until used.
|
||||||
|
return &*u;
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("No longer availabe");
|
throw std::runtime_error("No longer availabe");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
entity_instance(const IfcParse::IfcFile::instance_storage_type& shared)
|
entity_instance(
|
||||||
|
const IfcParse::IfcFile::instance_storage_type& shared,
|
||||||
|
const std::shared_ptr<IfcParse::IfcFile>& file
|
||||||
|
)
|
||||||
: data_(std::weak_ptr<IfcUtil::IfcBaseClass>(shared))
|
: data_(std::weak_ptr<IfcUtil::IfcBaseClass>(shared))
|
||||||
{}
|
, file_(file)
|
||||||
|
{
|
||||||
|
std::cout << "init " << this << " " << data_.which() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
entity_instance(IfcUtil::IfcBaseClass* naked)
|
entity_instance(IfcUtil::IfcBaseClass* naked)
|
||||||
: data_(IfcParse::IfcFile::instance_storage_type(naked))
|
: data_(naked)
|
||||||
{}
|
{
|
||||||
|
std::cout << "init " << this << " " << data_.which() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
operator IfcUtil::IfcBaseClass*() const {
|
~entity_instance() {
|
||||||
return &*boost::apply_visitor(visitor{}, data_);
|
if (data_.which() == 0) {
|
||||||
|
delete (const IfcUtil::IfcBaseClass*)*this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IfcUtil::IfcBaseClass* move() {
|
||||||
|
auto old = i();
|
||||||
|
data_ = boost::blank{};
|
||||||
|
std::cout << "reset " << this << " " << data_.which() << std::endl;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_instance(const entity_instance&) = delete;
|
||||||
|
entity_instance& operator=(const entity_instance&) = delete;
|
||||||
|
|
||||||
|
operator const IfcUtil::IfcBaseClass*() const {
|
||||||
|
std::cout << "visit" << this << std::endl;
|
||||||
|
return boost::apply_visitor(visitor{}, data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const IfcUtil::IfcBaseClass* i() const {
|
||||||
|
std::cout << "visit" << this << std::endl;
|
||||||
|
return boost::apply_visitor(visitor{}, data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator IfcUtil::IfcBaseClass*() {
|
||||||
|
std::cout << "visit" << this << std::endl;
|
||||||
|
return boost::apply_visitor(visitor{}, data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
IfcUtil::IfcBaseClass* i() {
|
||||||
|
std::cout << "visit" << this << std::endl;
|
||||||
|
return boost::apply_visitor(visitor{}, data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IfcParse::declaration& declaration() const {
|
const IfcParse::declaration& declaration() const {
|
||||||
|
std::cout << "visit" << this << std::endl;
|
||||||
return boost::apply_visitor(visitor{}, data_)->declaration();
|
return boost::apply_visitor(visitor{}, data_)->declaration();
|
||||||
}
|
}
|
||||||
|
|
||||||
const IfcEntityInstanceData& data() const {
|
const IfcEntityInstanceData& data() const {
|
||||||
|
std::cout << "visit" << this << std::endl;
|
||||||
return boost::apply_visitor(visitor{}, data_)->data();
|
return boost::apply_visitor(visitor{}, data_)->data();
|
||||||
}
|
}
|
||||||
|
|
||||||
IfcEntityInstanceData& data() {
|
IfcEntityInstanceData& data() {
|
||||||
|
std::cout << "visit" << this << std::endl;
|
||||||
return boost::apply_visitor(visitor{}, data_)->data();
|
return boost::apply_visitor(visitor{}, data_)->data();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t identity() const {
|
uint32_t identity() const {
|
||||||
|
std::cout << "visit" << this << std::endl;
|
||||||
return boost::apply_visitor(visitor{}, data_)->identity();
|
return boost::apply_visitor(visitor{}, data_)->identity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<IfcParse::IfcFile>& file_pointer() const {
|
||||||
|
return file_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%pythoncode %{
|
||||||
|
### hack hack hack
|
||||||
|
### restore
|
||||||
|
_object = _old_object
|
||||||
|
%}
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
// Using swig's builtin shared_ptr() feature does not work,
|
||||||
|
// because we wouldn't actually get access to this pointer
|
||||||
|
// in extend() calls, which is need to propagate the shared_ptr
|
||||||
|
// control block to the references to it in dependent instances.
|
||||||
|
class file {
|
||||||
|
private:
|
||||||
|
std::shared_ptr<IfcParse::IfcFile> ptr_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
file()
|
||||||
|
: ptr_(new IfcParse::IfcFile)
|
||||||
|
{}
|
||||||
|
|
||||||
|
IfcParse::IfcFile& operator* ()
|
||||||
|
{
|
||||||
|
return *ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
IfcParse::IfcFile* operator-> ()
|
||||||
|
{
|
||||||
|
return &*ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator const std::shared_ptr<IfcParse::IfcFile>&() const {
|
||||||
|
return ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string __repr__() const {
|
||||||
|
return "ifcopenshell.file object at " + std::to_string(reinterpret_cast<size_t>(ptr_.get()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
%}
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|
||||||
const std::string& helper_fn_declaration_get_name(const IfcParse::declaration* decl) {
|
const std::string& helper_fn_declaration_get_name(const IfcParse::declaration* decl) {
|
||||||
@@ -174,100 +304,102 @@ IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsi
|
|||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%extend IfcParse::IfcFile {
|
%extend file {
|
||||||
// Use to correlate to entity_instance.file_pointer, so that we
|
// Use to correlate to entity_instance.file_pointer, so that we
|
||||||
// can trace file ownership of instances on the python side.
|
// can trace file ownership of instances on the python side.
|
||||||
size_t file_pointer() const {
|
size_t file_pointer() {
|
||||||
return reinterpret_cast<size_t>($self);
|
return reinterpret_cast<size_t>(&**self);
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_instance by_guid(const std::string& guid) {
|
entity_instance* by_guid(const std::string& guid) {
|
||||||
return $self->instance_by_guid(guid);
|
return new entity_instance((*$self)->instance_by_guid(guid), (*$self));
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_instance by_id(int i) {
|
entity_instance* by_id(int i) {
|
||||||
return $self->instance_by_id_2(i);
|
return new entity_instance((*$self)->instance_by_id_2(i), (*$self));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<entity_instance> by_type(const std::string& ty) {
|
std::vector<entity_instance*> by_type(const std::string& ty) {
|
||||||
std::vector<entity_instance> vec;
|
std::vector<entity_instance*> vec;
|
||||||
auto range = $self->instances_by_type_range(ty);
|
auto range = (*$self)->instances_by_type_range(ty);
|
||||||
for (auto& inst : boost::make_iterator_range(range)) {
|
for (auto& inst : boost::make_iterator_range(range)) {
|
||||||
vec.push_back(inst);
|
vec.push_back(new entity_instance(inst, *$self));
|
||||||
}
|
}
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<entity_instance> by_type_excl_subtypes(const std::string& ty) {
|
std::vector<entity_instance*> by_type_excl_subtypes(const std::string& ty) {
|
||||||
std::vector<entity_instance> vec;
|
std::vector<entity_instance*> vec;
|
||||||
auto range = $self->instances_by_type_excl_subtypes_range(ty);
|
auto range = (*$self)->instances_by_type_excl_subtypes_range(ty);
|
||||||
for (auto& inst : boost::make_iterator_range(range)) {
|
for (auto& inst : boost::make_iterator_range(range)) {
|
||||||
vec.push_back(inst);
|
vec.push_back(new entity_instance(inst, *$self));
|
||||||
}
|
}
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_instance add(entity_instance& e, int i) {
|
entity_instance* add(entity_instance* e, int i) {
|
||||||
return $self->addEntity(e, i);
|
return new entity_instance((*$self)->addEntity(e->move(), i), *self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(entity_instance& e) {
|
void remove(entity_instance* e) {
|
||||||
return $self->removeEntity(e);
|
return (*$self)->removeEntity(*e);
|
||||||
}
|
}
|
||||||
|
|
||||||
aggregate_of_instance::ptr get_inverse(entity_instance& e) {
|
aggregate_of_instance::ptr get_inverse(entity_instance* e) {
|
||||||
return $self->getInverse(e.data().id(), 0, -1);
|
return (*$self)->getInverse(e->data().id(), 0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> get_inverse_indices(entity_instance& e) {
|
std::vector<int> get_inverse_indices(entity_instance* e) {
|
||||||
return $self->get_inverse_indices(e.data().id());
|
return (*$self)->get_inverse_indices(e->data().id());
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_total_inverses(entity_instance& e) {
|
int get_total_inverses(entity_instance* e) {
|
||||||
return $self->getTotalInverses(e.data().id());
|
return (*$self)->getTotalInverses(e->data().id());
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(const std::string& fn) {
|
void write(const std::string& fn) {
|
||||||
std::ofstream f(IfcUtil::path::from_utf8(fn).c_str());
|
std::ofstream f(IfcUtil::path::from_utf8(fn).c_str());
|
||||||
f << (*$self);
|
f << (**$self);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string() {
|
std::string to_string() {
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
s << (*$self);
|
s << (**$self);
|
||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned> entity_names() const {
|
std::vector<unsigned> entity_names() {
|
||||||
std::vector<unsigned> keys;
|
std::vector<unsigned> keys;
|
||||||
keys.reserve(std::distance($self->begin(), $self->end()));
|
keys.reserve(std::distance((*$self)->begin(), (*$self)->end()));
|
||||||
for (IfcParse::IfcFile::entity_by_id_t::const_iterator it = $self->begin(); it != $self->end(); ++ it) {
|
for (IfcParse::IfcFile::entity_by_id_t::const_iterator it = (*$self)->begin(); it != (*$self)->end(); ++ it) {
|
||||||
keys.push_back(it->first);
|
keys.push_back(it->first);
|
||||||
}
|
}
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> types() const {
|
std::vector<std::string> types() {
|
||||||
const size_t n = std::distance($self->types_begin(), $self->types_end());
|
const size_t n = std::distance((*$self)->types_begin(), (*$self)->types_end());
|
||||||
std::vector<std::string> ts;
|
std::vector<std::string> ts;
|
||||||
ts.reserve(n);
|
ts.reserve(n);
|
||||||
std::transform($self->types_begin(), $self->types_end(), std::back_inserter(ts), helper_fn_declaration_get_name);
|
std::transform((*$self)->types_begin(), (*$self)->types_end(), std::back_inserter(ts), helper_fn_declaration_get_name);
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> types_with_super() const {
|
std::vector<std::string> types_with_super() {
|
||||||
const size_t n = std::distance($self->types_incl_super_begin(), $self->types_incl_super_end());
|
const size_t n = std::distance((*$self)->types_incl_super_begin(), (*$self)->types_incl_super_end());
|
||||||
std::vector<std::string> ts;
|
std::vector<std::string> ts;
|
||||||
ts.reserve(n);
|
ts.reserve(n);
|
||||||
std::transform($self->types_incl_super_begin(), $self->types_incl_super_end(), std::back_inserter(ts), helper_fn_declaration_get_name);
|
std::transform((*$self)->types_incl_super_begin(), (*$self)->types_incl_super_end(), std::back_inserter(ts), helper_fn_declaration_get_name);
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string schema_name() const {
|
std::string schema_name() {
|
||||||
if ($self->schema() == 0) return "";
|
if ((*$self)->schema() == 0) return "";
|
||||||
return $self->schema()->name();
|
return (*$self)->schema()->name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IfcParse::IfcSpfHeader& header() { return (*$self)->header(); }
|
||||||
|
|
||||||
%pythoncode %{
|
%pythoncode %{
|
||||||
# Hide the getters with read-only property implementations
|
# Hide the getters with read-only property implementations
|
||||||
header = property(header)
|
header = property(header)
|
||||||
@@ -287,6 +419,10 @@ IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsi
|
|||||||
std::vector<const IfcParse::attribute*>::const_iterator it = attrs.begin();
|
std::vector<const IfcParse::attribute*>::const_iterator it = attrs.begin();
|
||||||
for (; it != attrs.end(); ++it) {
|
for (; it != attrs.end(); ++it) {
|
||||||
if ((*it)->name() == name) {
|
if ((*it)->name() == name) {
|
||||||
|
if (self->declaration().as_entity()->derived()[std::distance(attrs.begin(), it)]) {
|
||||||
|
// derived
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -368,13 +504,13 @@ IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsi
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<IfcUtil::ArgumentType,Argument*> get_argument(unsigned i) {
|
std::tuple<IfcUtil::ArgumentType, Argument*, entity_instance*> get_argument(unsigned i) {
|
||||||
return std::pair<IfcUtil::ArgumentType,Argument*>($self->data().getArgument(i)->type(), $self->data().getArgument(i));
|
return { $self->data().getArgument(i)->type(), $self->data().getArgument(i), self };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<IfcUtil::ArgumentType,Argument*> get_argument(const std::string& a) {
|
std::tuple<IfcUtil::ArgumentType, Argument*, entity_instance*> get_argument(const std::string& a) {
|
||||||
unsigned i = $self->declaration().as_entity()->attribute_index(a);
|
unsigned i = $self->declaration().as_entity()->attribute_index(a);
|
||||||
return std::pair<IfcUtil::ArgumentType,Argument*>($self->data().getArgument(i)->type(), $self->data().getArgument(i));
|
return { $self->data().getArgument(i)->type(), $self->data().getArgument(i), self };
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __eq__(entity_instance* other) const {
|
bool __eq__(entity_instance* other) const {
|
||||||
@@ -430,202 +566,213 @@ IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsi
|
|||||||
void setAttribute(unsigned int i, PyObject* obj) {
|
void setAttribute(unsigned int i, PyObject* obj) {
|
||||||
bool is_optional = $self->declaration().as_entity()->attribute_by_index(i)->optional();
|
bool is_optional = $self->declaration().as_entity()->attribute_by_index(i)->optional();
|
||||||
|
|
||||||
if ()
|
if (obj == Py_None) {
|
||||||
if (is_optional) {
|
if (is_optional) {
|
||||||
self->data().setArgument(i, new IfcWrite::IfcWriteArgument());
|
self->i()->unset_value(i);
|
||||||
} else {
|
return;
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
|
||||||
|
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsInt(unsigned int i, int v) {
|
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
|
||||||
if (arg_type == IfcUtil::Argument_INT) {
|
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
|
||||||
arg->set(v);
|
|
||||||
self->data().setArgument(i, arg);
|
|
||||||
} else if ( (arg_type == IfcUtil::Argument_BOOL) && ( (v == 0) || (v == 1) ) ) {
|
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
|
||||||
arg->set(v == 1);
|
|
||||||
self->data().setArgument(i, arg);
|
|
||||||
} else {
|
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsBool(unsigned int i, bool v) {
|
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
|
||||||
if (arg_type == IfcUtil::Argument_BOOL) {
|
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
|
||||||
arg->set(v);
|
|
||||||
self->data().setArgument(i, arg);
|
|
||||||
} else {
|
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsLogical(unsigned int i, boost::logic::tribool v) {
|
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
|
||||||
if (arg_type == IfcUtil::Argument_LOGICAL) {
|
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
|
||||||
arg->set(v);
|
|
||||||
self->data().setArgument(i, arg);
|
|
||||||
} else {
|
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsDouble(unsigned int i, double v) {
|
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
|
||||||
if (arg_type == IfcUtil::Argument_DOUBLE) {
|
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
|
||||||
arg->set(v);
|
|
||||||
self->data().setArgument(i, arg);
|
|
||||||
} else {
|
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsString(unsigned int i, const std::string& a) {
|
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
|
||||||
if (arg_type == IfcUtil::Argument_STRING) {
|
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
|
||||||
arg->set(a);
|
|
||||||
self->data().setArgument(i, arg);
|
|
||||||
} else if (arg_type == IfcUtil::Argument_ENUMERATION) {
|
|
||||||
const IfcParse::enumeration_type* enum_type = $self->declaration().schema()->declaration_by_name($self->declaration().type())->as_entity()->
|
|
||||||
attribute_by_index(i)->type_of_attribute()->as_named_type()->declared_type()->as_enumeration_type();
|
|
||||||
|
|
||||||
std::vector<std::string>::const_iterator it = std::find(
|
|
||||||
enum_type->enumeration_items().begin(),
|
|
||||||
enum_type->enumeration_items().end(),
|
|
||||||
a);
|
|
||||||
|
|
||||||
if (it == enum_type->enumeration_items().end()) {
|
|
||||||
throw IfcParse::IfcException(a + " does not name a valid item for " + enum_type->name());
|
|
||||||
}
|
|
||||||
|
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
|
||||||
arg->set(IfcWrite::IfcWriteArgument::EnumerationReference(it - enum_type->enumeration_items().begin(), it->c_str()));
|
|
||||||
self->data().setArgument(i, arg);
|
|
||||||
} else if (arg_type == IfcUtil::Argument_BINARY) {
|
|
||||||
if (IfcUtil::valid_binary_string(a)) {
|
|
||||||
boost::dynamic_bitset<> bits(a);
|
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
|
||||||
arg->set(bits);
|
|
||||||
self->data().setArgument(i, arg);
|
|
||||||
} else {
|
} else {
|
||||||
throw IfcParse::IfcException("String not a valid binary representation");
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsAggregateOfInt(unsigned int i, const std::vector<int>& v) {
|
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
||||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_INT) {
|
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
if (PyLong_Check(obj)) {
|
||||||
arg->set(v);
|
long v = PyLong_AsLong(obj);
|
||||||
self->data().setArgument(i, arg);
|
if (arg_type == IfcUtil::Argument_INT) {
|
||||||
} else {
|
self->i()->set_value<int>(i, v);
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
} else if ( (arg_type == IfcUtil::Argument_BOOL) && ( (v == 0) || (v == 1) ) ) {
|
||||||
|
self->i()->set_value<int>(i, v == 1);
|
||||||
|
} else {
|
||||||
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsAggregateOfDouble(unsigned int i, const std::vector<double>& v) {
|
else if (PyBool_Check(obj)) {
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
bool v = PyObject_IsTrue(obj);
|
||||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_DOUBLE) {
|
if (arg_type == IfcUtil::Argument_BOOL || arg_type == IfcUtil::Argument_LOGICAL) {
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
self->i()->set_value(i, v);
|
||||||
arg->set(v);
|
} else {
|
||||||
self->data().setArgument(i, arg);
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
} else {
|
}
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsAggregateOfString(unsigned int i, const std::vector<std::string>& v) {
|
else if (PyUnicode_Check(obj)) {
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
PyObject* ascii = PyUnicode_AsEncodedString(obj, "UTF-8", "strict");
|
||||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_STRING) {
|
if (ascii) {
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
auto s = std::string(PyBytes_AS_STRING(ascii));
|
||||||
arg->set(v);
|
Py_DECREF(ascii);
|
||||||
self->data().setArgument(i, arg);
|
if (arg_type == IfcUtil::Argument_LOGICAL) {
|
||||||
} else if (arg_type == IfcUtil::Argument_AGGREGATE_OF_BINARY) {
|
if (s == "UNKNOWN") {
|
||||||
std::vector< boost::dynamic_bitset<> > bits;
|
self->i()->set_value(i, boost::logic::tribool(boost::logic::indeterminate));
|
||||||
bits.reserve(v.size());
|
} else {
|
||||||
for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it) {
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
if (IfcUtil::valid_binary_string(*it)) {
|
}
|
||||||
bits.push_back(boost::dynamic_bitset<>(*it));
|
} else if (arg_type == IfcUtil::Argument_STRING) {
|
||||||
|
self->i()->set_value<std::string>(i, s);
|
||||||
|
} else if (arg_type == IfcUtil::Argument_ENUMERATION) {
|
||||||
|
const IfcParse::enumeration_type* enum_type = $self->declaration().schema()->declaration_by_name($self->declaration().type())->as_entity()->
|
||||||
|
attribute_by_index(i)->type_of_attribute()->as_named_type()->declared_type()->as_enumeration_type();
|
||||||
|
|
||||||
|
std::vector<std::string>::const_iterator it = std::find(
|
||||||
|
enum_type->enumeration_items().begin(),
|
||||||
|
enum_type->enumeration_items().end(),
|
||||||
|
s);
|
||||||
|
|
||||||
|
if (it == enum_type->enumeration_items().end()) {
|
||||||
|
throw IfcParse::IfcException(s + " does not name a valid item for " + enum_type->name());
|
||||||
|
}
|
||||||
|
|
||||||
|
self->i()->set_value(i, IfcWrite::IfcWriteArgument::EnumerationReference(it - enum_type->enumeration_items().begin(), it->c_str()));
|
||||||
|
} else if (arg_type == IfcUtil::Argument_BINARY) {
|
||||||
|
if (IfcUtil::valid_binary_string(s)) {
|
||||||
|
boost::dynamic_bitset<> bits(s);
|
||||||
|
self->i()->set_value(i, bits);
|
||||||
|
} else {
|
||||||
|
throw IfcParse::IfcException("String not a valid binary representation");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw IfcParse::IfcException("String not a valid binary representation");
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
|
||||||
arg->set(bits);
|
|
||||||
self->data().setArgument(i, arg);
|
|
||||||
} else {
|
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsEntityInstance(unsigned int i, entity_instance* v) {
|
else if (PyFloat_Check(obj)) {
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
double v = PyFloat_AsDouble(obj);
|
||||||
if (arg_type == IfcUtil::Argument_ENTITY_INSTANCE) {
|
if (arg_type == IfcUtil::Argument_DOUBLE) {
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
self->i()->set_value(i, v);
|
||||||
arg->set(v);
|
} else {
|
||||||
self->data().setArgument(i, arg);
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
} else {
|
}
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsAggregateOfEntityInstance(unsigned int i, aggregate_of_instance::ptr v) {
|
else if (check_aggregate_of_type(obj, get_python_type<int>())) {
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
auto v = python_sequence_as_vector<int>(obj);
|
||||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
|
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_INT) {
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
self->i()->set_value(i, v);
|
||||||
arg->set(v);
|
} else {
|
||||||
self->data().setArgument(i, arg);
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
} else {
|
}
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsAggregateOfAggregateOfInt(unsigned int i, const std::vector< std::vector<int> >& v) {
|
else if (check_aggregate_of_type(obj, get_python_type<double>())) {
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
auto v = python_sequence_as_vector<double>(obj);
|
||||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT) {
|
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_DOUBLE) {
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
self->i()->set_value(i, v);
|
||||||
arg->set(v);
|
} else {
|
||||||
self->data().setArgument(i, arg);
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
} else {
|
}
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsAggregateOfAggregateOfDouble(unsigned int i, const std::vector< std::vector<double> >& v) {
|
else if (check_aggregate_of_type(obj, get_python_type<std::string>())) {
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
auto v = python_sequence_as_vector<std::string>(obj);
|
||||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE) {
|
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_STRING) {
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
self->i()->set_value(i, v);
|
||||||
arg->set(v);
|
} else if (arg_type == IfcUtil::Argument_AGGREGATE_OF_BINARY) {
|
||||||
self->data().setArgument(i, arg);
|
std::vector< boost::dynamic_bitset<> > bits;
|
||||||
} else {
|
bits.reserve(v.size());
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it) {
|
||||||
|
if (IfcUtil::valid_binary_string(*it)) {
|
||||||
|
bits.push_back(boost::dynamic_bitset<>(*it));
|
||||||
|
} else {
|
||||||
|
throw IfcParse::IfcException("String not a valid binary representation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self->i()->set_value(i, bits);
|
||||||
|
} else {
|
||||||
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void setArgumentAsAggregateOfAggregateOfEntityInstance(unsigned int i, aggregate_of_aggregate_of_instance::ptr v) {
|
else if (auto inst = cast_pyobject<entity_instance*>(obj)) {
|
||||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
if (arg_type == IfcUtil::Argument_ENTITY_INSTANCE) {
|
||||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
|
self->i()->set_value(i, inst->i());
|
||||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
} else {
|
||||||
arg->set(v);
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
self->data().setArgument(i, arg);
|
}
|
||||||
} else {
|
}
|
||||||
throw IfcParse::IfcException("Attribute not set");
|
|
||||||
|
else if (check_aggregate_of_aggregate_of_type(obj, get_python_type<int>())) {
|
||||||
|
auto v = python_sequence_as_vector_of_vector<int>(obj);
|
||||||
|
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT) {
|
||||||
|
self->i()->set_value(i, v);
|
||||||
|
} else {
|
||||||
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (check_aggregate_of_aggregate_of_type(obj, get_python_type<double>())) {
|
||||||
|
auto v = python_sequence_as_vector_of_vector<double>(obj);
|
||||||
|
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE) {
|
||||||
|
self->i()->set_value(i, v);
|
||||||
|
} else {
|
||||||
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (PySequence_Check(obj)) {
|
||||||
|
aggregate_of_instance::ptr insts1d(new aggregate_of_instance);
|
||||||
|
aggregate_of_aggregate_of_instance::ptr insts2d(new aggregate_of_aggregate_of_instance);
|
||||||
|
for(Py_ssize_t i = 0; i < PySequence_Size(obj); ++i) {
|
||||||
|
PyObject* element_i = PySequence_GetItem(obj, i);
|
||||||
|
if (auto inst = cast_pyobject<entity_instance*>(element_i); insts1d) {
|
||||||
|
insts2d.reset();
|
||||||
|
|
||||||
|
insts1d->push(*inst);
|
||||||
|
} else if (PySequence_Check(element_i) && insts2d) {
|
||||||
|
insts1d.reset();
|
||||||
|
|
||||||
|
std::vector<IfcUtil::IfcBaseClass*> inner;
|
||||||
|
for(Py_ssize_t j = 0; j < PySequence_Size(element_i); ++j) {
|
||||||
|
PyObject* element_j = PySequence_GetItem(element_i, j);
|
||||||
|
if (auto inst = cast_pyobject<entity_instance*>(element_j); insts2d) {
|
||||||
|
inner.push_back(*inst);
|
||||||
|
} else {
|
||||||
|
insts2d.reset();
|
||||||
|
}
|
||||||
|
Py_DECREF(element_j);
|
||||||
|
if (!insts2d) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (insts2d) {
|
||||||
|
insts2d->push(inner);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
insts1d.reset();
|
||||||
|
insts2d.reset();
|
||||||
|
}
|
||||||
|
Py_DECREF(element_i);
|
||||||
|
if (!insts1d && !insts2d) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE && insts1d) {
|
||||||
|
self->i()->set_value(i, insts1d);
|
||||||
|
} else if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE && insts2d) {
|
||||||
|
self->i()->set_value(i, insts2d);
|
||||||
|
} else {
|
||||||
|
throw IfcParse::IfcException("Attribute not set");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%extend entity_instance {
|
||||||
|
%pythoncode %{
|
||||||
|
def __getattr__(self, name):
|
||||||
|
try:
|
||||||
|
return custom_base.__getattr__(self, name)
|
||||||
|
except:
|
||||||
|
return _swig_getattr(self, entity_instance, name)
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
try:
|
||||||
|
return custom_base.__setattr__(self, name, value)
|
||||||
|
except:
|
||||||
|
return _swig_setattr(self, entity_instance, name, value)
|
||||||
|
%}
|
||||||
|
};
|
||||||
|
|
||||||
%extend IfcParse::IfcSpfHeader {
|
%extend IfcParse::IfcSpfHeader {
|
||||||
%pythoncode %{
|
%pythoncode %{
|
||||||
# Hide the getters with read-only property implementations
|
# Hide the getters with read-only property implementations
|
||||||
@@ -696,7 +843,7 @@ IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsi
|
|||||||
return IFCOPENSHELL_VERSION;
|
return IFCOPENSHELL_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_instance new_IfcBaseClass(const std::string& schema_identifier, const std::string& name) {
|
entity_instance* make_instance(const std::string& schema_identifier, const std::string& name) {
|
||||||
const IfcParse::schema_definition* schema = IfcParse::schema_by_name(schema_identifier);
|
const IfcParse::schema_definition* schema = IfcParse::schema_by_name(schema_identifier);
|
||||||
const IfcParse::declaration* decl = schema->declaration_by_name(name);
|
const IfcParse::declaration* decl = schema->declaration_by_name(name);
|
||||||
IfcEntityInstanceData* data = new IfcEntityInstanceData(decl);
|
IfcEntityInstanceData* data = new IfcEntityInstanceData(decl);
|
||||||
@@ -719,7 +866,7 @@ IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema->instantiate(data);
|
return new entity_instance(schema->instantiate(data));
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
|||||||
@@ -149,12 +149,6 @@
|
|||||||
// Create docstrings for generated python code.
|
// Create docstrings for generated python code.
|
||||||
%feature("autodoc", "1");
|
%feature("autodoc", "1");
|
||||||
|
|
||||||
%include "utils/type_conversion.i"
|
|
||||||
|
|
||||||
%include "utils/typemaps_in.i"
|
|
||||||
|
|
||||||
%include "utils/typemaps_out.i"
|
|
||||||
|
|
||||||
%module ifcopenshell_wrapper %{
|
%module ifcopenshell_wrapper %{
|
||||||
#include "../ifcgeom/Converter.h"
|
#include "../ifcgeom/Converter.h"
|
||||||
#include "../ifcgeom/taxonomy.h"
|
#include "../ifcgeom/taxonomy.h"
|
||||||
|
|||||||
@@ -79,10 +79,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
IfcUtil::IfcBaseClass* cast_pyobject(PyObject* element) {
|
entity_instance* cast_pyobject(PyObject* element) {
|
||||||
void *arg = 0;
|
void *arg = 0;
|
||||||
int res = SWIG_ConvertPtr(element, &arg, SWIGTYPE_p_IfcUtil__IfcBaseClass, 0);
|
int res = SWIG_ConvertPtr(element, &arg, SWIGTYPE_p_entity_instance, 0);
|
||||||
return static_cast<IfcUtil::IfcBaseClass*>(SWIG_IsOK(res) ? arg : 0);
|
return static_cast<entity_instance*>(SWIG_IsOK(res) ? arg : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -156,6 +156,7 @@
|
|||||||
PyObject* pythonize(const double& t) { return PyFloat_FromDouble(t); }
|
PyObject* pythonize(const double& t) { return PyFloat_FromDouble(t); }
|
||||||
PyObject* pythonize(const std::string& t) { return PyUnicode_FromString(t.c_str()); }
|
PyObject* pythonize(const std::string& t) { return PyUnicode_FromString(t.c_str()); }
|
||||||
PyObject* pythonize(const IfcUtil::IfcBaseClass* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcUtil__IfcBaseClass, 0); }
|
PyObject* pythonize(const IfcUtil::IfcBaseClass* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcUtil__IfcBaseClass, 0); }
|
||||||
|
PyObject* pythonize(const entity_instance* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_entity_instance, SWIG_POINTER_OWN);}
|
||||||
PyObject* pythonize(const IfcParse::attribute* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcParse__attribute, 0); }
|
PyObject* pythonize(const IfcParse::attribute* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcParse__attribute, 0); }
|
||||||
PyObject* pythonize(const IfcParse::inverse_attribute* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcParse__inverse_attribute, 0); }
|
PyObject* pythonize(const IfcParse::inverse_attribute* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcParse__inverse_attribute, 0); }
|
||||||
PyObject* pythonize(const IfcParse::entity* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcParse__entity, 0); }
|
PyObject* pythonize(const IfcParse::entity* t) { return SWIG_NewPointerObj(SWIG_as_voidptr(t), SWIGTYPE_p_IfcParse__entity, 0); }
|
||||||
|
|||||||
@@ -23,13 +23,17 @@
|
|||||||
$result = SWIG_Python_str_FromChar(data_type_strings[(int)$1]);
|
$result = SWIG_Python_str_FromChar(data_type_strings[(int)$1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
%typemap(out) std::pair<IfcUtil::ArgumentType, Argument*> {
|
%typemap(out) std::tuple<IfcUtil::ArgumentType, Argument*, entity_instance*> {
|
||||||
// The SWIG %exception directive does not take care
|
// The SWIG %exception directive does not take care
|
||||||
// of our typemap. So the attribute conversion block
|
// of our typemap. So the attribute conversion block
|
||||||
// is wrapped in a try-catch block manually.
|
// is wrapped in a try-catch block manually.
|
||||||
try {
|
try {
|
||||||
const Argument& arg = *($1.second);
|
|
||||||
const IfcUtil::ArgumentType type = $1.first;
|
std::tuple<IfcUtil::ArgumentType, Argument*, entity_instance*>& res = $1;
|
||||||
|
const Argument& arg = *std::get<Argument*>(res);
|
||||||
|
const IfcUtil::ArgumentType type = std::get<IfcUtil::ArgumentType>(res);
|
||||||
|
entity_instance* host = std::get<entity_instance*>(res);
|
||||||
|
|
||||||
if (arg.isNull()) {
|
if (arg.isNull()) {
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
$result = Py_None;
|
$result = Py_None;
|
||||||
@@ -81,7 +85,10 @@
|
|||||||
break; }
|
break; }
|
||||||
case IfcUtil::Argument_ENTITY_INSTANCE: {
|
case IfcUtil::Argument_ENTITY_INSTANCE: {
|
||||||
IfcUtil::IfcBaseClass* v = arg;
|
IfcUtil::IfcBaseClass* v = arg;
|
||||||
$result = pythonize(v);
|
if (!v->data().file) {
|
||||||
|
throw std::runtime_error("No file");
|
||||||
|
}
|
||||||
|
$result = pythonize(new entity_instance(v->data().file->instance_by_id_2(v->data().id()), host->file_pointer()));
|
||||||
break; }
|
break; }
|
||||||
case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: {
|
case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: {
|
||||||
aggregate_of_instance::ptr v = arg;
|
aggregate_of_instance::ptr v = arg;
|
||||||
|
|||||||
Reference in New Issue
Block a user