1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 // This file is generated by a script.  Do not edit directly.  Edit the
26 // wrapVec.template.cpp file to make changes.
27 
28 #include "pxr/pxr.h"
29 #include "pxr/base/gf/vec4f.h"
30 
31 #include "pxr/base/gf/pyBufferUtils.h"
32 
33 #include "pxr/base/tf/py3Compat.h"
34 #include "pxr/base/tf/pyContainerConversions.h"
35 #include "pxr/base/tf/pyUtils.h"
36 #include "pxr/base/tf/stringUtils.h"
37 #include "pxr/base/tf/wrapTypeHelpers.h"
38 
39 // Include headers for other vec types to support wrapping conversions and
40 // operators.
41 #include "pxr/base/gf/vec4d.h"
42 #include "pxr/base/gf/vec4h.h"
43 #include "pxr/base/gf/vec4i.h"
44 
45 #include <boost/python/class.hpp>
46 #include <boost/python/def.hpp>
47 #include <boost/python/make_constructor.hpp>
48 #include <boost/python/operators.hpp>
49 #include <boost/python/overloads.hpp>
50 #include <boost/python/tuple.hpp>
51 #include <boost/python/slice.hpp>
52 
53 #include <boost/functional/hash.hpp>
54 
55 #include <string>
56 
57 using namespace boost::python;
58 
59 using std::string;
60 
61 PXR_NAMESPACE_USING_DIRECTIVE
62 
63 namespace {
64 
65 ////////////////////////////////////////////////////////////////////////
66 // Python buffer protocol support.
67 
68 #if PY_MAJOR_VERSION == 2
69 // Python's getreadbuf interface function.
70 static Py_ssize_t
getreadbuf(PyObject * self,Py_ssize_t segment,void ** ptrptr)71 getreadbuf(PyObject *self, Py_ssize_t segment, void **ptrptr) {
72     if (segment != 0) {
73         // Always one-segment.
74         PyErr_SetString(PyExc_ValueError, "accessed non-existent segment");
75         return -1;
76     }
77     GfVec4f &vec = extract<GfVec4f &>(self);
78     *ptrptr = static_cast<void *>(vec.data());
79     // Return size in bytes.
80     return sizeof(GfVec4f);
81 }
82 
83 // Python's getwritebuf interface function.
84 static Py_ssize_t
getwritebuf(PyObject * self,Py_ssize_t segment,void ** ptrptr)85 getwritebuf(PyObject *self, Py_ssize_t segment, void **ptrptr) {
86     PyErr_SetString(PyExc_ValueError, "writable buffers supported only with "
87                     "new-style buffer protocol.");
88     return -1;
89 }
90 
91 // Python's getsegcount interface function.
92 static Py_ssize_t
getsegcount(PyObject * self,Py_ssize_t * lenp)93 getsegcount(PyObject *self, Py_ssize_t *lenp) {
94     if (lenp)
95         *lenp = sizeof(GfVec4f);
96     return 1; // Always one contiguous segment.
97 }
98 
99 // Python's getcharbuf interface function.
100 static Py_ssize_t
getcharbuf(PyObject * self,Py_ssize_t segment,const char ** ptrptr)101 getcharbuf(PyObject *self, Py_ssize_t segment, const char **ptrptr) {
102     PyErr_SetString(PyExc_ValueError, "cannot treat binary data as text");
103     return -1;
104 }
105 #endif
106 
107 // Python's getbuffer interface function.
108 static int
getbuffer(PyObject * self,Py_buffer * view,int flags)109 getbuffer(PyObject *self, Py_buffer *view, int flags) {
110     if (view == NULL) {
111         PyErr_SetString(PyExc_ValueError, "NULL view in getbuffer");
112         return -1;
113     }
114 
115     // We don't support fortran order.
116     if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) {
117         PyErr_SetString(PyExc_ValueError, "Fortran contiguity unsupported");
118         return -1;
119     }
120 
121     GfVec4f &vec = extract<GfVec4f &>(self);
122 
123     view->obj = self;
124     view->buf = static_cast<void *>(vec.data());
125     view->len = sizeof(GfVec4f);
126     view->readonly = 0;
127     view->itemsize = sizeof(float);
128     if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
129         view->format = Gf_GetPyBufferFmtFor<float>();
130     } else {
131         view->format = NULL;
132     }
133     if ((flags & PyBUF_ND) == PyBUF_ND) {
134         view->ndim = 1;
135         static Py_ssize_t shape = 4;
136         view->shape = &shape;
137     } else {
138         view->ndim = 0;
139         view->shape = NULL;
140     }
141     if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
142         static Py_ssize_t strides = sizeof(float);
143         view->strides = &strides;
144     } else {
145         view->strides = NULL;
146     }
147     view->suboffsets = NULL;
148     view->internal = NULL;
149 
150     Py_INCREF(self); // need to retain a reference to self.
151     return 0;
152 }
153 
154 // This structure serves to instantiate a PyBufferProcs instance with pointers
155 // to the right buffer protocol functions.
156 static PyBufferProcs bufferProcs = {
157 #if PY_MAJOR_VERSION == 2
158     (readbufferproc) getreadbuf,   /*bf_getreadbuffer*/
159     (writebufferproc) getwritebuf, /*bf_getwritebuffer*/
160     (segcountproc) getsegcount,    /*bf_getsegcount*/
161     (charbufferproc) getcharbuf,   /*bf_getcharbuffer*/
162 #endif
163     (getbufferproc) getbuffer,
164     (releasebufferproc) 0,
165 };
166 
167 // End python buffer protocol support.
168 ////////////////////////////////////////////////////////////////////////
169 
170 
__repr__(GfVec4f const & self)171 static string __repr__(GfVec4f const &self) {
172     string elems;
173     for (size_t i = 0; i < self.dimension; ++i)
174         elems += (i ? ", " : "") + TfPyRepr(self[i]);
175 
176     return TF_PY_REPR_PREFIX + "Vec4f(" + elems + ")";
177 }
178 
__hash__(GfVec4f const & self)179 static size_t __hash__(GfVec4f const &self) {
180     return boost::hash<GfVec4f>()(self);
181 }
182 
183 
184 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(VecGetNormalized_overloads,
185                                        GetNormalized, 0, 1);
186 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(VecNormalize_overloads, Normalize, 0, 1);
187 BOOST_PYTHON_FUNCTION_OVERLOADS(GetNormalized_overloads,
188                                 GfGetNormalized, 1, 2);
189 
190 static float
NormalizeHelper(GfVec4f * vec,float eps=GF_MIN_VECTOR_LENGTH)191 NormalizeHelper(GfVec4f *vec, float eps = GF_MIN_VECTOR_LENGTH)
192 {
193     return GfNormalize(vec, eps);
194 }
195 
196 BOOST_PYTHON_FUNCTION_OVERLOADS(Normalize_overloads, NormalizeHelper, 1, 2);
197 
198 
199 
200 
201 static int
normalizeIndex(int index)202 normalizeIndex(int index) {
203     return TfPyNormalizeIndex(index, 4, true /*throw error*/);
204 }
205 
__len__(const GfVec4f & self)206 static int __len__(const GfVec4f &self) { return 4; }
207 
208 // Implements __getitem__ for a single index
__getitem__(const GfVec4f & self,int index)209 static float __getitem__(const GfVec4f &self, int index) {
210     return self[normalizeIndex(index)];
211 }
212 
213 // Implements __getitem__ for a slice
__getslice__(const GfVec4f & self,slice indices)214 static list __getslice__(const GfVec4f &self, slice indices) {
215     list result;
216 
217     const float* begin = self.data();
218     const float* end = begin + 4;
219 
220     slice::range<const float*> bounds;
221     try {
222         // This appears to be a typo in the boost headers.  The method
223         // name should be "get_indices".
224         //
225         bounds = indices.get_indicies<>(begin, end);
226     } catch (std::invalid_argument) {
227         return result;
228     }
229 
230     while (bounds.start != bounds.stop) {
231         result.append(*bounds.start);
232         bounds.start += bounds.step;
233     }
234     // Unlike STL ranges, bounds represents a *closed* interval.  This
235     // means that we must append exactly one more item at the end of
236     // the list.
237     //
238     result.append(*bounds.start);
239 
240     return result;
241 }
242 
__setitem__(GfVec4f & self,int index,float value)243 static void __setitem__(GfVec4f &self, int index, float value) {
244     self[normalizeIndex(index)] = value;
245 }
246 
247 // Handles refcounting & extraction for PySequence_GetItem.
_SequenceGetItem(PyObject * seq,Py_ssize_t i)248 static float _SequenceGetItem(PyObject *seq, Py_ssize_t i) {
249     boost::python::handle<> h(PySequence_GetItem(seq, i));
250     return extract<float>(boost::python::object(h));
251 }
252 
_SequenceCheckItem(PyObject * seq,Py_ssize_t i)253 static bool _SequenceCheckItem(PyObject *seq, Py_ssize_t i) {
254     boost::python::handle<> h(PySequence_GetItem(seq, i));
255     extract<float> e((boost::python::object(h)));
256     return e.check();
257 }
258 
__setslice__(GfVec4f & self,slice indices,object values)259 static void __setslice__(GfVec4f &self, slice indices, object values) {
260     // Verify our arguments
261     //
262     PyObject* valuesObj = values.ptr();
263 
264     if (!PySequence_Check(valuesObj)) {
265         TfPyThrowTypeError("value must be a sequence");
266     }
267 
268     float* begin = self.data();
269     float* end = begin + 4;
270 
271     Py_ssize_t sliceLength = -1;
272 
273     slice::range<float*> bounds;
274 
275     // Convince g++ that we're not using uninitialized values.
276     //
277     bounds.start = 0;
278     bounds.stop  = 0;
279     bounds.step  = 0;
280 
281     try {
282         // This appears to be a typo in the boost headers.  The method
283         // name should be "get_indices".
284         //
285         bounds = indices.get_indicies<>(begin, end);
286     } catch (std::invalid_argument) {
287         sliceLength = 0;
288     }
289 
290     // If sliceLength was not set in the exception handling code above,
291     // figure out how long it really is.
292     //
293     if (sliceLength == -1) {
294         sliceLength = ((bounds.stop - bounds.start) / bounds.step) + 1;
295     }
296 
297     if (PySequence_Length(valuesObj) != sliceLength) {
298         TfPyThrowValueError(
299             TfStringPrintf(
300                 "attempt to assign sequence of size %zd to slice of size %zd",
301                 PySequence_Length(valuesObj), sliceLength));
302     }
303 
304     // Short circuit for empty slices
305     //
306     if (sliceLength == 0) {
307         return;
308     }
309 
310     // Make sure that all items can be extracted before changing the GfVec4f.
311     //
312     for (Py_ssize_t i = 0; i < sliceLength; ++i) {
313         // This will throw a TypeError if any of the items cannot be converted.
314         _SequenceGetItem(valuesObj, i);
315     }
316 
317     for (Py_ssize_t i = 0; i < sliceLength; ++i) {
318         *bounds.start = _SequenceGetItem(valuesObj, i);
319         bounds.start += bounds.step;
320     }
321 }
322 
__contains__(const GfVec4f & self,float value)323 static bool __contains__(const GfVec4f &self, float value) {
324     for (size_t i = 0; i < 4; ++i) {
325         if (self[i] == value)
326             return true;
327     }
328     return false;
329 }
330 
331 #if PY_MAJOR_VERSION == 2
__truediv__(const GfVec4f & self,float value)332 static GfVec4f __truediv__(const GfVec4f &self, float value)
333 {
334     return self / value;
335 }
336 
__itruediv__(GfVec4f & self,float value)337 static GfVec4f __itruediv__(GfVec4f &self, float value)
338 {
339     return self /= value;
340 }
341 #endif
342 
343 template <class V>
__init__()344 static V *__init__() {
345     // Default contstructor zero-initializes from python.
346     return new V(0);
347 }
348 
349 struct FromPythonTuple {
FromPythonTuple__anon8d09094d0111::FromPythonTuple350     FromPythonTuple() {
351         converter::registry::
352             push_back(&_convertible, &_construct,
353                       boost::python::type_id<GfVec4f>());
354     }
355 
356   private:
357 
_convertible__anon8d09094d0111::FromPythonTuple358     static void *_convertible(PyObject *obj_ptr) {
359         // If this object is a GfVec already, disregard.
360         if (PyObject_HasAttrString(obj_ptr, "__isGfVec"))
361             return 0;
362 
363         typedef float Scalar;
364 
365         // XXX: Would like to allow general sequences, but currently clients
366         // depend on this behavior.
367         if ((PyTuple_Check(obj_ptr) || PyList_Check(obj_ptr)) &&
368             PySequence_Size(obj_ptr) == 4 &&
369             _SequenceCheckItem(obj_ptr, 0) &&
370             _SequenceCheckItem(obj_ptr, 1) &&
371             _SequenceCheckItem(obj_ptr, 2) &&
372             _SequenceCheckItem(obj_ptr, 3)) {
373             return obj_ptr;
374         }
375         return 0;
376     }
377 
_construct__anon8d09094d0111::FromPythonTuple378     static void _construct(PyObject *obj_ptr, converter::
379                            rvalue_from_python_stage1_data *data) {
380         typedef float Scalar;
381         void *storage = ((converter::rvalue_from_python_storage<GfVec4f>*)data)
382 	    ->storage.bytes;
383         new (storage)
384 	    GfVec4f(
385                 _SequenceGetItem(obj_ptr, 0),
386                 _SequenceGetItem(obj_ptr, 1),
387                 _SequenceGetItem(obj_ptr, 2),
388                 _SequenceGetItem(obj_ptr, 3));
389         data->convertible = storage;
390     }
391 };
392 
393 // This adds support for python's builtin pickling library
394 // This is used by our Shake plugins which need to pickle entire classes
395 // (including code), which we don't support in pxml.
396 struct PickleSuite : boost::python::pickle_suite
397 {
getinitargs__anon8d09094d0111::PickleSuite398     static boost::python::tuple getinitargs(const GfVec4f &v) {
399         return boost::python::make_tuple(v[0], v[1], v[2], v[3]);
400     }
401 };
402 
403 } // anonymous namespace
404 
wrapVec4f()405 void wrapVec4f()
406 {
407     typedef GfVec4f Vec;
408     typedef float Scalar;
409 
410     static const size_t _dimension = 4;
411     static const bool _true = true;
412 
413     def("Dot", (Scalar (*)( const Vec &, const Vec &))GfDot);
414 
415     def("CompDiv", (Vec (*)(const Vec &v1, const Vec&v2))GfCompDiv);
416     def("CompMult", (Vec (*)(const Vec &v1, const Vec&v2))GfCompMult);
417     def("GetLength", (Scalar (*)(const Vec &v))GfGetLength);
418     def("GetNormalized", (Vec (*)(const Vec &v, Scalar eps))
419         GfGetNormalized, GetNormalized_overloads());
420     def("GetProjection", (Vec (*)(const Vec &a, const Vec &b))
421         GfGetProjection);
422     def("GetComplement", (Vec (*)(const Vec &a, const Vec &b))
423         GfGetComplement);
424     def("IsClose", (bool (*)(const Vec &v1, const Vec &v2, double))
425         GfIsClose);
426     def("Normalize", NormalizeHelper, Normalize_overloads());
427 
428 
429 
430     class_<GfVec4f> cls("Vec4f", no_init);
431     cls
432         .def("__init__", make_constructor(__init__<Vec>))
433 
434         // A tag indicating that this is a GfVec class, for internal use.
435         .def_readonly("__isGfVec", _true)
436 
437         .def_pickle(PickleSuite())
438 
439         // Conversion from other vec types.
440         .def(init<GfVec4d>())
441         .def(init<GfVec4h>())
442         .def(init<GfVec4i>())
443 
444         .def(init<Vec>())
445         .def(init<Scalar>())
446         .def(init<Scalar, Scalar, Scalar, Scalar>())
447 
448         .def(TfTypePythonClass())
449 
450         .def("__len__", __len__ )
451         .def("__getitem__", __getitem__ )
452         .def("__getitem__", __getslice__ )
453         .def("__setitem__", __setitem__ )
454         .def("__setitem__", __setslice__ )
455         .def("__contains__", __contains__ )
456 
457         .def_readonly("dimension", _dimension)
458 
459         // Comparison to other vec types.
460         .def( self == GfVec4h() )
461         .def( self != GfVec4h() )
462         .def( self == GfVec4i() )
463         .def( self != GfVec4i() )
464 
465         .def(self == self)
466         .def(self != self)
467         .def(self += self)
468         .def(self -= self)
469         .def(self *= double())
470         .def(self * double())
471         .def(double() * self)
472         .def(self /= float())
473         .def(self / float())
474         .def(-self)
475         .def(self + self)
476         .def(self - self)
477         .def(self * self)
478         .def(str(self))
479 
480 #if PY_MAJOR_VERSION == 2
481         // Needed only to support "from __future__ import division" in
482         // python 2. In python 3 builds boost::python adds this for us.
483         .def("__truediv__", __truediv__ )
484         .def("__itruediv__", __itruediv__ )
485 #endif
486 
487         .def("Axis", &Vec::Axis).staticmethod("Axis")
488 
489         .def("XAxis", &Vec::XAxis).staticmethod("XAxis")
490         .def("YAxis", &Vec::YAxis).staticmethod("YAxis")
491         .def("ZAxis", &Vec::ZAxis).staticmethod("ZAxis")
492         .def("WAxis", &Vec::WAxis).staticmethod("WAxis")
493 
494         .def("GetDot", (Scalar (*)(const Vec &, const Vec &))GfDot)
495 
496         .def("GetComplement", &Vec::GetComplement)
497         .def("GetLength", &Vec::GetLength)
498         .def("GetNormalized", &Vec::GetNormalized, VecGetNormalized_overloads())
499         .def("GetProjection", &Vec::GetProjection)
500         .def("Normalize", &Vec::Normalize, VecNormalize_overloads())
501 
502         .def("__repr__", __repr__)
503         .def("__hash__", __hash__)
504         ;
505     to_python_converter<std::vector<GfVec4f>,
506         TfPySequenceToPython<std::vector<GfVec4f> > >();
507 
508     // Install buffer protocol: set the tp_as_buffer slot to point to a
509     // structure of function pointers that implement the buffer protocol for
510     // this type, and set the type flags to indicate that this type supports the
511     // buffer protocol.
512     auto *typeObj = reinterpret_cast<PyTypeObject *>(cls.ptr());
513     typeObj->tp_as_buffer = &bufferProcs;
514     typeObj->tp_flags |= (TfPy_TPFLAGS_HAVE_NEWBUFFER |
515                           TfPy_TPFLAGS_HAVE_GETCHARBUFFER);
516 
517     // Allow appropriate tuples to be passed where Vecs are expected.
518     FromPythonTuple();
519 
520     // Allow conversion of lists of GfVec4f to std::vector<GfVec4f>
521     TfPyContainerConversions::from_python_sequence<
522         std::vector<GfVec4f>,
523         TfPyContainerConversions::variable_capacity_policy >();
524 }
525