mc_rtc  2.14.0
fmt_formatters.h
Go to the documentation of this file.
1 /*
2  * Copyright 2026 CNRS-UM LIRMM, CNRS-AIST JRL
3  */
4 
5 #pragma once
6 #include <mc_rbdyn/rpy_utils.h>
7 #include <mc_rtc/constants.h>
8 #include <SpaceVecAlg/PTransform.h>
9 #include <fmt/format.h>
10 
11 // fmt 9.0.0 removed automated operator<< discovery we use fmt::streamed instead when needed through a macro
12 #if FMT_VERSION >= 9 * 10000
13 # define MC_FMT_STREAMED(X) fmt::streamed(X)
14 # include <boost/filesystem.hpp>
15 # include <eigen-fmt/fmt.h>
16 # include <filesystem>
17 # include <fmt/ostream.h>
18 
19 // Formatter for boost::filesystem::path
20 template<>
21 struct fmt::formatter<boost::filesystem::path> : fmt::formatter<std::string>
22 {
23  template<typename FormatContext>
24  auto format(const boost::filesystem::path & p, FormatContext & ctx)
25  {
26  return fmt::formatter<std::string>::format(p.string(), ctx);
27  }
28 };
29 
30 // Formatter for std::filesystem::path
31 template<>
32 struct fmt::formatter<std::filesystem::path> : fmt::formatter<std::string>
33 {
34  template<typename FormatContext>
35  auto format(const std::filesystem::path & p, FormatContext & ctx)
36  {
37  return fmt::formatter<std::string>::format(p.string(), ctx);
38  }
39 };
40 
71 template<>
72 struct fmt::formatter<sva::PTransformd>
73 {
74  int arg_id_vec = -1, arg_id_mat = -1;
75  // Default format strings
76  const std::string default_vec_fmt = "t;noal;p{3};csep{, };rpre{[};rsuf{]}";
77  const std::string default_mat_fmt = "p{3};csep{, };rpre{ [};rsuf{]};rsep{\n}";
78 
79  // Parse for up to two nested arguments: {:{}} or {:{}{}}
80  // arg(1) is formatting for vectors
81  // arg(2) is formatting for matrices
82  auto parse(format_parse_context & ctx)
83  {
84  auto it = ctx.begin(), end = ctx.end();
85  if(it == end || *it == '}') return it;
86  if(*it == '{')
87  {
88  ++it;
89  arg_id_vec = ctx.next_arg_id();
90  if(it != end && *it == '}')
91  {
92  ++it;
93  // Check for a second nested argument
94  if(it != end && *it == '{')
95  {
96  ++it;
97  arg_id_mat = ctx.next_arg_id();
98  if(it != end && *it == '}') { ++it; }
99  }
100  }
101  return it;
102  }
103  throw format_error("invalid format");
104  }
105 
106  template<typename FormatContext>
107  auto format(const sva::PTransformd & pt, FormatContext & ctx) const
108  {
109  // Get user format strings or use defaults
110  std::string vec_fmt = default_vec_fmt;
111  std::string mat_fmt = default_mat_fmt;
112 
113  if(arg_id_vec != -1)
114  {
115  vec_fmt = fmt::visit_format_arg(
116  [](auto val) -> std::string
117  {
118  if constexpr(std::is_same_v<std::decay_t<decltype(val)>, const char *>) { return std::string(val); }
119  else
120  {
121  return "";
122  }
123  },
124  ctx.arg(arg_id_vec));
125  if(vec_fmt.empty()) vec_fmt = default_vec_fmt;
126  }
127  if(arg_id_mat != -1)
128  {
129  mat_fmt = fmt::visit_format_arg(
130  [](auto && val) -> std::string
131  {
132  if constexpr(std::is_same_v<std::decay_t<decltype(val)>, const char *>) { return std::string(val); }
133  else
134  {
135  return "";
136  }
137  },
138  ctx.arg(arg_id_mat));
139  if(mat_fmt.empty()) mat_fmt = default_mat_fmt;
140  }
141 
142  const auto & rotation_ft = pt.rotation();
143  auto rotation_std = pt.rotation().transpose();
144 
145  auto rpy_ft = mc_rbdyn::rpyFromMat(rotation_ft);
146  auto rpy_ft_deg = rpy_ft * 180. / mc_rtc::constants::PI;
147 
148  auto rpy_std = mc_rbdyn::rpyFromMat(rotation_std);
149  auto rpy_std_deg = rpy_std * 180. / mc_rtc::constants::PI;
150 
151  return fmt::format_to(ctx.out(),
152  "translation: {:{}}\n"
153  "rotation:\n"
154  " - matrix (Featherstone, left-handed convention):\n{:{}}\n"
155  " - matrix (Standard, right-handed convention):\n{:{}}\n"
156  " - rpy (Featherstone): {:{}} (rad), {:{}} (deg)\n"
157  " - rpy (standard): {:{}} (rad), {:{}} (deg)\n",
158  pt.translation(), vec_fmt, rotation_ft, mat_fmt, rotation_std, mat_fmt, rpy_ft, vec_fmt,
159  rpy_ft_deg, vec_fmt, rpy_std, vec_fmt, rpy_std_deg, vec_fmt);
160  }
161 };
162 
163 #else
164 # define MC_FMT_STREAMED(X) X
165 #endif
Eigen::Vector3d rpyFromMat(const Eigen::Matrix3d &E)
Definition: rpy_utils.h:83
constexpr double PI
Definition: constants.h:18
Definition: Contact.h:67