OSVR-Core
JSONEigen.h
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 #ifndef INCLUDED_JSONEigen_h_GUID_A8A98FBE_0A98_4C83_9A13_D022330FE13E
26 #define INCLUDED_JSONEigen_h_GUID_A8A98FBE_0A98_4C83_9A13_D022330FE13E
27 
28 // Internal Includes
30 
31 // Library/third-party includes
32 #include <json/value.h>
33 #include <boost/lexical_cast.hpp>
34 #include <boost/algorithm/string.hpp>
35 #include <boost/range/algorithm/count_if.hpp>
36 #include <boost/assert.hpp>
37 
38 // Standard includes
39 #include <stdexcept>
40 #include <cstring>
41 #include <string>
42 
43 namespace osvr {
44 namespace common {
46  template <typename Derived>
47  inline Json::Value toJson(Eigen::QuaternionBase<Derived> const &quat) {
48  Json::Value ret(Json::objectValue);
49  ret["w"] = quat.w();
50  ret["x"] = quat.x();
51  ret["y"] = quat.y();
52  ret["z"] = quat.z();
53  return ret;
54  }
55 
57  template <typename Derived>
58  inline Json::Value toJson(Eigen::MatrixBase<Derived> const &vec) {
59  static_assert(Derived::ColsAtCompileTime == 1,
60  "This function is only for converting vectors to JSON");
61  Json::Value ret(Json::arrayValue);
62  for (size_t i = 0; i < Derived::RowsAtCompileTime; ++i) {
63  ret.append(vec[i]);
64  }
65  return ret;
66  }
67 
68  namespace detail {
69  static const char AXIS_NAMES[] = "XYZ";
70  static const char MINUS[] = "-";
71  template <typename VecType>
72  inline VecType stringToVector(std::string const &s) {
73  typedef typename VecType::Scalar Scalar;
74 
75  // Return value for NRVO
76  VecType ret = VecType::Zero();
77  if (s.empty()) {
78  throw std::runtime_error(
79  "Can't parse a vector from an empty string!");
80  }
81 
82  // Will work with uppercase string from here on out.
83  std::string upperS(boost::to_upper_copy(s));
84  {
85  // Input validity checks.
86  using boost::is_any_of;
87  using boost::algorithm::is_space;
88  using boost::count_if;
89  if ((!boost::algorithm::all(upperS, is_any_of(AXIS_NAMES) ||
90  is_any_of(MINUS) ||
91  is_space())) ||
92  count_if(upperS, is_any_of(AXIS_NAMES)) != 1 ||
93  count_if(upperS, is_any_of(MINUS)) > 1) {
94  throw std::runtime_error(
95  "Cannot turn the specified string into a vector: " + s);
96  }
97  }
98  Scalar factor =
99  (upperS.find(MINUS[0]) == std::string::npos) ? 1.0 : -1.0;
100  for (const char c : upperS) {
101  auto axisPtr = std::strchr(AXIS_NAMES, c);
102  if (nullptr != axisPtr) {
103  auto index = axisPtr - AXIS_NAMES;
104  if (index >= VecType::RowsAtCompileTime) {
105  throw std::runtime_error(
106  "A vector of this size cannot be initialized to " +
107  s);
108  }
109  ret[index] = factor;
110  return ret;
111  }
112  }
113 
114  BOOST_ASSERT_MSG(false, "Should never reach here!");
115  }
116  } // namespace detail
117 
118 #define OSVR_EXTRACT_JSON_MEMBER(_DATATYPENAME, _LOWER, _UPPER) \
119  if (json.isMember(#_LOWER)) { \
120  ret._LOWER() = json[#_LOWER].asDouble(); \
121  } else if (json.isMember(#_UPPER)) { \
122  ret._LOWER() = json[#_UPPER].asDouble(); \
123  } else { \
124  throw std::runtime_error("In parsing " _DATATYPENAME \
125  " from JSON, no " #_LOWER " element found!"); \
126  }
127 
128  Eigen::Quaterniond quatFromJson(Json::Value const &json) {
129  Eigen::Quaterniond ret;
130  if (json.isObject()) {
131  OSVR_EXTRACT_JSON_MEMBER("quaternion", w, W);
132  OSVR_EXTRACT_JSON_MEMBER("quaternion", x, X);
133  OSVR_EXTRACT_JSON_MEMBER("quaternion", y, Y);
134  OSVR_EXTRACT_JSON_MEMBER("quaternion", z, Z);
135  } else if (json.isArray()) {
136  // Array - ugh, must assume an order, guess we'll assume w, x, y, z
137  ret = Eigen::Quaterniond(json[0].asDouble(), json[1].asDouble(),
138  json[2].asDouble(), json[3].asDouble());
139  } else {
140  throw std::runtime_error("Could not parse quaternion from JSON - "
141  "neither an object nor an array");
142  }
143  return ret;
144  }
145 
146  inline Eigen::Vector3d vec3FromJson(Json::Value const &json) {
147  typedef Eigen::Vector3d type;
148 #define OSVR_PARSE_NAME "Vector3d"
149  type ret;
150  if (json.isString()) {
151  // Handle just straight axis names
152  if ((json == "x") || (json == "X")) {
153  ret = type::UnitX();
154  } else if ((json == "y") || (json == "Y")) {
155  ret = type::UnitY();
156  } else if ((json == "z") || (json == "Z")) {
157  ret = type::UnitZ();
158  } else {
159  throw std::runtime_error(
160  "Could not parse a " OSVR_PARSE_NAME
161  " from JSON string: looking for an axis name, got " +
162  json.asString());
163  }
164  } else if (json.isNumeric()) {
165  if (json == 0) {
166  ret = type::Zero();
167  } else {
168  throw std::runtime_error(
169  "Could not parse a " OSVR_PARSE_NAME
170  " from the scalar value " +
171  boost::lexical_cast<std::string>(json.asDouble()));
172  }
173  } else if (json.isArray()) {
174  if (json.size() != type::RowsAtCompileTime) {
175  throw std::runtime_error(
176  "Could not parse a " OSVR_PARSE_NAME
177  " from an array with " +
178  boost::lexical_cast<std::string>(json.size()) +
179  " elements");
180  }
181  ret = type(json[0].asDouble(), json[1].asDouble(),
182  json[2].asDouble());
183  } else if (json.isObject()) {
184  OSVR_EXTRACT_JSON_MEMBER(OSVR_PARSE_NAME, x, X);
185  OSVR_EXTRACT_JSON_MEMBER(OSVR_PARSE_NAME, y, Y);
186  OSVR_EXTRACT_JSON_MEMBER(OSVR_PARSE_NAME, z, Z);
187  } else {
188  throw std::runtime_error(
189  "Could not parse " OSVR_PARSE_NAME " from JSON - "
190  "not a component name, 0, an array, nor an object");
191  }
192  return ret;
193 #undef OSVR_PARSE_NAME
194  }
195 
196 #undef OSVR_EXTRACT_JSON_MEMBER
197 } // namespace common
198 } // namespace osvr
199 
200 #endif // INCLUDED_JSONEigen_h_GUID_A8A98FBE_0A98_4C83_9A13_D022330FE13E
Scalar z() const
Definition: Quaternion.h:64
Handles spatial transformations.
Definition: SerializationTraitExample_Complicated.h:40
The main namespace for all C++ elements of the framework, internal and external.
Definition: namespace_osvr.dox:3
Header wrapping include of <Eigen/Core> and <Eigen/Geometry> for warning quieting.
Scalar x() const
Definition: Quaternion.h:60
Definition: newuoa.h:1888
Definition: ForwardDeclarations.h:233
Definition: Quaternion.h:47
Quaternion< double > Quaterniond
double precision quaternion type
Definition: Quaternion.h:211
Scalar y() const
Definition: Quaternion.h:62
Json::Value toJson(Eigen::QuaternionBase< Derived > const &quat)
Converts quaternions to JSON objects.
Definition: JSONEigen.h:47
Base class for all dense matrices, vectors, and expressions.
Definition: MatrixBase.h:48
Scalar w() const
Definition: Quaternion.h:66
double Scalar
Common scalar type.
Definition: FlexibleKalmanBase.h:48