iMSTK
Interactive Medical Simulation Toolkit
imstkMath.h
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #pragma once
8 
9 #define NOMINMAX
10 
11 #include <vector>
12 #include <memory>
13 #include <utility>
14 
15 #include <Eigen/Geometry>
16 #include <Eigen/StdVector>
17 #include <Eigen/Sparse>
18 
19 #if !defined(_MSC_VER) && __cplusplus <= 201103L
20 namespace std
21 {
22 template<typename T, typename ... Args>
23 std::unique_ptr<T>
24 make_unique(Args&& ... args)
25 {
26  return std::unique_ptr<T>(new T(std::forward<Args>(args) ...));
27 }
28 } // namespace std
29 #endif
30 
31 namespace imstk
32 {
33 // 2D vector
34 // using Vec2f = Eigen::Vector2f;
35 // using Vec2d = Eigen::Vector2d;
36 using Vec2f = Eigen::Matrix<float, 2, 1>;
37 using Vec2d = Eigen::Matrix<double, 2, 1>;
38 using Vec2i = Eigen::Matrix<int, 2, 1>;
39 using StdVectorOfVec2f = std::vector<Vec2f, Eigen::aligned_allocator<Vec2f>>;
40 using StdVectorOfVec2d = std::vector<Vec2d, Eigen::aligned_allocator<Vec2d>>;
41 
42 // 3D vector
43 // using Vec3f = Eigen::Vector3f;
44 // using Vec3d = Eigen::Vector3d;
45 using Vec3f = Eigen::Matrix<float, 3, 1>;
46 using Vec3d = Eigen::Matrix<double, 3, 1>;
47 using Vec3i = Eigen::Matrix<int, 3, 1>;
48 using StdVectorOfVec3f = std::vector<Vec3f, Eigen::aligned_allocator<Vec3f>>;
49 using StdVectorOfVec3d = std::vector<Vec3d, Eigen::aligned_allocator<Vec3d>>;
50 
51 // 4D vector
52 // using Vec4f = Eigen::Vector4f;
53 // using Vec4d = Eigen::Vector4d;
54 using Vec4f = Eigen::Matrix<float, 4, 1>;
55 using Vec4d = Eigen::Matrix<double, 4, 1>;
56 using Vec4i = Eigen::Matrix<int, 4, 1>;
57 using StdVectorOfVec4f = std::vector<Vec4f, Eigen::aligned_allocator<Vec4f>>;
58 using StdVectorOfVec4d = std::vector<Vec4d, Eigen::aligned_allocator<Vec4d>>;
59 
60 // 6D vector
61 using Vec6f = Eigen::Matrix<float, 6, 1>;
62 using Vec6d = Eigen::Matrix<double, 6, 1>;
63 using Vec6i = Eigen::Matrix<int, 6, 1>;
64 
65 // 8D vector
66 using Vec8i = Eigen::Matrix<int, 8, 1>;
67 
68 // Dynamic size vector
69 using Vectorf = Eigen::VectorXf;
70 using Vectord = Eigen::VectorXd;
71 using StdVectorOfVectorf = std::vector<Vectorf, Eigen::aligned_allocator<Vectorf>>;
72 using StdVectorOfVectord = std::vector<Vectord, Eigen::aligned_allocator<Vectord>>;
73 
74 // Quaternion
75 using Quatf = Eigen::Quaternion<float>;
76 using Quatd = Eigen::Quaternion<double>;
77 using StdVectorOfQuatf = std::vector<Quatf, Eigen::aligned_allocator<Quatf>>;
78 using StdVectorOfQuatd = std::vector<Quatd, Eigen::aligned_allocator<Quatd>>;
79 
80 // Angle-Axis
81 using Rotf = Eigen::AngleAxisf;
82 using Rotd = Eigen::AngleAxisd;
83 
84 // 3x3 Matrix
85 using Mat3f = Eigen::Matrix<float, 3, 3>;
86 using Mat3d = Eigen::Matrix<double, 3, 3>;
87 using StdVectorOfMat3d = std::vector<Mat3d, Eigen::aligned_allocator<Mat3d>>;
88 
89 // 4x4 Matrix
90 using Mat4f = Eigen::Matrix<float, 4, 4>;
91 using Mat4d = Eigen::Matrix<double, 4, 4>;
92 
94 using Matrixf = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>;
95 
97 using Matrixd = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
98 
99 // A dynamic size sparse matrix of doubles
100 using SparseMatrixf = Eigen::SparseMatrix<float, Eigen::RowMajor>;
101 
102 // A dynamic size sparse matrix of doubles
103 using SparseMatrixd = Eigen::SparseMatrix<double, Eigen::RowMajor>;
104 
105 // Rigid transform (translation and rotation)
106 using RigidTransform3f = Eigen::Isometry3f;
107 using RigidTransform3d = Eigen::Isometry3d;
108 
109 // Affine transform (translation, rotation, scaling and shearing)
110 using AffineTransform3f = Eigen::Affine3f;
111 using AffineTransform3d = Eigen::Affine3d;
112 
114 #define PI 3.14159265358979323846
115 #define PI_2 1.57079632679489661923
116 #define PI_4 0.785398163397448309616
117 #define INV_1_PI 0.318309886183790671538
118 #define INV_2_PI 0.636619772367581343076
119 #define TWO_OVER_SQRT_PI 1.12837916709551257390
120 #define SQRT2 1.41421356237309504880
121 #define SQRT1_2 0.707106781186547524401
122 #define NLOG_E 2.71828182845904523536
123 #define LOG2E 1.44269504088896340736
124 #define LOG10E 0.434294481903251827651
125 #define LN2 0.693147180559945309417
126 #define LN10 2.30258509299404568402
127 
128 #define MAX_D std::numeric_limits<double>::max()
129 #define MIN_D std::numeric_limits<double>::min()
130 #define VERY_SMALL_EPSILON_D std::numeric_limits<double>::epsilon()
131 
132 #define MAX_F std::numeric_limits<float>::max()
133 #define MIN_F std::numeric_limits<float>::min()
134 #define VERY_SMALL_EPSILON_F std::numeric_limits<float>::epsilon()
135 
136 static inline Mat4d
137 mat4dTranslate(const Vec3d& translate)
138 {
139  return AffineTransform3d(Eigen::Translation3d(translate)).matrix();
140 }
141 
142 static inline Mat4d
143 mat4dScale(const Vec3d& scale)
144 {
145  Mat4d mScale = Mat4d::Identity();
146  mScale(0, 0) = scale[0];
147  mScale(1, 1) = scale[1];
148  mScale(2, 2) = scale[2];
149  return mScale;
150 }
151 
152 static inline Mat4d
153 mat4dRotation(const Quatd& rotation)
154 {
155  Mat4d mRot = Mat4d::Identity();
156  mRot.block<3, 3>(0, 0) = rotation.toRotationMatrix();
157  return mRot;
158 }
159 
160 static inline Mat4d
161 mat4dRotation(const Rotd& rotation)
162 {
163  Mat4d mRot = Mat4d::Identity();
164  mRot.block<3, 3>(0, 0) = rotation.toRotationMatrix();
165  return mRot;
166 }
167 
168 static inline Mat4d
169 mat4dRotation(const Mat3d& rotation)
170 {
171  Mat4d mRot = Mat4d::Identity();
172  mRot.block<3, 3>(0, 0) = rotation;
173  return mRot;
174 }
175 
179 static inline void
180 mat4dTRS(const Mat4d& m, Vec3d& t, Mat3d& r, Vec3d& s)
181 {
182  // Assumes affine, no shear
183  const Vec3d& x = m.block<3, 1>(0, 0);
184  const Vec3d& y = m.block<3, 1>(0, 1);
185  const Vec3d& z = m.block<3, 1>(0, 2);
186 
187  s = Vec3d(m.block<3, 1>(0, 0).norm(),
188  m.block<3, 1>(0, 1).norm(),
189  m.block<3, 1>(0, 2).norm());
190 
191  r = Mat3d::Identity();
192  r.block<3, 1>(0, 0) = x.normalized();
193  r.block<3, 1>(0, 1) = y.normalized();
194  r.block<3, 1>(0, 2) = z.normalized();
195 
196  t = m.block<3, 1>(0, 3);
197 }
198 
202 static double
203 tetVolume(Vec3d p0, Vec3d p1, Vec3d p2, Vec3d p3)
204 {
205  Mat4d m;
206  m.block<1, 3>(0, 0) = p0;
207  m.block<1, 3>(1, 0) = p1;
208  m.block<1, 3>(2, 0) = p2;
209  m.block<1, 3>(3, 0) = p3;
210  m(0, 3) = m(1, 3) = m(2, 3) = m(3, 3) = 1.0;
211  return m.determinant() / 6.0;
212 }
213 
219 static Vec2d
220 baryCentric(const Vec3d& pt, const Vec3d& p, const Vec3d& q)
221 {
222  Vec3d dir = q - p;
223  const double length = dir.norm();
224  dir /= length;
225  const double t = (pt - p).dot(dir) / length;
226  return Vec2d(1.0 - t, t);
227 }
228 
233 static Vec3d
234 baryCentric(const Vec2d& p, const Vec2d& a, const Vec2d& b, const Vec2d& c)
235 {
236  const Vec2d v0 = b - a;
237  const Vec2d v1 = c - a;
238  const Vec2d v2 = p - a;
239  const double den = v0[0] * v1[1] - v1[0] * v0[1];
240  const double v = (v2[0] * v1[1] - v1[0] * v2[1]) / den;
241  const double w = (v0[0] * v2[1] - v2[0] * v0[1]) / den;
242  const double u = 1.0 - v - w;
243  return Vec3d(u, v, w);
244 }
245 
251 static Vec3d
252 baryCentric(const Vec3d& p, const Vec3d& a, const Vec3d& b, const Vec3d& c)
253 {
254  const Vec3d v0 = b - a;
255  const Vec3d v1 = c - a;
256  const Vec3d v2 = p - a;
257  const double d00 = v0.dot(v0);
258  const double d01 = v0.dot(v1);
259  const double d11 = v1.dot(v1);
260  const double d20 = v2.dot(v0);
261  const double d21 = v2.dot(v1);
262  const double denom = d00 * d11 - d01 * d01;
263  const double v = (d11 * d20 - d01 * d21) / denom;
264  const double w = (d00 * d21 - d01 * d20) / denom;
265  const double u = 1.0 - v - w;
266  return Vec3d(u, v, w);
267 }
268 
273 static Vec4d
274 baryCentric(const Vec3d& p, const Vec3d& a, const Vec3d& b, const Vec3d& c, const Vec3d& d)
275 {
276  Mat4d A;
277  A << a[0], a[1], a[2], 1.0,
278  b[0], b[1], b[2], 1.0,
279  c[0], c[1], c[2], 1.0,
280  d[0], d[1], d[2], 1.0;
281 
282  Vec4d weights;
283  double det = A.determinant(); // Signed volume
284  for (int i = 0; i < 4; ++i)
285  {
286  Mat4d B = A;
287  B(i, 0) = p[0];
288  B(i, 1) = p[1];
289  B(i, 2) = p[2];
290  weights[i] = B.determinant() / det;
291  }
292  return weights;
293 }
294 
299 template<typename T>
300 static T
301 cantor(const T a, const T b)
302 {
303  return (a + b) * (a + b + 1) / 2 + b;
304 }
305 
311 template<typename T>
312 static T
313 symCantor(const T a, const T b)
314 {
315  const T max = std::max<T>(a, b);
316  const T min = std::min<T>(a, b);
317  return max * (max + 1) / 2 + min;
318 }
319 } // namespace imstk
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > Matrixd
A dynamic size matrix of doubles.
Definition: imstkMath.h:97
Compound Geometry.
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic > Matrixf
A dynamic size matrix of floats.
Definition: imstkMath.h:94