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