Skip to content

Commit 901ef57

Browse files
committed
1 parent b604e5c commit 901ef57

4 files changed

Lines changed: 138 additions & 26 deletions

File tree

src/ifcopenshell-python/ifcopenshell/file.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ def __init__(self, f=None):
2828
self.wrapped_data = f or ifcopenshell_wrapper.file()
2929
def create_entity(self,type,*args,**kwargs):
3030
e = entity_instance(type)
31+
self.wrapped_data.add(e.wrapped_data)
32+
e.wrapped_data.this.disown()
3133
attrs = list(enumerate(args)) + \
3234
[(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()]
3335
for idx, arg in attrs: e[idx] = arg
34-
self.wrapped_data.add(e.wrapped_data)
35-
e.wrapped_data.this.disown()
3636
return e
3737
def __getattr__(self, attr):
3838
if attr[0:6] == 'create': return functools.partial(self.create_entity,attr[6:])

src/ifcparse/IfcFile.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class IFC_PARSE_API IfcFile {
5555
IfcSpfHeader _header;
5656

5757
void setDefaultHeaderValues();
58-
void register_inverse(unsigned, Token);
58+
5959
public:
6060
IfcParse::IfcSpfLexer* tokens;
6161
IfcParse::IfcSpfStream* stream;
@@ -130,6 +130,10 @@ class IFC_PARSE_API IfcFile {
130130

131131
void load(const IfcEntityInstanceData&);
132132
void load(unsigned entity_instance_name, std::vector<Argument*>& attributes);
133+
134+
void register_inverse(unsigned, Token);
135+
void register_inverse(unsigned, IfcUtil::IfcBaseClass*);
136+
void unregister_inverse(unsigned, IfcUtil::IfcBaseClass*);
133137
};
134138

135139
}

src/ifcparse/IfcParse.cpp

Lines changed: 121 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,20 @@ void IfcParse::IfcFile::register_inverse(unsigned id_from, Token t) {
915915
byref[t.value_int].push_back(id_from);
916916
}
917917

918+
void IfcParse::IfcFile::register_inverse(unsigned id_from, IfcUtil::IfcBaseClass* inst) {
919+
byref[inst->entity->id()].push_back(id_from);
920+
}
921+
922+
void IfcParse::IfcFile::unregister_inverse(unsigned id_from, IfcUtil::IfcBaseClass* inst) {
923+
std::vector<unsigned int>& ids = byref[inst->entity->id()];
924+
std::vector<unsigned int>::const_iterator it = std::find(ids.begin(), ids.end(), id_from);
925+
if (it == ids.end()) {
926+
throw IfcParse::IfcException("Instance not found among inverses");
927+
} else {
928+
ids.erase(it);
929+
}
930+
}
931+
918932
//
919933
// Returns a string representation of the entity
920934
// Note that this initializes the entity if it is not initialized
@@ -1008,6 +1022,97 @@ Argument* IfcEntityInstanceData::getArgument(unsigned int i) const {
10081022
}
10091023
}
10101024

1025+
class unregister_inverse_visitor {
1026+
private:
1027+
IfcFile& file_;
1028+
const IfcEntityInstanceData& data_;
1029+
1030+
public:
1031+
unregister_inverse_visitor(IfcFile& file, const IfcEntityInstanceData& data)
1032+
: file_(file), data_(data)
1033+
{}
1034+
1035+
void operator()(IfcUtil::IfcBaseClass* inst) {
1036+
file_.unregister_inverse(data_.id(), inst);
1037+
}
1038+
};
1039+
1040+
class register_inverse_visitor {
1041+
private:
1042+
IfcFile& file_;
1043+
const IfcEntityInstanceData& data_;
1044+
1045+
public:
1046+
register_inverse_visitor(IfcFile& file, const IfcEntityInstanceData& data)
1047+
: file_(file), data_(data)
1048+
{}
1049+
1050+
void operator()(IfcUtil::IfcBaseClass* inst) {
1051+
file_.register_inverse(data_.id(), inst);
1052+
}
1053+
};
1054+
1055+
class add_to_instance_list_visitor {
1056+
private:
1057+
IfcEntityList::ptr& list_;
1058+
1059+
public:
1060+
add_to_instance_list_visitor(IfcEntityList::ptr& list)
1061+
: list_(list)
1062+
{}
1063+
1064+
void operator()(IfcUtil::IfcBaseClass* inst) {
1065+
list_->push(inst);
1066+
}
1067+
};
1068+
1069+
class apply_individual_instance_visitor {
1070+
private:
1071+
Argument* attribute_;
1072+
IfcEntityInstanceData* data_;
1073+
1074+
template <typename T>
1075+
void apply_attribute_(T& t, Argument* attr) const {
1076+
if (attr->type() == IfcUtil::Argument_ENTITY_INSTANCE) {
1077+
IfcUtil::IfcBaseClass* inst = *attr;
1078+
t(inst);
1079+
} else if (attr->type() == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
1080+
IfcEntityList::ptr entity_list_attribute = *attr;
1081+
for (IfcEntityList::it it = entity_list_attribute->begin(); it != entity_list_attribute->end(); ++it) {
1082+
t(*it);
1083+
}
1084+
} else if (attr->type() == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
1085+
IfcEntityListList::ptr entity_list_attribute = *attr;
1086+
for (IfcEntityListList::outer_it it = entity_list_attribute->begin(); it != entity_list_attribute->end(); ++it) {
1087+
for (IfcEntityListList::inner_it jt = it->begin(); jt != it->end(); ++jt) {
1088+
t(*jt);
1089+
}
1090+
}
1091+
}
1092+
};
1093+
public:
1094+
apply_individual_instance_visitor(Argument* attribute)
1095+
: attribute_(attribute), data_(0)
1096+
{}
1097+
1098+
apply_individual_instance_visitor(IfcEntityInstanceData* data)
1099+
: attribute_(0), data_(data)
1100+
{}
1101+
1102+
template <typename T>
1103+
void apply(T& t) const {
1104+
if (attribute_) {
1105+
apply_attribute_(t, attribute_);
1106+
} else {
1107+
for (unsigned i = 0; i < data_->getArgumentCount(); ++i) {
1108+
Argument* attr = data_->getArgument(i);
1109+
apply_attribute_(t, attr);
1110+
}
1111+
}
1112+
};
1113+
1114+
};
1115+
10111116
void IfcEntityInstanceData::setArgument(unsigned int i, Argument* a, IfcUtil::ArgumentType attr_type) {
10121117
if (!initialized_) {
10131118
load();
@@ -1017,10 +1122,6 @@ void IfcEntityInstanceData::setArgument(unsigned int i, Argument* a, IfcUtil::Ar
10171122
attributes_.push_back(new NullArgument());
10181123
}
10191124

1020-
if (i < attributes_.size()) {
1021-
delete attributes_[i];
1022-
}
1023-
10241125
if (attr_type == IfcUtil::Argument_UNKNOWN) {
10251126
attr_type = a->type();
10261127
}
@@ -1117,6 +1218,20 @@ void IfcEntityInstanceData::setArgument(unsigned int i, Argument* a, IfcUtil::Ar
11171218
break;
11181219
}
11191220

1221+
if (i < attributes_.size()) {
1222+
Argument* current_attribute = attributes_[i];
1223+
if (this->file) {
1224+
unregister_inverse_visitor visitor(*this->file, *this);
1225+
apply_individual_instance_visitor(current_attribute).apply(visitor);
1226+
}
1227+
delete attributes_[i];
1228+
}
1229+
1230+
if (this->file) {
1231+
register_inverse_visitor visitor(*this->file, *this);
1232+
apply_individual_instance_visitor(copy).apply(visitor);
1233+
}
1234+
11201235
if (i < attributes_.size()) {
11211236
attributes_[i] = copy;
11221237
} else {
@@ -1271,25 +1386,8 @@ void traverse_(IfcUtil::IfcBaseClass* instance, std::set<IfcUtil::IfcBaseClass*>
12711386

12721387
if (level >= max_level && max_level > 0) return;
12731388

1274-
for (unsigned i = 0; i < instance->getArgumentCount(); ++i) {
1275-
Argument* arg = instance->getArgument(i);
1276-
1277-
if (arg->type() == IfcUtil::Argument_ENTITY_INSTANCE) {
1278-
traverse_(*arg, visited, list, level + 1, max_level);
1279-
} else if (arg->type() == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
1280-
IfcEntityList::ptr entity_list_attribute = *arg;
1281-
for (IfcEntityList::it it = entity_list_attribute->begin(); it != entity_list_attribute->end(); ++it) {
1282-
traverse_(*it, visited, list, level + 1, max_level);
1283-
}
1284-
} else if (arg->type() == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
1285-
IfcEntityListList::ptr entity_list_attribute = *arg;
1286-
for (IfcEntityListList::outer_it it = entity_list_attribute->begin(); it != entity_list_attribute->end(); ++it) {
1287-
for (IfcEntityListList::inner_it jt = it->begin(); jt != it->end(); ++jt) {
1288-
traverse_(*jt, visited, list, level + 1, max_level);
1289-
}
1290-
}
1291-
}
1292-
}
1389+
add_to_instance_list_visitor visit(list);
1390+
apply_individual_instance_visitor(instance->entity).apply(visit);
12931391
}
12941392

12951393
IfcEntityList::ptr IfcParse::traverse(IfcUtil::IfcBaseClass* instance, int max_level) {

test/tests.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@
5252
assert "('John','Matthew')" in str(f[22])
5353
assert ("Id", "123") in list(f[22].get_info().items())
5454

55+
# Assignment of instances and implications on inverse attributes
56+
assert f[288].ConnectedTo[0].RelatingElement == f[288]
57+
num_connections_1 = len(f[340].ConnectedTo + f[340].ConnectedFrom)
58+
f[288].ConnectedTo[0].RelatingElement = f[340]
59+
num_connections_2 = len(f[340].ConnectedTo + f[340].ConnectedFrom)
60+
assert num_connections_2 == num_connections_1 + 1
61+
assert f[288].ConnectedTo == ()
62+
rel = f.createIfcRelConnectsPathElements(RelatingElement=f[288])
63+
assert f[288].ConnectedTo == (rel,)
64+
5565
# Some operations on ifcopenshell.guid
5666
assert len(ifcopenshell.guid.compress(uuid.uuid1().hex)) == 22
5767

0 commit comments

Comments
 (0)