origin.cpp
Go to the documentation of this file.
1 
29 #include <stdexcept>
30 #include <vector>
31 
32 #include <boost/algorithm/string.hpp>
33 #include <Eigen/Geometry>
34 #include <tesseract_common/utils.h>
35 #include <tinyxml2.h>
37 
38 #include <tesseract_urdf/origin.h>
39 
40 namespace tesseract_urdf
41 {
42 Eigen::Isometry3d parseOrigin(const tinyxml2::XMLElement* xml_element)
43 {
44  Eigen::Isometry3d origin = Eigen::Isometry3d::Identity();
45 
46  if (xml_element->Attribute("xyz") == nullptr && xml_element->Attribute("rpy") == nullptr &&
47  xml_element->Attribute("wxyz") == nullptr)
48  std::throw_with_nested(std::runtime_error("Origin: Error missing required attributes 'xyz' and 'rpy' and/or 'wxyz' "
49  "for origin element!"));
50 
51  std::string xyz_string, rpy_string, wxyz_string;
52  int status = tesseract_common::QueryStringAttribute(xml_element, "xyz", xyz_string);
53  if (status != tinyxml2::XML_NO_ATTRIBUTE && status != tinyxml2::XML_SUCCESS)
54  std::throw_with_nested(std::runtime_error("Origin: Failed to parse attribute 'xyz'!"));
55 
56  if (status != tinyxml2::XML_NO_ATTRIBUTE)
57  {
58  std::vector<std::string> tokens;
59  boost::split(tokens, xyz_string, boost::is_any_of(" "), boost::token_compress_on);
60  if (tokens.size() != 3 || !tesseract_common::isNumeric(tokens))
61  std::throw_with_nested(std::runtime_error("Origin: Failed to parse attribute 'xyz' string!"));
62 
63  double x{ 0 }, y{ 0 }, z{ 0 };
64  // No need to check return values because the tokens are verified above
68 
69  origin.translation() = Eigen::Vector3d(x, y, z);
70  }
71 
72  if (xml_element->Attribute("wxyz") == nullptr)
73  {
74  status = tesseract_common::QueryStringAttribute(xml_element, "rpy", rpy_string);
75  if (status != tinyxml2::XML_NO_ATTRIBUTE && status != tinyxml2::XML_SUCCESS)
76  std::throw_with_nested(std::runtime_error("Origin: Failed to parse attribute 'rpy'!"));
77 
78  if (status != tinyxml2::XML_NO_ATTRIBUTE)
79  {
80  std::vector<std::string> tokens;
81  boost::split(tokens, rpy_string, boost::is_any_of(" "), boost::token_compress_on);
82  if (tokens.size() != 3 || !tesseract_common::isNumeric(tokens))
83  std::throw_with_nested(std::runtime_error("Origin: Failed to parse attribute 'rpy' string!"));
84 
85  double r{ 0 }, p{ 0 }, y{ 0 };
86  // No need to check return values because the tokens are verified above
90 
91  Eigen::AngleAxisd rollAngle(r, Eigen::Vector3d::UnitX());
92  Eigen::AngleAxisd pitchAngle(p, Eigen::Vector3d::UnitY());
93  Eigen::AngleAxisd yawAngle(y, Eigen::Vector3d::UnitZ());
94 
95  Eigen::Quaterniond rpy{ yawAngle * pitchAngle * rollAngle };
96 
97  origin.linear() = rpy.toRotationMatrix();
98  }
99  }
100  else
101  {
102  status = tesseract_common::QueryStringAttribute(xml_element, "wxyz", wxyz_string);
103  if (status != tinyxml2::XML_NO_ATTRIBUTE && status != tinyxml2::XML_SUCCESS)
104  std::throw_with_nested(std::runtime_error("Origin: Failed to parse attribute 'wxyz'!"));
105 
106  if (status != tinyxml2::XML_NO_ATTRIBUTE)
107  {
108  std::vector<std::string> tokens;
109  boost::split(tokens, wxyz_string, boost::is_any_of(" "), boost::token_compress_on);
110  if (tokens.size() != 4 || !tesseract_common::isNumeric(tokens))
111  std::throw_with_nested(std::runtime_error("Origin: Failed to parse attribute 'wxyz' string!"));
112 
113  double qw{ 0 }, qx{ 0 }, qy{ 0 }, qz{ 0 };
114  // No need to check return values because the tokens are verified above
119 
120  Eigen::Quaterniond q(qw, qx, qy, qz);
121  q.normalize();
122 
123  origin.linear() = q.toRotationMatrix();
124  }
125  }
126  return origin;
127 }
128 
129 tinyxml2::XMLElement* writeOrigin(const Eigen::Isometry3d& origin, tinyxml2::XMLDocument& doc)
130 {
131  tinyxml2::XMLElement* xml_element = doc.NewElement(ORIGIN_ELEMENT_NAME.data());
132  Eigen::IOFormat eigen_format(Eigen::StreamPrecision, Eigen::DontAlignCols, " ", " ");
133 
134  // Format and write the translation
135  if (!origin.translation().isZero(std::numeric_limits<double>::epsilon()))
136  {
137  std::stringstream xyz_string;
138  xyz_string << origin.translation().format(eigen_format);
139  xml_element->SetAttribute("xyz", xyz_string.str().c_str());
140  }
141 
142  // Extract, format, and write the rotation
143  if (!origin.linear().isIdentity(std::numeric_limits<double>::epsilon()))
144  {
145  Eigen::Vector3d ypr = origin.linear().eulerAngles(2, 1, 0);
146  Eigen::Vector3d rpy(ypr.z(), ypr.y(), ypr.x());
147  std::stringstream rpy_string;
148  rpy_string << rpy.format(eigen_format);
149  xml_element->SetAttribute("rpy", rpy_string.str().c_str());
150 
151  /*
152  // Extract rotation as Quaternion - Tesseract Exclusive
153  Eigen::Quaterniond q(origin.linear());
154  std::stringstream wxyz_string;
155  wxyz_string << Eigen::Vector4d(q.w(), q.x(), q.y(), q.z()).format(eigen_format);
156  xml_element->SetAttribute("wxyz", wxyz_string.str().c_str());
157  */
158  }
159 
160  return xml_element;
161 }
162 
163 } // namespace tesseract_urdf
tesseract_urdf::ORIGIN_ELEMENT_NAME
static constexpr std::string_view ORIGIN_ELEMENT_NAME
Definition: origin.h:43
utils.h
tesseract_urdf::parseOrigin
Eigen::Isometry3d parseOrigin(const tinyxml2::XMLElement *xml_element)
Parse xml element origin.
Definition: origin.cpp:42
origin.h
Parse origin from xml string.
TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
#define TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
tesseract_common::QueryStringAttribute
int QueryStringAttribute(const tinyxml2::XMLElement *xml_element, const char *name, std::string &value)
r
S r
TESSERACT_COMMON_IGNORE_WARNINGS_POP
tesseract_urdf::writeOrigin
tinyxml2::XMLElement * writeOrigin(const Eigen::Isometry3d &origin, tinyxml2::XMLDocument &doc)
Definition: origin.cpp:129
tesseract_common::isNumeric
bool isNumeric(const std::string &s)
tesseract_common::toNumeric< double >
template bool toNumeric< double >(const std::string &, double &)
macros.h
tesseract_urdf
Definition: box.h:43


tesseract_urdf
Author(s): Levi Armstrong
autogenerated on Thu Apr 24 2025 03:10:44