OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
DOTGraphOutput.cpp
Go to the documentation of this file.
1 
11 // Copyright 2015 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 // Internal Includes
26 #include "DOTGraphOutput.h"
28 
29 // Library/third-party includes
30 #include <boost/range/iterator_range_core.hpp>
31 
32 // Standard includes
33 #include <sstream>
34 #include <map>
35 #include <set>
36 #include <algorithm>
37 
38 DOTNode::DOTNode(std::string const &id) : m_id(id) {}
39 
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());
46 }
48  m_os << "digraph {\n";
49  m_os << "rankdir = LR\n";
50  auto endOfReferencedIds = end(m_referencedIds);
51 
53  for (auto const &idAndOutput : m_idAndOutput) {
54  if (m_referencedIds.find(idAndOutput.first) != endOfReferencedIds) {
55  m_os << idAndOutput.second << "\n";
56  }
57  }
58 
59  if (m_treeShape) {
62  typedef uint8_t Rank;
63  std::set<Rank> ranks;
64  std::multimap<Rank, std::string> rankAndIDs;
65  for (auto const &nameNode : m_nodes) {
66  if (m_referencedIds.find(nameNode.second->getID()) ==
67  endOfReferencedIds) {
69  continue;
70  }
71  Rank rank;
72  if (nameNode.first == "/") {
73  // This is the root - special
74  rank = 0;
75  } else {
76  rank = std::count(nameNode.first.begin(), nameNode.first.end(),
77  '/');
78  }
79  ranks.insert(rank);
80  rankAndIDs.insert(std::make_pair(rank, nameNode.second->getID()));
81  }
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 << " ";
87  }
88  m_os << "}\n";
89  }
90  }
91  m_os << "}\n";
92 }
93 
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);
101  return node;
102  }
103  return *(it->second);
104 }
105 NodeInterface &DOTGraphOutput::getNode(std::string const &name) {
106  return m_getNode(name);
107 }
109  std::string const &type, std::string const &data) {
110 
111  std::string attributes;
112  if (type == "alias") {
113  if (!data.empty()) {
114  attributes = "label=\"has transform\"";
115  }
118  }
119  auto &dotHead = m_getNode(head);
120  auto &dotTail = m_getNode(tail);
121  addEdge(dotTail, dotHead, attributes);
122 }
123 
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 << "]";
132  }
133  os << ";";
134  m_outputLineWithId(tail.getID(), os.str());
135 }
136 
138 
139 DOTNode &DOTGraphOutput::m_getNode(NodeInterface const &node) {
140  return m_getNode(m_nodePathsByID.at(node.getID()));
141 }
142 
143 DOTNode &DOTGraphOutput::m_getNode(std::string const &fullPath) {
144  return *m_nodes.at(fullPath);
145 }
146 
147 void DOTGraphOutput::m_outputNode(std::string const &label,
148  std::string const &id,
149  std::string const &type) {
150  using namespace osvr::common;
151  std::ostringstream os;
152  os << id << "[shape=box,label=\"" << label << "\"";
153  if (type == elements::getTypeName<elements::SensorElement>()) {
154  os << ",style=filled,color=green";
155  }
156  os << "];";
157  m_outputLineWithId(id, os.str());
158 }
159 void DOTGraphOutput::m_outputLineWithId(std::string const &id,
160  std::string const &line) {
161  m_idAndOutput.push_back(std::make_pair(id, line));
162 }
163 DOTNode &DOTGraphOutput::m_addNode(std::string const &fullPath) {
164  auto id = m_getNextID();
165  m_nodes.emplace(
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);
169 }
170 
171 std::string DOTGraphOutput::m_getNextID() {
172  std::ostringstream id;
173  id << "n" << m_count;
174  m_count++;
175  return id.str();
176 }
Handles spatial transformations.
typename detail::split_list_< List...>::head head
Get the first element of a list.
Definition: SplitList.h:54
typename detail::split_list_< List...>::tail tail
Get the list without its first element.
Definition: SplitList.h:58
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.