Skip to content

Commit 490c35b

Browse files
committed
Fix IfcOpenShell#244 and provide instances by entity type without subtypes
1 parent b019ff6 commit 490c35b

File tree

9 files changed

+138
-15
lines changed

9 files changed

+138
-15
lines changed

src/ifcexpressparser/templates.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
} Enum;
7474
IFC_PARSE_API boost::optional<Enum> Parent(Enum v);
7575
IFC_PARSE_API Enum FromString(const std::string& s);
76-
IFC_PARSE_API std::string ToString(Enum v);
76+
IFC_PARSE_API const std::string& ToString(Enum v);
7777
IFC_PARSE_API bool IsSimple(Enum v);
7878
}
7979
@@ -128,9 +128,9 @@
128128
}
129129
}
130130
131-
std::string Type::ToString(Enum v) {
131+
const std::string& Type::ToString(Enum v) {
132132
if (v < 0 || v >= %(max_id)d) throw IfcException("Unable to find find keyword in schema");
133-
const char* names[] = { %(type_name_strings)s };
133+
static std::string names[] = { %(type_name_strings)s };
134134
return names[v];
135135
}
136136

src/ifcparse/Ifc2x3.cpp

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

src/ifcparse/Ifc2x3enum.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ namespace Type {
4242
} Enum;
4343
IFC_PARSE_API boost::optional<Enum> Parent(Enum v);
4444
IFC_PARSE_API Enum FromString(const std::string& s);
45-
IFC_PARSE_API std::string ToString(Enum v);
45+
IFC_PARSE_API const std::string& ToString(Enum v);
4646
IFC_PARSE_API bool IsSimple(Enum v);
4747
}
4848

src/ifcparse/Ifc4.cpp

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

src/ifcparse/Ifc4enum.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ namespace Type {
4242
} Enum;
4343
IFC_PARSE_API boost::optional<Enum> Parent(Enum v);
4444
IFC_PARSE_API Enum FromString(const std::string& s);
45-
IFC_PARSE_API std::string ToString(Enum v);
45+
IFC_PARSE_API const std::string& ToString(Enum v);
4646
IFC_PARSE_API bool IsSimple(Enum v);
4747
}
4848

src/ifcparse/IfcFile.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,36 @@ class IFC_PARSE_API IfcFile {
3939
typedef std::map<std::string, IfcSchema::IfcRoot*> entity_by_guid_t;
4040
typedef std::map<unsigned int, std::vector<unsigned int> > entities_by_ref_t;
4141
typedef entity_by_id_t::const_iterator const_iterator;
42+
43+
class type_iterator : public entities_by_type_t::const_iterator {
44+
public:
45+
type_iterator() : entities_by_type_t::const_iterator() {};
46+
47+
type_iterator(const entities_by_type_t::const_iterator& it)
48+
: entities_by_type_t::const_iterator(it)
49+
{};
50+
51+
entities_by_type_t::key_type const * operator->() const {
52+
return &entities_by_type_t::const_iterator::operator->()->first;
53+
}
54+
55+
const entities_by_type_t::key_type& operator*() const {
56+
return entities_by_type_t::const_iterator::operator*().first;
57+
}
58+
59+
const std::string& as_string() const {
60+
return IfcSchema::Type::ToString(**this);
61+
}
62+
};
63+
4264
private:
4365
typedef std::map<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*> entity_entity_map_t;
4466

4567
bool parsing_complete_;
4668

4769
entity_by_id_t byid;
4870
entities_by_type_t bytype;
71+
entities_by_type_t bytype_excl;
4972
entities_by_ref_t byref;
5073
entity_by_guid_t byguid;
5174
entity_entity_map_t entity_file_map;
@@ -69,7 +92,13 @@ class IFC_PARSE_API IfcFile {
6992
/// Returns the last entity in the file, this probably is the entity
7093
/// with the highest id (EXPRESS ENTITY_INSTANCE_NAME)
7194
const_iterator end() const;
72-
95+
96+
type_iterator types_begin() const;
97+
type_iterator types_end() const;
98+
99+
type_iterator types_incl_super_begin() const;
100+
type_iterator types_incl_super_end() const;
101+
73102
/// Returns all entities in the file that match the template argument.
74103
/// NOTE: This also returns subtypes of the requested type, for example:
75104
/// IfcWall will also return IfcWallStandardCase entities
@@ -88,6 +117,9 @@ class IFC_PARSE_API IfcFile {
88117
/// IfcWall will also return IfcWallStandardCase entities
89118
IfcEntityList::ptr entitiesByType(IfcSchema::Type::Enum t);
90119

120+
/// Returns all entities in the file that match the positional argument.
121+
IfcEntityList::ptr entitiesByTypeExclSubtypes(IfcSchema::Type::Enum t);
122+
91123
/// Returns all entities in the file that match the positional argument.
92124
/// NOTE: This also returns subtypes of the requested type, for example:
93125
/// IfcWall will also return IfcWallStandardCase entities

src/ifcparse/IfcParse.cpp

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,16 @@ bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
13201320
}
13211321

13221322
IfcSchema::Type::Enum ty = instance->type();
1323+
1324+
{
1325+
IfcEntityList::ptr instances_by_type = entitiesByTypeExclSubtypes(ty);
1326+
if (!instances_by_type) {
1327+
instances_by_type = IfcEntityList::ptr(new IfcEntityList());
1328+
bytype_excl[ty] = instances_by_type;
1329+
}
1330+
instances_by_type->push(instance);
1331+
}
1332+
13231333
for (;;) {
13241334
IfcEntityList::ptr instances_by_type = entitiesByType(ty);
13251335
if (!instances_by_type) {
@@ -1334,7 +1344,7 @@ bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
13341344
break;
13351345
}
13361346
}
1337-
1347+
13381348
if (byid.find(current_id) != byid.end()) {
13391349
std::stringstream ss;
13401350
ss << "Overwriting instance with name #" << current_id;
@@ -1567,6 +1577,16 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
15671577

15681578
// The mapping by entity type is updated.
15691579
IfcSchema::Type::Enum ty = new_entity->type();
1580+
1581+
{
1582+
IfcEntityList::ptr instances_by_type = entitiesByTypeExclSubtypes(ty);
1583+
if (!instances_by_type) {
1584+
instances_by_type = IfcEntityList::ptr(new IfcEntityList());
1585+
bytype_excl[ty] = instances_by_type;
1586+
}
1587+
instances_by_type->push(new_entity);
1588+
}
1589+
15701590
for (;;) {
15711591
IfcEntityList::ptr instances_by_type = entitiesByType(ty);
15721592
if (!instances_by_type) {
@@ -1582,7 +1602,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
15821602
break;
15831603
}
15841604
}
1585-
1605+
15861606
int new_id = -1;
15871607
if (!new_entity->entity->file) {
15881608
// For newly created entities ensure a valid ENTITY_INSTANCE_NAME is set
@@ -1720,10 +1740,33 @@ void IfcFile::removeEntity(IfcUtil::IfcBaseClass* entity) {
17201740
}
17211741

17221742
byid.erase(byid.find(id));
1723-
1724-
IfcEntityList::ptr instances_of_same_type = entitiesByType(entity->type());
1725-
instances_of_same_type->remove(entity);
17261743

1744+
IfcSchema::Type::Enum ty = entity->type();
1745+
1746+
{
1747+
IfcEntityList::ptr instances_of_same_type = entitiesByTypeExclSubtypes(ty);
1748+
instances_of_same_type->remove(entity);
1749+
if (instances_of_same_type->size() == 0) {
1750+
bytype_excl.erase(ty);
1751+
}
1752+
}
1753+
1754+
for (;;) {
1755+
IfcEntityList::ptr instances_of_same_type = entitiesByType(ty);
1756+
if (instances_of_same_type) {
1757+
instances_of_same_type->remove(entity);
1758+
}
1759+
if (instances_of_same_type->size() == 0) {
1760+
bytype.erase(ty);
1761+
}
1762+
boost::optional<IfcSchema::Type::Enum> pt = IfcSchema::Type::Parent(ty);
1763+
if (pt) {
1764+
ty = *pt;
1765+
} else {
1766+
break;
1767+
}
1768+
}
1769+
17271770
delete entity->entity;
17281771
delete entity;
17291772
}
@@ -1733,6 +1776,11 @@ IfcEntityList::ptr IfcFile::entitiesByType(IfcSchema::Type::Enum t) {
17331776
return (it == bytype.end()) ? IfcEntityList::ptr() : it->second;
17341777
}
17351778

1779+
IfcEntityList::ptr IfcFile::entitiesByTypeExclSubtypes(IfcSchema::Type::Enum t) {
1780+
entities_by_type_t::const_iterator it = bytype_excl.find(t);
1781+
return (it == bytype_excl.end()) ? IfcEntityList::ptr() : it->second;
1782+
}
1783+
17361784
IfcEntityList::ptr IfcFile::entitiesByType(const std::string& t) {
17371785
return entitiesByType(IfcSchema::Type::FromString(boost::to_upper_copy(t)));
17381786
}
@@ -1787,6 +1835,22 @@ IfcFile::entity_by_id_t::const_iterator IfcFile::end() const {
17871835
return byid.end();
17881836
}
17891837

1838+
IfcFile::type_iterator IfcFile::types_begin() const {
1839+
return bytype_excl.begin();
1840+
}
1841+
1842+
IfcFile::type_iterator IfcFile::types_end() const {
1843+
return bytype_excl.end();
1844+
}
1845+
1846+
IfcFile::type_iterator IfcFile::types_incl_super_begin() const {
1847+
return bytype.begin();
1848+
}
1849+
1850+
IfcFile::type_iterator IfcFile::types_incl_super_end() const {
1851+
return bytype.end();
1852+
}
1853+
17901854
std::ostream& operator<< (std::ostream& os, const IfcParse::IfcFile& f) {
17911855
f.header().write(os);
17921856

src/ifcwrap/IfcParseWrapper.i

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ private:
4242
%ignore IfcParse::IfcSpfHeader::stream;
4343
%ignore IfcParse::HeaderEntity::is;
4444

45+
%ignore IfcParse::IfcFile::type_iterator;
46+
4547
%ignore IfcUtil::IfcBaseClass::is;
4648

4749
%rename("by_id") entityById;
@@ -80,6 +82,22 @@ private:
8082
return keys;
8183
}
8284

85+
std::vector<std::string> types() const {
86+
const size_t n = std::distance($self->types_begin(), $self->types_end());
87+
std::vector<std::string> ts;
88+
ts.reserve(n);
89+
std::transform($self->types_begin(), $self->types_end(), std::back_inserter(ts), IfcSchema::Type::ToString);
90+
return ts;
91+
}
92+
93+
std::vector<std::string> types_with_super() const {
94+
const size_t n = std::distance($self->types_incl_super_begin(), $self->types_incl_super_end());
95+
std::vector<std::string> ts;
96+
ts.reserve(n);
97+
std::transform($self->types_incl_super_begin(), $self->types_incl_super_end(), std::back_inserter(ts), IfcSchema::Type::ToString);
98+
return ts;
99+
}
100+
83101
%pythoncode %{
84102
if _newclass:
85103
# Hide the getters with read-only property implementations

test/tests.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@
5959
assert f2.add(app).get_info(False, True) == app.get_info(False, True)
6060
assert "Version" in dir(app)
6161

62+
# Enumeration of entity type names
63+
g = ifcopenshell.open()
64+
p = g.createIfcCartesianPoint((0.,0.))
65+
assert len(g.types()) == 1
66+
assert "IfcPoint" in g.types_with_super()
67+
g.remove(p)
68+
assert len(g.types()) == 0
69+
assert len(g.types_with_super()) == 0
70+
6271
# Some operations on ifcopenshell.entity_instance
6372
assert f[22].Id == ''
6473
assert f[22].Addresses is None

0 commit comments

Comments
 (0)