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