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/vec2f.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/vec2d.h"
42 #include "pxr/base/gf/vec2h.h"
43 #include "pxr/base/gf/vec2i.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 GfVec2f &vec = extract<GfVec2f &>(self);
78 *ptrptr = static_cast<void *>(vec.data());
79 // Return size in bytes.
80 return sizeof(GfVec2f);
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(GfVec2f);
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 GfVec2f &vec = extract<GfVec2f &>(self);
122
123 view->obj = self;
124 view->buf = static_cast<void *>(vec.data());
125 view->len = sizeof(GfVec2f);
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 = 2;
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__(GfVec2f const & self)171 static string __repr__(GfVec2f 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 + "Vec2f(" + elems + ")";
177 }
178
__hash__(GfVec2f const & self)179 static size_t __hash__(GfVec2f const &self) {
180 return boost::hash<GfVec2f>()(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(GfVec2f * vec,float eps=GF_MIN_VECTOR_LENGTH)191 NormalizeHelper(GfVec2f *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, 2, true /*throw error*/);
204 }
205
__len__(const GfVec2f & self)206 static int __len__(const GfVec2f &self) { return 2; }
207
208 // Implements __getitem__ for a single index
__getitem__(const GfVec2f & self,int index)209 static float __getitem__(const GfVec2f &self, int index) {
210 return self[normalizeIndex(index)];
211 }
212
213 // Implements __getitem__ for a slice
__getslice__(const GfVec2f & self,slice indices)214 static list __getslice__(const GfVec2f &self, slice indices) {
215 list result;
216
217 const float* begin = self.data();
218 const float* end = begin + 2;
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__(GfVec2f & self,int index,float value)243 static void __setitem__(GfVec2f &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__(GfVec2f & self,slice indices,object values)259 static void __setslice__(GfVec2f &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 + 2;
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 GfVec2f.
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 GfVec2f & self,float value)323 static bool __contains__(const GfVec2f &self, float value) {
324 for (size_t i = 0; i < 2; ++i) {
325 if (self[i] == value)
326 return true;
327 }
328 return false;
329 }
330
331 #if PY_MAJOR_VERSION == 2
__truediv__(const GfVec2f & self,float value)332 static GfVec2f __truediv__(const GfVec2f &self, float value)
333 {
334 return self / value;
335 }
336
__itruediv__(GfVec2f & self,float value)337 static GfVec2f __itruediv__(GfVec2f &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__anon885eb80b0111::FromPythonTuple350 FromPythonTuple() {
351 converter::registry::
352 push_back(&_convertible, &_construct,
353 boost::python::type_id<GfVec2f>());
354 }
355
356 private:
357
_convertible__anon885eb80b0111::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) == 2 &&
369 _SequenceCheckItem(obj_ptr, 0) &&
370 _SequenceCheckItem(obj_ptr, 1)) {
371 return obj_ptr;
372 }
373 return 0;
374 }
375
_construct__anon885eb80b0111::FromPythonTuple376 static void _construct(PyObject *obj_ptr, converter::
377 rvalue_from_python_stage1_data *data) {
378 typedef float Scalar;
379 void *storage = ((converter::rvalue_from_python_storage<GfVec2f>*)data)
380 ->storage.bytes;
381 new (storage)
382 GfVec2f(
383 _SequenceGetItem(obj_ptr, 0),
384 _SequenceGetItem(obj_ptr, 1));
385 data->convertible = storage;
386 }
387 };
388
389 // This adds support for python's builtin pickling library
390 // This is used by our Shake plugins which need to pickle entire classes
391 // (including code), which we don't support in pxml.
392 struct PickleSuite : boost::python::pickle_suite
393 {
getinitargs__anon885eb80b0111::PickleSuite394 static boost::python::tuple getinitargs(const GfVec2f &v) {
395 return boost::python::make_tuple(v[0], v[1]);
396 }
397 };
398
399 } // anonymous namespace
400
wrapVec2f()401 void wrapVec2f()
402 {
403 typedef GfVec2f Vec;
404 typedef float Scalar;
405
406 static const size_t _dimension = 2;
407 static const bool _true = true;
408
409 def("Dot", (Scalar (*)( const Vec &, const Vec &))GfDot);
410
411 def("CompDiv", (Vec (*)(const Vec &v1, const Vec&v2))GfCompDiv);
412 def("CompMult", (Vec (*)(const Vec &v1, const Vec&v2))GfCompMult);
413 def("GetLength", (Scalar (*)(const Vec &v))GfGetLength);
414 def("GetNormalized", (Vec (*)(const Vec &v, Scalar eps))
415 GfGetNormalized, GetNormalized_overloads());
416 def("GetProjection", (Vec (*)(const Vec &a, const Vec &b))
417 GfGetProjection);
418 def("GetComplement", (Vec (*)(const Vec &a, const Vec &b))
419 GfGetComplement);
420 def("IsClose", (bool (*)(const Vec &v1, const Vec &v2, double))
421 GfIsClose);
422 def("Normalize", NormalizeHelper, Normalize_overloads());
423
424
425
426 class_<GfVec2f> cls("Vec2f", no_init);
427 cls
428 .def("__init__", make_constructor(__init__<Vec>))
429
430 // A tag indicating that this is a GfVec class, for internal use.
431 .def_readonly("__isGfVec", _true)
432
433 .def_pickle(PickleSuite())
434
435 // Conversion from other vec types.
436 .def(init<GfVec2d>())
437 .def(init<GfVec2h>())
438 .def(init<GfVec2i>())
439
440 .def(init<Vec>())
441 .def(init<Scalar>())
442 .def(init<Scalar, Scalar>())
443
444 .def(TfTypePythonClass())
445
446 .def("__len__", __len__ )
447 .def("__getitem__", __getitem__ )
448 .def("__getitem__", __getslice__ )
449 .def("__setitem__", __setitem__ )
450 .def("__setitem__", __setslice__ )
451 .def("__contains__", __contains__ )
452
453 .def_readonly("dimension", _dimension)
454
455 // Comparison to other vec types.
456 .def( self == GfVec2h() )
457 .def( self != GfVec2h() )
458 .def( self == GfVec2i() )
459 .def( self != GfVec2i() )
460
461 .def(self == self)
462 .def(self != self)
463 .def(self += self)
464 .def(self -= self)
465 .def(self *= double())
466 .def(self * double())
467 .def(double() * self)
468 .def(self /= float())
469 .def(self / float())
470 .def(-self)
471 .def(self + self)
472 .def(self - self)
473 .def(self * self)
474 .def(str(self))
475
476 #if PY_MAJOR_VERSION == 2
477 // Needed only to support "from __future__ import division" in
478 // python 2. In python 3 builds boost::python adds this for us.
479 .def("__truediv__", __truediv__ )
480 .def("__itruediv__", __itruediv__ )
481 #endif
482
483 .def("Axis", &Vec::Axis).staticmethod("Axis")
484
485 .def("XAxis", &Vec::XAxis).staticmethod("XAxis")
486 .def("YAxis", &Vec::YAxis).staticmethod("YAxis")
487
488 .def("GetDot", (Scalar (*)(const Vec &, const Vec &))GfDot)
489
490 .def("GetComplement", &Vec::GetComplement)
491 .def("GetLength", &Vec::GetLength)
492 .def("GetNormalized", &Vec::GetNormalized, VecGetNormalized_overloads())
493 .def("GetProjection", &Vec::GetProjection)
494 .def("Normalize", &Vec::Normalize, VecNormalize_overloads())
495
496 .def("__repr__", __repr__)
497 .def("__hash__", __hash__)
498 ;
499 to_python_converter<std::vector<GfVec2f>,
500 TfPySequenceToPython<std::vector<GfVec2f> > >();
501
502 // Install buffer protocol: set the tp_as_buffer slot to point to a
503 // structure of function pointers that implement the buffer protocol for
504 // this type, and set the type flags to indicate that this type supports the
505 // buffer protocol.
506 auto *typeObj = reinterpret_cast<PyTypeObject *>(cls.ptr());
507 typeObj->tp_as_buffer = &bufferProcs;
508 typeObj->tp_flags |= (TfPy_TPFLAGS_HAVE_NEWBUFFER |
509 TfPy_TPFLAGS_HAVE_GETCHARBUFFER);
510
511 // Allow appropriate tuples to be passed where Vecs are expected.
512 FromPythonTuple();
513
514 // Allow conversion of lists of GfVec2f to std::vector<GfVec2f>
515 TfPyContainerConversions::from_python_sequence<
516 std::vector<GfVec2f>,
517 TfPyContainerConversions::variable_capacity_policy >();
518 }
519