Unify and fix group handling in geofeaturegroups

This commit is contained in:
Stefan Tröger
2017-02-08 07:08:45 +01:00
committed by wmayer
parent c3a9d43143
commit fd62ef30f3
16 changed files with 121 additions and 147 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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))

View File

@@ -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

View File

@@ -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 ---------------------------------------------------------

View File

@@ -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);
};

View File

@@ -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) {

View File

@@ -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);
//@}

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);
};

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;