25
#include "PreCompiled.h"
27
#include <App/Document.h>
28
#include <Base/Tools.h>
30
#include "GeoFeatureGroupExtension.h"
33
#include "OriginFeature.h"
34
#include "OriginGroupExtension.h"
40
EXTENSION_PROPERTY_SOURCE(App::GeoFeatureGroupExtension, App::GroupExtension)
47
GeoFeatureGroupExtension::GeoFeatureGroupExtension()
49
initExtensionType(GeoFeatureGroupExtension::getExtensionClassTypeId());
50
Group.setScope(LinkScope::Child);
53
GeoFeatureGroupExtension::~GeoFeatureGroupExtension() = default;
55
void GeoFeatureGroupExtension::initExtension(ExtensionContainer* obj) {
57
if(!obj->isDerivedFrom(App::GeoFeature::getClassTypeId()))
58
throw Base::RuntimeError("GeoFeatureGroupExtension can only be applied to GeoFeatures");
60
App::GroupExtension::initExtension(obj);
63
PropertyPlacement& GeoFeatureGroupExtension::placement() {
65
if(!getExtendedContainer())
66
throw Base::RuntimeError("GeoFeatureGroupExtension was not applied to GeoFeature");
68
return static_cast<App::GeoFeature*>(getExtendedContainer())->Placement;
72
void GeoFeatureGroupExtension::transformPlacement(const Base::Placement &transform)
75
Base::Placement plm = this->placement().getValue();
76
plm = transform * plm;
77
this->placement().setValue(plm);
80
DocumentObject* GeoFeatureGroupExtension::getGroupOfObject(const DocumentObject* obj)
86
if(obj->isDerivedFrom(App::OriginFeature::getClassTypeId()))
87
return OriginGroupExtension::getGroupOfObject(obj);
92
auto list = obj->getInList();
93
for (auto inObj : list) {
98
auto group = inObj->getExtensionByType<GeoFeatureGroupExtension>(true);
99
if(group && group->hasObject(obj))
106
Base::Placement GeoFeatureGroupExtension::globalGroupPlacement()
108
if (getExtendedObject()->isRecomputing()) {
109
throw Base::RuntimeError("Global placement cannot be calculated on recompute");
112
std::unordered_set<GeoFeatureGroupExtension*> history;
113
history.insert(this);
114
return recursiveGroupPlacement(this, history);
118
Base::Placement GeoFeatureGroupExtension::recursiveGroupPlacement(GeoFeatureGroupExtension* group,
119
std::unordered_set<GeoFeatureGroupExtension*>& history)
121
history.insert(this);
123
auto inList = group->getExtendedObject()->getInList();
124
for (auto* link : inList) {
125
auto parent = link->getExtensionByType<GeoFeatureGroupExtension>(true);
126
if (parent && parent->hasObject(group->getExtendedObject())) {
128
if (history.count(parent) > 0) {
131
return recursiveGroupPlacement(parent, history) * group->placement().getValue();
135
return group->placement().getValue();
138
std::vector<DocumentObject*> GeoFeatureGroupExtension::addObjects(std::vector<App::DocumentObject*> objects) {
140
std::vector<DocumentObject*> grp = Group.getValues();
141
std::vector<DocumentObject*> ret;
143
for(auto object : objects) {
145
if(!allowObject(object))
149
std::vector<App::DocumentObject*> links = getCSRelevantLinks(object);
150
links.push_back(object);
152
for( auto obj : links) {
154
auto *group = App::GeoFeatureGroupExtension::getGroupOfObject(obj);
155
if(group && group != getExtendedObject())
156
group->getExtensionByType<App::GroupExtension>()->removeObject(obj);
158
if (!hasObject(obj)) {
165
Group.setValues(grp);
169
std::vector<DocumentObject*> GeoFeatureGroupExtension::removeObjects(std::vector<App::DocumentObject*> objects) {
171
std::vector<DocumentObject*> removed;
172
std::vector<DocumentObject*> grp = Group.getValues();
174
for(auto object : objects) {
176
std::vector< DocumentObject* > links = getCSRelevantLinks(object);
177
links.push_back(object);
180
for(auto link : links) {
181
auto end = std::remove(grp.begin(), grp.end(), link);
182
if(end != grp.end()) {
183
grp.erase(end, grp.end());
184
removed.push_back(link);
190
Group.setValues(grp);
195
void GeoFeatureGroupExtension::extensionOnChanged(const Property* p) {
198
if(p == &Group && !Group.testStatus(Property::User3)) {
200
if((!getExtendedObject()->isRestoring()
201
|| getExtendedObject()->getDocument()->testStatus(Document::Importing))
202
&& !getExtendedObject()->getDocument()->isPerformingTransaction()) {
205
auto corrected = Group.getValues();
206
for(auto obj : Group.getValues()) {
210
auto list = obj->getInList();
211
for (auto in : list) {
212
if(in == getExtendedObject())
214
auto parent = in->getExtensionByType<GeoFeatureGroupExtension>(true);
215
if(parent && parent->hasObject(obj)) {
217
corrected.erase(std::remove(corrected.begin(), corrected.end(), obj), corrected.end());
224
Base::ObjectStatusLocker<Property::Status, Property> guard(Property::User3, &Group);
225
Group.setValues(corrected);
226
throw Base::RuntimeError("Object can only be in a single GeoFeatureGroup");
231
App::GroupExtension::extensionOnChanged(p);
235
std::vector< DocumentObject* > GeoFeatureGroupExtension::getScopedObjectsFromLinks(const DocumentObject* obj, LinkScope scope) {
241
std::vector< App::DocumentObject* > result;
242
std::vector<App::Property*> list;
243
obj->getPropertyList(list);
244
for(App::Property* prop : list) {
245
auto vec = getScopedObjectsFromLink(prop, scope);
246
result.insert(result.end(), vec.begin(), vec.end());
250
std::sort(result.begin(), result.end());
251
result.erase(std::unique(result.begin(), result.end()), result.end());
256
std::vector< DocumentObject* > GeoFeatureGroupExtension::getScopedObjectsFromLink(App::Property* prop, LinkScope scope) {
261
std::vector< App::DocumentObject* > result;
262
auto link = Base::freecad_dynamic_cast<PropertyLinkBase>(prop);
263
if(link && link->getScope()==scope)
264
link->getLinks(result);
269
void GeoFeatureGroupExtension::getCSOutList(const App::DocumentObject* obj,
270
std::vector< DocumentObject* >& vec) {
277
auto result = getScopedObjectsFromLinks(obj, LinkScope::Local);
280
result.erase(std::remove_if(result.begin(), result.end(), [](App::DocumentObject* obj)->bool {
281
return (obj->isDerivedFrom(App::OriginFeature::getClassTypeId()) ||
282
obj->isDerivedFrom(App::Origin::getClassTypeId()));
285
vec.insert(vec.end(), result.begin(), result.end());
288
std::sort(vec.begin(), vec.end());
289
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
292
void GeoFeatureGroupExtension::getCSInList(const DocumentObject* obj,
293
std::vector< DocumentObject* >& vec) {
299
for(App::DocumentObject* parent : obj->getInList()) {
302
if(parent->hasExtension(App::GroupExtension::getExtensionClassTypeId()))
307
auto res = getScopedObjectsFromLinks(parent, LinkScope::Local);
308
if(std::find(res.begin(), res.end(), obj) != res.end())
309
vec.push_back(parent);
313
std::sort(vec.begin(), vec.end());
314
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
317
std::vector< DocumentObject* > GeoFeatureGroupExtension::getCSRelevantLinks(const DocumentObject* obj) {
323
std::vector<DocumentObject*> vec;
325
recursiveCSRelevantLinks(obj, vec);
328
std::sort(vec.begin(), vec.end());
329
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
330
vec.erase(std::remove(vec.begin(), vec.end(), obj), vec.end());
335
void GeoFeatureGroupExtension::recursiveCSRelevantLinks(const DocumentObject* obj,
336
std::vector< DocumentObject* >& vec) {
341
std::vector< DocumentObject* > links;
342
getCSOutList(obj, links);
343
getCSInList(obj, links);
346
for(auto o : links) {
347
if(!o || o == obj || std::find(vec.begin(), vec.end(), o) != vec.end())
351
recursiveCSRelevantLinks(o, vec);
355
bool GeoFeatureGroupExtension::extensionGetSubObject(DocumentObject *&ret, const char *subname,
356
PyObject **pyObj, Base::Matrix4D *mat, bool transform, int depth) const
360
if(!subname || *subname==0) {
361
auto obj = dynamic_cast<const DocumentObject*>(getExtendedContainer());
362
ret = const_cast<DocumentObject*>(obj);
364
*mat *= const_cast<GeoFeatureGroupExtension*>(this)->placement().getValue().toMatrix();
365
}else if((dot=strchr(subname,'.'))) {
367
ret = Group.findUsingMap(std::string(subname,dot));
369
std::string name = std::string(subname+1,dot);
370
for(auto child : Group.getValues()) {
371
if(name == child->Label.getStrValue()){
380
&& !ret->hasExtension(App::LinkBaseExtension::getExtensionClassTypeId())
381
&& !ret->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId()))
394
const char *next = strchr(dot,'.');
396
App::DocumentObject *nret=nullptr;
397
extensionGetSubObject(nret,dot,pyObj,mat,transform,depth+1);
405
*mat *= const_cast<GeoFeatureGroupExtension*>(this)->placement().getValue().toMatrix();
406
ret = ret->getSubObject(dot?dot:"",pyObj,mat,true,depth+1);
412
bool GeoFeatureGroupExtension::areLinksValid(const DocumentObject* obj) {
417
std::vector<App::Property*> list;
418
obj->getPropertyList(list);
419
for(App::Property* prop : list) {
420
if(!isLinkValid(prop)) {
428
bool GeoFeatureGroupExtension::isLinkValid(App::Property* prop) {
434
if(!prop->getContainer()->isDerivedFrom(App::DocumentObject::getClassTypeId()))
436
auto obj = static_cast<App::DocumentObject*>(prop->getContainer());
439
auto result = getScopedObjectsFromLink(prop, LinkScope::Local);
440
auto group = getGroupOfObject(obj);
441
for(auto link : result) {
442
if(getGroupOfObject(link) != group)
447
if(obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())) {
448
result = getScopedObjectsFromLink(prop, LinkScope::Child);
449
auto groupExt = obj->getExtensionByType<App::GeoFeatureGroupExtension>();
450
for(auto link : result) {
451
if(!groupExt->hasObject(link, true))
459
void GeoFeatureGroupExtension::getInvalidLinkObjects(const DocumentObject* obj, std::vector< DocumentObject* >& vec) {
465
auto result = getScopedObjectsFromLinks(obj, LinkScope::Local);
466
auto group = obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId()) ? obj : getGroupOfObject(obj);
467
for(auto link : result) {
468
if(getGroupOfObject(link) != group)
474
result = getScopedObjectsFromLinks(obj, LinkScope::Child);
475
auto groupExt = group->getExtensionByType<App::GeoFeatureGroupExtension>();
476
for(auto link : result) {
477
if(!groupExt->hasObject(link, true))
483
bool GeoFeatureGroupExtension::extensionGetSubObjects(std::vector<std::string> &ret, int) const {
484
for(auto obj : Group.getValues()) {
485
if(obj && obj->isAttachedToDocument() && !obj->testStatus(ObjectStatus::GeoExcluded))
486
ret.push_back(std::string(obj->getNameInDocument())+'.');
495
EXTENSION_PROPERTY_SOURCE_TEMPLATE(App::GeoFeatureGroupExtensionPython, App::GeoFeatureGroupExtension)
498
template class AppExport ExtensionPythonT<GroupExtensionPythonT<GeoFeatureGroupExtension>>;