Developer Documentation

PythonTypeConversions.hh
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42 #include <pybind11/include/pybind11/pybind11.h>
43 #include <pybind11/include/pybind11/numpy.h>
44 #include <OpenFlipper/common/UpdateType.hh>
45 #include <QString>
46
47 namespace py = pybind11;
48
49 namespace pybind11 { namespace detail {
50 template <> struct type_caster<QString> {
51 public:
57 PYBIND11_TYPE_CASTER(QString, _("str"));
58
64 bool load(handle src, bool ) {
65
66 /* Extract PyObject from handle */
67 PyObject *source = src.ptr();
68
69 if (!PyUnicode_Check(source))
70 return false;
71
72 Py_ssize_t size;
73 const char *ptr = PyUnicode_AsUTF8AndSize(source, &size);
74
75 if (!ptr) {
76 return false;
77 }
78
79 /* Now try to convert into a C++ int */
80 value = QString::fromUtf8(ptr, size);
81
82 /* Ensure return code was OK (to avoid out-of-range errors etc) */
83 return ( !PyErr_Occurred() );
84 }
85
93 static handle cast(QString src, return_value_policy /* policy */, handle /* parent */) {
94 return (PyUnicode_FromString( src.toUtf8().data()) );
95 }
96 };
97 }} // namespace pybind11::detail
98
116 namespace pybind11 { namespace detail {
117 template <> struct type_caster<Vector> {
118 public:
124 PYBIND11_TYPE_CASTER(Vector, _("Vector"));
125
131 bool load(handle src, bool convert ) {
132
133 /* Extract PyObject from handle */
134 PyObject* source = src.ptr();
135
136 if ( PyList_Check(source) ) {
137
138 if ( PyList_Size(source) != 3) {
139 PyErr_SetString(PyExc_RuntimeError, "Vector Conversion: List size should be 3!");
140 throw py::error_already_set();
141 return false;
142 }
143
144 /* Now try to convert into a C++ int */
145 value = Vector(PyFloat_AsDouble(PyList_GetItem(source,0)),PyFloat_AsDouble(PyList_GetItem(source,1)),PyFloat_AsDouble(PyList_GetItem(source,2)));
146
147 } else if ( PyTuple_Check(source) ) {
148 if ( PyTuple_Size(source) != 3) {
149 PyErr_SetString(PyExc_RuntimeError, "Vector Conversion: Tuple size should be 3!");
150 throw py::error_already_set();
151 return false;
152 }
153
154 /* Now try to convert into a C++ int */
155 value = Vector(PyFloat_AsDouble(PyTuple_GetItem(source,0)),PyFloat_AsDouble(PyTuple_GetItem(source,1)),PyFloat_AsDouble(PyTuple_GetItem(source,2)));
156
157 } else if ( py::cast<py::array>(source) ) {
158
159 py::array array = py::cast<py::array>(source);
160
161 if ( array.size() != 3) {
162 PyErr_SetString(PyExc_RuntimeError, "Vector Conversion: Numpy Array size should be 3!");
163 throw py::error_already_set();
164 return false;
165 }
166
167 if (!convert && !py::array_t<double>::check_(src)) {
168 PyErr_SetString(PyExc_RuntimeError, "Vector Conversion: Numpy Array, wrong dtype, conversion disabled");
169 return false;
170 }
171
172 auto buf = py::array_t<double, py::array::c_style | py::array::forcecast>::ensure(src);
173
174 if (!buf) {
175 PyErr_SetString(PyExc_RuntimeError, "Vector Conversion: Numpy Array, conversion failed.");
176 return false;
177 }
178 if (buf.ndim() != 1 || buf.size() != 3) {
179 PyErr_SetString(PyExc_RuntimeError, "Vector Conversion: Numpy Array dimension or size error. Dimension should be one, size 3!");
180 return false;
181 }
182
183 value = Vector(buf.data());
184 return true;
185
186 } else {
187 PyErr_SetString(PyExc_RuntimeError, "Vector Conversion: Not a list or a tuple or a numpy array.");
188 throw py::error_already_set();
189 return false;
190 }
191
192 /* Ensure return code was OK (to avoid out-of-range errors etc) */
193 return ( !PyErr_Occurred() );
194 }
195
203 static handle cast(Vector src, return_value_policy /* policy */, handle parent ) {
204 // Create numpy array
205 py::array a(3, src.data());
206 return a.release();
207 }
208 };
209 }} // namespace pybind11::detail
210
229 namespace pybind11 { namespace detail {
230 template <> struct type_caster<Matrix4x4> {
231 public:
237 PYBIND11_TYPE_CASTER(Matrix4x4, _("Matrix4x4"));
238
244 bool load(handle src, bool convert ) {
245
246 /* Extract PyObject from handle */
247 PyObject* source = src.ptr();
248
249 if ( PyList_Check(source) ) {
250
251 if ( PyList_Size(source) != 16) {
252 PyErr_SetString(PyExc_RuntimeError, "Matrix4x4 Conversion: List size should be 16!");
253 throw py::error_already_set();
254 return false;
255 }
256
257 double convert[16] = { PyFloat_AsDouble(PyList_GetItem(source,0)),
258 PyFloat_AsDouble(PyList_GetItem(source,1)),
259 PyFloat_AsDouble(PyList_GetItem(source,2)),
260 PyFloat_AsDouble(PyList_GetItem(source,3)),
261 PyFloat_AsDouble(PyList_GetItem(source,4)),
262 PyFloat_AsDouble(PyList_GetItem(source,5)),
263 PyFloat_AsDouble(PyList_GetItem(source,6)),
264 PyFloat_AsDouble(PyList_GetItem(source,7)),
265 PyFloat_AsDouble(PyList_GetItem(source,8)),
266 PyFloat_AsDouble(PyList_GetItem(source,9)),
267 PyFloat_AsDouble(PyList_GetItem(source,0)),
268 PyFloat_AsDouble(PyList_GetItem(source,11)),
269 PyFloat_AsDouble(PyList_GetItem(source,12)),
270 PyFloat_AsDouble(PyList_GetItem(source,13)),
271 PyFloat_AsDouble(PyList_GetItem(source,14)),
272 PyFloat_AsDouble(PyList_GetItem(source,15))};
273
274 /* Now convert into a C++ Matrix4x4 */
275 value = Matrix4x4(convert);
276
277 } else if ( PyTuple_Check(source) ) {
278 if ( PyTuple_Size(source) != 16) {
279 PyErr_SetString(PyExc_RuntimeError, "Matrix4x4 Conversion: Tuple size should be 3!");
280 throw py::error_already_set();
281 return false;
282 }
283
284 double convert[16] = { PyFloat_AsDouble(PyTuple_GetItem(source,0)),
285 PyFloat_AsDouble(PyTuple_GetItem(source,1)),
286 PyFloat_AsDouble(PyTuple_GetItem(source,2)),
287 PyFloat_AsDouble(PyTuple_GetItem(source,3)),
288 PyFloat_AsDouble(PyTuple_GetItem(source,4)),
289 PyFloat_AsDouble(PyTuple_GetItem(source,5)),
290 PyFloat_AsDouble(PyTuple_GetItem(source,6)),
291 PyFloat_AsDouble(PyTuple_GetItem(source,7)),
292 PyFloat_AsDouble(PyTuple_GetItem(source,8)),
293 PyFloat_AsDouble(PyTuple_GetItem(source,9)),
294 PyFloat_AsDouble(PyTuple_GetItem(source,10)),
295 PyFloat_AsDouble(PyTuple_GetItem(source,11)),
296 PyFloat_AsDouble(PyTuple_GetItem(source,12)),
297 PyFloat_AsDouble(PyTuple_GetItem(source,13)),
298 PyFloat_AsDouble(PyTuple_GetItem(source,14)),
299 PyFloat_AsDouble(PyTuple_GetItem(source,15))};
300
301 /* Now convert into a C++ Matrix4x4 */
302 value = Matrix4x4(convert);
303
304 } else if ( py::cast<py::array>(source) ) {
305
306 py::array array = py::cast<py::array>(source);
307
308 if ( array.size() != 16) {
309 PyErr_SetString(PyExc_RuntimeError, "Matrix4x4 Conversion: Numpy Array size should be 16!");
310 throw py::error_already_set();
311 return false;
312 }
313
314 if (!convert && !py::array_t<double>::check_(src)) {
315 PyErr_SetString(PyExc_RuntimeError, "Matrix4x4 Conversion: Numpy Array, wrong dtype, conversion disabled");
316 return false;
317 }
318
319 auto buf = py::array_t<double, py::array::c_style | py::array::forcecast>::ensure(src);
320
321 if (!buf) {
322 PyErr_SetString(PyExc_RuntimeError, "Matrix4x4 Conversion: Numpy Array, conversion failed.");
323 return false;
324 }
325
326 // Check Dimension : Matrix has 2 dimensions
327 // Check buffer size : 4x4 -> 16 entries
328 // Check shape : 2 dimensions, each has size 4
329 if (buf.ndim() != 2 || buf.size() != 16 || buf.shape()[0] !=4 || buf.shape()[1] !=4) {
330 PyErr_SetString(PyExc_RuntimeError, "Matrix4x4 Conversion: Numpy Array dimension or size error. Dimension should be four, size 16, and shape 4x4!");
331 return false;
332 }
333
334 value = Matrix4x4(buf.data());
335 return true;
336
337 } else {
338 PyErr_SetString(PyExc_RuntimeError, "Matrix4x4 Conversion: Not a list or a tuple or a numpy array.");
339 throw py::error_already_set();
340 return false;
341 }
342
343 /* Ensure return code was OK (to avoid out-of-range errors etc) */
344 return ( !PyErr_Occurred() );
345 }
346
354 static handle cast(Matrix4x4 src, return_value_policy /* policy */, handle parent ) {
355 // Create numpy array
356 py::array a({4,4}, src.data());
357 return a.release();
358 }
359 };
360 }} // namespace pybind11::detail
361
362
379 namespace pybind11 { namespace detail {
380 template <> struct type_caster<IdList> {
381 public:
387 PYBIND11_TYPE_CASTER(IdList, _("IdList"));
388
394 bool load(handle src, bool convert ) {
395
396 /* Extract PyObject from handle */
397 PyObject* source = src.ptr();
398
399 if ( PyList_Check(source) ) {
400
401 const auto size = PyList_Size(source);
402
403 value.resize(size);
404
405 for ( auto i = 0 ; i < size ; ++i ) {
406 value[i] = static_cast<int>(PyLong_AsLong(PyList_GET_ITEM(source,i)));
407 }
408
409 } else if ( PyTuple_Check(source) ) {
410
411 const auto size = PyTuple_Size(source);
412
413 value.resize(size);
414
415 for ( auto i = 0 ; i < size ; ++i ) {
416 value[i] = static_cast<int>(PyLong_AsLong(PyTuple_GET_ITEM(source,i)));
417 }
418
419 } else if ( py::cast<py::array>(source) ) {
420
421 py::array array = py::cast<py::array>(source);
422
423 if ( array.ndim() != 1) {
424 PyErr_SetString(PyExc_RuntimeError, "IdList Conversion: Numpy Array dimension should be one!");
425 throw py::error_already_set();
426 return false;
427 }
428
429 auto buf = py::array_t<int, py::array::c_style | py::array::forcecast>::ensure(src);
430
431 if (!buf) {
432 PyErr_SetString(PyExc_RuntimeError, "IdList Conversion: Numpy Array, conversion failed.");
433 return false;
434 }
435
436 std::cerr << "Buffer size : " << buf.size() << std::endl;
437
438 value.resize(buf.size());
439 for ( auto i = 0 ; i < buf.size() ; ++i ) {
440 value[i] = *buf.data(i) ;
441 }
442
443 return true;
444
445 } else {
446 PyErr_SetString(PyExc_RuntimeError, "Vector Conversion: Not a list or a tuple or a numpy array.");
447 throw py::error_already_set();
448 return false;
449 }
450
451 /* Ensure return code was OK (to avoid out-of-range errors etc) */
452 return ( !PyErr_Occurred() );
453 }
454
462 static handle cast(IdList src, return_value_policy /* policy */, handle parent ) {
463 // Create numpy array
464 py::array a(src.size(), src.data());
465 return a.release();
466 }
467 };
468 }} // namespace pybind11::detail
469
498 namespace pybind11 { namespace detail {
499 template <> struct type_caster<UpdateType> {
500 public:
506 PYBIND11_TYPE_CASTER(UpdateType, _("UpdateType"));
507
513 bool load(handle src, bool ) {
514
515 /* Extract PyObject from handle */
516 PyObject *source = src.ptr();
517
518 if (!PyUnicode_Check(source))
519 return false;
520
521 Py_ssize_t size;
522 const char *ptr = PyUnicode_AsUTF8AndSize(source, &size);
523
524 if (!ptr) {
525 return false;
526 }
527
528 QString updateString = QString::fromUtf8(ptr, size);
529
530 if ( updateString.contains("UPDATE_ALL") ) {
531 std::cerr << "Update_ALL" << std::endl;
532 value = UPDATE_ALL;
533
534 return true;
535 }
536
537
538 if ( updateString.contains("All") ) {
539 std::cerr << "Update_ALL" << std::endl;
540 value = UPDATE_ALL;
541
542 return true;
543 }
544
545 UpdateType type;
546
547 QStringList updateList = updateString.split(";");
548
549 for ( auto i = 0 ; i < updateList.size() ; ++i ) {
550 type |= updateType(updateList[i]);
551 std::cerr << "Update " << updateList[i].toStdString() << std::endl;
552 }
553
554 value = type;
555
556 /* Ensure return code was OK (to avoid out-of-range errors etc) */
557 return ( !PyErr_Occurred() );
558 }
559
567 static handle cast(UpdateType src, return_value_policy /* policy */, handle /* parent */) {
568 return (PyUnicode_FromString( updateTypeName(src).toUtf8().data()) );
569 }
570 };
571 }} // namespace pybind11::detail
572
573
574
606 namespace pybind11 { namespace detail {
607 template <> struct type_caster<DataType> {
608 public:
614 PYBIND11_TYPE_CASTER(DataType, _("DataType"));
615
621 bool load(handle src, bool ) {
622
623 /* Extract PyObject from handle */
624 PyObject *source = src.ptr();
625
626 if (!PyUnicode_Check(source))
627 return false;
628
629 Py_ssize_t size;
630 const char *ptr = PyUnicode_AsUTF8AndSize(source, &size);
631
632 if (!ptr) {
633 return false;
634 }
635
636 QString typeString = QString::fromUtf8(ptr, size);
637
638 value = typeId(typeString);
639
640 /* Ensure return code was OK (to avoid out-of-range errors etc) */
641 return ( !PyErr_Occurred() );
642 }
643
651 static handle cast(DataType src, return_value_policy /* policy */, handle /* parent */) {
652 return (PyUnicode_FromString( typeName(src).toUtf8().data()) );
653 }
654 };
655 }} // namespace pybind11::detail
656
657
658
pybind11::detail::type_caster< Vector >::cast
static handle cast(Vector src, return_value_policy, handle parent)
Definition: PythonTypeConversions.hh:203
UpdateType
Update type class.
Definition: UpdateType.hh:60
UPDATE_ALL
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
Matrix4x4
ACG::Matrix4x4d Matrix4x4
Standard Type for a 4x4 Matrix used for scripting.
Definition: DataTypes.hh:181
typeName
DLLEXPORT QString typeName(DataType _id)
Get the name of a type with given id.
Definition: Types.cc:154
pybind11::detail::type_caster< Vector >::load
bool load(handle src, bool convert)
Definition: PythonTypeConversions.hh:131
pybind11::detail::type_caster< IdList >::load
bool load(handle src, bool convert)
Definition: PythonTypeConversions.hh:394
pybind11
Definition: PythonTypeConversions.hh:49
pybind11::detail::type_caster< QString >::cast
static handle cast(QString src, return_value_policy, handle)
Definition: PythonTypeConversions.hh:93
OpenMesh::VectorT::data
Scalar * data()
access to Scalar array
Definition: Vector11T.hh:195
IdList
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:179
pybind11::detail::type_caster< IdList >::cast
static handle cast(IdList src, return_value_policy, handle parent)
Definition: PythonTypeConversions.hh:462
pybind11::detail::type_caster< DataType >::load
bool load(handle src, bool)
Definition: PythonTypeConversions.hh:621
ACG::Matrix4x4T< double >
DataType
Predefined datatypes.
Definition: DataTypes.hh:83
updateTypeName
QString updateTypeName(UpdateType _id)
Get the name of a type with given id.
Definition: UpdateType.cc:267
updateType
UpdateType updateType(QString _name)
Get the id of a type with given name.
Definition: UpdateType.cc:252
OpenMesh::VectorT
Definition: Vector11T.hh:83
Vector
ACG::Vec3d Vector
Standard Type for 3d Vector used for scripting.
Definition: DataTypes.hh:174
pybind11::detail::type_caster< Matrix4x4 >::cast
static handle cast(Matrix4x4 src, return_value_policy, handle parent)
Definition: PythonTypeConversions.hh:354
pybind11::detail::type_caster< Matrix4x4 >::load
bool load(handle src, bool convert)
Definition: PythonTypeConversions.hh:244
pybind11::detail::type_caster< UpdateType >::load
bool load(handle src, bool)
Definition: PythonTypeConversions.hh:513
typeId
DLLEXPORT DataType typeId(QString _name)
Given a dataType Identifier string this function will return the id of the datatype.
Definition: Types.cc:139
pybind11::detail::type_caster< DataType >::cast
static handle cast(DataType src, return_value_policy, handle)
Definition: PythonTypeConversions.hh:651
pybind11::detail::type_caster< QString >::load
bool load(handle src, bool)
Definition: PythonTypeConversions.hh:64
pybind11::detail::type_caster< UpdateType >::cast
static handle cast(UpdateType src, return_value_policy, handle)
Definition: PythonTypeConversions.hh:567