1 | |
2 | // |
3 | // This source file is part of appleseed. |
4 | // Visit http://appleseedhq.net/ for additional information and resources. |
5 | // |
6 | // This software is released under the MIT license. |
7 | // |
8 | // Copyright (c) 2012-2013 Esteban Tovagliari, Jupiter Jazz Limited |
9 | // Copyright (c) 2014-2017 Esteban Tovagliari, The appleseedhq Organization |
10 | // |
11 | // Permission is hereby granted, free of charge, to any person obtaining a copy |
12 | // of this software and associated documentation files (the "Software"), to deal |
13 | // in the Software without restriction, including without limitation the rights |
14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
15 | // copies of the Software, and to permit persons to whom the Software is |
16 | // furnished to do so, subject to the following conditions: |
17 | // |
18 | // The above copyright notice and this permission notice shall be included in |
19 | // all copies or substantial portions of the Software. |
20 | // |
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
27 | // THE SOFTWARE. |
28 | // |
29 | |
30 | #ifndef APPLESEED_PYTHON_UNALIGNEDMATRIX44_H |
31 | #define APPLESEED_PYTHON_UNALIGNEDMATRIX44_H |
32 | |
33 | // appleseed.python headers. |
34 | #include "pyseed.h" // has to be first, to avoid redefinition warnings |
35 | |
36 | // appleseed.foundation headers. |
37 | #include "foundation/math/matrix.h" |
38 | #include "foundation/math/quaternion.h" |
39 | #include "foundation/math/vector.h" |
40 | #include "foundation/utility/iostreamop.h" |
41 | |
42 | // Standard headers. |
43 | #include <cstddef> |
44 | |
45 | namespace foundation |
46 | { |
47 | |
48 | template <typename T> |
49 | class UnalignedMatrix44 |
50 | { |
51 | public: |
52 | static UnalignedMatrix44<T> identity() |
53 | { |
54 | return UnalignedMatrix44<T>(Matrix<T, 4, 4>::identity()); |
55 | } |
56 | |
57 | static UnalignedMatrix44<T> make_translation(const Vector<T, 3>& v) |
58 | { |
59 | return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_translation(v)); |
60 | } |
61 | |
62 | static UnalignedMatrix44<T> make_scaling(const Vector<T, 3>& s) |
63 | { |
64 | return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_scaling(s)); |
65 | } |
66 | |
67 | static UnalignedMatrix44<T> make_rotation_x(const T angle) |
68 | { |
69 | return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation_x(angle)); |
70 | } |
71 | |
72 | static UnalignedMatrix44<T> make_rotation_y(const T angle) |
73 | { |
74 | return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation_y(angle)); |
75 | } |
76 | |
77 | static UnalignedMatrix44<T> make_rotation_z(const T angle) |
78 | { |
79 | return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation_z(angle)); |
80 | } |
81 | |
82 | static UnalignedMatrix44<T> make_rotation(const T yaw, const T pitch, const T roll) |
83 | { |
84 | return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation(yaw, pitch, roll)); |
85 | } |
86 | |
87 | static UnalignedMatrix44<T> make_rotation(const Vector<T, 3>& axis, const T angle) |
88 | { |
89 | return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation(axis, angle)); |
90 | } |
91 | |
92 | static UnalignedMatrix44<T> make_rotation(const Quaternion<T>& q) |
93 | { |
94 | return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation(q)); |
95 | } |
96 | |
97 | static UnalignedMatrix44<T> make_lookat(const Vector<T, 3>& origin, const Vector<T, 3>& target, const Vector<T, 3>& up) |
98 | { |
99 | return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_lookat(origin, target, up)); |
100 | } |
101 | |
102 | UnalignedMatrix44() {} |
103 | |
104 | explicit UnalignedMatrix44(const T x) |
105 | { |
106 | for (size_t i = 0; i < 16; ++i) |
107 | m_data[i] = x; |
108 | } |
109 | |
110 | template <class U> |
111 | explicit UnalignedMatrix44(const Matrix<U, 4, 4>& m) |
112 | { |
113 | for (size_t i = 0; i < 16; ++i) |
114 | m_data[i] = static_cast<T>(m[i]); |
115 | } |
116 | |
117 | template <class U> |
118 | explicit UnalignedMatrix44(const UnalignedMatrix44<U>& m) |
119 | { |
120 | for (size_t i = 0; i < 16; ++i) |
121 | m_data[i] = static_cast<T>(m[i]); |
122 | } |
123 | |
124 | #ifdef APPLESEED_ENABLE_IMATH_INTEROP |
125 | |
126 | UnalignedMatrix44(const Imath::Matrix44<T>& rhs) |
127 | { |
128 | T *p = m_data; |
129 | |
130 | for (int i = 0; i < 3; ++i) |
131 | { |
132 | for (int j = 0; j < 3; ++j) |
133 | *p++ = rhs[j][i]; |
134 | } |
135 | } |
136 | |
137 | operator Imath::Matrix44<T>() const |
138 | { |
139 | return as_foundation_matrix(); |
140 | } |
141 | |
142 | #endif |
143 | |
144 | template <class U> |
145 | UnalignedMatrix44<T>& operator=(const UnalignedMatrix44<U>& m) |
146 | { |
147 | for (size_t i = 0; i < 16; ++i) |
148 | m_data[i] = static_cast<T>(m[i]); |
149 | |
150 | return *this; |
151 | } |
152 | |
153 | Matrix<T, 4, 4> as_foundation_matrix() const |
154 | { |
155 | return Matrix<T, 4, 4>(m_data); |
156 | } |
157 | |
158 | T operator[](const size_t index) const |
159 | { |
160 | return m_data[index]; |
161 | } |
162 | |
163 | T& operator[](const size_t index) |
164 | { |
165 | return m_data[index]; |
166 | } |
167 | |
168 | T operator()(const size_t row, const size_t col) const |
169 | { |
170 | return m_data[row * 4 + col]; |
171 | } |
172 | |
173 | T& operator()(const size_t row, const size_t col) |
174 | { |
175 | return m_data[row * 4 + col]; |
176 | } |
177 | |
178 | Matrix<T, 3, 3> () const |
179 | { |
180 | return as_foundation_matrix().extract_matrix3(); |
181 | } |
182 | |
183 | Vector<T, 3> () const |
184 | { |
185 | return as_foundation_matrix().extract_translation(); |
186 | } |
187 | |
188 | Vector<T, 3> transform_vector(const Vector<T, 3>& v) const |
189 | { |
190 | Vector<T, 3> res; |
191 | |
192 | res[0] = m_data[0] * v[0] + m_data[1] * v[1] + m_data[ 2] * v[2]; |
193 | res[1] = m_data[4] * v[0] + m_data[5] * v[1] + m_data[ 6] * v[2]; |
194 | res[2] = m_data[8] * v[0] + m_data[9] * v[1] + m_data[10] * v[2]; |
195 | |
196 | return res; |
197 | } |
198 | |
199 | Vector<T, 3> transform_normal(const Vector<T, 3>& n) const |
200 | { |
201 | Vector<T, 3> res; |
202 | |
203 | res.x = m_data[ 0] * n.x + |
204 | m_data[ 4] * n.y + |
205 | m_data[ 8] * n.z; |
206 | |
207 | res.y = m_data[ 1] * n.x + |
208 | m_data[ 5] * n.y + |
209 | m_data[ 9] * n.z; |
210 | |
211 | res.z = m_data[ 2] * n.x + |
212 | m_data[ 6] * n.y + |
213 | m_data[10] * n.z; |
214 | |
215 | return res; |
216 | } |
217 | |
218 | Vector<T, 3> transform_point(const Vector<T, 3>& p) const |
219 | { |
220 | Vector<T, 3> res; |
221 | |
222 | res.x = m_data[ 0] * p.x + |
223 | m_data[ 1] * p.y + |
224 | m_data[ 2] * p.z + |
225 | m_data[ 3]; |
226 | |
227 | res.y = m_data[ 4] * p.x + |
228 | m_data[ 5] * p.y + |
229 | m_data[ 6] * p.z + |
230 | m_data[ 7]; |
231 | |
232 | res.z = m_data[ 8] * p.x + |
233 | m_data[ 9] * p.y + |
234 | m_data[10] * p.z + |
235 | m_data[11]; |
236 | |
237 | const T w = m_data[12] * p.x + |
238 | m_data[13] * p.y + |
239 | m_data[14] * p.z + |
240 | m_data[15]; |
241 | |
242 | if (w == T(0.0)) |
243 | { |
244 | PyErr_SetString(PyExc_RuntimeError, "Zero homogeneous coordinate in appleseed.Matrix44.transform_point" ); |
245 | boost::python::throw_error_already_set(); |
246 | return res; |
247 | } |
248 | |
249 | res /= w; |
250 | |
251 | return res; |
252 | } |
253 | |
254 | private: |
255 | T m_data[16]; |
256 | }; |
257 | |
258 | template <typename T> |
259 | UnalignedMatrix44<T> operator*(const UnalignedMatrix44<T>& a, const UnalignedMatrix44<T>& b) |
260 | { |
261 | return UnalignedMatrix44<T>(a.as_foundation_matrix() * b.as_foundation_matrix()); |
262 | } |
263 | |
264 | template <typename T> |
265 | Vector<T, 4> operator*(const UnalignedMatrix44<T>& a, const Vector<T, 4>& v) |
266 | { |
267 | return a.as_foundation_matrix() * v; |
268 | } |
269 | |
270 | template <typename T> |
271 | UnalignedMatrix44<T> invert_matrix(const UnalignedMatrix44<T>& mat) |
272 | { |
273 | try |
274 | { |
275 | return UnalignedMatrix44<T>(inverse(mat.as_foundation_matrix())); |
276 | } |
277 | catch (ExceptionSingularMatrix&) |
278 | { |
279 | PyErr_SetString(PyExc_RuntimeError, "Singular matrix in appleseed.Matrix.inverse" ); |
280 | boost::python::throw_error_already_set(); |
281 | } |
282 | |
283 | return UnalignedMatrix44<T>(); |
284 | } |
285 | |
286 | template <typename T> |
287 | std::ostream& operator<<(std::ostream& s, const UnalignedMatrix44<T>& matrix) |
288 | { |
289 | return s << matrix.as_foundation_matrix(); |
290 | } |
291 | |
292 | } // namespace foundation |
293 | |
294 | #endif // !APPLESEED_PYTHON_UNALIGNEDMATRIX44_H |
295 | |