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 | // appleseed.python headers. |
31 | #include "pyseed.h" // has to be first, to avoid redefinition warnings |
32 | |
33 | // appleseed.foundation headers. |
34 | #include "foundation/math/vector.h" |
35 | #include "foundation/utility/iostreamop.h" |
36 | |
37 | // Standard headers. |
38 | #include <cstddef> |
39 | #include <memory> |
40 | |
41 | namespace bpy = boost::python; |
42 | using namespace foundation; |
43 | using namespace std; |
44 | |
45 | namespace |
46 | { |
47 | template <typename T, size_t N> |
48 | Vector<T, N>* construct_vec_from_list(bpy::list l) |
49 | { |
50 | if (bpy::len(l) != N) |
51 | { |
52 | PyErr_SetString(PyExc_RuntimeError, "Invalid list length given to appleseed.Vector" ); |
53 | bpy::throw_error_already_set(); |
54 | } |
55 | |
56 | auto_ptr<Vector<T, N> > r(new Vector<T, N>()); |
57 | |
58 | for (size_t i = 0; i < N; ++i) |
59 | { |
60 | bpy::extract<T> ex(l[i]); |
61 | if (!ex.check()) |
62 | { |
63 | PyErr_SetString(PyExc_TypeError, "Incompatible type." ); |
64 | bpy::throw_error_already_set(); |
65 | } |
66 | |
67 | (*r)[i] = ex(); |
68 | } |
69 | |
70 | return r.release(); |
71 | } |
72 | |
73 | template <typename T, size_t N> |
74 | struct VectorHelper {}; |
75 | |
76 | template <typename T> |
77 | struct VectorHelper<T, 2> |
78 | { |
79 | typedef Vector<T, 2> VectorType; |
80 | |
81 | static VectorType* construct(const T x, const T y) |
82 | { |
83 | return new VectorType(x, y); |
84 | } |
85 | |
86 | static T norm(const VectorType& v) |
87 | { |
88 | return foundation::norm(v); |
89 | } |
90 | |
91 | static VectorType normalize(const VectorType& v) |
92 | { |
93 | return foundation::normalize(v); |
94 | } |
95 | |
96 | static T dot(const VectorType& lhs, const VectorType& rhs) |
97 | { |
98 | return foundation::dot(lhs, rhs); |
99 | } |
100 | }; |
101 | |
102 | template <typename T> |
103 | struct VectorHelper<T, 3> |
104 | { |
105 | typedef Vector<T, 3> VectorType; |
106 | |
107 | static VectorType* construct(const T x, const T y, const T z) |
108 | { |
109 | return new VectorType(x, y, z); |
110 | } |
111 | |
112 | static T norm(const VectorType& v) |
113 | { |
114 | return foundation::norm(v); |
115 | } |
116 | |
117 | static VectorType normalize(const VectorType& v) |
118 | { |
119 | return foundation::normalize(v); |
120 | } |
121 | |
122 | static T dot(const VectorType& lhs, const VectorType& rhs) |
123 | { |
124 | return foundation::dot(lhs, rhs); |
125 | } |
126 | |
127 | static VectorType cross(const VectorType& lhs, const VectorType& rhs) |
128 | { |
129 | return foundation::cross(lhs, rhs); |
130 | } |
131 | }; |
132 | |
133 | template <typename T> |
134 | struct VectorHelper<T, 4> |
135 | { |
136 | typedef Vector<T, 4> VectorType; |
137 | |
138 | static VectorType* construct(const T x, const T y, const T z, const T w) |
139 | { |
140 | return new VectorType(x, y, z, w); |
141 | } |
142 | |
143 | static T norm(const VectorType& v) |
144 | { |
145 | return foundation::norm(v); |
146 | } |
147 | |
148 | static VectorType normalize(const VectorType& v) |
149 | { |
150 | return foundation::normalize(v); |
151 | } |
152 | |
153 | static T dot(const VectorType& lhs, const VectorType& rhs) |
154 | { |
155 | return foundation::dot(lhs, rhs); |
156 | } |
157 | }; |
158 | |
159 | template <typename T, size_t N> |
160 | struct vector_indexer |
161 | { |
162 | static T get(const Vector<T, N>& x, int i) |
163 | { |
164 | if (i < 0) |
165 | i = N + i; |
166 | |
167 | if (i >= 0 && i < N) |
168 | return x[i]; |
169 | else |
170 | { |
171 | PyErr_SetString(PyExc_IndexError, "Invalid index in appleseed.Vector" ); |
172 | boost::python::throw_error_already_set(); |
173 | } |
174 | |
175 | return T(); |
176 | } |
177 | |
178 | static void set(Vector<T, N>& x, int i, const T& v) |
179 | { |
180 | if (i < 0) |
181 | i = N + i; |
182 | |
183 | if (i >= 0 && i < N) |
184 | x[i] = v; |
185 | else |
186 | { |
187 | PyErr_SetString(PyExc_IndexError, "Invalid index in appleseed.Vector" ); |
188 | boost::python::throw_error_already_set(); |
189 | } |
190 | } |
191 | }; |
192 | |
193 | template <typename T, size_t N> |
194 | void do_bind_vector(const char* class_name) |
195 | { |
196 | bpy::class_<Vector<T, N> >(class_name) |
197 | .def(bpy::init<>()) |
198 | .def(bpy::init<T>()) |
199 | .def("__init__" , bpy::make_constructor(&VectorHelper<T, N>::construct)) |
200 | .def("__init__" , bpy::make_constructor(&construct_vec_from_list<T, N>)) |
201 | |
202 | // operator[] |
203 | .def("__getitem__" , &vector_indexer<T, N>::get) |
204 | .def("__setitem__" , &vector_indexer<T, N>::set) |
205 | |
206 | // Operators. |
207 | .def(bpy::self += bpy::self) |
208 | .def(bpy::self + bpy::self) |
209 | .def(bpy::self -= bpy::self) |
210 | .def(bpy::self - bpy::self) |
211 | |
212 | .def(bpy::self *= T()) |
213 | .def(bpy::self * T()) |
214 | .def(T() * bpy::self) |
215 | |
216 | .def(bpy::self /= T()) |
217 | .def(bpy::self / bpy::self) |
218 | .def(bpy::self / T()) |
219 | .def(-bpy::self) |
220 | .def(bpy::self == bpy::self) |
221 | .def(bpy::self != bpy::self) |
222 | |
223 | // Because of a bug in Boost.Python, this needs the extra self_ns qualification. |
224 | .def(bpy::self_ns::str(bpy::self)) |
225 | .def(bpy::self_ns::repr(bpy::self)); |
226 | |
227 | bpy::def("dot" , &VectorHelper<T, N>::dot); |
228 | } |
229 | } |
230 | |
231 | void bind_vector() |
232 | { |
233 | do_bind_vector<int, 2>("Vector2i" ); |
234 | do_bind_vector<float, 2>("Vector2f" ); |
235 | do_bind_vector<double, 2>("Vector2d" ); |
236 | |
237 | do_bind_vector<int, 3>("Vector3i" ); |
238 | do_bind_vector<float, 3>("Vector3f" ); |
239 | do_bind_vector<double, 3>("Vector3d" ); |
240 | |
241 | do_bind_vector<int, 4>("Vector4i" ); |
242 | do_bind_vector<float, 4>("Vector4f" ); |
243 | do_bind_vector<double, 4>("Vector4d" ); |
244 | |
245 | bpy::def("norm" , &VectorHelper<float, 2>::norm); |
246 | bpy::def("norm" , &VectorHelper<double, 2>::norm); |
247 | bpy::def("norm" , &VectorHelper<float, 3>::norm); |
248 | bpy::def("norm" , &VectorHelper<double, 3>::norm); |
249 | bpy::def("norm" , &VectorHelper<float, 4>::norm); |
250 | bpy::def("norm" , &VectorHelper<double, 4>::norm); |
251 | |
252 | bpy::def("normalize" , &VectorHelper<float, 2>::normalize); |
253 | bpy::def("normalize" , &VectorHelper<double, 2>::normalize); |
254 | bpy::def("normalize" , &VectorHelper<float, 3>::normalize); |
255 | bpy::def("normalize" , &VectorHelper<double, 3>::normalize); |
256 | bpy::def("normalize" , &VectorHelper<float, 4>::normalize); |
257 | bpy::def("normalize" , &VectorHelper<double, 4>::normalize); |
258 | |
259 | bpy::def("cross" , &VectorHelper<float, 3>::cross); |
260 | bpy::def("cross" , &VectorHelper<double, 3>::cross); |
261 | |
262 | #ifdef APPLESEED_ENABLE_IMATH_INTEROP |
263 | bpy::implicitly_convertible<Vector2i, Imath::V2i>(); |
264 | bpy::implicitly_convertible<Imath::V2i, Vector2i>(); |
265 | |
266 | bpy::implicitly_convertible<Vector2f, Imath::V2f>(); |
267 | bpy::implicitly_convertible<Imath::V2f, Vector2f>(); |
268 | |
269 | bpy::implicitly_convertible<Vector2d, Imath::V2d>(); |
270 | bpy::implicitly_convertible<Imath::V2d, Vector2d>(); |
271 | |
272 | bpy::implicitly_convertible<Vector3i, Imath::V3i>(); |
273 | bpy::implicitly_convertible<Imath::V3i, Vector3i>(); |
274 | |
275 | bpy::implicitly_convertible<Vector3f, Imath::V3f>(); |
276 | bpy::implicitly_convertible<Imath::V3f, Vector3f>(); |
277 | |
278 | bpy::implicitly_convertible<Vector3d, Imath::V3d>(); |
279 | bpy::implicitly_convertible<Imath::V3d, Vector3d>(); |
280 | #endif |
281 | } |
282 | |