GteChebyshevRatio.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
10 #include <GTEngineDEF.h>
11 #include <cmath>
12 
13 // Let f(t,A) = sin(t*A)/sin(A). The slerp of quaternions q0 and q1 is
14 // slerp(t,q0,q1) = f(1-t,A)*q0 + f(t,A)*q1.
15 // Let y = 1-cos(A); we allow A in [0,pi], so y in [0,1]. As a function of y,
16 // a series representation for f(t,y) is
17 // f(t,y) = sum_{i=0}^{infinity} c_{i}(t) y^{i}
18 // where c_0(t) = t, c_{i}(t) = c_{i-1}(t)*(i^2 - t^2)/(i*(2*i+1)) for i >= 1.
19 // The c_{i}(t) are polynomials in t of degree 2*i+1. The paper
20 //
21 // A Fast and Accurate Algorithm for Computing SLERP,
22 // David Eberly,
23 // Journal of Graphics, GPU, and Game Tools, 15 : 3, 161 - 176, 2011
24 // http://www.tandfonline.com/doi/abs/10.1080/2151237X.2011.610255#.VHRB7ouUd8E
25 //
26 // derives an approximation
27 // g(t,y) = sum_{i=0}^{n-1} c_{i}(t) y^{i} + (1+u_n) c_{n}(t) y^n
28 // which has degree 2*n+1 in t and degree n in y. The u_n were chosen to
29 // balance the error at y = 1 (A = pi/2). Unfortunately, the analysis for the
30 // global error bounds (0 <= y <= 1) is flawed; the error bounds printed in
31 // the paper are too small by about one order of magnitude (factor of 10).
32 // Instead they are the following, verified by Mathematica using larger
33 // precision than 'float' or 'double':
34 //
35 // n | error | n | error | n | error | n | error
36 // --+------------+----+------------+----+------------+----+-------------
37 // 1 | 2.60602e-2 | 5 | 3.63188e-4 | 9 | 1.12223e-5 | 13 | 4.37180e-7
38 // 2 | 7.43321e-3 | 6 | 1.47056e-4 | 10 | 4.91138e-6 | 14 | 1.98230e-7
39 // 3 | 2.51798e-3 | 7 | 6.11808e-5 | 11 | 2.17345e-6 | 15 | 9.04302e-8
40 // 4 | 9.30819e-4 | 8 | 2.59880e-5 | 12 | 9.70876e-7 | 16 | 4.03665e-8
41 //
42 // The maximum errors all occur for an angle that is nearly pi/2. The
43 // approximation is much more accurate when for angles A in [0,pi/4]. With
44 // this restriction, the global error bounds are
45 //
46 // n | error | n | error | n | error | n | error
47 // --+------------+----+------------+----+-------------+----+-------------
48 // 1 | 1.90648e-2 | 5 | 5.83197e-6 | 9 | 6.80465e-10 | 13 | 3.39728e-13
49 // 2 | 2.43581e-3 | 6 | 8.00278e-6 | 10 | 9.12477e-11 | 14 | 4.70735e-14
50 // 3 | 3.20235e-4 | 7 | 1.10649e-7 | 11 | 4.24608e-11 | 15 | 1.55431e-15
51 // 4 | 4.29242e-5 | 8 | 1.53828e-7 | 12 | 5.93392e-12 | 16 | 1.11022e-16
52 //
53 // Given q0 and q1 such that cos(A) = dot(q0,q1) in [0,1], in which case
54 // A in [0,pi/2], let qh = (q0+q1)/|q0 + q1| = slerp(1/2,q0,q1). Note that
55 // |q0 + q1| = 2*cos(A/2) because
56 // sin(A/2)/sin(A) = sin(A/2)/(2*sin(A/2)*cos(A/2)) = 1/(2*cos(A/2))
57 // The angle between q0 and qh is the same as the angle between qh and q1,
58 // namely, A/2 in [0,pi/4]. It may be shown that
59 // +--
60 // slerp(t,q0,q1) = | slerp(2*t,q0,qh), 0 <= t <= 1/2
61 // | slerp(2*t-1,qh,q1), 1/2 <= t <= 1
62 // +--
63 // The slerp functions on the right-hand side involve angles in [0,pi/4], so
64 // the approximation is more accurate for those evaluations than using the
65 // original.
66 
67 namespace gte
68 {
69 
70 template <typename Real>
72 {
73 public:
74  // Compute f(t,A) = sin(t*A)/sin(A), where t in [0,1], A in [0,pi/2],
75  // cosA = cos(A), f0 = f(1-t,A), and f1 = f(t,A).
76  inline static void Get(Real t, Real cosA, Real& f0, Real& f1);
77 
78  // Compute estimates for f(t,y) = sin(t*A)/sin(A), where t in [0,1],
79  // A in [0,pi/2], y = 1 - cos(A), f0 is the estimate for f(1-t,y), and
80  // f1 is the estimate for f(t,y). The approximating function is a
81  // polynomial of two variables. The template parameter N must be in
82  // {1..16}. The degree in t is 2*N+1 and the degree in Y is N.
83  template <int N>
84  inline static void GetEstimate(Real t, Real y, Real& f0, Real& f1);
85 };
86 
87 
88 template <typename Real> inline
89 void ChebyshevRatio<Real>::Get(Real t, Real cosA, Real& f0, Real& f1)
90 {
91  if (cosA < (Real)1)
92  {
93  // The angle A is in (0,pi/2].
94  Real A = acos(cosA);
95  Real invSinA = ((Real)1) / sin(A);
96  f0 = sin(((Real)1 - t) * A) * invSinA;
97  f1 = sin(t * A) * invSinA;
98  }
99  else
100  {
101  // The angle theta is 0.
102  f0 = (Real)1 - t;
103  f1 = (Real)t;
104  }
105 }
106 
107 template <typename Real>
108 template <int N> inline
109 void ChebyshevRatio<Real>::GetEstimate(Real t, Real y, Real& f0, Real& f1)
110 {
111  static_assert(1 <= N && N <= 16, "Invalid degree.");
112 
113  // The ASM output of the MSVS 2013 Release build shows that the constants
114  // in these arrays are loaded to XMM registers as literal values, and only
115  // those constants required for the specified degree D are loaded. That
116  // is, the compiler does a good job of optimizing the code.
117 
118  Real const onePlusMu[16] =
119  {
120  (Real)1.62943436108234530,
121  (Real)1.73965850021313961,
122  (Real)1.79701067629566813,
123  (Real)1.83291820510335812,
124  (Real)1.85772477879039977,
125  (Real)1.87596835698904785,
126  (Real)1.88998444919711206,
127  (Real)1.90110745351730037,
128  (Real)1.91015881189952352,
129  (Real)1.91767344933047190,
130  (Real)1.92401541194159076,
131  (Real)1.92944142668012797,
132  (Real)1.93413793373091059,
133  (Real)1.93824371262559758,
134  (Real)1.94186426368404708,
135  (Real)1.94508125972497303
136  };
137 
138  Real const a[16] =
139  {
140  (N != 1 ? (Real)1 : onePlusMu[0]) / ((Real)1 * (Real)3),
141  (N != 2 ? (Real)1 : onePlusMu[1]) / ((Real)2 * (Real)5),
142  (N != 3 ? (Real)1 : onePlusMu[2]) / ((Real)3 * (Real)7),
143  (N != 4 ? (Real)1 : onePlusMu[3]) / ((Real)4 * (Real)9),
144  (N != 5 ? (Real)1 : onePlusMu[4]) / ((Real)5 * (Real)11),
145  (N != 6 ? (Real)1 : onePlusMu[5]) / ((Real)6 * (Real)13),
146  (N != 7 ? (Real)1 : onePlusMu[6]) / ((Real)7 * (Real)15),
147  (N != 8 ? (Real)1 : onePlusMu[7]) / ((Real)8 * (Real)17),
148  (N != 9 ? (Real)1 : onePlusMu[8]) / ((Real)9 * (Real)19),
149  (N != 10 ? (Real)1 : onePlusMu[9]) / ((Real)10 * (Real)21),
150  (N != 11 ? (Real)1 : onePlusMu[10]) / ((Real)11 * (Real)23),
151  (N != 12 ? (Real)1 : onePlusMu[11]) / ((Real)12 * (Real)25),
152  (N != 13 ? (Real)1 : onePlusMu[12]) / ((Real)13 * (Real)27),
153  (N != 14 ? (Real)1 : onePlusMu[13]) / ((Real)14 * (Real)29),
154  (N != 15 ? (Real)1 : onePlusMu[14]) / ((Real)15 * (Real)31),
155  (N != 16 ? (Real)1 : onePlusMu[15]) / ((Real)16 * (Real)33)
156  };
157 
158  Real const b[16] =
159  {
160  (N != 1 ? (Real)1 : onePlusMu[0]) * (Real)1 / (Real)3,
161  (N != 2 ? (Real)1 : onePlusMu[1]) * (Real)2 / (Real)5,
162  (N != 3 ? (Real)1 : onePlusMu[2]) * (Real)3 / (Real)7,
163  (N != 4 ? (Real)1 : onePlusMu[3]) * (Real)4 / (Real)9,
164  (N != 5 ? (Real)1 : onePlusMu[4]) * (Real)5 / (Real)11,
165  (N != 6 ? (Real)1 : onePlusMu[5]) * (Real)6 / (Real)13,
166  (N != 7 ? (Real)1 : onePlusMu[6]) * (Real)7 / (Real)15,
167  (N != 8 ? (Real)1 : onePlusMu[7]) * (Real)8 / (Real)17,
168  (N != 9 ? (Real)1 : onePlusMu[8]) * (Real)9 / (Real)19,
169  (N != 10 ? (Real)1 : onePlusMu[9]) * (Real)10 / (Real)21,
170  (N != 11 ? (Real)1 : onePlusMu[10]) * (Real)11 / (Real)23,
171  (N != 12 ? (Real)1 : onePlusMu[11]) * (Real)12 / (Real)25,
172  (N != 13 ? (Real)1 : onePlusMu[12]) * (Real)13 / (Real)27,
173  (N != 14 ? (Real)1 : onePlusMu[13]) * (Real)14 / (Real)29,
174  (N != 15 ? (Real)1 : onePlusMu[14]) * (Real)15 / (Real)31,
175  (N != 16 ? (Real)1 : onePlusMu[15]) * (Real)16 / (Real)33
176  };
177 
178  Real term0 = (Real)1 - t, term1 = t;
179  Real sqr0 = term0 * term0, sqr1 = term1 * term1;
180  f0 = term0;
181  f1 = term1;
182  for (int i = 0; i < N; ++i)
183  {
184  term0 *= (b[i] - a[i] * sqr0) * y;
185  term1 *= (b[i] - a[i] * sqr1) * y;
186  f0 += term0;
187  f1 += term1;
188  }
189 }
190 
191 
192 }
static void Get(Real t, Real cosA, Real &f0, Real &f1)
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1217
GLdouble GLdouble t
Definition: glext.h:239
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1217
static void GetEstimate(Real t, Real y, Real &f0, Real &f1)
GLint y
Definition: glcorearb.h:98


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:59