method to get paths between two objects
This commit is contained in:
@@ -3026,3 +3026,76 @@ std::vector<App::DocumentObject*> Document::getRootObjects() const
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace App {
|
||||
typedef vector <size_t> Node;
|
||||
typedef vector <size_t> Path;
|
||||
void _findAllPathsAt(const std::vector <Node> &all_nodes, size_t id,
|
||||
std::vector <Path> &all_paths, Path tmp)
|
||||
{
|
||||
if (std::find(tmp.begin(), tmp.end(), id) != tmp.end()) {
|
||||
Path tmp2(tmp);
|
||||
tmp2.push_back(id);
|
||||
all_paths.push_back(tmp2);
|
||||
return; // a cycle
|
||||
}
|
||||
|
||||
tmp.push_back(id);
|
||||
if (all_nodes[id].empty()) {
|
||||
all_paths.push_back(tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i=0; i < all_nodes[id].size(); i++) {
|
||||
Path tmp2(tmp);
|
||||
_findAllPathsAt(all_nodes, all_nodes[id][i], all_paths, tmp2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::list<App::DocumentObject*> >
|
||||
Document::getPathsByOutList(const App::DocumentObject* from, const App::DocumentObject* to) const
|
||||
{
|
||||
std::map<const DocumentObject*, size_t> indexMap;
|
||||
for (size_t i=0; i<d->objectArray.size(); ++i) {
|
||||
indexMap[d->objectArray[i]] = i;
|
||||
}
|
||||
|
||||
std::vector <Node> all_nodes(d->objectArray.size());
|
||||
for (size_t i=0; i<d->objectArray.size(); ++i) {
|
||||
DocumentObject* obj = d->objectArray[i];
|
||||
std::vector<DocumentObject*> outList = obj->getOutList();
|
||||
for (auto it : outList) {
|
||||
all_nodes[i].push_back(indexMap[it]);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::list<App::DocumentObject*> > array;
|
||||
if (from == to)
|
||||
return array;
|
||||
|
||||
size_t index_from = indexMap[from];
|
||||
size_t index_to = indexMap[to];
|
||||
Path tmp;
|
||||
std::vector<Path> all_paths;
|
||||
_findAllPathsAt(all_nodes, index_from, all_paths, tmp);
|
||||
|
||||
for (std::vector<Path>::iterator it = all_paths.begin(); it != all_paths.end(); ++it) {
|
||||
Path::iterator jt = std::find(it->begin(), it->end(), index_to);
|
||||
if (jt != it->end()) {
|
||||
std::list<App::DocumentObject*> path;
|
||||
for (Path::iterator kt = it->begin(); kt != jt; ++kt) {
|
||||
path.push_back(d->objectArray[*kt]);
|
||||
}
|
||||
|
||||
path.push_back(d->objectArray[*jt]);
|
||||
array.push_back(path);
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicates
|
||||
std::sort(array.begin(), array.end());
|
||||
array.erase(std::unique(array.begin(), array.end()), array.end());
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
@@ -332,6 +332,9 @@ public:
|
||||
std::vector<App::DocumentObject*> topologicalSort() const;
|
||||
/// get all root objects (objects no other one reference too)
|
||||
std::vector<App::DocumentObject*> getRootObjects() const;
|
||||
/// get all possible paths from one object to another following the OutList
|
||||
std::vector<std::list<App::DocumentObject*> > getPathsByOutList
|
||||
(const App::DocumentObject* from, const App::DocumentObject* to) const;
|
||||
//@}
|
||||
|
||||
/// Function called to signal that an object identifier has been renamed
|
||||
|
||||
@@ -271,6 +271,12 @@ std::vector<App::DocumentObject*> DocumentObject::getOutListRecursive(void) cons
|
||||
return array;
|
||||
}
|
||||
|
||||
std::vector<std::list<App::DocumentObject*> >
|
||||
DocumentObject::getPathsByOutList(App::DocumentObject* to) const
|
||||
{
|
||||
return _pDoc->getPathsByOutList(this, to);
|
||||
}
|
||||
|
||||
DocumentObjectGroup* DocumentObject::getGroup() const
|
||||
{
|
||||
return dynamic_cast<DocumentObjectGroup*>(GroupExtension::getGroupOfObject(this));
|
||||
|
||||
@@ -140,6 +140,8 @@ public:
|
||||
std::vector<App::DocumentObject*> getOutList(void) const;
|
||||
/// returns a list of objects this object is pointing to by Links and all further descended
|
||||
std::vector<App::DocumentObject*> getOutListRecursive(void) const;
|
||||
/// get all possible paths from this to another object following the OutList
|
||||
std::vector<std::list<App::DocumentObject*> > getPathsByOutList(App::DocumentObject* to) const;
|
||||
/// get all objects link to this object
|
||||
std::vector<App::DocumentObject*> getInList(void) const;
|
||||
/// get all objects link directly or indirectly to this object
|
||||
|
||||
@@ -69,6 +69,11 @@
|
||||
in a single group, hence only a single return value.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getPathsByOutList">
|
||||
<Documentation>
|
||||
<UserDocu>Get all paths from this object to another object following the OutList.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="OutList" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>A list of all objects this object links to.</UserDocu>
|
||||
|
||||
@@ -361,6 +361,31 @@ PyObject* DocumentObjectPy::getParentGeoFeatureGroup(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getPathsByOutList(PyObject *args)
|
||||
{
|
||||
PyObject* o;
|
||||
if (!PyArg_ParseTuple(args, "O!", &DocumentObjectPy::Type, &o))
|
||||
return NULL;
|
||||
|
||||
try {
|
||||
DocumentObject* target = static_cast<DocumentObjectPy*>
|
||||
(o)->getDocumentObjectPtr();
|
||||
auto array = getDocumentObjectPtr()->getPathsByOutList(target);
|
||||
Py::List list;
|
||||
for (auto it : array) {
|
||||
Py::List path;
|
||||
for (auto jt : it) {
|
||||
path.append(Py::asObject(jt->getPyObject()));
|
||||
}
|
||||
list.append(path);
|
||||
}
|
||||
return Py::new_reference_to(list);
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
throw Py::RuntimeError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *DocumentObjectPy::getCustomAttributes(const char* attr) const
|
||||
{
|
||||
// search for dynamic property
|
||||
|
||||
Reference in New Issue
Block a user