1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright Contributors to the OpenEXR Project.
4 //
5
6 // clang-format off
7
8 #ifndef _PyImathVec_h_
9 #define _PyImathVec_h_
10
11 #include <Python.h>
12 #include <boost/python.hpp>
13 #include <ImathVec.h>
14 #include "PyImath.h"
15 #include "PyImathFixedArray.h"
16
17 namespace PyImath {
18
19 template <class T> boost::python::class_<IMATH_NAMESPACE::Vec2<T> > register_Vec2();
20 template <class T> boost::python::class_<FixedArray<IMATH_NAMESPACE::Vec2<T> > > register_Vec2Array();
21 typedef FixedArray<IMATH_NAMESPACE::V2s> V2sArray;
22 typedef FixedArray<IMATH_NAMESPACE::V2i> V2iArray;
23 typedef FixedArray<IMATH_NAMESPACE::V2i64> V2i64Array;
24 typedef FixedArray<IMATH_NAMESPACE::V2f> V2fArray;
25 typedef FixedArray<IMATH_NAMESPACE::V2d> V2dArray;
26
27 // TODO: template <class T> class Vec2Array : public FixedArray<IMATH_NAMESPACE::Vec2<T> >
28
29 }
30
31 // define vector*float array multiplication
32 template <class T>
33 static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a0, T v1) {
34 PY_IMATH_LEAVE_PYTHON;
35 size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*v1; return f;
36 }
37 template <class T>
38 static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator * (T v0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a1) { return a1*v0; }
39 template <class T>
40 static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a0, const PyImath::FixedArray<T> &a1) {
41 PY_IMATH_LEAVE_PYTHON;
42 size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*a1[i]; return f;
43 }
44 template <class T>
45 static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator * (const PyImath::FixedArray<T> &a0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a1) {
46 return a1*a0;
47 }
48
49 // define vector/float array division
50 template <class T>
51 static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a0, T v1) {
52 PY_IMATH_LEAVE_PYTHON;
53 size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/v1; return f;
54 }
55 template <class T>
56 static PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > &a0, const PyImath::FixedArray<T> &a1) {
57 PY_IMATH_LEAVE_PYTHON;
58 size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec2<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/a1[i]; return f;
59 }
60
61
62 namespace PyImath {
63
64 template <class T> boost::python::class_<IMATH_NAMESPACE::Vec3<T> > register_Vec3();
65 template <class T> boost::python::class_<FixedArray<IMATH_NAMESPACE::Vec3<T> > > register_Vec3Array();
66 typedef FixedArray<IMATH_NAMESPACE::Vec3<unsigned char> > V3cArray;
67 typedef FixedArray<IMATH_NAMESPACE::V3s> V3sArray;
68 typedef FixedArray<IMATH_NAMESPACE::V3i> V3iArray;
69 typedef FixedArray<IMATH_NAMESPACE::V3i64> V3i64Array;
70 typedef FixedArray<IMATH_NAMESPACE::V3f> V3fArray;
71 typedef FixedArray<IMATH_NAMESPACE::V3d> V3dArray;
72
73 // TODO: template <class T> class Vec3Array : public FixedArray<IMATH_NAMESPACE::Vec3<T> >
74 }
75
76 // define vector*float array multiplication
77 template <class T>
78 static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a0, T v1) {
79 PY_IMATH_LEAVE_PYTHON;
80 size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*v1; return f;
81 }
82 template <class T>
83 static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (T v0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a1) { return a1*v0; }
84 template <class T>
85 static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a0, const PyImath::FixedArray<T> &a1) {
86 PY_IMATH_LEAVE_PYTHON;
87 size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*a1[i]; return f;
88 }
89 template <class T>
90 static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (const PyImath::FixedArray<T> &a0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a1) {
91 return a1*a0;
92 }
93 template <class T>
94 static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &va, const IMATH_NAMESPACE::M44f &m) {
95 PY_IMATH_LEAVE_PYTHON;
96 size_t len = va.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va[i] * m; return f;
97 }
98
99 template <class T>
100 static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &va, const IMATH_NAMESPACE::M44d &m) {
101 PY_IMATH_LEAVE_PYTHON;
102 size_t len = va.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va[i] * m; return f;
103 }
104
105 // define vector/float array division
106 template <class T>
107 static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a0, T v1) {
108 PY_IMATH_LEAVE_PYTHON;
109 size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/v1; return f;
110 }
111 template <class T>
112 static PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > &a0, const PyImath::FixedArray<T> &a1) {
113 PY_IMATH_LEAVE_PYTHON;
114 size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec3<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/a1[i]; return f;
115 }
116
117 namespace PyImath {
118
119 template <class T> boost::python::class_<IMATH_NAMESPACE::Vec4<T> > register_Vec4();
120 template <class T> boost::python::class_<PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > > register_Vec4Array();
121 typedef FixedArray<IMATH_NAMESPACE::Vec4<unsigned char> > V4cArray;
122 typedef FixedArray<IMATH_NAMESPACE::V4s> V4sArray;
123 typedef FixedArray<IMATH_NAMESPACE::V4i> V4iArray;
124 typedef FixedArray<IMATH_NAMESPACE::V4i64> V4i64Array;
125 typedef FixedArray<IMATH_NAMESPACE::V4f> V4fArray;
126 typedef FixedArray<IMATH_NAMESPACE::V4d> V4dArray;
127
128 // TODO: template <class T> class Vec3Array : public FixedArray<IMATH_NAMESPACE::Vec3<T> >
129 }
130
131 // define vector*float array multiplication
132 template <class T>
133 static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a0, T v1) {
134 PY_IMATH_LEAVE_PYTHON;
135 size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*v1; return f;
136 }
137 template <class T>
138 static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (T v0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a1) { return a1*v0; }
139 template <class T>
140 static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a0, const PyImath::FixedArray<T> &a1) {
141 PY_IMATH_LEAVE_PYTHON;
142 size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]*a1[i]; return f;
143 }
144 template <class T>
145 static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (const PyImath::FixedArray<T> &a0, const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a1) {
146 return a1*a0;
147 }
148 template <class T>
149 static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &va, const IMATH_NAMESPACE::M44f &m) {
150 PY_IMATH_LEAVE_PYTHON;
151 size_t len = va.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va[i] * m; return f;
152 }
153
154 template <class T>
155 static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator * (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &va, const IMATH_NAMESPACE::M44d &m) {
156 PY_IMATH_LEAVE_PYTHON;
157 size_t len = va.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i = 0; i < len; ++i) f[i] = va[i] * m; return f;
158 }
159
160 // define vector/float array division
161 template <class T>
162 static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a0, T v1) {
163 PY_IMATH_LEAVE_PYTHON;
164 size_t len = a0.len(); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/v1; return f;
165 }
166 template <class T>
167 static PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > operator / (const PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > &a0, const PyImath::FixedArray<T> &a1) {
168 PY_IMATH_LEAVE_PYTHON;
169 size_t len = a0.match_dimension(a1); PyImath::FixedArray<IMATH_NAMESPACE::Vec4<T> > f(len); for (size_t i=0;i<len;++i) f[i]=a0[i]/a1[i]; return f;
170 }
171
172
173 //
174
175 namespace PyImath {
176
177 // Other code in the Zeno code base assumes the existance of a class with the
178 // same name as the Imath class, and with static functions wrap() and
179 // convert() to produce a PyImath object from an Imath object and vice-versa,
180 // respectively. The class Boost generates from the Imath class does not
181 // have these properties, so we define a companion class here.
182 // The template argument, T, is the element type for the vector (e.g., int,
183 // float, double).
184
185 template <class T>
186 class V2 {
187 public:
188 static PyObject * wrap (const IMATH_NAMESPACE::Vec2<T> &v);
189 static int convert (PyObject *p, IMATH_NAMESPACE::Vec2<T> *v);
190 };
191
192 template <class T>
193 class V3 {
194 public:
195 static PyObject * wrap (const IMATH_NAMESPACE::Vec3<T> &v);
196 static int convert (PyObject *p, IMATH_NAMESPACE::Vec3<T> *v);
197 };
198
199 template <class T>
200 class V4 {
201 public:
202 static PyObject * wrap (const IMATH_NAMESPACE::Vec4<T> &v);
203 static int convert (PyObject *p, IMATH_NAMESPACE::Vec4<T> *v);
204 };
205
206 template <class T>
207 PyObject *
wrap(const IMATH_NAMESPACE::Vec2<T> & v)208 V2<T>::wrap (const IMATH_NAMESPACE::Vec2<T> &v)
209 {
210 typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Vec2<T> >::type converter;
211 PyObject *p = converter (v);
212 return p;
213 }
214
215 template <class T>
216 PyObject *
wrap(const IMATH_NAMESPACE::Vec3<T> & v)217 V3<T>::wrap (const IMATH_NAMESPACE::Vec3<T> &v)
218 {
219 typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Vec3<T> >::type converter;
220 PyObject *p = converter (v);
221 return p;
222 }
223
224 template <class T>
225 PyObject *
wrap(const IMATH_NAMESPACE::Vec4<T> & v)226 V4<T>::wrap (const IMATH_NAMESPACE::Vec4<T> &v)
227 {
228 typename boost::python::return_by_value::apply < IMATH_NAMESPACE::Vec4<T> >::type converter;
229 PyObject *p = converter (v);
230 return p;
231 }
232
233 template <class T>
234 int
convert(PyObject * p,IMATH_NAMESPACE::Vec2<T> * v)235 V2<T>::convert (PyObject *p, IMATH_NAMESPACE::Vec2<T> *v)
236 {
237 boost::python::extract <IMATH_NAMESPACE::V2i> extractorV2i (p);
238 if (extractorV2i.check())
239 {
240 IMATH_NAMESPACE::V2i v2i = extractorV2i();
241 v->setValue (T(v2i[0]), T(v2i[1]));
242 return 1;
243 }
244
245 boost::python::extract <IMATH_NAMESPACE::V2i64> extractorV2i64 (p);
246 if (extractorV2i64.check())
247 {
248 IMATH_NAMESPACE::V2i64 v2i64 = extractorV2i64();
249 v->setValue (T(v2i64[0]), T(v2i64[1]));
250 return 1;
251 }
252
253 boost::python::extract <IMATH_NAMESPACE::V2f> extractorV2f (p);
254 if (extractorV2f.check())
255 {
256 IMATH_NAMESPACE::V2f v2f = extractorV2f();
257 v->setValue (T(v2f[0]), T(v2f[1]));
258 return 1;
259 }
260
261 boost::python::extract <IMATH_NAMESPACE::V2d> extractorV2d (p);
262 if (extractorV2d.check())
263 {
264 IMATH_NAMESPACE::V2d v2d = extractorV2d();
265 v->setValue (T(v2d[0]), T(v2d[1]));
266 return 1;
267 }
268
269 boost::python::extract <boost::python::tuple> extractorTuple (p);
270 if (extractorTuple.check())
271 {
272 boost::python::tuple t = extractorTuple();
273 if (t.attr ("__len__") () == 2)
274 {
275 // Extracting the tuple elements as doubles and casting them to
276 // Ts in setValue() works better than extracting them as Ts from
277 // the start. Extracting them as Ts can fail in certain
278 // circumstances if T is int and the tuples elemnts are floats.
279 // In particular, this kind of failure occurs in PyImathBox.h,
280 // when Box2<int>::convert() is passed a tuple of two tuples of
281 // floats.
282
283 double a = boost::python::extract <double> (t[0]);
284 double b = boost::python::extract <double> (t[1]);
285 v->setValue (T(a), T(b));
286 return 1;
287 }
288 }
289
290 boost::python::extract <boost::python::list> extractorList (p);
291 if (extractorList.check())
292 {
293 boost::python::list l = extractorList();
294 if (l.attr ("__len__") () == 2)
295 {
296 boost::python::extract <double> extractor0 (l[0]);
297 boost::python::extract <double> extractor1 (l[1]);
298 if (extractor0.check() && extractor1.check())
299 {
300 v->setValue (T(extractor0()), T(extractor1()));
301 return 1;
302 }
303 }
304 }
305
306 return 0;
307 }
308
309 template <class T>
310 int
convert(PyObject * p,IMATH_NAMESPACE::Vec3<T> * v)311 V3<T>::convert (PyObject *p, IMATH_NAMESPACE::Vec3<T> *v)
312 {
313 boost::python::extract <IMATH_NAMESPACE::V3i> extractorV3i (p);
314 if (extractorV3i.check())
315 {
316 IMATH_NAMESPACE::V3i v3i = extractorV3i();
317 v->setValue (T(v3i[0]), T(v3i[1]), T(v3i[2]));
318 return 1;
319 }
320
321 boost::python::extract <IMATH_NAMESPACE::V3i64> extractorV3i64 (p);
322 if (extractorV3i64.check())
323 {
324 IMATH_NAMESPACE::V3i64 v3i64 = extractorV3i64();
325 v->setValue (T(v3i64[0]), T(v3i64[1]), T(v3i64[2]));
326 return 1;
327 }
328
329 boost::python::extract <IMATH_NAMESPACE::V3f> extractorV3f (p);
330 if (extractorV3f.check())
331 {
332 IMATH_NAMESPACE::V3f v3f = extractorV3f();
333 v->setValue (T(v3f[0]), T(v3f[1]), T(v3f[2]));
334 return 1;
335 }
336
337 boost::python::extract <IMATH_NAMESPACE::V3d> extractorV3d (p);
338 if (extractorV3d.check())
339 {
340 IMATH_NAMESPACE::V3d v3d = extractorV3d();
341 v->setValue (T(v3d[0]), T(v3d[1]), T(v3d[2]));
342 return 1;
343 }
344
345 boost::python::extract <boost::python::tuple> extractorTuple (p);
346 if (extractorTuple.check())
347 {
348 boost::python::tuple t = extractorTuple();
349 if (t.attr ("__len__") () == 3)
350 {
351 // See the comment in V2<T>::convert().
352
353 double a = boost::python::extract <double> (t[0]);
354 double b = boost::python::extract <double> (t[1]);
355 double c = boost::python::extract <double> (t[2]);
356 v->setValue (T(a), T(b), T(c));
357 return 1;
358 }
359 }
360
361 boost::python::extract <boost::python::list> extractorList (p);
362 if (extractorList.check())
363 {
364 boost::python::list l = extractorList();
365 if (l.attr ("__len__") () == 3)
366 {
367 boost::python::extract <double> extractor0 (l[0]);
368 boost::python::extract <double> extractor1 (l[1]);
369 boost::python::extract <double> extractor2 (l[2]);
370 if (extractor0.check() && extractor1.check() &&
371 extractor2.check())
372 {
373 v->setValue (T(extractor0()), T(extractor1()),
374 T(extractor2()));
375 return 1;
376 }
377 }
378 }
379
380 return 0;
381 }
382
383 template <class T>
384 int
convert(PyObject * p,IMATH_NAMESPACE::Vec4<T> * v)385 V4<T>::convert (PyObject *p, IMATH_NAMESPACE::Vec4<T> *v)
386 {
387 boost::python::extract <IMATH_NAMESPACE::V4i> extractorV4i (p);
388 if (extractorV4i.check())
389 {
390 IMATH_NAMESPACE::V4i v4i = extractorV4i();
391 *v = IMATH_NAMESPACE::Vec4<T>(v4i);
392 return 1;
393 }
394
395 boost::python::extract <IMATH_NAMESPACE::V4f> extractorV4f (p);
396 if (extractorV4f.check())
397 {
398 IMATH_NAMESPACE::V4f v4f = extractorV4f();
399 *v = IMATH_NAMESPACE::Vec4<T>(v4f);
400 return 1;
401 }
402
403 boost::python::extract <IMATH_NAMESPACE::V4d> extractorV4d (p);
404 if (extractorV4d.check())
405 {
406 IMATH_NAMESPACE::V4d v4d = extractorV4d();
407 *v = IMATH_NAMESPACE::Vec4<T>(v4d);
408 return 1;
409 }
410
411 boost::python::extract <boost::python::tuple> extractorTuple (p);
412 if (extractorTuple.check())
413 {
414 boost::python::tuple t = extractorTuple();
415 if (t.attr ("__len__") () == 4)
416 {
417 // See the comment in V2<T>::convert().
418
419 double a = boost::python::extract <double> (t[0]);
420 double b = boost::python::extract <double> (t[1]);
421 double c = boost::python::extract <double> (t[2]);
422 double d = boost::python::extract <double> (t[3]);
423 *v = IMATH_NAMESPACE::Vec4<T>(T(a), T(b), T(c), T(d));
424 return 1;
425 }
426 }
427
428 boost::python::extract <boost::python::list> extractorList (p);
429 if (extractorList.check())
430 {
431 boost::python::list l = extractorList();
432 if (l.attr ("__len__") () == 4)
433 {
434 boost::python::extract <double> extractor0 (l[0]);
435 boost::python::extract <double> extractor1 (l[1]);
436 boost::python::extract <double> extractor2 (l[2]);
437 boost::python::extract <double> extractor3 (l[3]);
438 if (extractor0.check() && extractor1.check() &&
439 extractor2.check() && extractor3.check())
440 {
441 *v = IMATH_NAMESPACE::Vec4<T>(T(extractor0()), T(extractor1()),
442 T(extractor2()), T(extractor3()));
443 return 1;
444 }
445 }
446 }
447
448 return 0;
449 }
450
451
452 typedef V2<int> V2i;
453 typedef V2<float> V2f;
454 typedef V2<double> V2d;
455 typedef V3<int> V3i;
456 typedef V3<float> V3f;
457 typedef V3<double> V3d;
458 typedef V4<int> V4i;
459 typedef V4<float> V4f;
460 typedef V4<double> V4d;
461
462 }
463
464 #endif
465