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