OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
JSONTransformVisitor.cpp
Go to the documentation of this file.
1 
13 // Copyright 2014 Sensics, Inc.
14 //
15 // Licensed under the Apache License, Version 2.0 (the "License");
16 // you may not use this file except in compliance with the License.
17 // You may obtain a copy of the License at
18 //
19 // http://www.apache.org/licenses/LICENSE-2.0
20 //
21 // Unless required by applicable law or agreed to in writing, software
22 // distributed under the License is distributed on an "AS IS" BASIS,
23 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 // See the License for the specific language governing permissions and
25 // limitations under the License.
26 
27 // Internal Includes
29 #include <osvr/Common/Transform.h>
32 #include <osvr/Util/StdInt.h>
33 
34 // Library/third-party includes
35 #include <json/value.h>
36 #include <json/reader.h>
37 #include <boost/algorithm/string.hpp>
38 #include <boost/range/algorithm/count_if.hpp>
39 
40 // Standard includes
41 #include <string>
42 
43 namespace osvr {
44 namespace common {
45 
46  static const char AXIS_NAMES[] = "XYZ";
47  static const char MINUS[] = "-";
48  template <typename T = Eigen::Vector3d>
49  inline T vectorFromJson(Json::Value const &v) {
50  T ret = T::Zero();
51  if (v.isString()) {
52  std::string inVal = v.asString();
53  if (inVal.empty()) {
54  throw std::runtime_error(
55  "Empty string can't be turned into a vector!");
56  }
57  using boost::is_any_of;
58  std::string val(boost::to_upper_copy(inVal));
59  if ((!boost::algorithm::all(
60  val, is_any_of(AXIS_NAMES) || is_any_of(MINUS) ||
61  boost::algorithm::is_space())) ||
62  boost::count_if(val, is_any_of(AXIS_NAMES)) != 1 ||
63  boost::count_if(val, is_any_of(MINUS)) > 1) {
64  throw std::runtime_error(
65  "Cannot turn the specified string into a vector: " + inVal);
66  }
67  double factor =
68  (val.find(MINUS[0]) == std::string::npos) ? 1.0 : -1.0;
69  const std::string axisnames(AXIS_NAMES);
70  for (const char c : val) {
71  auto location = axisnames.find(c);
72  if (location != std::string::npos) {
73  ret[location] = factor;
74  return ret;
75  }
76  }
77  BOOST_ASSERT_MSG(false, "Should never reach here!");
78  }
79  if (v.isArray()) {
80  if (v.size() != T::RowsAtCompileTime) {
81  throw std::runtime_error(
82  "Vector size wrong when converting from JSON!");
83  }
84  for (Json::ArrayIndex i = 0, e = v.size(); i < e; ++i) {
85  ret[i] = v[i].asFloat();
86  }
87  return ret;
88  }
89  throw std::runtime_error("Could not convert JSON to vector: " +
90  v.toStyledString());
91  }
92 
93  static const char DEGREES_KEY[] = "degrees";
94  static const char RADIANS_KEY[] = "radians";
95  static inline double angleAsRadians(Json::Value const &rotation) {
96  double ret = 0;
97  if (rotation[DEGREES_KEY].isNumeric()) {
98  ret = degreesToRadians(rotation[DEGREES_KEY].asFloat());
99  } else if (rotation[RADIANS_KEY].isNumeric()) {
100  ret = rotation[RADIANS_KEY].asFloat();
101  } else {
102  throw std::runtime_error(
103  "Cannot have a rotation with either degrees or radians!");
104  }
105  return ret;
106  }
107 
108  static const char TRANSLATE_KEY[] = "posttranslate";
109  static const char PRETRANSLATE_KEY[] = "translate";
110  static const char ROTATE_KEY[] = "postrotate";
111  static const char PREROTATE_KEY[] = "rotate";
112  static const char AXIS_KEY[] = "axis";
113  static const char CHANGE_BASIS_KEY[] = "changeBasis";
114  static const char X_KEY[] = "x";
115  static const char Y_KEY[] = "y";
116  static const char Z_KEY[] = "z";
117  static inline void handleLevel(Transform &t, Json::Value const &v) {
118  if (!v.isObject()) {
119  // This is a non-object leaf node.
120  return;
121  }
122  if (v.isMember(CHANGE_BASIS_KEY)) {
123  Json::Value changeBasis = v[CHANGE_BASIS_KEY];
124  ChangeOfBasis cb;
125  cb.setNewX(vectorFromJson<>(changeBasis[X_KEY]));
126  cb.setNewY(vectorFromJson<>(changeBasis[Y_KEY]));
127  cb.setNewZ(vectorFromJson<>(changeBasis[Z_KEY]));
128  t.transform(cb.get());
129  return;
130  }
131  Eigen::Vector3d position = Eigen::Vector3d::Zero();
132  Eigen::AngleAxisd orientation = Eigen::AngleAxisd::Identity();
133  Eigen::Vector3d preposition = Eigen::Vector3d::Zero();
134  Eigen::AngleAxisd preorientation = Eigen::AngleAxisd::Identity();
135  bool haveTransform = false;
136  bool havePreTransform = false;
137  if (v.isMember(TRANSLATE_KEY)) {
138  position = vectorFromJson<>(v[TRANSLATE_KEY]);
139  haveTransform = true;
140  }
141  if (v.isMember(PRETRANSLATE_KEY)) {
142  preposition = vectorFromJson<>(v[PRETRANSLATE_KEY]);
143  havePreTransform = true;
144  }
145  if (v.isMember(ROTATE_KEY)) {
146  Json::Value rotate = v[ROTATE_KEY];
147  orientation = Eigen::AngleAxisd(angleAsRadians(rotate),
148  vectorFromJson<>(rotate[AXIS_KEY]));
149  haveTransform = true;
150  }
151  if (v.isMember(PREROTATE_KEY)) {
152  Json::Value rotate = v[PREROTATE_KEY];
153  preorientation = Eigen::AngleAxisd(
154  angleAsRadians(rotate), vectorFromJson<>(rotate[AXIS_KEY]));
155  havePreTransform = true;
156  }
157  if (haveTransform) {
158  Eigen::Affine3d xform;
159  xform.fromPositionOrientationScale(position, orientation,
160  Eigen::Vector3d::Constant(1));
161  t.concatPost(xform.matrix());
162  }
163  if (havePreTransform) {
164  Eigen::Affine3d xform;
165  xform.fromPositionOrientationScale(preposition, preorientation,
166  Eigen::Vector3d::Constant(1));
167  t.concatPre(xform.matrix());
168  }
169  }
170 
171  static const char CHILD_KEY[] = "child";
173  std::vector<Json::Value> levels;
174  Json::Value current = root;
175  levels.push_back(current);
176  while (current.isObject() && current.isMember(CHILD_KEY)) {
177  current = current[CHILD_KEY];
178  levels.push_back(current);
179  }
180  m_leaf = current;
181  while (!levels.empty()) {
182  handleLevel(m_transform, levels.back());
183  levels.pop_back();
184  }
185  }
186 
187  JSONTransformVisitor::~JSONTransformVisitor() {}
188 
189  Transform const &JSONTransformVisitor::getTransform() const {
190  return m_transform;
191  }
192 
193  Json::Value const &JSONTransformVisitor::getLeaf() const { return m_leaf; }
194 
195 } // namespace common
196 } // namespace osvr
Header wrapping the C99 standard stdint header.
JSONTransformVisitor(Json::Value const &root)
Parses json describing a transformation to compute the overall transformation.
Header.