FreeCAD/src/Gui/DAGView/DAGModelGraph.h

292 lines
10 KiB
C++

/***************************************************************************
* Copyright (c) 2015 Thomas Anderson <blobfish[at]gmx.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef DAGMODELGRAPH_H
#define DAGMODELGRAPH_H
#include <memory>
#include <bitset>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/reverse_graph.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include "DAGRectItem.h"
namespace App{class DocumentObject;}
namespace Gui
{
class ViewProviderDocumentObject;
namespace DAG
{
enum class VisibilityState
{
None = 0, //<! not determined.
On, //<! shown
Off //<! hidden
};
enum class FeatureState
{
None = 0, //<! not determined.
Pass, //<! feature updated ok.
Fail, //<! feature failed to update.
Pending //<! feature is pending an update.
};
//limit of column width? boost::dynamic_bitset?
//did a trial run with this set at 4096, not much difference.
//going to leave a big number by default and see how it goes.
typedef std::bitset<1024> ColumnMask;
/*! @brief Graph vertex information
*
* My data stored for each vertex;
*/
struct VertexProperty
{
VertexProperty();
std::shared_ptr<RectItem> rectangle; //!< background
std::shared_ptr<QGraphicsEllipseItem> point; //!< point
std::shared_ptr<QGraphicsPixmapItem> visibleIcon; //!< visible Icon
std::shared_ptr<QGraphicsPixmapItem> stateIcon; //!< visible Icon
std::shared_ptr<QGraphicsPixmapItem> icon; //!< icon
std::shared_ptr<QGraphicsTextItem> text; //!< text
int row; //!< row for this entry.
ColumnMask column; //!< column number containing the point.
int topoSortIndex;
VisibilityState lastVisibleState; //!< visibility test.
FeatureState lastFeatureState; //!< feature state test.
bool dagVisible; //!< should entry be visible in the DAG view.
};
/*! @brief boost data for each vertex.
*
* needed to create an internal index for vertex. needed for listS.
* color is needed by some algorithms */
typedef boost::property
<
boost::vertex_index_t, std::size_t,
boost::property <boost::vertex_color_t, boost::default_color_type, VertexProperty>
> vertex_prop;
/*! @brief Graph edge information
*
* My data stored for each edge;
*/
struct EdgeProperty
{
//! Feature relation meta data. Not used right now.
enum class BranchTag
{
None = 0, //!< not defined.
Create, //!< create a new branch.
Continue, //!< continue a branch.
Terminate //!< terminate a branch.
};
EdgeProperty();
BranchTag relation;
std::shared_ptr <QGraphicsPathItem> connector; //!< line representing link between nodes.
};
/*! @brief needed to create an internal index for graph edges. needed for setS.*/
typedef boost::property<boost::edge_index_t, std::size_t, EdgeProperty> edge_prop;
typedef boost::adjacency_list<boost::setS, boost::listS, boost::bidirectionalS, vertex_prop, edge_prop> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
typedef boost::graph_traits<Graph>::edge_descriptor Edge;
typedef boost::graph_traits<Graph>::vertex_iterator VertexIterator;
typedef boost::graph_traits<Graph>::edge_iterator EdgeIterator;
typedef boost::graph_traits<Graph>::in_edge_iterator InEdgeIterator;
typedef boost::graph_traits<Graph>::out_edge_iterator OutEdgeIterator;
typedef boost::graph_traits<Graph>::adjacency_iterator VertexAdjacencyIterator;
typedef boost::reverse_graph<Graph, Graph&> GraphReversed;
typedef std::vector<Vertex> Path; //!< a path or any array of vertices
template <class GraphEW>
class Edge_writer {
public:
Edge_writer(const GraphEW &graphEWIn) : graphEW(graphEWIn) {}
template <class EdgeW>
void operator()(std::ostream& out, const EdgeW& edgeW) const
{
out << "[label=\"";
out << "edge";
out << "\"]";
}
private:
const GraphEW &graphEW;
};
template <class GraphVW>
class Vertex_writer {
public:
Vertex_writer(const GraphVW &graphVWIn) : graphVW(graphVWIn) {}
template <class VertexW>
void operator()(std::ostream& out, const VertexW& vertexW) const
{
out << "[label=\"";
out << graphVW[vertexW].text->toPlainText().toAscii().data();
out << "\"]";
}
private:
const GraphVW &graphVW;
};
template <class GraphIn>
void outputGraphviz(const GraphIn &graphIn, const std::string &filePath)
{
std::ofstream file(filePath.c_str());
boost::write_graphviz(file, graphIn, Vertex_writer<GraphIn>(graphIn),
Edge_writer<GraphIn>(graphIn));
}
//! get all the leaves of the templated graph. Not used right now.
template <class GraphIn>
class RakeLeaves
{
typedef boost::graph_traits<Graph>::vertex_descriptor GraphInVertex;
typedef std::vector<GraphInVertex> GraphInVertices;
public:
RakeLeaves(const GraphIn &graphIn) : graph(graphIn) {}
GraphInVertices operator()() const
{
GraphInVertices out;
BGL_FORALL_VERTICES_T(currentVertex, graph, GraphIn)
{
if (boost::out_degree(currentVertex, graph) == 0)
out.push_back(currentVertex);
}
return out;
}
private:
const GraphIn &graph;
};
//! get all the roots of the templated graph. Not used right now.
template <class GraphIn>
class DigRoots
{
typedef boost::graph_traits<Graph>::vertex_descriptor GraphInVertex;
typedef std::vector<GraphInVertex> GraphInVertices;
public:
DigRoots(const GraphIn &graphIn) : graph(graphIn) {}
GraphInVertices operator()() const
{
GraphInVertices out;
BGL_FORALL_VERTICES_T(currentVertex, graph, GraphIn)
{
if (boost::in_degree(currentVertex, graph) == 0)
out.push_back(currentVertex);
}
return out;
}
private:
const GraphIn &graph;
};
/*! @brief Get connected components.
*/
class ConnectionVisitor : public boost::default_bfs_visitor
{
public:
ConnectionVisitor(std::vector<Vertex> &verticesIn) : vertices(verticesIn){}
template<typename TVertex, typename TGraph>
void discover_vertex(TVertex vertex, TGraph &graph)
{
vertices.push_back(vertex);
}
private:
std::vector<Vertex> &vertices;
};
/*! Multi_index record. */
struct GraphLinkRecord
{
const App::DocumentObject *DObject; //!< document object
const Gui::ViewProviderDocumentObject *VPDObject; //!< view provider
const RectItem *rectItem; //!< qgraphics item.
std::string uniqueName; //!< name for document object.
Vertex vertex; //!< vertex in graph.
//@{
//! used as tags.
struct ByDObject{};
struct ByVPDObject{};
struct ByRectItem{};
struct ByUniqueName{};
struct ByVertex{};
//@}
};
namespace BMI = boost::multi_index;
typedef boost::multi_index_container
<
GraphLinkRecord,
BMI::indexed_by
<
BMI::ordered_unique
<
BMI::tag<GraphLinkRecord::ByDObject>,
BMI::member<GraphLinkRecord, const App::DocumentObject*, &GraphLinkRecord::DObject>
>,
BMI::ordered_unique
<
BMI::tag<GraphLinkRecord::ByVPDObject>,
BMI::member<GraphLinkRecord, const Gui::ViewProviderDocumentObject*, &GraphLinkRecord::VPDObject>
>,
BMI::ordered_unique
<
BMI::tag<GraphLinkRecord::ByRectItem>,
BMI::member<GraphLinkRecord, const RectItem*, &GraphLinkRecord::rectItem>
>,
BMI::ordered_unique
<
BMI::tag<GraphLinkRecord::ByUniqueName>,
BMI::member<GraphLinkRecord, std::string, &GraphLinkRecord::uniqueName>
>,
BMI::ordered_unique
<
BMI::tag<GraphLinkRecord::ByVertex>,
BMI::member<GraphLinkRecord, Vertex, &GraphLinkRecord::vertex>
>
>
> GraphLinkContainer;
const GraphLinkRecord& findRecord(Vertex vertexIn, const GraphLinkContainer &containerIn);
const GraphLinkRecord& findRecord(const App::DocumentObject* dObjectIn, const GraphLinkContainer &containerIn);
const GraphLinkRecord& findRecord(const Gui::ViewProviderDocumentObject* VPDObjectIn, const GraphLinkContainer &containerIn);
const GraphLinkRecord& findRecord(const RectItem* rectIn, const GraphLinkContainer &containerIn);
const GraphLinkRecord& findRecord(const std::string &stringIn, const GraphLinkContainer &containerIn);
void eraseRecord(const Gui::ViewProviderDocumentObject* VPDObjectIn, GraphLinkContainer &containerIn);
}
}
#endif // DAGMODELGRAPH_H