diff --git a/src/App/Document.cpp b/src/App/Document.cpp index af2622a671..7275adc431 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -301,8 +301,10 @@ void Document::exportGraphviz(std::ostream& out) const void setGraphAttributes(const DocumentObject * obj) { assert(GraphList[obj] != 0); - get_property(*GraphList[obj], graph_name) = getClusterName(obj); - get_property(*GraphList[obj], graph_graph_attribute)["bgcolor"] = "#e0e0e0"; + get_property(*GraphList[obj], graph_name) = getClusterName(obj); + + get_property(*GraphList[obj], graph_graph_attribute)["bgcolor"] = "#e0e0e0"; + get_property(*GraphList[obj], graph_graph_attribute)["style"] = "rounded,filled"; setGraphLabel(*GraphList[obj], obj); } @@ -2886,11 +2888,11 @@ std::vector Document::getObjectsOfType(const Base::Type& typeId return Objects; } -std::vector< DocumentObject* > Document::getObjectsWithExtension(const Base::Type& typeId) const { +std::vector< DocumentObject* > Document::getObjectsWithExtension(const Base::Type& typeId, bool derived) const { std::vector Objects; for (std::vector::const_iterator it = d->objectArray.begin(); it != d->objectArray.end(); ++it) { - if ((*it)->hasExtension(typeId)) + if ((*it)->hasExtension(typeId, derived)) Objects.push_back(*it); } return Objects; diff --git a/src/App/Document.h b/src/App/Document.h index c507d71799..996d37abf2 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -230,7 +230,8 @@ public: /// Returns a list of all Objects std::vector getObjects() const; std::vector getObjectsOfType(const Base::Type& typeId) const; - std::vector getObjectsWithExtension(const Base::Type& typeId) const; + /// Returns all object with given extensions. If derived=true also all objects with extenions derived from the given one + std::vector getObjectsWithExtension(const Base::Type& typeId, bool derived = true) const; std::vector findObjects(const Base::Type& typeId, const char* objname) const; /// Returns an array with the correct types already. template inline std::vector getObjectsOfType() const; diff --git a/src/App/ExtensionContainer.cpp b/src/App/ExtensionContainer.cpp index be52ac6922..64ff37606c 100644 --- a/src/App/ExtensionContainer.cpp +++ b/src/App/ExtensionContainer.cpp @@ -68,11 +68,11 @@ void ExtensionContainer::registerExtension(Base::Type extension, Extension* ext) _extensions[extension] = ext; } -bool ExtensionContainer::hasExtension(Base::Type t) const { +bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const { //check for the exact type bool found = _extensions.find(t) != _extensions.end(); - if(!found) { + if(!found && derived) { //and for types derived from it, as they can be cast to the extension for(auto entry : _extensions) { if(entry.first.isDerivedFrom(t)) @@ -94,10 +94,10 @@ bool ExtensionContainer::hasExtension(const std::string& name) const { } -Extension* ExtensionContainer::getExtension(Base::Type t) const { +Extension* ExtensionContainer::getExtension(Base::Type t, bool derived) const { auto result = _extensions.find(t); - if(result == _extensions.end()) { + if((result == _extensions.end()) && derived) { //we need to check for derived types for(auto entry : _extensions) { if(entry.first.isDerivedFrom(t)) diff --git a/src/App/ExtensionContainer.h b/src/App/ExtensionContainer.h index 511d70e6ed..43e169f87b 100644 --- a/src/App/ExtensionContainer.h +++ b/src/App/ExtensionContainer.h @@ -124,10 +124,10 @@ public: virtual ~ExtensionContainer(); void registerExtension(Base::Type extension, App::Extension* ext); - bool hasExtension(Base::Type) const; //returns first of type (or derived from) and throws otherwise + bool hasExtension(Base::Type, bool derived=true) const; //returns first of type (or derived from if set to true) and throws otherwise bool hasExtension(const std::string& name) const; //this version does not check derived classes bool hasExtensions() const; - App::Extension* getExtension(Base::Type) const; + App::Extension* getExtension(Base::Type, bool derived = true) const; App::Extension* getExtension(const std::string& name) const; //this version does not check derived classes //returns first of type (or derived from) and throws otherwise diff --git a/src/App/GeoFeatureGroupExtension.cpp b/src/App/GeoFeatureGroupExtension.cpp index 3b3b9a7e54..85843bdcfb 100644 --- a/src/App/GeoFeatureGroupExtension.cpp +++ b/src/App/GeoFeatureGroupExtension.cpp @@ -77,87 +77,18 @@ void GeoFeatureGroupExtension::transformPlacement(const Base::Placement &transfo this->placement().setValue(plm); } -std::vector GeoFeatureGroupExtension::getGeoSubObjects () const { - const auto & objs = Group.getValues(); - - std::set processedGroups; - std::set rvSet; - std::set curSearchSet (objs.begin(), objs.end()); - - processedGroups.insert ( this ); - - while ( !curSearchSet.empty() ) { - rvSet.insert ( curSearchSet.begin (), curSearchSet.end () ); - - std::set nextSearchSet; - for ( auto obj: curSearchSet) { - if ( isNonGeoGroup (obj) ) { - auto *grp = obj->getExtensionByType(); - // Check if we havent already processed the element may happen in case of nontree structure - // Note: if the condition is false this generally indicates malformed structure - if ( processedGroups.find (grp) == processedGroups.end() ) { - processedGroups.insert ( grp ); - const auto & objs = grp->Group.getValues(); - nextSearchSet.insert (objs.begin(), objs.end()); - } - } - } - nextSearchSet.swap (curSearchSet); - } - - return std::vector ( rvSet.begin(), rvSet.end() ); -} - -bool GeoFeatureGroupExtension::geoHasObject (const DocumentObject* obj) const { - const auto & objs = Group.getValues(); - - if (!obj) { - return false; - } - - std::set processedGroups; - std::set curSearchSet (objs.begin(), objs.end()); - - processedGroups.insert ( this ); - - while ( !curSearchSet.empty() ) { - if ( curSearchSet.find (obj) != curSearchSet.end() ) { - return true; - } - std::set nextSearchSet; - for ( auto obj: curSearchSet) { - if ( isNonGeoGroup (obj) ) { - auto *grp = obj->getExtensionByType(); - if ( processedGroups.find (grp) == processedGroups.end() ) { - processedGroups.insert ( grp ); - const auto & objs = grp->Group.getValues(); - nextSearchSet.insert (objs.begin(), objs.end()); - } - } - } - nextSearchSet.swap (curSearchSet); - } - return false; -} - -DocumentObject* GeoFeatureGroupExtension::getGroupOfObject(const DocumentObject* obj, bool indirect) +DocumentObject* GeoFeatureGroupExtension::getGroupOfObject(const DocumentObject* obj) { - const Document* doc = obj->getDocument(); - std::vector grps = doc->getObjectsWithExtension(GeoFeatureGroupExtension::getExtensionClassTypeId()); - for (std::vector::const_iterator it = grps.begin(); it != grps.end(); ++it) { - GeoFeatureGroupExtension* grp = (*it)->getExtensionByType(); - if ( indirect ) { - if (grp->geoHasObject(obj)) { - return grp->getExtendedObject(); - } - } else { - if (grp->hasObject(obj)) { - return grp->getExtendedObject(); - } - } + //compared to GroupExtension we do return here all geofeaturegroups including all extensions erived from it + //like origingroup. That is needed as we use this function to get all local coordinate systems. Also there + //is no reason to distuinguish between geofeatuergroups, there is only between group/geofeaturegroup + auto list = obj->getInList(); + for (auto obj : list) { + if(obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())) + return obj; } - return 0; + return nullptr; } Base::Placement GeoFeatureGroupExtension::globalGroupPlacement() { @@ -178,6 +109,25 @@ Base::Placement GeoFeatureGroupExtension::recursiveGroupPlacement(GeoFeatureGrou return group->placement().getValue(); } +void GeoFeatureGroupExtension::addObject(App::DocumentObject* obj) { + + if(!allowObject(obj)) + return; + + //only one geofeaturegroup per object. This is the reason why we need to override addObject, + //we need to check here for GeoFeatureGroups only. It is allowed to be at the same time in a + //GeoFeatureGroup and a Group + auto *group = App::GeoFeatureGroupExtension::getGroupOfObject(obj); + if(group && group != getExtendedObject()) + group->getExtensionByType()->removeObject(obj); + + if (!hasObject(obj)) { + std::vector grp = Group.getValues(); + grp.push_back(obj); + Group.setValues(grp); + } +} + // Python feature --------------------------------------------------------- diff --git a/src/App/GeoFeatureGroupExtension.h b/src/App/GeoFeatureGroupExtension.h index ecb51cf66a..77d1b729ee 100644 --- a/src/App/GeoFeatureGroupExtension.h +++ b/src/App/GeoFeatureGroupExtension.h @@ -34,7 +34,19 @@ namespace App { /** - * The base class for placeable group of DocumentObjects + * @brief The base class for placeable group of DocumentObjects. It represents a local coordnate system + * + * This class is the FreeCAD way of representing local coordinate systems. It groups its childs beneath + * it and transforms them all with the GeoFeatureGroup placement. A few important properties: + * - Every child that belongs to the CS must be in the Group proeprty. Even if a sketch is part of a pad, + * it must be in the Group property of the same GeoFeatureGroup as pad. This also holds for normal + * GroupExtensions. They can be added to a GeoFeatureGroup, but all objects that the group holds must + * also be added to the GeoFeatureGroup + * - Objects can be only in a single GeoFeatureGroup. It is not allowed to have a document object in + * multiple GeoFeatureGroups + * - PropertyLinks between different GeoFeatureGroups are forbidden. There are special link proeprties + * that allow such cross-CS links. + * - Expressions can cross GeoFeatureGroup borders */ class AppExport GeoFeatureGroupExtension : public App::GroupExtension { @@ -52,16 +64,11 @@ public: * @param transform (input). */ virtual void transformPlacement(const Base::Placement &transform); + /// Constructor GeoFeatureGroupExtension(void); virtual ~GeoFeatureGroupExtension(); - /// Returns all geometrically controlled objects: all objects of this group and it's non-geo subgroups - std::vector getGeoSubObjects () const; - - /// Returns true if either the group or one of it's non-geo subgroups has the object - bool geoHasObject (const DocumentObject* obj) const; - /** Returns the geo feature group which contains this object. * In case this object is not part of any geoFeatureGroup 0 is returned. * Unlike DocumentObjectGroup::getGroupOfObject serches only for GeoFeatureGroups @@ -69,7 +76,7 @@ public: * @param indirect if true return if the group that so-called geoHas the object, @see geoHasObject() * default is true */ - static DocumentObject* getGroupOfObject(const DocumentObject* obj, bool indirect=true); + static DocumentObject* getGroupOfObject(const DocumentObject* obj); /** * @brief Calculates the global placement of this group @@ -89,6 +96,8 @@ public: !obj->hasExtension(GeoFeatureGroupExtension::getExtensionClassTypeId()); } + virtual void addObject(DocumentObject* obj); + private: Base::Placement recursiveGroupPlacement(GeoFeatureGroupExtension* group); }; diff --git a/src/App/GroupExtension.cpp b/src/App/GroupExtension.cpp index 3e2b9541d9..0af4e9b638 100644 --- a/src/App/GroupExtension.cpp +++ b/src/App/GroupExtension.cpp @@ -63,7 +63,8 @@ void GroupExtension::addObject(DocumentObject* obj) if(!allowObject(obj)) return; - //only one group per object + //only one group per object. Note that it is allowed to be in a group and geofeaturegroup. However, + //getGroupOfObject() returns only normal groups, no GeoFeatureGroups. Hence this works. auto *group = App::GroupExtension::getGroupOfObject(obj); if(group && group != getExtendedObject()) group->getExtensionByType()->removeObject(obj); @@ -207,15 +208,16 @@ int GroupExtension::countObjectsOfType(const Base::Type& typeId) const DocumentObject* GroupExtension::getGroupOfObject(const DocumentObject* obj) { - const Document* doc = obj->getDocument(); - std::vector grps = doc->getObjectsWithExtension(GroupExtension::getExtensionClassTypeId()); - for (std::vector::const_iterator it = grps.begin(); it != grps.end(); ++it) { - GroupExtension* grp = (*it)->getExtensionByType(); - if (grp->hasObject(obj)) - return *it; + //note that we return here only Groups, but nothing derived from it, e.g. no GeoFeatureGroups. + //That is important as there are clear differences between groups/geofeature groups (e.g. a object + //can be in only one group, and only one geofeaturegroup, however, it can be in both at the same time) + auto list = obj->getInList(); + for (auto obj : list) { + if(obj->hasExtension(App::GroupExtension::getExtensionClassTypeId(), false)) + return obj; } - return 0; + return nullptr; } PyObject* GroupExtension::getExtensionPyObject(void) { diff --git a/src/App/GroupExtension.h b/src/App/GroupExtension.h index 8fd70d4273..97b2aaf6eb 100644 --- a/src/App/GroupExtension.h +++ b/src/App/GroupExtension.h @@ -91,7 +91,9 @@ public: */ int countObjectsOfType(const Base::Type& typeId) const; /** Returns the object group of the document which the given object \a obj is part of. - * In case this object is not part of a group 0 is returned. + * In case this object is not part of a group 0 is returned. + * @note This only returns objects that are normal groups, not any special derived type + * like geofeaturegroups or origingroups. To retrieve those please youse their appropriate functions */ static DocumentObject* getGroupOfObject(const DocumentObject* obj); //@} diff --git a/src/App/OriginGroupExtension.cpp b/src/App/OriginGroupExtension.cpp index 212a390f1e..f6f869a156 100644 --- a/src/App/OriginGroupExtension.cpp +++ b/src/App/OriginGroupExtension.cpp @@ -65,27 +65,15 @@ App::Origin *OriginGroupExtension::getOrigin () const { } } -App::DocumentObject *OriginGroupExtension::getGroupOfObject (const DocumentObject* obj, bool indirect) { - const Document* doc = obj->getDocument(); - std::vector grps = doc->getObjectsWithExtension ( OriginGroupExtension::getExtensionClassTypeId() ); - for (auto grpObj: grps) { - OriginGroupExtension* grp = dynamic_cast (grpObj->getExtension( - OriginGroupExtension::getExtensionClassTypeId())); - - if(!grp) throw Base::TypeError("Wrong type in origin group extenion"); - - if ( indirect ) { - if ( grp->geoHasObject (obj) ) { - return grp->getExtendedObject(); - } - } else { - if ( grp->hasObject (obj) ) { - return grp->getExtendedObject(); - } - } +App::DocumentObject *OriginGroupExtension::getGroupOfObject (const DocumentObject* obj) { + + auto list = obj->getInList(); + for (auto obj : list) { + if(obj->hasExtension(App::OriginGroupExtension::getExtensionClassTypeId())) + return obj; } - return 0; + return nullptr; } short OriginGroupExtension::extensionMustExecute() { diff --git a/src/App/OriginGroupExtension.h b/src/App/OriginGroupExtension.h index 6b393c9c09..2e98bae3a0 100644 --- a/src/App/OriginGroupExtension.h +++ b/src/App/OriginGroupExtension.h @@ -55,7 +55,7 @@ public: * @param indirect if true return if the group that so-called geoHas the object, @see geoHasObject() * default is true */ - static DocumentObject* getGroupOfObject (const DocumentObject* obj, bool indirect=true); + static DocumentObject* getGroupOfObject (const DocumentObject* obj); /// Returns true on changing OriginFeature set virtual short extensionMustExecute () override; diff --git a/src/App/Part.cpp b/src/App/Part.cpp index 360004cf01..4c2c06bc85 100644 --- a/src/App/Part.cpp +++ b/src/App/Part.cpp @@ -67,24 +67,17 @@ Part::~Part(void) { } -App::Part *Part::getPartOfObject (const DocumentObject* obj, bool indirect) { - const Document* doc = obj->getDocument(); - std::vector grps = doc->getObjectsOfType ( Part::getClassTypeId() ); - - for (auto partObj: grps) { - Part* part = static_cast (partObj); - if ( indirect ) { - if ( part->geoHasObject (obj) ) { - return part; - } - } else { - if ( part->hasObject (obj) ) { - return part; - } - } +App::Part *Part::getPartOfObject (const DocumentObject* obj) { + + //as a Part is a geofeaturegroup it must directly link to all objects it contains, even + //if they are in additional groups etc. + auto list = obj->getInList(); + for (auto obj : list) { + if(obj->isDerivedFrom(App::Part::getClassTypeId())) + return static_cast(obj); } - return 0; + return nullptr; } diff --git a/src/App/Part.h b/src/App/Part.h index 416e665a77..a3726251a1 100644 --- a/src/App/Part.h +++ b/src/App/Part.h @@ -91,7 +91,7 @@ public: * @param indirect if true return if the part that so-called geoHas the object, @see geoHasObject() * default is true */ - static App::Part* getPartOfObject (const DocumentObject* obj, bool indirect=true); + static App::Part* getPartOfObject (const DocumentObject* obj); virtual PyObject *getPyObject(void); }; diff --git a/src/Gui/ViewProviderGeoFeatureGroupExtension.cpp b/src/Gui/ViewProviderGeoFeatureGroupExtension.cpp index d9221c3da1..2f9dce8e83 100644 --- a/src/Gui/ViewProviderGeoFeatureGroupExtension.cpp +++ b/src/Gui/ViewProviderGeoFeatureGroupExtension.cpp @@ -33,6 +33,7 @@ #include "Application.h" #include "Document.h" #include +#include #include using namespace Gui; @@ -55,8 +56,33 @@ ViewProviderGeoFeatureGroupExtension::~ViewProviderGeoFeatureGroupExtension() std::vector ViewProviderGeoFeatureGroupExtension::extensionClaimChildren3D(void) const { + + //all object in the group must be claimed in 3D, as we are a coordinate system for all of them auto* ext = getExtendedViewProvider()->getObject()->getExtensionByType(); - return ext ? ext->getGeoSubObjects() : std::vector(); + if(ext) { + auto objs = ext->Group.getValues(); + return objs; + } + return std::vector(); +} + +std::vector ViewProviderGeoFeatureGroupExtension::extensionClaimChildren(void) const { + + //we must be carefull which objects to claim, as there might be stacked relations inside the coordinate system, + //like pad/sketch + auto* ext = getExtendedViewProvider()->getObject()->getExtensionByType(); + if(ext) { + //filter out all objects with more than one inlink, as they are most likely hold by annother + //object in the tree + std::vector claim; + auto objs = ext->Group.getValues(); + for(auto obj : objs) { + if(obj->getInList().size()<=1) + claim.push_back(obj); + } + return claim; + } + return std::vector(); } void ViewProviderGeoFeatureGroupExtension::extensionAttach(App::DocumentObject* pcObject) diff --git a/src/Gui/ViewProviderGeoFeatureGroupExtension.h b/src/Gui/ViewProviderGeoFeatureGroupExtension.h index c1ec419748..d409ae27ee 100644 --- a/src/Gui/ViewProviderGeoFeatureGroupExtension.h +++ b/src/Gui/ViewProviderGeoFeatureGroupExtension.h @@ -42,6 +42,7 @@ public: virtual ~ViewProviderGeoFeatureGroupExtension(); virtual std::vector extensionClaimChildren3D(void)const override; + virtual std::vector< App::DocumentObject* > extensionClaimChildren(void) const override; virtual SoGroup* extensionGetChildRoot(void) const override {return pcGroupChildren;}; virtual void extensionAttach(App::DocumentObject* pcObject) override; virtual void extensionSetDisplayMode(const char* ModeName) override; diff --git a/src/Gui/ViewProviderOriginGroupExtension.cpp b/src/Gui/ViewProviderOriginGroupExtension.cpp index 5026463bc1..2ca1742a6a 100644 --- a/src/Gui/ViewProviderOriginGroupExtension.cpp +++ b/src/Gui/ViewProviderOriginGroupExtension.cpp @@ -173,7 +173,7 @@ void ViewProviderOriginGroupExtension::updateOriginSize () { // calculate the bounding box for out content SbBox3f bbox(0,0,0, 0,0,0); - for(App::DocumentObject* obj : group->getGeoSubObjects()) { + for(App::DocumentObject* obj : group->Group.getValues()) { ViewProvider *vp = Gui::Application::Instance->getViewProvider(obj); if (!vp) { continue; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 08b54834d1..45f96a3274 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -2034,8 +2034,8 @@ bool SketchObject::isExternalAllowed(App::Document *pDoc, App::DocumentObject *p //App::DocumentObject *support = this->Support.getValue(); Part::BodyBase* body_this = Part::BodyBase::findBodyOf(this); Part::BodyBase* body_obj = Part::BodyBase::findBodyOf(pObj); - App::Part* part_this = App::Part::getPartOfObject(this, true); - App::Part* part_obj = App::Part::getPartOfObject(pObj, true); + App::Part* part_this = App::Part::getPartOfObject(this); + App::Part* part_obj = App::Part::getPartOfObject(pObj); if (part_this == part_obj){ //either in the same part, or in the root of document if (body_this == NULL) { return true;