30 #include <boost/range/iterator_range_core.hpp>
38 DOTNode::DOTNode(std::string
const &
id) : m_id(id) {}
40 DOTGraphOutput::DOTGraphOutput(std::ostream &stream)
41 : m_count(0), m_os(stream), m_treeShape(false) {
42 auto &root = m_addNode(
"/");
43 std::ostringstream os;
44 os << root.getID() <<
"[shape=circle, label=\"root\"];";
45 m_outputLineWithId(root.getID(), os.str());
48 m_os <<
"digraph {\n";
49 m_os <<
"rankdir = LR\n";
50 auto endOfReferencedIds = end(m_referencedIds);
53 for (
auto const &idAndOutput : m_idAndOutput) {
54 if (m_referencedIds.find(idAndOutput.first) != endOfReferencedIds) {
55 m_os << idAndOutput.second <<
"\n";
64 std::multimap<Rank, std::string> rankAndIDs;
65 for (
auto const &nameNode : m_nodes) {
66 if (m_referencedIds.find(nameNode.second->getID()) ==
72 if (nameNode.first ==
"/") {
76 rank = std::count(nameNode.first.begin(), nameNode.first.end(),
80 rankAndIDs.insert(std::make_pair(rank, nameNode.second->getID()));
82 for (
auto const rank : ranks) {
83 m_os <<
"{ rank=same; ";
84 for (
auto const &rankAndID :
85 boost::make_iterator_range(rankAndIDs.equal_range(rank))) {
86 m_os << rankAndID.second <<
" ";
94 NodeInterface &DOTGraphOutput::addNode(std::string
const &label,
95 std::string
const &fullPath,
96 std::string
const &type) {
97 auto it = m_nodes.find(fullPath);
98 if (m_nodes.end() == it) {
99 auto &node = m_addNode(fullPath);
100 m_outputNode(label, node.getID(), type);
103 return *(it->second);
105 NodeInterface &DOTGraphOutput::getNode(std::string
const &name) {
106 return m_getNode(name);
109 std::string
const &type, std::string
const &data) {
111 std::string attributes;
112 if (type ==
"alias") {
114 attributes =
"label=\"has transform\"";
119 auto &dotHead = m_getNode(head);
120 auto &dotTail = m_getNode(tail);
121 addEdge(dotTail, dotHead, attributes);
125 std::string
const &attributes) {
126 m_referencedIds.insert(tail.getID());
127 m_referencedIds.insert(head.getID());
128 std::ostringstream os;
129 os << tail.getID() <<
" -> " << head.getID();
130 if (!attributes.empty()) {
131 os <<
"[" << attributes <<
"]";
134 m_outputLineWithId(tail.getID(), os.str());
140 return m_getNode(m_nodePathsByID.at(node.getID()));
143 DOTNode &DOTGraphOutput::m_getNode(std::string
const &fullPath) {
144 return *m_nodes.at(fullPath);
147 void DOTGraphOutput::m_outputNode(std::string
const &label,
148 std::string
const &
id,
149 std::string
const &type) {
151 std::ostringstream os;
152 os <<
id <<
"[shape=box,label=\"" << label <<
"\"";
153 if (type == elements::getTypeName<elements::SensorElement>()) {
154 os <<
",style=filled,color=green";
157 m_outputLineWithId(
id, os.str());
159 void DOTGraphOutput::m_outputLineWithId(std::string
const &
id,
160 std::string
const &line) {
161 m_idAndOutput.push_back(std::make_pair(
id, line));
163 DOTNode &DOTGraphOutput::m_addNode(std::string
const &fullPath) {
164 auto id = m_getNextID();
166 std::make_pair(fullPath, osvr::unique_ptr<DOTNode>(
new DOTNode(
id))));
167 m_nodePathsByID.insert(std::make_pair(
id, fullPath));
168 return m_getNode(fullPath);
171 std::string DOTGraphOutput::m_getNextID() {
172 std::ostringstream id;
173 id <<
"n" << m_count;
Handles spatial transformations.
typename detail::split_list_< List...>::head head
Get the first element of a list.
typename detail::split_list_< List...>::tail tail
Get the list without its first element.
virtual void addEdge(NodeInterface &tail, NodeInterface &head, std::string const &type, std::string const &data=std::string())
virtual ~DOTGraphOutput()
virtual void enableTreeOrganization()
Sets a flag indicating that we should try to organize nodes in the path tree structure.