mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 16:01:36 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 55657a5c07 | |||
| c32dd8ba7d | |||
| b08a550519 | |||
| c1fb953a82 |
@@ -1508,7 +1508,7 @@ namespace latebound_access {
|
||||
IfcParse::IfcGlobalId guid;
|
||||
latebound_access::set(inst, "GlobalId", (std::string) guid);
|
||||
}
|
||||
return f.addEntity(inst);
|
||||
return &*f.addEntity(inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ except Exception as e:
|
||||
|
||||
from . import guid
|
||||
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
|
||||
try:
|
||||
from .stream import stream, stream_entity
|
||||
@@ -171,7 +171,7 @@ def create_entity(type, schema="IFC4", *args, **kwargs):
|
||||
model = ifcopenshell.file()
|
||||
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()]
|
||||
for idx, arg in attrs:
|
||||
e[idx] = arg
|
||||
@@ -195,7 +195,6 @@ def register_schema(schema):
|
||||
schema.schema.this.disown()
|
||||
schema.disown()
|
||||
ifcopenshell_wrapper.register_schema(schema.schema)
|
||||
register_schema_attributes(schema.schema)
|
||||
|
||||
|
||||
def schema_by_name(
|
||||
|
||||
@@ -42,66 +42,8 @@ except ImportError as e:
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def set_derived_attribute(*args):
|
||||
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)
|
||||
|
||||
# poor man's enum
|
||||
ATTR_INVALID, ATTR_FORWARD, ATTR_INVERSE, ATTR_FORWARD_DERIVED = range(4)
|
||||
|
||||
class entity_instance(object):
|
||||
"""Base class for all IFC objects.
|
||||
@@ -120,44 +62,22 @@ class entity_instance(object):
|
||||
>>> #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
|
||||
def file(self):
|
||||
# ugh circular imports, name collisions
|
||||
from . import file
|
||||
|
||||
return file.from_pointer(self.wrapped_data.file_pointer())
|
||||
return file.from_pointer(self.file_pointer())
|
||||
|
||||
def __getattr__(self, name):
|
||||
INVALID, FORWARD, INVERSE = range(3)
|
||||
attr_cat = self.wrapped_data.get_attribute_category(name)
|
||||
if attr_cat == FORWARD:
|
||||
idx = self.wrapped_data.get_argument_index(name)
|
||||
if _method_dict[self.is_a(True)][idx] != set_derived_attribute:
|
||||
# A bit ugly, but we fall through to derived attribute handling below
|
||||
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)
|
||||
attr_cat = self.get_attribute_category(name)
|
||||
if attr_cat == ATTR_FORWARD:
|
||||
idx = self.get_argument_index(name)
|
||||
return self.get_argument(idx)
|
||||
elif attr_cat == ATTR_INVERSE:
|
||||
vs = self.get_inverse(name)
|
||||
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())
|
||||
inv = [i for i in ent.all_inverse_attributes() if i.name() == name][0]
|
||||
if (inv.bound1(), inv.bound2()) == (-1, -1):
|
||||
@@ -166,9 +86,9 @@ class entity_instance(object):
|
||||
else:
|
||||
vs = None
|
||||
return vs
|
||||
|
||||
|
||||
# derived attribute perhaps?
|
||||
schema_name = self.wrapped_data.is_a(True).split(".")[0]
|
||||
schema_name = self.is_a(True).split(".")[0]
|
||||
try:
|
||||
rules = importlib.import_module(f"ifcopenshell.express.rules.{schema_name}")
|
||||
except:
|
||||
@@ -180,21 +100,21 @@ class entity_instance(object):
|
||||
subprocess.run([sys.executable, "-m", "ifcopenshell.express.rule_compiler", schema_path, fn], check=True)
|
||||
time.sleep(1.)
|
||||
rules = importlib.import_module(schema_name)
|
||||
|
||||
|
||||
def yield_supertypes():
|
||||
decl = ifcopenshell_wrapper.schema_by_name(schema_name).declaration_by_name(self.is_a())
|
||||
while decl:
|
||||
yield decl.name()
|
||||
decl = decl.supertype()
|
||||
|
||||
|
||||
for sty in yield_supertypes():
|
||||
fn = getattr(rules, f"calc_{sty}_{name}", None)
|
||||
if fn:
|
||||
return fn(self)
|
||||
|
||||
|
||||
if attr_cat != FORWARD:
|
||||
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
|
||||
@@ -235,26 +155,6 @@ class entity_instance(object):
|
||||
else:
|
||||
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:
|
||||
"""Return the data type of a positional attribute of the element
|
||||
|
||||
@@ -262,8 +162,8 @@ class entity_instance(object):
|
||||
:type attr: int
|
||||
:rtype: string
|
||||
"""
|
||||
attr_idx = attr if isinstance(attr, numbers.Integral) else self.wrapped_data.get_argument_index(attr)
|
||||
return self.wrapped_data.get_argument_type(attr_idx)
|
||||
attr_idx = attr if isinstance(attr, numbers.Integral) else self.get_argument_index(attr)
|
||||
return self.get_argument_type(attr_idx)
|
||||
|
||||
def attribute_name(self, attr_idx: int) -> str:
|
||||
"""Return the name of a positional attribute of the element
|
||||
@@ -272,37 +172,28 @@ class entity_instance(object):
|
||||
:type attr_idx: int
|
||||
: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:
|
||||
index = self.wrapped_data.get_argument_index(key)
|
||||
index = self.get_argument_index(key)
|
||||
self[index] = value
|
||||
|
||||
def __getitem__(self, key: int) -> Any:
|
||||
if key < 0 or key >= len(self):
|
||||
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:
|
||||
if self.wrapped_data.file and self.wrapped_data.file.transaction:
|
||||
self.wrapped_data.file.transaction.store_edit(self, idx, value)
|
||||
|
||||
if self.method_list is None:
|
||||
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))
|
||||
|
||||
if self.file and self.file.transaction:
|
||||
self.file.transaction.store_edit(self, idx, value)
|
||||
|
||||
self.setAttribute(idx, value)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def __len__(self):
|
||||
return len(self.wrapped_data)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.wrapped_data)
|
||||
|
||||
@@ -315,7 +206,7 @@ class entity_instance(object):
|
||||
the specific control directives.
|
||||
"""
|
||||
|
||||
return self.wrapped_data.to_string(valid_spf)
|
||||
return self.to_string(valid_spf)
|
||||
|
||||
@overload
|
||||
def is_a(self) -> str: ...
|
||||
@@ -348,19 +239,19 @@ class entity_instance(object):
|
||||
f.is_a('IfcPerson')
|
||||
>>> True
|
||||
"""
|
||||
return self.wrapped_data.is_a(*args)
|
||||
return self.is_a(*args)
|
||||
|
||||
def id(self) -> int:
|
||||
"""Return the STEP numerical identifier
|
||||
|
||||
:rtype: int
|
||||
"""
|
||||
return self.wrapped_data.id()
|
||||
return self.id()
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(self, type(other)):
|
||||
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
|
||||
# and we need this for where rule evaluation
|
||||
return self.get_info(recursive=True, include_identifier=False) == other.get_info(
|
||||
@@ -373,10 +264,10 @@ class entity_instance(object):
|
||||
if self.id():
|
||||
return self.wrapped_data == other.wrapped_data
|
||||
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[0],
|
||||
other.wrapped_data.file_pointer(),
|
||||
other.file_pointer(),
|
||||
)
|
||||
|
||||
def is_entity(self) -> bool:
|
||||
@@ -385,7 +276,7 @@ class entity_instance(object):
|
||||
Returns:
|
||||
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())
|
||||
return isinstance(decl, ifcopenshell_wrapper.entity)
|
||||
|
||||
@@ -459,17 +350,17 @@ class entity_instance(object):
|
||||
# step id. Selected type instances (such as IfcPropertySingleValue.NominalValue
|
||||
# always have id=0, so we hash <type, value, file pointer>
|
||||
if self.id():
|
||||
return hash((self.id(), self.wrapped_data.file_pointer()))
|
||||
return hash((self.id(), self.file_pointer()))
|
||||
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):
|
||||
return sorted(
|
||||
set(
|
||||
itertools.chain(
|
||||
dir(type(self)),
|
||||
map(str, self.wrapped_data.get_attribute_names()),
|
||||
map(str, self.wrapped_data.get_inverse_attribute_names()),
|
||||
map(str, self.get_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))
|
||||
for i in range(len(self)):
|
||||
try:
|
||||
if self.wrapped_data.get_attribute_names()[i] in ignore:
|
||||
if self.get_attribute_names()[i] in ignore:
|
||||
continue
|
||||
attr_value = self[i]
|
||||
|
||||
@@ -548,7 +439,8 @@ class entity_instance(object):
|
||||
|
||||
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=()):
|
||||
"""More perfomant version of `.get_info()` but with limited arguments values.\n
|
||||
|
||||
@@ -328,7 +328,7 @@ class file(object):
|
||||
"""
|
||||
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}.
|
||||
# Keyword arguments are mapped to their corresponding
|
||||
@@ -337,7 +337,7 @@ class file(object):
|
||||
# @todo we should probably check that values for
|
||||
# attributes are not passed as duplicates using
|
||||
# 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
|
||||
# as the creation it self is already stored with
|
||||
@@ -353,14 +353,13 @@ class file(object):
|
||||
if attrs:
|
||||
self.transaction = transaction
|
||||
|
||||
# Once the values are populated add the instance
|
||||
# Once the values are populated move the instance
|
||||
# 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
|
||||
# this instance. Tell SWIG that it is no longer
|
||||
# the owner.
|
||||
e.wrapped_data.this.disown()
|
||||
|
||||
if self.transaction:
|
||||
self.transaction.store_create(e)
|
||||
@@ -398,9 +397,9 @@ class file(object):
|
||||
|
||||
def __getitem__(self, key):
|
||||
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):
|
||||
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:
|
||||
"""Return an IFC entity instance filtered by IFC ID.
|
||||
@@ -441,8 +440,8 @@ class file(object):
|
||||
|
||||
if self.transaction:
|
||||
max_id = self.wrapped_data.getMaxId()
|
||||
inst.wrapped_data.this.disown()
|
||||
result = entity_instance(self.wrapped_data.add(inst.wrapped_data, -1 if _id is None else _id), self)
|
||||
# inst.wrapped_data.this.disown()
|
||||
result = self.wrapped_data.add(inst, -1 if _id is None else _id)
|
||||
if self.transaction:
|
||||
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)]
|
||||
@@ -461,8 +460,8 @@ class file(object):
|
||||
:rtype: list[ifcopenshell.entity_instance.entity_instance]
|
||||
"""
|
||||
if include_subtypes:
|
||||
return [entity_instance(e, self) for e in 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(type)
|
||||
return self.wrapped_data.by_type_excl_subtypes(type)
|
||||
|
||||
def traverse(
|
||||
self, inst: ifcopenshell.entity_instance, max_levels=None, breadth_first=False
|
||||
@@ -486,7 +485,7 @@ class file(object):
|
||||
else:
|
||||
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(
|
||||
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:
|
||||
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 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))
|
||||
else:
|
||||
return inverses
|
||||
@@ -523,7 +522,7 @@ class file(object):
|
||||
:returns: The total number of references
|
||||
: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:
|
||||
"""Deletes an IFC object in the file.
|
||||
@@ -538,7 +537,7 @@ class file(object):
|
||||
"""
|
||||
if self.transaction:
|
||||
self.transaction.store_delete(inst)
|
||||
return self.wrapped_data.remove(inst.wrapped_data)
|
||||
return self.wrapped_data.remove(inst)
|
||||
|
||||
def batch(self):
|
||||
"""Low-level mechanism to speed up deletion of large subgraphs"""
|
||||
@@ -605,4 +604,4 @@ class file(object):
|
||||
|
||||
@staticmethod
|
||||
def from_pointer(v):
|
||||
return file_dict.get(v)()
|
||||
return file_dict.get(v)() if v else None
|
||||
|
||||
+77
-29
@@ -68,10 +68,18 @@ class IFC_PARSE_API file_open_status {
|
||||
/// and provide access to the entities in an IFC file
|
||||
class IFC_PARSE_API IfcFile {
|
||||
public:
|
||||
typedef std::map<const IfcParse::declaration*, aggregate_of_instance::ptr> entities_by_type_t;
|
||||
typedef boost::unordered_map<unsigned int, IfcUtil::IfcBaseClass*> entity_by_id_t;
|
||||
typedef boost::unordered_map<uint32_t, IfcUtil::IfcBaseClass*> entity_by_iden_t;
|
||||
typedef std::map<std::string, IfcUtil::IfcBaseClass*> entity_by_guid_t;
|
||||
#ifndef NO_SHARED_POINTER_STORAGE
|
||||
typedef std::shared_ptr<IfcUtil::IfcBaseClass> instance_storage_type;
|
||||
typedef std::weak_ptr<IfcUtil::IfcBaseClass> instance_reference_type;
|
||||
#else
|
||||
typedef IfcUtil::IfcBaseClass* instance_storage_type;
|
||||
typedef IfcUtil::IfcBaseClass* instance_reference_type;
|
||||
#endif
|
||||
|
||||
typedef std::multimap<const IfcParse::declaration*, instance_storage_type> entities_by_type_t;
|
||||
typedef boost::unordered_map<unsigned int, instance_storage_type> entity_by_id_t;
|
||||
typedef boost::unordered_map<uint32_t, instance_storage_type> entity_by_iden_t;
|
||||
typedef std::map<std::string, instance_storage_type> entity_by_guid_t;
|
||||
typedef std::tuple<int, int, int> inverse_attr_record;
|
||||
enum INVERSE_ATTR {
|
||||
INSTANCE_ID,
|
||||
@@ -80,9 +88,9 @@ class IFC_PARSE_API IfcFile {
|
||||
};
|
||||
typedef std::map<inverse_attr_record, std::vector<int>> entities_by_ref_t;
|
||||
typedef std::map<int, std::vector<int>> entities_by_ref_excl_t;
|
||||
typedef std::map<unsigned int, aggregate_of_instance::ptr> ref_map_t;
|
||||
typedef entity_by_id_t::const_iterator const_iterator;
|
||||
|
||||
template <typename T>
|
||||
class type_iterator : private entities_by_type_t::const_iterator {
|
||||
public:
|
||||
type_iterator() : entities_by_type_t::const_iterator(){};
|
||||
@@ -90,16 +98,35 @@ class IFC_PARSE_API IfcFile {
|
||||
type_iterator(const entities_by_type_t::const_iterator& iter)
|
||||
: entities_by_type_t::const_iterator(iter){};
|
||||
|
||||
entities_by_type_t::key_type const* operator->() const {
|
||||
return &entities_by_type_t::const_iterator::operator->()->first;
|
||||
T const* operator->() const {
|
||||
if constexpr (std::is_same_v<T, entities_by_type_t::key_type>) {
|
||||
return &entities_by_type_t::const_iterator::operator->()->first;
|
||||
} else {
|
||||
return &entities_by_type_t::const_iterator::operator->()->second;
|
||||
}
|
||||
}
|
||||
|
||||
entities_by_type_t::key_type const& operator*() const {
|
||||
return entities_by_type_t::const_iterator::operator*().first;
|
||||
T const& operator*() const {
|
||||
if constexpr (std::is_same_v<T, entities_by_type_t::key_type>) {
|
||||
return entities_by_type_t::const_iterator::operator*().first;
|
||||
} else {
|
||||
return entities_by_type_t::const_iterator::operator*().second;
|
||||
}
|
||||
}
|
||||
|
||||
type_iterator& operator++() {
|
||||
entities_by_type_t::const_iterator::operator++();
|
||||
auto k = **this;
|
||||
// @todo we changed from map(aggregate) to multimap(instance)
|
||||
// (why again?) so now we need to keep iterating in our type
|
||||
// iterator. Given the distribution of entity types, this
|
||||
// likely has performance impliciations, but this function is
|
||||
// probably hardly ever used.
|
||||
do {
|
||||
entities_by_type_t::const_iterator::operator++();
|
||||
if constexpr (std::is_same_v<T, entities_by_type_t::value_type>) {
|
||||
break;
|
||||
}
|
||||
} while (k == **this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -116,6 +143,8 @@ class IFC_PARSE_API IfcFile {
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::pair<type_iterator<entities_by_type_t::value_type::second_type>, type_iterator<entities_by_type_t::value_type::second_type>> type_iterator_range_t;
|
||||
|
||||
static bool lazy_load_;
|
||||
static bool lazy_load() { return lazy_load_; }
|
||||
static void lazy_load(bool b) { lazy_load_ = b; }
|
||||
@@ -125,7 +154,7 @@ class IFC_PARSE_API IfcFile {
|
||||
static void guid_map(bool b) { guid_map_ = b; }
|
||||
|
||||
private:
|
||||
typedef std::map<uint32_t, IfcUtil::IfcBaseClass*> entity_entity_map_t;
|
||||
typedef std::map<uint32_t, instance_storage_type> entity_entity_map_t;
|
||||
|
||||
bool parsing_complete_;
|
||||
file_open_status good_ = file_open_status::SUCCESS;
|
||||
@@ -192,47 +221,55 @@ class IFC_PARSE_API IfcFile {
|
||||
/// with the highest id (EXPRESS ENTITY_INSTANCE_NAME)
|
||||
const_iterator end() const;
|
||||
|
||||
type_iterator types_begin() const;
|
||||
type_iterator types_end() const;
|
||||
type_iterator<entities_by_type_t::key_type> types_begin() const;
|
||||
type_iterator<entities_by_type_t::key_type> types_end() const;
|
||||
|
||||
type_iterator types_incl_super_begin() const;
|
||||
type_iterator types_incl_super_end() const;
|
||||
type_iterator<entities_by_type_t::key_type> types_incl_super_begin() const;
|
||||
type_iterator<entities_by_type_t::key_type> types_incl_super_end() const;
|
||||
|
||||
/// Returns all entities in the file that match the template argument.
|
||||
/// NOTE: This also returns subtypes of the requested type, for example:
|
||||
/// IfcWall will also return IfcWallStandardCase entities
|
||||
template <class T>
|
||||
typename T::list::ptr instances_by_type() {
|
||||
aggregate_of_instance::ptr untyped_list = instances_by_type(&T::Class());
|
||||
if (untyped_list) {
|
||||
return untyped_list->as<T>();
|
||||
auto range = instances_by_type_range(&T::Class());
|
||||
typename T::list::ptr vec(new typename T::list);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
vec->push((*it)->template as<T>());
|
||||
}
|
||||
return typename T::list::ptr(new typename T::list);
|
||||
return vec;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename T::list::ptr instances_by_type_excl_subtypes() {
|
||||
aggregate_of_instance::ptr untyped_list = instances_by_type_excl_subtypes(&T::Class());
|
||||
if (untyped_list) {
|
||||
return untyped_list->as<T>();
|
||||
auto range = instances_by_type_excl_subtypes_range(&T::Class());
|
||||
typename T::list::ptr vec(new typename T::list);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
vec->push((*it)->template as<T>());
|
||||
}
|
||||
return typename T::list::ptr(new typename T::list);
|
||||
return vec;
|
||||
}
|
||||
|
||||
/// Returns all entities in the file that match the positional argument.
|
||||
/// NOTE: This also returns subtypes of the requested type, for example:
|
||||
/// IfcWall will also return IfcWallStandardCase entities
|
||||
aggregate_of_instance::ptr instances_by_type(const IfcParse::declaration*);
|
||||
type_iterator_range_t instances_by_type_range(const IfcParse::declaration*);
|
||||
|
||||
/// Returns all entities in the file that match the positional argument.
|
||||
aggregate_of_instance::ptr instances_by_type_excl_subtypes(const IfcParse::declaration*);
|
||||
type_iterator_range_t instances_by_type_excl_subtypes_range(const IfcParse::declaration*);
|
||||
|
||||
/// Returns all entities in the file that match the positional argument.
|
||||
/// NOTE: This also returns subtypes of the requested type, for example:
|
||||
/// IfcWall will also return IfcWallStandardCase entities
|
||||
aggregate_of_instance::ptr instances_by_type(const std::string& type);
|
||||
type_iterator_range_t instances_by_type_range(const std::string& type);
|
||||
|
||||
/// Returns all entities in the file that match the positional argument.
|
||||
type_iterator_range_t instances_by_type_excl_subtypes_range(const std::string& type);
|
||||
|
||||
/// Compatibility functions that take the ranges from above and turn into an aggregate
|
||||
aggregate_of_instance::ptr instances_by_type(const IfcParse::declaration* decl);
|
||||
aggregate_of_instance::ptr instances_by_type_excl_subtypes(const IfcParse::declaration* decl);
|
||||
aggregate_of_instance::ptr instances_by_type(const std::string& type);
|
||||
aggregate_of_instance::ptr instances_by_type_excl_subtypes(const std::string& type);
|
||||
|
||||
/// Returns all entities in the file that reference the id
|
||||
@@ -241,8 +278,10 @@ class IFC_PARSE_API IfcFile {
|
||||
/// Returns the entity with the specified id
|
||||
IfcUtil::IfcBaseClass* instance_by_id(int id);
|
||||
|
||||
IfcFile::instance_storage_type instance_by_id_2(int id);
|
||||
|
||||
/// Returns the entity with the specified GlobalId
|
||||
IfcUtil::IfcBaseClass* instance_by_guid(const std::string& guid);
|
||||
IfcFile::instance_storage_type instance_by_guid(const std::string& guid);
|
||||
|
||||
/// Performs a depth-first traversal, returning all entity instance
|
||||
/// attributes as a flat list. NB: includes the root instance specified
|
||||
@@ -274,7 +313,7 @@ class IFC_PARSE_API IfcFile {
|
||||
|
||||
void recalculate_id_counter();
|
||||
|
||||
IfcUtil::IfcBaseClass* addEntity(IfcUtil::IfcBaseClass* entity, int id = -1);
|
||||
IfcFile::instance_storage_type addEntity(IfcUtil::IfcBaseClass* entity, int id = -1);
|
||||
void addEntities(aggregate_of_instance::ptr entities);
|
||||
|
||||
void batch() { batch_mode_ = true; }
|
||||
@@ -327,13 +366,22 @@ IFC_PARSE_API IfcFile* parse_ifcxml(const std::string& filename);
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct iterator_traits<IfcParse::IfcFile::type_iterator> {
|
||||
struct iterator_traits<IfcParse::IfcFile::type_iterator<IfcParse::IfcFile::entities_by_type_t::key_type>> {
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef const IfcParse::declaration* value_type;
|
||||
typedef const IfcParse::declaration*& reference;
|
||||
typedef const IfcParse::declaration** pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct iterator_traits<IfcParse::IfcFile::type_iterator<IfcParse::IfcFile::entities_by_type_t::value_type::second_type>> {
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef IfcParse::IfcFile::entities_by_type_t::value_type value_type;
|
||||
typedef IfcParse::IfcFile::entities_by_type_t::value_type reference;
|
||||
typedef IfcParse::IfcFile::entities_by_type_t::value_type* pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
|
||||
+112
-85
@@ -1555,7 +1555,7 @@ void IfcEntityInstanceData::setArgument(size_t i, Argument* a, IfcUtil::Argument
|
||||
if (it != this->file->internal_guid_map().end()) {
|
||||
Logger::Warning("Duplicate guid " + guid);
|
||||
}
|
||||
this->file->internal_guid_map()[guid] = this->file->instance_by_id(this->id());
|
||||
this->file->internal_guid_map()[guid] = this->file->instance_by_id_2(this->id());
|
||||
} catch (IfcParse::IfcException& e) {
|
||||
Logger::Error(e);
|
||||
}
|
||||
@@ -1656,7 +1656,7 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) {
|
||||
boost::circular_buffer<Token> token_stream(3, Token());
|
||||
|
||||
IfcEntityInstanceData* data;
|
||||
IfcUtil::IfcBaseClass* instance = 0;
|
||||
instance_storage_type instance = 0;
|
||||
|
||||
unsigned current_id = 0;
|
||||
int progress = 0;
|
||||
@@ -1682,7 +1682,7 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) {
|
||||
}
|
||||
|
||||
data = new IfcEntityInstanceData(entity_type, this, current_id, token_stream[2].startPos);
|
||||
instance = schema()->instantiate(data);
|
||||
instance = instance_storage_type(schema()->instantiate(data));
|
||||
|
||||
/// @todo Printing to stdout in a library class feels weird. Maybe move the progress prints to the client code?
|
||||
// Update the status after every 1000 instances parsed
|
||||
@@ -1715,22 +1715,10 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) {
|
||||
|
||||
const IfcParse::declaration* ty = &instance->declaration();
|
||||
|
||||
{
|
||||
aggregate_of_instance::ptr insts = instances_by_type_excl_subtypes(ty);
|
||||
if (!insts) {
|
||||
insts = aggregate_of_instance::ptr(new aggregate_of_instance());
|
||||
bytype_excl_[ty] = insts;
|
||||
}
|
||||
insts->push(instance);
|
||||
}
|
||||
bytype_excl_.insert({ ty, instance });
|
||||
|
||||
for (;;) {
|
||||
aggregate_of_instance::ptr insts = instances_by_type(ty);
|
||||
if (!insts) {
|
||||
insts = aggregate_of_instance::ptr(new aggregate_of_instance());
|
||||
bytype_[ty] = insts;
|
||||
}
|
||||
insts->push(instance);
|
||||
bytype_.insert({ ty, instance });
|
||||
const IfcParse::declaration* pt = ty->as_entity()->supertype();
|
||||
if (pt != nullptr) {
|
||||
ty = pt;
|
||||
@@ -1898,7 +1886,7 @@ void IfcFile::addEntities(aggregate_of_instance::ptr entities) {
|
||||
}
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id) {
|
||||
IfcFile::instance_storage_type IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id) {
|
||||
if (id != -1 && byid_.find((unsigned)id) != byid_.end()) {
|
||||
throw IfcParse::IfcException("An instance with id " + boost::lexical_cast<std::string>(id) + " is already part of this file");
|
||||
}
|
||||
@@ -1914,8 +1902,6 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
||||
return mit->second;
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* new_entity = entity;
|
||||
|
||||
// Obtain all forward references by a depth-first
|
||||
// traversal and add them to the file.
|
||||
if (parsing_complete_) {
|
||||
@@ -1934,17 +1920,31 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
||||
}
|
||||
}
|
||||
|
||||
instance_storage_type new_entity;
|
||||
|
||||
// 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->declaration().as_entity() == nullptr) {
|
||||
// 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
|
||||
// nothing else needs to be done.
|
||||
return entity;
|
||||
if constexpr (std::is_same_v<IfcFile::instance_storage_type, IfcUtil::IfcBaseClass*>) {
|
||||
return entity;
|
||||
} else {
|
||||
for (auto& x : byid_) {
|
||||
if (&*x.second == entity) {
|
||||
return x.second;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Internal error");
|
||||
}
|
||||
}
|
||||
|
||||
// An instance is being added from another file. A copy of the
|
||||
@@ -1952,7 +1952,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
||||
// need to be updated to point to instances in this file.
|
||||
IfcFile* other_file = entity->data().file;
|
||||
IfcEntityInstanceData* we = new IfcEntityInstanceData(entity->data());
|
||||
new_entity = schema()->instantiate(we);
|
||||
new_entity = instance_storage_type(schema()->instantiate(we));
|
||||
|
||||
// In case an entity is added that contains geometry, the unit
|
||||
// information needs to be accounted for for IfcLengthMeasures.
|
||||
@@ -1981,7 +1981,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
||||
}
|
||||
|
||||
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
|
||||
copy->set(eit->second);
|
||||
copy->set(&*eit->second);
|
||||
we->setArgument(i, copy);
|
||||
} else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
|
||||
aggregate_of_instance::ptr instances = *attr;
|
||||
@@ -1991,7 +1991,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
||||
if (eit == entity_file_map_.end()) {
|
||||
throw IfcParse::IfcException("Unable to map instance to file");
|
||||
}
|
||||
new_instances->push(eit->second);
|
||||
new_instances->push(&*eit->second);
|
||||
}
|
||||
|
||||
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
|
||||
@@ -2007,7 +2007,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
||||
if (eit == entity_file_map_.end()) {
|
||||
throw IfcParse::IfcException("Unable to map instance to file");
|
||||
}
|
||||
list.push_back(eit->second);
|
||||
list.push_back(&*eit->second);
|
||||
}
|
||||
new_instances->push(list);
|
||||
}
|
||||
@@ -2076,7 +2076,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
||||
}
|
||||
}
|
||||
|
||||
entity_file_map_.insert(entity_entity_map_t::value_type(entity->identity(), new_entity));
|
||||
entity_file_map_.insert(entity_entity_map_t::value_type(entity->identity(), &*new_entity));
|
||||
}
|
||||
|
||||
// For subtypes of IfcRoot, the GUID mapping needs to be updated.
|
||||
@@ -2098,21 +2098,11 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
||||
const IfcParse::declaration* ty = &new_entity->declaration();
|
||||
|
||||
if (ty->as_entity() != nullptr) {
|
||||
aggregate_of_instance::ptr insts = instances_by_type_excl_subtypes(ty);
|
||||
if (!insts) {
|
||||
insts = aggregate_of_instance::ptr(new aggregate_of_instance());
|
||||
bytype_excl_[ty] = insts;
|
||||
}
|
||||
insts->push(new_entity);
|
||||
bytype_excl_.insert({ ty, new_entity });
|
||||
}
|
||||
|
||||
for (; ty->as_entity() != nullptr;) {
|
||||
aggregate_of_instance::ptr insts = instances_by_type(ty);
|
||||
if (!insts) {
|
||||
insts = aggregate_of_instance::ptr(new aggregate_of_instance());
|
||||
bytype_[ty] = insts;
|
||||
}
|
||||
insts->push(new_entity);
|
||||
bytype_.insert({ ty, new_entity });
|
||||
|
||||
const IfcParse::declaration* pt = ty->as_entity()->supertype();
|
||||
if (pt != nullptr) {
|
||||
@@ -2158,7 +2148,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
||||
}
|
||||
|
||||
if (parsing_complete_ && (ty->as_entity() != nullptr)) {
|
||||
build_inverses_(new_entity);
|
||||
build_inverses_(&*new_entity);
|
||||
}
|
||||
|
||||
return new_entity;
|
||||
@@ -2323,20 +2313,24 @@ void IfcFile::process_deletion_() {
|
||||
const IfcParse::declaration* ty = &entity->declaration();
|
||||
|
||||
{
|
||||
aggregate_of_instance::ptr instances_of_same_type = instances_by_type_excl_subtypes(ty);
|
||||
instances_of_same_type->remove(entity);
|
||||
if (instances_of_same_type->size() == 0) {
|
||||
bytype_excl_.erase(ty);
|
||||
auto instances_of_same_type = bytype_excl_.equal_range(ty);
|
||||
for (auto it = instances_of_same_type.first; it != instances_of_same_type.second;) {
|
||||
if (&*it->second == entity) {
|
||||
it = bytype_excl_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
aggregate_of_instance::ptr instances_of_same_type = instances_by_type(ty);
|
||||
if (instances_of_same_type) {
|
||||
instances_of_same_type->remove(entity);
|
||||
}
|
||||
if (instances_of_same_type->size() == 0) {
|
||||
bytype_.erase(ty);
|
||||
auto instances_of_same_type = bytype_.equal_range(ty);
|
||||
for (auto it = instances_of_same_type.first; it != instances_of_same_type.second;) {
|
||||
if (&*it->second == entity) {
|
||||
it = bytype_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
const IfcParse::declaration* pt = ty->as_entity()->supertype();
|
||||
@@ -2350,14 +2344,16 @@ void IfcFile::process_deletion_() {
|
||||
// entity_file_map is in place to prevent duplicate definitions with usage of add().
|
||||
// Upon deletion the pairs need to be erased.
|
||||
for (auto it = entity_file_map_.begin(); it != entity_file_map_.end();) {
|
||||
if (it->second == entity) {
|
||||
if (&*it->second == entity) {
|
||||
it = entity_file_map_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
delete entity;
|
||||
if constexpr (std::is_same_v<IfcFile::instance_storage_type, IfcUtil::IfcBaseClass*>) {
|
||||
delete entity;
|
||||
}
|
||||
}
|
||||
|
||||
if (batch_mode_) {
|
||||
@@ -2397,22 +2393,20 @@ void IfcFile::process_deletion_() {
|
||||
batch_deletion_ids_.clear();
|
||||
}
|
||||
|
||||
aggregate_of_instance::ptr IfcFile::instances_by_type(const IfcParse::declaration* t) {
|
||||
entities_by_type_t::const_iterator it = bytype_.find(t);
|
||||
return (it == bytype_.end()) ? aggregate_of_instance::ptr() : it->second;
|
||||
IfcFile::type_iterator_range_t IfcFile::instances_by_type_range(const IfcParse::declaration* t) {
|
||||
return bytype_.equal_range(t);
|
||||
}
|
||||
|
||||
aggregate_of_instance::ptr IfcFile::instances_by_type_excl_subtypes(const IfcParse::declaration* t) {
|
||||
entities_by_type_t::const_iterator it = bytype_excl_.find(t);
|
||||
return (it == bytype_excl_.end()) ? aggregate_of_instance::ptr() : it->second;
|
||||
IfcFile::type_iterator_range_t IfcFile::instances_by_type_excl_subtypes_range(const IfcParse::declaration* t) {
|
||||
return bytype_.equal_range(t);
|
||||
}
|
||||
|
||||
aggregate_of_instance::ptr IfcFile::instances_by_type(const std::string& t) {
|
||||
return instances_by_type(schema()->declaration_by_name(t));
|
||||
IfcFile::type_iterator_range_t IfcFile::instances_by_type_range(const std::string& t) {
|
||||
return instances_by_type_range(schema()->declaration_by_name(t));
|
||||
}
|
||||
|
||||
aggregate_of_instance::ptr IfcFile::instances_by_type_excl_subtypes(const std::string& t) {
|
||||
return instances_by_type_excl_subtypes(schema()->declaration_by_name(t));
|
||||
IfcFile::type_iterator_range_t IfcFile::instances_by_type_excl_subtypes_range(const std::string& t) {
|
||||
return instances_by_type_excl_subtypes_range(schema()->declaration_by_name(t));
|
||||
}
|
||||
|
||||
aggregate_of_instance::ptr IfcFile::instances_by_reference(int t) {
|
||||
@@ -2424,6 +2418,14 @@ aggregate_of_instance::ptr IfcFile::instances_by_reference(int t) {
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcFile::instance_by_id(int id) {
|
||||
entity_by_id_t::const_iterator it = byid_.find(id);
|
||||
if (it == byid_.end()) {
|
||||
throw IfcException("Instance #" + boost::lexical_cast<std::string>(id) + " not found");
|
||||
}
|
||||
return &*it->second;
|
||||
}
|
||||
|
||||
IfcFile::instance_storage_type IfcFile::instance_by_id_2(int id) {
|
||||
entity_by_id_t::const_iterator it = byid_.find(id);
|
||||
if (it == byid_.end()) {
|
||||
throw IfcException("Instance #" + boost::lexical_cast<std::string>(id) + " not found");
|
||||
@@ -2431,7 +2433,7 @@ IfcUtil::IfcBaseClass* IfcFile::instance_by_id(int id) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcFile::instance_by_guid(const std::string& guid) {
|
||||
IfcFile::instance_storage_type IfcFile::instance_by_guid(const std::string& guid) {
|
||||
entity_by_guid_t::const_iterator it = byguid_.find(guid);
|
||||
if (it == byguid_.end()) {
|
||||
throw IfcException("Instance with GlobalId '" + guid + "' not found");
|
||||
@@ -2441,15 +2443,17 @@ IfcUtil::IfcBaseClass* IfcFile::instance_by_guid(const std::string& guid) {
|
||||
|
||||
// FIXME: Test destructor to delete entity and arg allocations
|
||||
IfcFile::~IfcFile() {
|
||||
std::set<IfcUtil::IfcBaseClass*> entities_to_delete;
|
||||
for (const auto& pair : byid_) {
|
||||
entities_to_delete.insert(pair.second);
|
||||
}
|
||||
for (const auto& pair : byidentity_) {
|
||||
entities_to_delete.insert(pair.second);
|
||||
}
|
||||
for (auto* entity : entities_to_delete) {
|
||||
delete entity;
|
||||
if constexpr (std::is_same_v<IfcFile::instance_storage_type, IfcUtil::IfcBaseClass*>) {
|
||||
std::set<IfcFile::instance_storage_type> entities_to_delete;
|
||||
for (const auto& pair : byid_) {
|
||||
entities_to_delete.insert(pair.second);
|
||||
}
|
||||
for (const auto& pair : byidentity_) {
|
||||
entities_to_delete.insert(pair.second);
|
||||
}
|
||||
for (auto entity : entities_to_delete) {
|
||||
delete &*entity;
|
||||
}
|
||||
}
|
||||
delete stream;
|
||||
delete tokens;
|
||||
@@ -2463,19 +2467,19 @@ IfcFile::entity_by_id_t::const_iterator IfcFile::end() const {
|
||||
return byid_.end();
|
||||
}
|
||||
|
||||
IfcFile::type_iterator IfcFile::types_begin() const {
|
||||
IfcFile::type_iterator<IfcFile::entities_by_type_t::key_type> IfcFile::types_begin() const {
|
||||
return bytype_excl_.begin();
|
||||
}
|
||||
|
||||
IfcFile::type_iterator IfcFile::types_end() const {
|
||||
IfcFile::type_iterator<IfcFile::entities_by_type_t::key_type> IfcFile::types_end() const {
|
||||
return bytype_excl_.end();
|
||||
}
|
||||
|
||||
IfcFile::type_iterator IfcFile::types_incl_super_begin() const {
|
||||
IfcFile::type_iterator<IfcFile::entities_by_type_t::key_type> IfcFile::types_incl_super_begin() const {
|
||||
return bytype_.begin();
|
||||
}
|
||||
|
||||
IfcFile::type_iterator IfcFile::types_incl_super_end() const {
|
||||
IfcFile::type_iterator<IfcFile::entities_by_type_t::key_type> IfcFile::types_incl_super_end() const {
|
||||
return bytype_.end();
|
||||
}
|
||||
|
||||
@@ -2490,12 +2494,12 @@ struct id_instance_pair_sorter {
|
||||
std::ostream& operator<<(std::ostream& out, const IfcParse::IfcFile& file) {
|
||||
file.header().write(out);
|
||||
|
||||
typedef std::vector<std::pair<unsigned int, IfcUtil::IfcBaseClass*>> vector_t;
|
||||
typedef std::vector<std::pair<unsigned int, IfcParse::IfcFile::instance_storage_type>> vector_t;
|
||||
vector_t sorted(file.begin(), file.end());
|
||||
std::sort(sorted.begin(), sorted.end(), id_instance_pair_sorter());
|
||||
|
||||
for (vector_t::const_iterator it = sorted.begin(); it != sorted.end(); ++it) {
|
||||
const IfcUtil::IfcBaseClass* e = it->second;
|
||||
auto& e = it->second;
|
||||
if (e->declaration().as_entity() != nullptr) {
|
||||
out << e->data().toString(true) << ";" << std::endl;
|
||||
}
|
||||
@@ -2622,16 +2626,16 @@ void IfcFile::setDefaultHeaderValues() {
|
||||
std::pair<IfcUtil::IfcBaseClass*, double> IfcFile::getUnit(const std::string& unit_type) {
|
||||
std::pair<IfcUtil::IfcBaseClass*, double> return_value(0, 1.);
|
||||
|
||||
aggregate_of_instance::ptr projects = instances_by_type(schema()->declaration_by_name("IfcProject"));
|
||||
if (!projects || projects->size() == 0) {
|
||||
auto projects = instances_by_type_range(schema()->declaration_by_name("IfcProject"));
|
||||
if (std::distance(projects.first, projects.second) == 0) {
|
||||
try {
|
||||
projects = instances_by_type(schema()->declaration_by_name("IfcContext"));
|
||||
projects = instances_by_type_range(schema()->declaration_by_name("IfcContext"));
|
||||
} catch (IfcException& e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (projects && projects->size() == 1) {
|
||||
IfcUtil::IfcBaseClass* project = *projects->begin();
|
||||
if (std::distance(projects.first, projects.second) == 1) {
|
||||
auto project = *projects.first;
|
||||
|
||||
IfcUtil::IfcBaseClass* unit_assignment = *project->data().getArgument(
|
||||
project->declaration().as_entity()->attribute_index("UnitsInContext"));
|
||||
@@ -2704,10 +2708,33 @@ void IfcParse::IfcFile::build_inverses_(IfcUtil::IfcBaseClass* inst) {
|
||||
|
||||
void IfcParse::IfcFile::build_inverses() {
|
||||
for (const auto& pair : *this) {
|
||||
build_inverses_(pair.second);
|
||||
build_inverses_(&*pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compatibility functions that take the ranges from above and turn into an aggregate
|
||||
aggregate_of_instance::ptr IfcParse::IfcFile::instances_by_type(const IfcParse::declaration* decl) {
|
||||
aggregate_of_instance::ptr aggr(new aggregate_of_instance);
|
||||
for (auto& inst : boost::make_iterator_range(instances_by_type_range(decl))) {
|
||||
aggr->push(&*inst);
|
||||
}
|
||||
return aggr;
|
||||
}
|
||||
aggregate_of_instance::ptr IfcParse::IfcFile::instances_by_type_excl_subtypes(const IfcParse::declaration* decl) {
|
||||
aggregate_of_instance::ptr aggr(new aggregate_of_instance);
|
||||
for (auto& inst : boost::make_iterator_range(instances_by_type_excl_subtypes_range(decl))) {
|
||||
aggr->push(&*inst);
|
||||
}
|
||||
return aggr;
|
||||
}
|
||||
aggregate_of_instance::ptr IfcParse::IfcFile::instances_by_type(const std::string& type) {
|
||||
return instances_by_type(schema()->declaration_by_name(type));
|
||||
}
|
||||
aggregate_of_instance::ptr IfcParse::IfcFile::instances_by_type_excl_subtypes(const std::string& type) {
|
||||
return instances_by_type_excl_subtypes(schema()->declaration_by_name(type));
|
||||
}
|
||||
|
||||
|
||||
std::atomic_uint32_t IfcUtil::IfcBaseClass::counter_(0);
|
||||
|
||||
bool IfcParse::IfcFile::lazy_load_ = true;
|
||||
|
||||
@@ -480,7 +480,7 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs)
|
||||
if (state->dialect == ifcxml_dialect_ifc4) {
|
||||
// In IFC2X3 not added directly because attrs such as GlobalId are in
|
||||
// subsequent child nodes
|
||||
newinst = state->file->addEntity(newinst);
|
||||
newinst = &*state->file->addEntity(newinst);
|
||||
if (id) {
|
||||
state->idmap[*id] = newinst->data().id();
|
||||
}
|
||||
|
||||
@@ -44,6 +44,10 @@ INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS})
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
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).
|
||||
# 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
|
||||
@@ -68,6 +72,15 @@ endif()
|
||||
# directory in which the wrapper can be installed.
|
||||
FIND_PACKAGE(PythonInterp)
|
||||
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)
|
||||
set(python_package_dir "${PYTHON_MODULE_INSTALL_DIR}")
|
||||
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>
|
||||
std::string to_locale_invariant_string(const T& t) {
|
||||
|
||||
+451
-211
@@ -46,13 +46,18 @@ private:
|
||||
|
||||
%ignore IfcUtil::IfcBaseClass::is;
|
||||
|
||||
%rename("by_id") instance_by_id;
|
||||
%rename("by_type") instances_by_type;
|
||||
%rename("by_type_excl_subtypes") instances_by_type_excl_subtypes;
|
||||
%rename("entity_instance") IfcBaseClass;
|
||||
%rename("file") IfcFile;
|
||||
%rename("add") addEntity;
|
||||
%rename("remove") removeEntity;
|
||||
%ignore IfcParse::IfcFile::instance_by_id;
|
||||
%ignore IfcParse::IfcFile::instances_by_type;
|
||||
%ignore IfcParse::IfcFile::instances_by_type_excl_subtypes;
|
||||
|
||||
%ignore IfcParse::IfcFile::addEntity;
|
||||
%ignore IfcParse::IfcFile::addEntities;
|
||||
%ignore IfcParse::IfcFile::removeEntity;
|
||||
|
||||
%ignore IfcParse::IfcFile;
|
||||
%ignore IfcUtil::IfcBaseClass;
|
||||
%ignore IfcUtil::IfcBaseEntity;
|
||||
%ignore IfcUtil::IfcBaseInterface;
|
||||
|
||||
class attribute_value_derived {};
|
||||
%{
|
||||
@@ -87,13 +92,197 @@ PyObject* get_feature(const std::string& x) {
|
||||
|
||||
%}
|
||||
|
||||
%ignore entity_instance::entity_instance;
|
||||
|
||||
%{
|
||||
class entity_instance;
|
||||
const std::string& helper_fn_declaration_get_name(const IfcParse::declaration* decl);
|
||||
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 %{
|
||||
class entity_instance {
|
||||
boost::variant<
|
||||
IfcUtil::IfcBaseClass*,
|
||||
std::weak_ptr<IfcUtil::IfcBaseClass>,
|
||||
boost::blank
|
||||
> data_;
|
||||
std::shared_ptr<IfcParse::IfcFile> file_;
|
||||
|
||||
struct visitor {
|
||||
const IfcUtil::IfcBaseClass* const operator()(const IfcUtil::IfcBaseClass* const & t) {
|
||||
return t;
|
||||
}
|
||||
const IfcUtil::IfcBaseClass* const operator()(const 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 {
|
||||
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 {
|
||||
throw std::runtime_error("No longer availabe");
|
||||
}
|
||||
}
|
||||
};
|
||||
public:
|
||||
entity_instance(
|
||||
const IfcParse::IfcFile::instance_storage_type& shared,
|
||||
const std::shared_ptr<IfcParse::IfcFile>& file
|
||||
)
|
||||
: data_(std::weak_ptr<IfcUtil::IfcBaseClass>(shared))
|
||||
, file_(file)
|
||||
{
|
||||
std::cout << "init " << this << " " << data_.which() << std::endl;
|
||||
}
|
||||
|
||||
entity_instance(IfcUtil::IfcBaseClass* naked)
|
||||
: data_(naked)
|
||||
{
|
||||
std::cout << "init " << this << " " << data_.which() << std::endl;
|
||||
}
|
||||
|
||||
~entity_instance() {
|
||||
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 {
|
||||
std::cout << "visit" << this << std::endl;
|
||||
return boost::apply_visitor(visitor{}, data_)->declaration();
|
||||
}
|
||||
|
||||
const IfcEntityInstanceData& data() const {
|
||||
std::cout << "visit" << this << std::endl;
|
||||
return boost::apply_visitor(visitor{}, data_)->data();
|
||||
}
|
||||
|
||||
IfcEntityInstanceData& data() {
|
||||
std::cout << "visit" << this << std::endl;
|
||||
return boost::apply_visitor(visitor{}, data_)->data();
|
||||
}
|
||||
|
||||
uint32_t identity() const {
|
||||
std::cout << "visit" << this << std::endl;
|
||||
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()));
|
||||
}
|
||||
};
|
||||
%}
|
||||
|
||||
%{
|
||||
|
||||
static const std::string& helper_fn_declaration_get_name(const IfcParse::declaration* decl) {
|
||||
const std::string& helper_fn_declaration_get_name(const IfcParse::declaration* decl) {
|
||||
return decl->name();
|
||||
}
|
||||
|
||||
static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClass* inst, unsigned i) {
|
||||
IfcUtil::ArgumentType helper_fn_attribute_type(const entity_instance* inst, unsigned i) {
|
||||
const IfcParse::parameter_type* pt = 0;
|
||||
if (inst->declaration().as_entity()) {
|
||||
pt = inst->declaration().as_entity()->attribute_by_index(i)->type_of_attribute();
|
||||
@@ -115,70 +304,102 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
||||
}
|
||||
%}
|
||||
|
||||
%extend IfcParse::IfcFile {
|
||||
%extend file {
|
||||
// Use to correlate to entity_instance.file_pointer, so that we
|
||||
// can trace file ownership of instances on the python side.
|
||||
size_t file_pointer() const {
|
||||
return reinterpret_cast<size_t>($self);
|
||||
size_t file_pointer() {
|
||||
return reinterpret_cast<size_t>(&**self);
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* by_guid(const std::string& guid) {
|
||||
return $self->instance_by_guid(guid);
|
||||
entity_instance* by_guid(const std::string& guid) {
|
||||
return new entity_instance((*$self)->instance_by_guid(guid), (*$self));
|
||||
}
|
||||
|
||||
entity_instance* by_id(int 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*> vec;
|
||||
auto range = (*$self)->instances_by_type_range(ty);
|
||||
for (auto& inst : boost::make_iterator_range(range)) {
|
||||
vec.push_back(new entity_instance(inst, *$self));
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
std::vector<entity_instance*> by_type_excl_subtypes(const std::string& ty) {
|
||||
std::vector<entity_instance*> vec;
|
||||
auto range = (*$self)->instances_by_type_excl_subtypes_range(ty);
|
||||
for (auto& inst : boost::make_iterator_range(range)) {
|
||||
vec.push_back(new entity_instance(inst, *$self));
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
entity_instance* add(entity_instance* e, int i) {
|
||||
return new entity_instance((*$self)->addEntity(e->move(), i), *self);
|
||||
}
|
||||
|
||||
void remove(entity_instance* e) {
|
||||
return (*$self)->removeEntity(*e);
|
||||
}
|
||||
|
||||
aggregate_of_instance::ptr get_inverse(IfcUtil::IfcBaseClass* e) {
|
||||
return $self->getInverse(e->data().id(), 0, -1);
|
||||
aggregate_of_instance::ptr get_inverse(entity_instance* e) {
|
||||
return (*$self)->getInverse(e->data().id(), 0, -1);
|
||||
}
|
||||
|
||||
std::vector<int> get_inverse_indices(IfcUtil::IfcBaseClass* e) {
|
||||
return $self->get_inverse_indices(e->data().id());
|
||||
std::vector<int> get_inverse_indices(entity_instance* e) {
|
||||
return (*$self)->get_inverse_indices(e->data().id());
|
||||
}
|
||||
|
||||
int get_total_inverses(IfcUtil::IfcBaseClass* e) {
|
||||
return $self->getTotalInverses(e->data().id());
|
||||
int get_total_inverses(entity_instance* e) {
|
||||
return (*$self)->getTotalInverses(e->data().id());
|
||||
}
|
||||
|
||||
void write(const std::string& fn) {
|
||||
std::ofstream f(IfcUtil::path::from_utf8(fn).c_str());
|
||||
f << (*$self);
|
||||
f << (**$self);
|
||||
}
|
||||
|
||||
std::string to_string() {
|
||||
std::stringstream s;
|
||||
s << (*$self);
|
||||
s << (**$self);
|
||||
return s.str();
|
||||
}
|
||||
|
||||
std::vector<unsigned> entity_names() const {
|
||||
std::vector<unsigned> entity_names() {
|
||||
std::vector<unsigned> keys;
|
||||
keys.reserve(std::distance($self->begin(), $self->end()));
|
||||
for (IfcParse::IfcFile::entity_by_id_t::const_iterator it = $self->begin(); it != $self->end(); ++ it) {
|
||||
keys.reserve(std::distance((*$self)->begin(), (*$self)->end()));
|
||||
for (IfcParse::IfcFile::entity_by_id_t::const_iterator it = (*$self)->begin(); it != (*$self)->end(); ++ it) {
|
||||
keys.push_back(it->first);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
std::vector<std::string> types() const {
|
||||
const size_t n = std::distance($self->types_begin(), $self->types_end());
|
||||
std::vector<std::string> types() {
|
||||
const size_t n = std::distance((*$self)->types_begin(), (*$self)->types_end());
|
||||
std::vector<std::string> ts;
|
||||
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;
|
||||
}
|
||||
|
||||
std::vector<std::string> types_with_super() const {
|
||||
const size_t n = std::distance($self->types_incl_super_begin(), $self->types_incl_super_end());
|
||||
std::vector<std::string> types_with_super() {
|
||||
const size_t n = std::distance((*$self)->types_incl_super_begin(), (*$self)->types_incl_super_end());
|
||||
std::vector<std::string> ts;
|
||||
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;
|
||||
}
|
||||
|
||||
std::string schema_name() const {
|
||||
if ($self->schema() == 0) return "";
|
||||
return $self->schema()->name();
|
||||
std::string schema_name() {
|
||||
if ((*$self)->schema() == 0) return "";
|
||||
return (*$self)->schema()->name();
|
||||
}
|
||||
|
||||
IfcParse::IfcSpfHeader& header() { return (*$self)->header(); }
|
||||
|
||||
%pythoncode %{
|
||||
# Hide the getters with read-only property implementations
|
||||
header = property(header)
|
||||
@@ -186,7 +407,7 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
||||
%}
|
||||
}
|
||||
|
||||
%extend IfcUtil::IfcBaseClass {
|
||||
%extend entity_instance {
|
||||
|
||||
int get_attribute_category(const std::string& name) const {
|
||||
if (!$self->declaration().as_entity()) {
|
||||
@@ -198,6 +419,10 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
||||
std::vector<const IfcParse::attribute*>::const_iterator it = attrs.begin();
|
||||
for (; it != attrs.end(); ++it) {
|
||||
if ((*it)->name() == name) {
|
||||
if (self->declaration().as_entity()->derived()[std::distance(attrs.begin(), it)]) {
|
||||
// derived
|
||||
return 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -279,16 +504,16 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
||||
return t;
|
||||
}
|
||||
|
||||
std::pair<IfcUtil::ArgumentType,Argument*> get_argument(unsigned i) {
|
||||
return std::pair<IfcUtil::ArgumentType,Argument*>($self->data().getArgument(i)->type(), $self->data().getArgument(i));
|
||||
std::tuple<IfcUtil::ArgumentType, Argument*, entity_instance*> get_argument(unsigned 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);
|
||||
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__(IfcUtil::IfcBaseClass* other) const {
|
||||
bool __eq__(entity_instance* other) const {
|
||||
return $self->identity() == other->identity();
|
||||
}
|
||||
|
||||
@@ -338,201 +563,216 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
||||
}
|
||||
}
|
||||
|
||||
void setArgumentAsNull(unsigned int i) {
|
||||
void setAttribute(unsigned int i, PyObject* obj) {
|
||||
bool is_optional = $self->declaration().as_entity()->attribute_by_index(i)->optional();
|
||||
if (is_optional) {
|
||||
self->data().setArgument(i, new IfcWrite::IfcWriteArgument());
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (obj == Py_None) {
|
||||
if (is_optional) {
|
||||
self->i()->unset_value(i);
|
||||
return;
|
||||
} 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);
|
||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_INT) {
|
||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
||||
arg->set(v);
|
||||
self->data().setArgument(i, arg);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
|
||||
if (PyLong_Check(obj)) {
|
||||
long v = PyLong_AsLong(obj);
|
||||
if (arg_type == IfcUtil::Argument_INT) {
|
||||
self->i()->set_value<int>(i, v);
|
||||
} 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) {
|
||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_DOUBLE) {
|
||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
||||
arg->set(v);
|
||||
self->data().setArgument(i, arg);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
else if (PyBool_Check(obj)) {
|
||||
bool v = PyObject_IsTrue(obj);
|
||||
if (arg_type == IfcUtil::Argument_BOOL || arg_type == IfcUtil::Argument_LOGICAL) {
|
||||
self->i()->set_value(i, v);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setArgumentAsAggregateOfString(unsigned int i, const std::vector<std::string>& v) {
|
||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_STRING) {
|
||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
||||
arg->set(v);
|
||||
self->data().setArgument(i, arg);
|
||||
} else if (arg_type == IfcUtil::Argument_AGGREGATE_OF_BINARY) {
|
||||
std::vector< boost::dynamic_bitset<> > bits;
|
||||
bits.reserve(v.size());
|
||||
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 if (PyUnicode_Check(obj)) {
|
||||
PyObject* ascii = PyUnicode_AsEncodedString(obj, "UTF-8", "strict");
|
||||
if (ascii) {
|
||||
auto s = std::string(PyBytes_AS_STRING(ascii));
|
||||
Py_DECREF(ascii);
|
||||
if (arg_type == IfcUtil::Argument_LOGICAL) {
|
||||
if (s == "UNKNOWN") {
|
||||
self->i()->set_value(i, boost::logic::tribool(boost::logic::indeterminate));
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
}
|
||||
} 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 {
|
||||
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, IfcUtil::IfcBaseClass* v) {
|
||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
||||
if (arg_type == IfcUtil::Argument_ENTITY_INSTANCE) {
|
||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
||||
arg->set(v);
|
||||
self->data().setArgument(i, arg);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
else if (PyFloat_Check(obj)) {
|
||||
double v = PyFloat_AsDouble(obj);
|
||||
if (arg_type == IfcUtil::Argument_DOUBLE) {
|
||||
self->i()->set_value(i, v);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setArgumentAsAggregateOfEntityInstance(unsigned int i, aggregate_of_instance::ptr v) {
|
||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
|
||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
||||
arg->set(v);
|
||||
self->data().setArgument(i, arg);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
else if (check_aggregate_of_type(obj, get_python_type<int>())) {
|
||||
auto v = python_sequence_as_vector<int>(obj);
|
||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_INT) {
|
||||
self->i()->set_value(i, v);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setArgumentAsAggregateOfAggregateOfInt(unsigned int i, const std::vector< std::vector<int> >& v) {
|
||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT) {
|
||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
||||
arg->set(v);
|
||||
self->data().setArgument(i, arg);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
else if (check_aggregate_of_type(obj, get_python_type<double>())) {
|
||||
auto v = python_sequence_as_vector<double>(obj);
|
||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_DOUBLE) {
|
||||
self->i()->set_value(i, v);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setArgumentAsAggregateOfAggregateOfDouble(unsigned int i, const std::vector< std::vector<double> >& v) {
|
||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE) {
|
||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
||||
arg->set(v);
|
||||
self->data().setArgument(i, arg);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
else if (check_aggregate_of_type(obj, get_python_type<std::string>())) {
|
||||
auto v = python_sequence_as_vector<std::string>(obj);
|
||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_STRING) {
|
||||
self->i()->set_value(i, v);
|
||||
} else if (arg_type == IfcUtil::Argument_AGGREGATE_OF_BINARY) {
|
||||
std::vector< boost::dynamic_bitset<> > bits;
|
||||
bits.reserve(v.size());
|
||||
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) {
|
||||
IfcUtil::ArgumentType arg_type = helper_fn_attribute_type($self, i);
|
||||
if (arg_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
|
||||
IfcWrite::IfcWriteArgument* arg = new IfcWrite::IfcWriteArgument();
|
||||
arg->set(v);
|
||||
self->data().setArgument(i, arg);
|
||||
} else {
|
||||
throw IfcParse::IfcException("Attribute not set");
|
||||
else if (auto inst = cast_pyobject<entity_instance*>(obj)) {
|
||||
if (arg_type == IfcUtil::Argument_ENTITY_INSTANCE) {
|
||||
self->i()->set_value(i, inst->i());
|
||||
} 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 {
|
||||
%pythoncode %{
|
||||
# Hide the getters with read-only property implementations
|
||||
@@ -603,7 +843,7 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
||||
return IFCOPENSHELL_VERSION;
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* 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::declaration* decl = schema->declaration_by_name(name);
|
||||
IfcEntityInstanceData* data = new IfcEntityInstanceData(decl);
|
||||
@@ -626,7 +866,7 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
||||
}
|
||||
}
|
||||
|
||||
return schema->instantiate(data);
|
||||
return new entity_instance(schema->instantiate(data));
|
||||
}
|
||||
%}
|
||||
|
||||
|
||||
@@ -149,12 +149,6 @@
|
||||
// Create docstrings for generated python code.
|
||||
%feature("autodoc", "1");
|
||||
|
||||
%include "utils/type_conversion.i"
|
||||
|
||||
%include "utils/typemaps_in.i"
|
||||
|
||||
%include "utils/typemaps_out.i"
|
||||
|
||||
%module ifcopenshell_wrapper %{
|
||||
#include "../ifcgeom/Converter.h"
|
||||
#include "../ifcgeom/taxonomy.h"
|
||||
|
||||
@@ -79,10 +79,10 @@
|
||||
}
|
||||
|
||||
template <>
|
||||
IfcUtil::IfcBaseClass* cast_pyobject(PyObject* element) {
|
||||
entity_instance* cast_pyobject(PyObject* element) {
|
||||
void *arg = 0;
|
||||
int res = SWIG_ConvertPtr(element, &arg, SWIGTYPE_p_IfcUtil__IfcBaseClass, 0);
|
||||
return static_cast<IfcUtil::IfcBaseClass*>(SWIG_IsOK(res) ? arg : 0);
|
||||
int res = SWIG_ConvertPtr(element, &arg, SWIGTYPE_p_entity_instance, 0);
|
||||
return static_cast<entity_instance*>(SWIG_IsOK(res) ? arg : 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -156,6 +156,7 @@
|
||||
PyObject* pythonize(const double& t) { return PyFloat_FromDouble(t); }
|
||||
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 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::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); }
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
%typemap(out) aggregate_of_instance::ptr {
|
||||
const unsigned size = $1 ? $1->size() : 0;
|
||||
$result = PyTuple_New(size);
|
||||
for (unsigned i = 0; i < size; ++i) {
|
||||
PyTuple_SetItem($result, i, pythonize((*$1)[i]));
|
||||
}
|
||||
}
|
||||
|
||||
%typemap(out) IfcUtil::ArgumentType {
|
||||
$result = SWIG_Python_str_FromChar(IfcUtil::ArgumentTypeToString($1));
|
||||
}
|
||||
@@ -31,13 +23,17 @@
|
||||
$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
|
||||
// of our typemap. So the attribute conversion block
|
||||
// is wrapped in a try-catch block manually.
|
||||
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()) {
|
||||
Py_INCREF(Py_None);
|
||||
$result = Py_None;
|
||||
@@ -89,7 +85,10 @@
|
||||
break; }
|
||||
case IfcUtil::Argument_ENTITY_INSTANCE: {
|
||||
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; }
|
||||
case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: {
|
||||
aggregate_of_instance::ptr v = arg;
|
||||
@@ -141,7 +140,7 @@ CREATE_VECTOR_TYPEMAP_OUT(int)
|
||||
CREATE_VECTOR_TYPEMAP_OUT(unsigned int)
|
||||
CREATE_VECTOR_TYPEMAP_OUT(double)
|
||||
CREATE_VECTOR_TYPEMAP_OUT(std::string)
|
||||
// CREATE_VECTOR_TYPEMAP_OUT(IfcGeom::Material)
|
||||
CREATE_VECTOR_TYPEMAP_OUT(entity_instance)
|
||||
CREATE_VECTOR_TYPEMAP_OUT(IfcParse::attribute const *)
|
||||
CREATE_VECTOR_TYPEMAP_OUT(IfcParse::inverse_attribute const *)
|
||||
CREATE_VECTOR_TYPEMAP_OUT(IfcParse::entity const *)
|
||||
|
||||
Reference in New Issue
Block a user