HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
math.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_GF_MATH_H
8 #define PXR_BASE_GF_MATH_H
9 
10 /// \file gf/math.h
11 /// \ingroup group_gf_BasicMath
12 /// Assorted mathematical utility functions.
13 
14 #include "pxr/pxr.h"
15 #include "pxr/base/arch/math.h"
16 #include "pxr/base/gf/api.h"
17 #include "pxr/base/gf/traits.h"
18 
19 #include <type_traits>
20 
22 
23 /// Returns true if \p a and \p b are with \p epsilon of each other.
24 /// \ingroup group_gf_BasicMath
25 inline bool GfIsClose(double a, double b, double epsilon) {
26  return fabs(a-b) < epsilon;
27 }
28 
29 /// Converts an angle in radians to degrees.
30 /// \ingroup group_gf_BasicMath
31 inline double GfRadiansToDegrees(double radians) {
32  return radians * (180.0 / M_PI);
33 }
34 
35 /// Converts an angle in degrees to radians.
36 /// \ingroup group_gf_BasicMath
37 inline double GfDegreesToRadians(double degrees) {
38  return degrees * (M_PI / 180.0);
39 }
40 
41 /// Smooth step function using a cubic hermite blend.
42 /// \ingroup group_gf_BasicMath
43 ///
44 /// Returns 0 if \p val <= \p min, and 1 if \p val >= \p max.
45 /// As \p val varies between \p min and \p max, the return value smoothly
46 /// varies from 0 to 1 using a cubic hermite blend, with given slopes at the
47 /// min and max points. The slopes are in the space that min and max are in.
48 GF_API
49 double GfSmoothStep(double min, double max, double val,
50  double slope0 = 0.0, double slope1 = 0.0);
51 
52 /// Smooth Step with independently controllable shoulders
53 /// \ingroup group_gf_BasicMath
54 ///
55 /// Based on an idea and different implementation by Rob Cook. See his
56 /// notes attached at the end.
57 ///
58 /// I (whorfin) extended this to have independently controllable shoulders at
59 /// either end, and to specify shoulders directly in the domain of the curve.
60 /// Rob's derivation frankly confused me, so I proceeded slightly differently.
61 /// This derivation has more degrees of freedom but is the same order, so some
62 /// tricks must be done.
63 ///
64 /// Summary: This function is similar to "smoothstep" except that instead of
65 /// using a Hermite curve, the interpolation is done with a linear ramp with
66 /// smooth shoulders (i.e., C1 = continuous first derivatives).
67 ///
68 /// Conceptually, it's a line with variable C1 zero-slope junctures.
69 ///
70 /// Additionally, w0 + w1 <= 1. Otherwise, the curves will take up
71 /// more space than is available, and "that would be bad".
72 ///
73 /// A value of 0 for w0 and w1 gives a pure linear ramp.
74 /// A reasonable value for a symmetric smooth ramp is .2 for w0 and w1.
75 /// this means that the middle 60% of the ramp is linear, and the left
76 /// 20% and right 20% are the transition into and out of the linear ramp.
77 ///
78 /// The ramp looks like this:
79 /// <pre>
80 /// smooth ********** <-result = 1
81 /// ***|
82 /// ** |
83 /// * | |
84 /// linear * | |
85 /// * | |
86 /// * | |
87 /// smooth ** | tmax = end of ramp
88 /// *** | |
89 /// result=0 -> ******* | tmax - w1*(tmax-tmin) = end of linear region
90 /// | |
91 /// | tmin + w0*(tmax-tmin) = start of linear region
92 /// |
93 /// tmin = start of ramp
94 /// </pre>
95 /// Derivation:
96 ///
97 /// We're going to splice parabolas onto both ends for the "0 slope smooth"
98 /// connectors. So we therefore constrain the parabolic sections to have
99 /// a given width and given slope (the slope of the connecting line segment)
100 /// at the "w" edge.
101 ///
102 /// We'll first derive the equations for the parabolic splicing segment,
103 /// expressed at the origin (but generalizable by flipping).
104 ///
105 /// Given:
106 /// <pre>
107 /// f(t) = a t� + b t + c
108 /// f(0) = 0
109 /// f'(0) = 0
110 /// f(w) = y At the "w" edge of the shoulder, value is y
111 /// f'(w) = s ...what is the slope there? s...
112 ///
113 /// -->
114 /// c = 0
115 /// b = 0
116 /// a = � s/w
117 /// y = � w s
118 /// -->
119 /// g(t,w,s) = � s t� / w # Our parabolic segment
120 /// </pre>
121 ///
122 /// Now, in our desired composite curve, the slope is the same at
123 /// both endpoints (since they're connected by a line).
124 /// This slope is (1-y0-y1)/(1-w0-w1) [from simple geometry].
125 ///
126 /// More formally, let's express the constraints
127 /// Given:
128 /// <pre>
129 /// y(w,s) = w s /2
130 /// s = ( 1 - y(w0, s) - y(w1, s) ) / (1 - w0 - w1)
131 ///
132 /// -->
133 /// s(w0,w1) = 2 / (2 - w0 - w1)
134 /// </pre>
135 ///
136 /// So now we're done; we splice these two together and connect
137 /// with a line.
138 ///
139 /// The domain and range of this function is [0,1]
140 /// <pre>
141 /// f(t, w0, w1) =
142 /// g(t, w0, s(w0,w1)) t<w0
143 ///
144 /// 1-g(1-t, w1, s(w0,w1)) t>1-w1
145 ///
146 /// s(w0,w1) t - y(w0, s(w0,w1)) w0 <= t <= 1-w1
147 /// </pre>
148 ///
149 /// Expanding and collecting terms gives us the result expressed in the
150 /// code below. We also generalize to tmin/tmax form, in keeping with
151 /// smoothstep. This simply involves reranging to [0,1] on input.
152 ///
153 /// @param tmin where the ramp starts
154 /// @param tmax where the ramp ends (must be > tmin)
155 /// @param t location to evaluate in this call
156 /// @param w0 size of the first smooth section as a fraction of
157 /// the size of the ramp (tmax-tmin). This value must
158 /// be in the range 0-1.
159 /// @param w1 size of the second smooth section as a fraction of
160 /// the size of the ramp (tmax-tmin). This value must
161 /// be in the range 0-1.
162 GF_API
163 double GfSmoothRamp(double tmin, double tmax, double t, double w0, double w1);
164 
165 /// Returns the inner product of \c x with itself: specifically, \c x*x.
166 /// Defined for \c int, \c float, \c double, and all \c GfVec types.
167 /// \ingroup group_gf_BasicMath
168 template <class T>
169 inline double GfSqr(const T& x) {
170  return x * x;
171 }
172 
173 /// Return the signum of \p v (i.e. -1, 0, or 1).
174 ///
175 /// The type \c T must implement the < and > operators; the function returns
176 /// zero only if value neither positive, nor negative.
177 ///
178 /// \ingroup group_gf_BasicMath
179 template <typename T>
180 inline T
181 GfSgn(T v) {
182  return (v < 0) ? -1 : ((v > 0) ? 1 : 0);
183 }
184 
185 /// Return sqrt(\p f).
186 /// \ingroup group_gf_BasicMath
187 inline double GfSqrt(double f) { return std::sqrt(f); }
188 /// Return sqrt(\p f).
189 /// \ingroup group_gf_BasicMath
190 inline float GfSqrt(float f) { return std::sqrt(f); }
191 
192 /// Return exp(\p f).
193 /// \ingroup group_gf_BasicMath
194 inline double GfExp(double f) { return std::exp(f); }
195 /// Return exp(\p f).
196 /// \ingroup group_gf_BasicMath
197 inline float GfExp(float f) { return std::exp(f); }
198 
199 /// Return log(\p f).
200 /// \ingroup group_gf_BasicMath
201 inline double GfLog(double f) { return std::log(f); }
202 /// Return log(\p f).
203 /// \ingroup group_gf_BasicMath
204 inline float GfLog(float f) { return std::log(f); }
205 
206 /// Return floor(\p f).
207 /// \ingroup group_gf_BasicMath
208 inline double GfFloor(double f) { return std::floor(f); }
209 /// Return floor(\p f).
210 /// \ingroup group_gf_BasicMath
211 inline float GfFloor(float f) { return std::floor(f); }
212 
213 /// Return ceil(\p f).
214 /// \ingroup group_gf_BasicMath
215 inline double GfCeil(double f) { return std::ceil(f); }
216 /// Return ceil(\p f).
217 /// \ingroup group_gf_BasicMath
218 inline float GfCeil(float f) { return std::ceil(f); }
219 
220 /// Return abs(\p f).
221 /// \ingroup group_gf_BasicMath
222 inline double GfAbs(double f) { return std::fabs(f); }
223 /// Return abs(\p f).
224 /// \ingroup group_gf_BasicMath
225 inline float GfAbs(float f) { return std::fabs(f); }
226 
227 /// Return round(\p f).
228 /// \ingroup group_gf_BasicMath
229 inline double GfRound(double f) { return std::rint(f); }
230 /// Return round(\p f).
231 /// \ingroup group_gf_BasicMath
232 inline float GfRound(float f) { return std::rint(f); }
233 
234 /// Return pow(\p f, \p p).
235 /// \ingroup group_gf_BasicMath
236 inline double GfPow(double f, double p) { return std::pow(f, p); }
237 /// Return pow(\p f, \p p).
238 /// \ingroup group_gf_BasicMath
239 inline float GfPow(float f, float p) { return std::pow(f, p); }
240 
241 /// Return sin(\p v).
242 /// \ingroup group_gf_BasicMath
243 inline double GfSin(double v) { return std::sin(v); }
244 /// Return sin(\p v).
245 /// \ingroup group_gf_BasicMath
246 inline float GfSin(float v) { return std::sin(v); }
247 /// Return cos(\p v).
248 /// \ingroup group_gf_BasicMath
249 inline double GfCos(double v) { return std::cos(v); }
250 /// Return cos(\p v).
251 /// \ingroup group_gf_BasicMath
252 inline float GfCos(float v) { return std::cos(v); }
253 /// Return sin(\p v) in \p s and cos(\p v) in \p c.
254 /// \ingroup group_gf_BasicMath
255 inline void GfSinCos(double v, double *s, double *c) { ArchSinCos(v, s, c); }
256 /// Return sin(\p v) in \p s and cos(\p v) in \p c.
257 /// \ingroup group_gf_BasicMath
258 inline void GfSinCos(float v, float *s, float *c) { ArchSinCosf(v, s, c); }
259 
260 /// Return the resulting of clamping \p value to lie between
261 /// \p min and \p max. This function is also defined for GfVecs.
262 /// \ingroup group_gf_BasicMath
263 inline double GfClamp(double value, double min, double max) {
264  if (value < min) return min;
265  if (value > max) return max;
266  return value;
267 }
268 
269 /// \overload
270 /// \ingroup group_gf_BasicMath
271 inline float GfClamp(float value, float min, float max) {
272  if (value < min) return min;
273  if (value > max) return max;
274  return value;
275 }
276 
277 /// The mod function with "correct" behaviour for negative numbers.
278 ///
279 /// If \p a = \c n \p b for some integer \p n, zero is returned.
280 /// Otherwise, for positive \p a, the value returned is \c fmod(a,b),
281 /// and for negative \p a, the value returned is \c fmod(a,b)+b.
282 ///
283 /// \ingroup group_gf_BasicMath
284 GF_API
285 double GfMod(double a, double b);
286 /// \overload
287 // \ingroup group_gf_BasicMath
288 GF_API
289 float GfMod(float a, float b);
290 
291 /// Linear interpolation function.
292 ///
293 /// For any type that supports multiplication by a scalar and binary addition, returns
294 /// \code
295 /// (1-alpha) * a + alpha * b
296 /// \endcode
297 ///
298 /// \ingroup group_gf_BasicMath
299 template <class T>
300 inline T GfLerp( double alpha, const T& a, const T& b) {
301  return (1-alpha)* a + alpha * b;
302 }
303 
304 /// Returns the smallest of the given \c values.
305 /// \ingroup group_gf_BasicMath
306 template <class T>
307 inline T GfMin(T a1, T a2) {
308  return (a1 < a2 ? a1 : a2);
309 }
310 template <class T>
311 inline T GfMin(T a1, T a2, T a3) {
312  return GfMin(GfMin(a1, a2), a3);
313 }
314 template <class T>
315 inline T GfMin(T a1, T a2, T a3, T a4) {
316  return GfMin(GfMin(a1, a2, a3), a4);
317 }
318 template <class T>
319 inline T GfMin(T a1, T a2, T a3, T a4, T a5) {
320  return GfMin(GfMin(a1, a2, a3, a4), a5);
321 }
322 
323 /// Returns the largest of the given \c values.
324 /// \ingroup group_gf_BasicMath
325 template <class T>
326 inline T GfMax(T a1, T a2) {
327  return (a1 < a2 ? a2 : a1);
328 }
329 template <class T>
330 inline T GfMax(T a1, T a2, T a3) {
331  return GfMax(GfMax(a1, a2), a3);
332 }
333 template <class T>
334 inline T GfMax(T a1, T a2, T a3, T a4) {
335  return GfMax(GfMax(a1, a2, a3), a4);
336 }
337 template <class T>
338 inline T GfMax(T a1, T a2, T a3, T a4, T a5) {
339  return GfMax(GfMax(a1, a2, a3, a4), a5);
340 }
341 
342 /// Returns the dot (inner) product of two vectors.
343 /// For scalar types, this is just the regular product.
344 /// \ingroup group_gf_BasicMath
345 template <typename Left, typename Right,
348 inline decltype(std::declval<Left>() * std::declval<Right>())
350  return left * right;
351 }
352 
353 /// Returns component-wise multiplication of vectors.
354 /// For scalar types, this is just the regular product.
355 /// \ingroup group_gf_BasicMath
356 template <typename Left, typename Right,
359 inline decltype(std::declval<Left>() * std::declval<Right>())
361  return left * right;
362 }
363 
364 /// Returns component-wise quotient of vectors.
365 /// For scalar types, this is just the regular quotient.
366 /// \ingroup group_gf_BasicMath
367 template <typename Left, typename Right,
369  GfIsArithmetic<Right>::value, int> = 0>
370 inline decltype(std::declval<Left>() / std::declval<Right>())
372  return left / right;
373 }
374 
375 
377 
378 #endif // PXR_BASE_GF_MATH_H
SYS_API double cos(double x)
decltype(std::declval< Left >()*std::declval< Right >()) GfCompMult(Left left, Right right)
Definition: math.h:360
#define M_PI
Definition: math.h:24
double GfSqrt(double f)
Definition: math.h:187
double GfClamp(double value, double min, double max)
Definition: math.h:263
IMATH_HOSTDEVICE constexpr int floor(T x) IMATH_NOEXCEPT
Definition: ImathFun.h:112
GLint left
Definition: glcorearb.h:2005
const GLdouble * v
Definition: glcorearb.h:837
GLsizei const GLfloat * value
Definition: glcorearb.h:824
vfloat4 sqrt(const vfloat4 &a)
Definition: simd.h:7694
GLdouble right
Definition: glad.h:2817
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
GF_API double GfSmoothStep(double min, double max, double val, double slope0=0.0, double slope1=0.0)
GLdouble s
Definition: glad.h:3009
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
T GfSgn(T v)
Definition: math.h:181
void GfSinCos(double v, double *s, double *c)
Definition: math.h:255
T GfLerp(double alpha, const T &a, const T &b)
Definition: math.h:300
double GfPow(double f, double p)
Definition: math.h:236
double GfAbs(double f)
Definition: math.h:222
T GfMin(T a1, T a2)
Definition: math.h:307
double GfExp(double f)
Definition: math.h:194
double GfRound(double f)
Definition: math.h:229
ImageBuf OIIO_API pow(const ImageBuf &A, cspan< float > B, ROI roi={}, int nthreads=0)
GLfloat f
Definition: glcorearb.h:1926
GF_API double GfSmoothRamp(double tmin, double tmax, double t, double w0, double w1)
T GfMax(T a1, T a2)
Definition: math.h:326
double GfCeil(double f)
Definition: math.h:215
double GfSin(double v)
Definition: math.h:243
GLfloat GLfloat GLfloat alpha
Definition: glcorearb.h:112
double GfSqr(const T &x)
Definition: math.h:169
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
PXR_NAMESPACE_OPEN_SCOPE bool GfIsClose(double a, double b, double epsilon)
Definition: math.h:25
GLint GLenum GLint x
Definition: glcorearb.h:409
double GfCos(double v)
Definition: math.h:249
double GfDegreesToRadians(double degrees)
Definition: math.h:37
GLdouble t
Definition: glad.h:2397
double GfFloor(double f)
Definition: math.h:208
double GfLog(double f)
Definition: math.h:201
IMATH_HOSTDEVICE constexpr int ceil(T x) IMATH_NOEXCEPT
Definition: ImathFun.h:119
GF_API double GfMod(double a, double b)
decltype(std::declval< Left >()/std::declval< Right >()) GfCompDiv(Left left, Right right)
Definition: math.h:371
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
decltype(std::declval< Left >()*std::declval< Right >()) GfDot(Left left, Right right)
Definition: math.h:349
GLuint GLfloat * val
Definition: glcorearb.h:1608
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
OIIO_FORCEINLINE T log(const T &v)
Definition: simd.h:7905
vint4 rint(const vfloat4 &a)
Definition: simd.h:7669
OIIO_FORCEINLINE OIIO_HOSTDEVICE T radians(T deg)
Convert degrees to radians.
Definition: fmath.h:677
double GfRadiansToDegrees(double radians)
Definition: math.h:31
SYS_API double sin(double x)
#define GF_API
Definition: api.h:23
OIIO_FORCEINLINE OIIO_HOSTDEVICE T degrees(T rad)
Convert radians to degrees.
Definition: fmath.h:681