OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
OriginalSource.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
27 #include <osvr/Common/PathNode.h>
30 
31 // Library/third-party includes
32 #include <boost/variant/static_visitor.hpp>
33 #include <boost/variant/apply_visitor.hpp>
34 #include <boost/variant/get.hpp>
35 #include <boost/optional.hpp>
36 #include <boost/lexical_cast.hpp>
37 
38 // Standard includes
39 #include <string>
40 
41 namespace osvr {
42 namespace common {
43 
44  OriginalSource::OriginalSource()
45  : m_device(nullptr), m_interface(nullptr), m_sensor(nullptr) {}
46 
47  bool OriginalSource::isResolved() const {
48  return m_device != nullptr && m_interface != nullptr;
49  }
50 
51  void OriginalSource::setDevice(common::PathNode &device) {
52  BOOST_ASSERT_MSG(m_device == nullptr,
53  "Device should only be set once.");
54  m_device = &device;
55  }
56 
57  void OriginalSource::setInterface(common::PathNode &iface) {
58  BOOST_ASSERT_MSG(m_interface == nullptr,
59  "Interface should only be set once.");
60  m_interface = &iface;
61  }
62 
63  void OriginalSource::setSensor(common::PathNode &sensor) {
64  BOOST_ASSERT_MSG(m_sensor == nullptr,
65  "Sensor should only be set once.");
66  m_sensor = &sensor;
67  }
68 
69  void OriginalSource::nestTransform(Json::Value const &transform) {
70  m_transform.nest(transform);
71  }
72 
73  std::string OriginalSource::getDevicePath() const {
74  BOOST_ASSERT_MSG(isResolved(),
75  "Only makes sense when called on a resolved source.");
76  return getFullPath(*getDevice());
77  }
78 
79  common::PathNode *OriginalSource::getDevice() const { return m_device; }
80 
82  OriginalSource::getDeviceElement() const {
83  BOOST_ASSERT_MSG(isResolved(),
84  "Only makes sense when called on a resolved source.");
85  return boost::get<common::elements::DeviceElement>(m_device->value());
86  }
87 
88  common::PathNode *OriginalSource::getInterface() const {
89  return m_interface;
90  }
91 
92  std::string OriginalSource::getInterfaceName() const {
93  BOOST_ASSERT_MSG(isResolved(),
94  "Only makes sense when called on a resolved source.");
95  std::string ret;
96  if (nullptr == m_interface) {
97  return ret;
98  }
99  ret = m_interface->getName();
100  return ret;
101  }
102 
103  common::PathNode *OriginalSource::getSensor() const { return m_sensor; }
104 
105  template <typename T>
106  inline boost::optional<T>
107  getSensorNumberHelper(OriginalSource const &self) {
108  BOOST_ASSERT_MSG(self.isResolved(),
109  "Only makes sense when called on a resolved source.");
110  boost::optional<T> ret;
111  if (nullptr == self.getSensor()) {
112  return ret;
113  }
114  try {
115  ret = boost::lexical_cast<T>(self.getSensor()->getName());
116  } catch (boost::bad_lexical_cast &) {
117  // Just means we can't convert to the type, so returning an empty
118  // optional is fine.
119  }
120  return ret;
121  }
122 
123  boost::optional<int> OriginalSource::getSensorNumber() const {
124  return getSensorNumberHelper<int>(*this);
125  }
126 
127  boost::optional<OSVR_ChannelCount>
128  OriginalSource::getSensorNumberAsChannelCount() const {
129  return getSensorNumberHelper<OSVR_ChannelCount>(*this);
130  }
131 
132  Json::Value OriginalSource::getTransformJson() const {
133  BOOST_ASSERT_MSG(isResolved(),
134  "Only makes sense when called on a resolved source.");
135  return m_transform.get(m_getPath());
136  }
137 
138  bool OriginalSource::hasTransform() const {
139  BOOST_ASSERT_MSG(isResolved(),
140  "Only makes sense when called on a resolved source.");
141  return !m_transform.empty();
142  }
143 
144  std::string OriginalSource::m_getPath() const {
145  BOOST_ASSERT_MSG(isResolved(),
146  "Only makes sense when called on a resolved source.");
147  PathNode *node = getSensor();
148  if (!node) {
149  node = getInterface();
150  }
151  if (!node) {
152  node = getDevice();
153  }
154  if (node) {
155  return getFullPath(*node);
156  }
157  return std::string{};
158  }
159  namespace {
160  class DecomposeOriginalSource : public boost::static_visitor<>,
161  boost::noncopyable {
162  public:
163  DecomposeOriginalSource(PathNode &node, OriginalSource &source)
164  : boost::static_visitor<>(), m_source(source) {
165  m_applyVisitor(node);
166  }
167 
168  template <typename T> void operator()(PathNode &, T &) {
169  throw std::runtime_error("Element type encountered that is not "
170  "recognized in decomposition!");
171  }
172 
173  void operator()(PathNode &node, elements::SensorElement &) {
174  m_source.setSensor(node);
175  if (nullptr == node.getParent()) {
176  throw exceptions::invariants::SensorMissingParent(
177  getFullPath(node));
178  }
179  m_applyVisitor(*node.getParent());
180  if (nullptr == m_source.getInterface()) {
181  // Hmm, finished traversing upward and didn't get an
182  // interface.
183  throw exceptions::invariants::SensorMissingInterfaceParent(
184  getFullPath(node));
185  }
186  }
187 
188  void operator()(PathNode &node, elements::InterfaceElement &) {
189  m_source.setInterface(node);
190  if (nullptr == node.getParent()) {
191  throw exceptions::invariants::InterfaceMissingParent(
192  getFullPath(node));
193  }
194  m_applyVisitor(*node.getParent());
195  }
196 
197  void operator()(PathNode &node, elements::DeviceElement &) {
198  m_source.setDevice(node);
201  }
202 
203  private:
204  void m_applyVisitor(PathNode &node) {
205  applyPathNodeVisitor(*this, node);
206  }
207  OriginalSource &m_source;
208  };
209  } // namespace
210  void OriginalSource::decompose(PathNode &node) {
211  DecomposeOriginalSource decomp{node, *this};
212  }
213 } // namespace common
214 } // namespace osvr
::osvr::util::TreeNode< PathElement > PathNode
The specific tree node type that contains a path element.
Definition: PathNode_fwd.h:42
The element type corresponding to a particular sensor of an interface.
The element type corresponding to a device, which implements 0 or more interfaces.
std::string getFullPath(PathNode const &node)
Gets the absolute path for the given node.
Definition: PathNode.cpp:42
t_< detail::transform_< List, Fun >> transform
Definition: Transform.h:54
The element type corresponding to an interface, which often may have one or more sensors.
Visitor::result_type applyPathNodeVisitor(Visitor &v, PathNode &node)
Visit a node's element's contained type, similar to boost::apply_visitor, but passing both the PathNo...
Header.