1
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2015-2018 Esteban Tovagliari, The appleseedhq Organization
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 //
28
29 #pragma once
30
31 // appleseed.foundation headers.
32 #include "foundation/math/vector.h"
33
34 // Standard headers.
35 #include <cassert>
36
37 namespace foundation
38 {
39
40 //
41 // Dual holds a quantity and optionally its partial derivatives wrt. X and Y.
42 //
43
44 template <typename T>
45 class Dual
46 {
47 public:
48 // Types.
49 typedef T ValueType;
50
51 // Constructors.
52 #if APPLESEED_COMPILER_CXX_DEFAULTED_FUNCTIONS
53 Dual() = default; // leave all components uninitialized
54 #else
Dual()55 Dual() {} // leave all components uninitialized
56 #endif
57
58 explicit Dual(const T& value);
59 Dual(const T& value, const T& dx, const T& dy);
60
61 // Construct a dual from another dual of a different type.
62 template <typename U>
63 explicit Dual(const Dual<U>& rhs);
64
65 // Value.
66 const T& get_value() const;
67
68 // Derivatives.
69 bool has_derivatives() const;
70 const T& get_dx() const;
71 const T& get_dy() const;
72
73 void set_derivatives(const T& dx, const T& dy);
74
75 private:
76 template <typename U>
77 friend class Dual;
78
79 T m_value;
80 T m_dx;
81 T m_dy;
82 bool m_has_derivatives;
83 };
84
85
86 //
87 // Full specializations for scalars and vectors of type float and double.
88 //
89
90 typedef Dual<float> Dual1f;
91 typedef Dual<double> Dual1d;
92
93 typedef Dual<Vector2f> Dual2f;
94 typedef Dual<Vector2d> Dual2d;
95
96 typedef Dual<Vector3f> Dual3f;
97 typedef Dual<Vector3d> Dual3d;
98
99
100 //
101 // Dual class implementation.
102 //
103
104 template <typename T>
Dual(const T & value)105 inline Dual<T>::Dual(const T& value)
106 : m_value(value)
107 , m_has_derivatives(false)
108 {
109 }
110
111 template <typename T>
Dual(const T & value,const T & dx,const T & dy)112 inline Dual<T>::Dual(const T& value, const T& dx, const T& dy)
113 : m_value(value)
114 , m_dx(dx)
115 , m_dy(dy)
116 , m_has_derivatives(true)
117 {
118 }
119
120 template <typename T>
121 template <typename U>
Dual(const Dual<U> & rhs)122 inline Dual<T>::Dual(const Dual<U>& rhs)
123 : m_value(rhs.m_value)
124 , m_dx(rhs.m_dx)
125 , m_dy(rhs.m_dy)
126 , m_has_derivatives(rhs.m_has_derivatives)
127 {
128 }
129
130 template <typename T>
get_value()131 inline const T& Dual<T>::get_value() const
132 {
133 return m_value;
134 }
135
136 template <typename T>
has_derivatives()137 inline bool Dual<T>::has_derivatives() const
138 {
139 return m_has_derivatives;
140 }
141
142 template <typename T>
get_dx()143 inline const T& Dual<T>::get_dx() const
144 {
145 assert(m_has_derivatives);
146 return m_dx;
147 }
148
149 template <typename T>
get_dy()150 inline const T& Dual<T>::get_dy() const
151 {
152 assert(m_has_derivatives);
153 return m_dy;
154 }
155
156 template <typename T>
set_derivatives(const T & dx,const T & dy)157 inline void Dual<T>::set_derivatives(const T& dx, const T& dy)
158 {
159 m_dx = dx;
160 m_dy = dy;
161 m_has_derivatives = true;
162 }
163
164 } // namespace foundation
165