Privacy
An open-source, flexible 3D physical simulation framework
mathUtils.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2012. 2014, DFKI GmbH Robotics Innovation Center
3  *
4  * This file is part of the MARS simulation framework.
5  *
6  * MARS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation, either version 3
9  * of the License, or (at your option) any later version.
10  *
11  * MARS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with MARS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "mathUtils.h"
22 #include "misc.h"
23 
24 #include <stdexcept>
25 #include <cmath>
26 #include <algorithm>
27 #include <Eigen/Core>
28 //#include <stdio.h>
29 
30 namespace mars {
31  namespace utils {
32 
34  if(s == "pipe") return FUNCTION_PIPE;
35  if(s == "polynom2") return FUNCTION_POLYNOM2;
36  if(s == "polynom3") return FUNCTION_POLYNOM3;
37  if(s == "polynom4") return FUNCTION_POLYNOM4;
38  if(s == "polynom5") return FUNCTION_POLYNOM5;
39  if(s == "gaussian") return FUNCTION_GAUSSIAN;
40  return FUNCTION_UNKNOWN;
41  }
42 
44  if(s == "polynom2D1") return FUNCTION_POLYNOM2D1;
45  if(s == "polynom2D2") return FUNCTION_POLYNOM2D2;
46  //if(s == "polynom2D3") return FUNCTION_POLYNOM2D3;
47  return FUNCTION_UNKNOWN2D;
48  }
49 
50  double pipe(double* x, std::vector<double>* c) {
51  return (*x);
52  }
53 
54  double polynom2(double* x, std::vector<double>* c) {
55  return (*c)[0]*pow((*x),2) + (*c)[1]*((*x)) + (*c)[2];
56  }
57 
58  double polynom3(double* x, std::vector<double>* c) {
59  return (*c)[0]*pow((*x),3) + (*c)[1]*pow((*x),2) + (*c)[2]*((*x)) + (*c)[3];
60  }
61 
62  double polynom4(double* x, std::vector<double>* c) {
63  return (*c)[0]*pow((*x),4) + (*c)[1]*pow((*x),3)
64  + (*c)[2]*pow((*x),2) + (*c)[3]*((*x)) + (*c)[4];
65  }
66 
67  double polynom5(double* x, std::vector<double>* c) {
68  return (*c)[0]*pow((*x),5) + (*c)[1]*pow((*x),4) + (*c)[2]*pow((*x),3)
69  + (*c)[3]*pow((*x),2) + (*c)[4]*((*x)) + (*c)[5];
70  }
71 
72  /* first parameter is mu, second is sigma
73  */
74  double gaussian(double* x, std::vector<double>* c) {
75  return 1/(SQRT2PI*(*c)[1])*exp(-0.5*pow(((*x)-(*c)[0])/(*c)[1], 2));
76  }
77 
78  /*double beta_distribution(double* x, std::vector<double>* c) {
79 
80  }
81 
82  double gamma_distribution(double* x, std::vector<double>* c) {
83 
84  }*/
85 
86  //return x*y + x + y +c
87  double polynom2D1(double* x, double* y, std::vector<double>* c) {
88  return (*c)[0]*(*x)*(*y) + (*c)[1]*((*x)) + (*c)[2]*((*x)) + (*c)[3];
89  }
90 
91  //return x^2*y^2 + x^2*y + x*y^2 + x^2 + y^2 + x*y + x + y +c
92  double polynom2D2(double* x, double* y, std::vector<double>* c) {
93  return (*c)[0]*pow((*x),2)*pow((*y),2) + (*c)[1]*pow((*x),2)*(*y) + (*c)[2]*(*x)*pow((*y),2)
94  + (*c)[3]*pow((*x),2) + (*c)[4]*pow((*y),2) + (*c)[5]*(*x)*(*y) + (*c)[6]*((*x))
95  + (*c)[7]*((*x)) + (*c)[8];
96  }
97 
98  static const int EULER_AXIS_1 = 2;
99  static const int EULER_AXIS_2 = 0;
100  static const int EULER_AXIS_3 = 1;
101 
102  double getYaw(const Quaternion &q){
103  Eigen::Vector3d v = q * Eigen::Vector3d::UnitX();
104  return ::atan2(v[1],v[0]);
105  }
106 
107  double angleBetween(const Vector &v1, const Vector &v2, Vector *axis) {
108  double squared_length1 = v1.squaredNorm();
109  double squared_length2 = v2.squaredNorm();
110  double tmp = sqrt(squared_length1 * squared_length2);
111  double angle = acos(v1.dot(v2) / tmp);
112  if (axis != NULL) {
113  // special case 0 and 180 degrees where the axis is ambiguous
114  // Note that acos returns a value in [0, M_PI] so angle is in that range
115  if ((angle <= EPSILON) || (M_PI - angle <= EPSILON)) {
116  // find an axis that isn't zero and switch it with another one
117  // make sure to keep the length intact
118  Vector dummy;
119  if (v1(0) > EPSILON) {
120  dummy = Vector(v1.y(), -v1.x(), v1.z());
121  } else {
122  dummy = Vector(v1.x(), v1.z(), -v1.y());
123  }
124  *axis = dummy.cross(v2) / tmp;
125  } else {
126  *axis = v1.cross(v2) / tmp;
127  }
128  }
129  return angle;
130  }
131 
132 
134 #if 1
135  double _heading = degToRad(euler_v[2]);
136  double _attitude = degToRad(euler_v[1]);
137  double _bank = degToRad(euler_v[0]);
138  double c1 = cos(_heading/2);
139  double s1 = sin(_heading/2);
140  double c2 = cos(_attitude/2);
141  double s2 = sin(_attitude/2);
142  double c3 = cos(_bank/2);
143  double s3 = sin(_bank/2);
144  double c1c2 = c1*c2;
145  double s1s2 = s1*s2;
146  Quaternion q;
147  q.w() = (double) (c1c2*c3 + s1s2*s3);
148  q.x() = (double) (c1c2*s3 - s1s2*c3);
149  q.y() = (double) (c1*s2*c3 + s1*c2*s3);
150  q.z() = (double) (s1*c2*c3 - c1*s2*s3);
151  return q.normalized();
152 #else
153  return
154  Eigen::AngleAxisd(euler_v.x()/180.0*M_PI,
155  Eigen::Vector3d::Unit(EULER_AXIS_1)) *
156  Eigen::AngleAxisd(euler_v.z()/180.0*M_PI,
157  Eigen::Vector3d::Unit(EULER_AXIS_2)) *
158  Eigen::AngleAxisd(euler_v.y()/180.0*M_PI,
159  Eigen::Vector3d::Unit(EULER_AXIS_3));
160 #endif
161  }
162 
164 #if 1
165  sRotation euler;
166  double sqw = value.w()*value.w();
167  double sqx = value.x()*value.x();
168  double sqy = value.y()*value.y();
169  double sqz = value.z()*value.z();
170  // heading
171  euler.gamma = radToDeg(atan2(2.*(value.x()*value.y()+value.z()*value.w()),
172  (sqx - sqy - sqz + sqw)));
173  // bank
174  euler.alpha = radToDeg(atan2(2.*(value.y()*value.z()+value.x()*value.w()),
175  (-sqx - sqy + sqz + sqw)));
176  // attitude
177  double test = -2. * (value.x()*value.z() - value.y()*value.w());
178  test = (test > 1. ? 1. : (test < -1. ? -1. : test));
179  euler.beta = radToDeg(asin(test));
180  return euler;
181 #else
182  Vector yaw_roll_pitch = value.toRotationMatrix().eulerAngles(EULER_AXIS_1,
183  EULER_AXIS_2,
184  EULER_AXIS_3);
185  sRotation rot;
186  rot.alpha = radToDeg(yaw_roll_pitch.x());
187  rot.beta = radToDeg(yaw_roll_pitch.y());
188  rot.gamma = radToDeg(yaw_roll_pitch.z());
189 
190  return rot;
191 #endif
192  }
193 
194 
195  Vector slerp(const Vector &from, const Vector &to, double t) {
196  if (fabs(t) > 1) {
197  throw std::runtime_error("Argument t to Vector::slerp must be in range [-1, 1].");
198  }
199 
200  double length1 = from.norm();
201  double length2 = to.norm();
202  double tmp = from.dot(to) / (length1 * length2);
203  /* make sure tmp is in the range [-1:1] so acos won't return NaN */
204  tmp = (tmp < -1 ? -1 : (tmp > 1 ? 1: tmp));
205  double angle = acos(tmp);
206 
207  /* if t < 0 we take the long arch of the greate circle to the destiny */
208  if (t < 0) {
209  angle -= 2 * M_PI;
210  t = -t;
211  }
212  if (from.x() * to.y() < from.y() * to.x())
213  angle *= -1;
214 
215  Vector ret;
216  /* special case angle==0 and angle==360 */
217  if ((fabs(angle) <= EPSILON) ||
218  (fabs(fabs(angle) - 2 * M_PI) <= EPSILON)) {
219  /* approximate with lerp, because slerp diverges with 1/sin(angle) */
220  ret = lerp(from, to, t);
221  }
222  /* special case angle==180 and angle==-180 */
223  else if (fabs(fabs(angle) - M_PI) <= EPSILON) {
224  throw std::runtime_error("SLERP with 180 degrees is undefined.");
225  }
226  else {
227  double f0 = ((length2 - length1) * t + length1) / ::sin(angle);
228  double f1 = ::sin(angle * (1-t)) / length1;
229  double f2 = ::sin(angle * t) / length2;
230  ret = ((from.array() * f1 + to.array() * f2) * f0).matrix();
231  }
232  return ret;
233  }
234 
235  Vector lerp(const Vector &from, const Vector &to, double t) {
236  if (t < 0 || t > 1) {
237  throw std::runtime_error("Argument t to Vector::lerp must be in range [0, 1]");
238  }
239  return (from.array() * (1-t) + to.array() * t).matrix();
240  }
241 
242  void vectorToSpherical(const Vector &v, double *r, double *theta, double *phi) {
243  *r = v.norm();
244  if (fabs(*r) < EPSILON) {
245  *theta = 0;
246  *phi = 0;
247  return;
248  }
249  *theta = acos(v.z() / (*r));
250  *phi = atan2(v.y(), v.x());
251  }
252 
253  Vector getProjection(const Vector &v1, const Vector &v2) {
254  double a = v1.dot(v2);
255  double b = v2.dot(v2);
256  Vector ret(v2);
257  ret *= a/b;
258  return ret;
259  }
260 
261  Vector vectorFromSpherical(double r, double theta, double phi) {
262  return Vector(r * sin(theta) * cos(phi),
263  r * sin(theta) * sin(phi),
264  r * cos(theta));
265  }
266 
268  v->x() = (*item)["x"];
269  v->y() = (*item)["y"];
270  v->z() = (*item)["z"];
271  return true;
272  }
273 
275  (*item)["x"] = v->x();
276  (*item)["y"] = v->y();
277  (*item)["z"] = v->z();
278  }
279 
281  q->w() = (*item)["w"];
282  q->x() = (*item)["x"];
283  q->y() = (*item)["y"];
284  q->z() = (*item)["z"];
285  return true;
286  }
287 
289  (*item)["w"] = q->w();
290  (*item)["x"] = q->x();
291  (*item)["y"] = q->y();
292  (*item)["z"] = q->z();
293  }
294 
295  void inertiaTensorToConfigItem(ConfigItem *item, double *inertia) {
296  (*item)["i00"] = inertia[0];
297  (*item)["i01"] = inertia[1];
298  (*item)["i02"] = inertia[2];
299  (*item)["i10"] = inertia[3];
300  (*item)["i11"] = inertia[4];
301  (*item)["i12"] = inertia[5];
302  (*item)["i20"] = inertia[6];
303  (*item)["i21"] = inertia[7];
304  (*item)["i22"] = inertia[8];
305  }
306 
307  double random_number(double min, double max, int digits) {
308  int range = pow(10, digits);
309  int r = rand() % range;
310  return r / (double)range * (max-min) + min;
311  }
312 
313  double random_normal_number(double mean, double std, double low, double high) {
314  // C++11 - does not work on all compilers, yet
315  // std::default_random_engine generator;
316  // std::normal_real_distribution<double> normal_dis(mean, std);
317  //return normal_dis(generator);
318 
319  // return a normally distributed random number, restricted to range [min, max]
320  double u1=random_number(0, 1, 3);
321  double u2=random_number(0, 1, 3);
322  double num = cos(2*M_PI*u2)*sqrt(-2.*log(u1)) * std + mean;
323  //fprintf(stderr, "normal num: %f, %f, %f\n", u1, u2, num);
324  return std::min(std::max(num, low), high);
325  }
326 
327 
328 
329  } // end of namespace utils
330 } /* end of namespace mars */
Vector slerp(const Vector &from, const Vector &to, double t)
Definition: mathUtils.cpp:195
Vector lerp(const Vector &from, const Vector &to, double t)
Definition: mathUtils.cpp:235
static const int EULER_AXIS_1
Definition: mathUtils.cpp:98
double angleBetween(const Vector &v1, const Vector &v2, Vector *axis)
Angle between two vectors.
Definition: mathUtils.cpp:107
Vector vectorFromSpherical(double r, double theta, double phi)
Definition: mathUtils.cpp:261
double random_number(double min, double max, int digits)
Definition: mathUtils.cpp:307
double degToRad(const double &d)
converts an angle given in degrees to radians.
Definition: misc.h:55
void inertiaTensorToConfigItem(ConfigItem *item, double *inertia)
Definition: mathUtils.cpp:295
u_int8_t b
Definition: CameraSensor.h:43
Definition: tsort.c:44
static const int EULER_AXIS_2
Definition: mathUtils.cpp:99
ApproximationFunction getApproximationFunctionFromString(std::string s)
Definition: mathUtils.cpp:33
sRotation quaternionTosRotation(const Quaternion &value)
Definition: mathUtils.cpp:163
bool vectorFromConfigItem(ConfigItem *item, Vector *v)
Definition: mathUtils.cpp:267
double radToDeg(const double &r)
converts an angle given in radians to degrees.
Definition: misc.h:45
u_int8_t r
Definition: CameraSensor.h:41
bool quaternionFromConfigItem(ConfigItem *item, Quaternion *q)
Definition: mathUtils.cpp:280
static const int EULER_AXIS_3
Definition: mathUtils.cpp:100
void vectorToConfigItem(ConfigItem *item, Vector *v)
Definition: mathUtils.cpp:274
Base object of the configmaps library!
Definition: ConfigItem.hpp:58
u_int8_t a
Definition: CameraSensor.h:44
void vectorToSpherical(const Vector &v, double *r, double *theta, double *phi)
Definition: mathUtils.cpp:242
Quaternion eulerToQuaternion(const Vector &euler_v)
Definition: mathUtils.cpp:133
double polynom3(double *x, std::vector< double > *c)
Definition: mathUtils.cpp:58
double polynom2(double *x, std::vector< double > *c)
Definition: mathUtils.cpp:54
ApproximationFunction2D getApproximationFunction2DFromString(std::string s)
Definition: mathUtils.cpp:43
ApproximationFunction2D
Definition: mathUtils.h:47
Vector getProjection(const Vector &v1, const Vector &v2)
Definition: mathUtils.cpp:253
void quaternionToConfigItem(ConfigItem *item, Quaternion *q)
Definition: mathUtils.cpp:288
double getYaw(const Quaternion &q)
Definition: mathUtils.cpp:102
Copyright 2012, DFKI GmbH Robotics Innovation Center.
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vector
Definition: Vector.h:43
ApproximationFunction
Definition: mathUtils.h:35
Eigen::Quaternion< double, Eigen::DontAlign > Quaternion
Definition: Quaternion.h:56
#define max(x, y)
Definition: envmap.cpp:33
double random_normal_number(double mean, double std, double low, double high)
Definition: mathUtils.cpp:313
double polynom2D1(double *x, double *y, std::vector< double > *c)
Definition: mathUtils.cpp:87
const double EPSILON
Definition: mathUtils.h:70
#define M_PI
Definition: Quaternion.h:39
double polynom5(double *x, std::vector< double > *c)
Definition: mathUtils.cpp:67
const double SQRT2PI
Definition: mathUtils.h:57
double pipe(double *x, std::vector< double > *c)
Definition: mathUtils.cpp:50
double gaussian(double *x, std::vector< double > *c)
Definition: mathUtils.cpp:74
double polynom4(double *x, std::vector< double > *c)
Definition: mathUtils.cpp:62
double polynom2D2(double *x, double *y, std::vector< double > *c)
Definition: mathUtils.cpp:92