Unify and fix group handling in geofeaturegroups
This commit is contained in:
@@ -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_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<DocumentObject*> Document::getObjectsOfType(const Base::Type& typeId
|
||||
return Objects;
|
||||
}
|
||||
|
||||
}
|
||||
std::vector< DocumentObject* > Document::getObjectsWithExtension(const Base::Type& typeId, bool derived) const {
|
||||
|
||||
std::vector<DocumentObject*> Objects;
|
||||
for (std::vector<DocumentObject*>::const_iterator it = d->objectArray.begin(); it != d->objectArray.end(); ++it) {
|
||||
std::vector<DocumentObject*> Objects;
|
||||
if ((*it)->hasExtension(typeId, derived))
|
||||
Objects.push_back(*it);
|
||||
}
|
||||
return Objects;
|
||||
|
||||
@@ -230,7 +230,8 @@ public:
|
||||
/// Returns a list of all Objects
|
||||
std::vector<DocumentObject*> getObjects() const;
|
||||
std::vector<DocumentObject*> getObjectsOfType(const Base::Type& typeId) const;
|
||||
std::vector<DocumentObject*> 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<DocumentObject*> getObjectsWithExtension(const Base::Type& typeId, bool derived = true) const;
|
||||
std::vector<DocumentObject*> findObjects(const Base::Type& typeId, const char* objname) const;
|
||||
/// Returns an array with the correct types already.
|
||||
template<typename T> inline std::vector<T*> getObjectsOfType() const;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -77,87 +77,18 @@ void GeoFeatureGroupExtension::transformPlacement(const Base::Placement &transfo
|
||||
this->placement().setValue(plm);
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> GeoFeatureGroupExtension::getGeoSubObjects () const {
|
||||
const auto & objs = Group.getValues();
|
||||
|
||||
std::set<const App::GroupExtension*> processedGroups;
|
||||
std::set<App::DocumentObject*> rvSet;
|
||||
std::set<App::DocumentObject*> curSearchSet (objs.begin(), objs.end());
|
||||
|
||||
processedGroups.insert ( this );
|
||||
|
||||
while ( !curSearchSet.empty() ) {
|
||||
rvSet.insert ( curSearchSet.begin (), curSearchSet.end () );
|
||||
|
||||
std::set<App::DocumentObject*> nextSearchSet;
|
||||
for ( auto obj: curSearchSet) {
|
||||
if ( isNonGeoGroup (obj) ) {
|
||||
auto *grp = obj->getExtensionByType<App::GroupExtension>();
|
||||
// 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<App::DocumentObject*> ( rvSet.begin(), rvSet.end() );
|
||||
}
|
||||
|
||||
bool GeoFeatureGroupExtension::geoHasObject (const DocumentObject* obj) const {
|
||||
const auto & objs = Group.getValues();
|
||||
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<const App::GroupExtension*> processedGroups;
|
||||
std::set<const App::DocumentObject*> curSearchSet (objs.begin(), objs.end());
|
||||
|
||||
processedGroups.insert ( this );
|
||||
|
||||
while ( !curSearchSet.empty() ) {
|
||||
if ( curSearchSet.find (obj) != curSearchSet.end() ) {
|
||||
return true;
|
||||
}
|
||||
std::set<const App::DocumentObject*> nextSearchSet;
|
||||
for ( auto obj: curSearchSet) {
|
||||
if ( isNonGeoGroup (obj) ) {
|
||||
auto *grp = obj->getExtensionByType<App::GroupExtension>();
|
||||
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<DocumentObject*> grps = doc->getObjectsWithExtension(GeoFeatureGroupExtension::getExtensionClassTypeId());
|
||||
for (std::vector<DocumentObject*>::const_iterator it = grps.begin(); it != grps.end(); ++it) {
|
||||
GeoFeatureGroupExtension* grp = (*it)->getExtensionByType<GeoFeatureGroupExtension>();
|
||||
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<App::GroupExtension>()->removeObject(obj);
|
||||
|
||||
if (!hasObject(obj)) {
|
||||
std::vector<DocumentObject*> grp = Group.getValues();
|
||||
grp.push_back(obj);
|
||||
Group.setValues(grp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Python feature ---------------------------------------------------------
|
||||
|
||||
|
||||
@@ -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<App::DocumentObject*> 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);
|
||||
};
|
||||
|
||||
@@ -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<App::GroupExtension>()->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<DocumentObject*> grps = doc->getObjectsWithExtension(GroupExtension::getExtensionClassTypeId());
|
||||
for (std::vector<DocumentObject*>::const_iterator it = grps.begin(); it != grps.end(); ++it) {
|
||||
GroupExtension* grp = (*it)->getExtensionByType<GroupExtension>();
|
||||
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) {
|
||||
|
||||
@@ -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);
|
||||
//@}
|
||||
|
||||
@@ -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<DocumentObject*> grps = doc->getObjectsWithExtension ( OriginGroupExtension::getExtensionClassTypeId() );
|
||||
for (auto grpObj: grps) {
|
||||
OriginGroupExtension* grp = dynamic_cast <OriginGroupExtension* >(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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -67,24 +67,17 @@ Part::~Part(void)
|
||||
{
|
||||
}
|
||||
|
||||
App::Part *Part::getPartOfObject (const DocumentObject* obj, bool indirect) {
|
||||
const Document* doc = obj->getDocument();
|
||||
std::vector<DocumentObject*> grps = doc->getObjectsOfType ( Part::getClassTypeId() );
|
||||
|
||||
for (auto partObj: grps) {
|
||||
Part* part = static_cast <Part* >(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<App::Part*>(obj);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "Application.h"
|
||||
#include "Document.h"
|
||||
#include <App/GeoFeatureGroupExtension.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Inventor/nodes/SoGroup.h>
|
||||
|
||||
using namespace Gui;
|
||||
@@ -55,8 +56,33 @@ ViewProviderGeoFeatureGroupExtension::~ViewProviderGeoFeatureGroupExtension()
|
||||
|
||||
|
||||
std::vector<App::DocumentObject*> 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<App::GeoFeatureGroupExtension>();
|
||||
return ext ? ext->getGeoSubObjects() : std::vector<App::DocumentObject*>();
|
||||
if(ext) {
|
||||
auto objs = ext->Group.getValues();
|
||||
return objs;
|
||||
}
|
||||
return std::vector<App::DocumentObject*>();
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> 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<App::GeoFeatureGroupExtension>();
|
||||
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<App::DocumentObject*> claim;
|
||||
auto objs = ext->Group.getValues();
|
||||
for(auto obj : objs) {
|
||||
if(obj->getInList().size()<=1)
|
||||
claim.push_back(obj);
|
||||
}
|
||||
return claim;
|
||||
}
|
||||
return std::vector<App::DocumentObject*>();
|
||||
}
|
||||
|
||||
void ViewProviderGeoFeatureGroupExtension::extensionAttach(App::DocumentObject* pcObject)
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
virtual ~ViewProviderGeoFeatureGroupExtension();
|
||||
|
||||
virtual std::vector<App::DocumentObject*> 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user