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 
static handle cast(Vector src, return_value_policy, handle parent)
Update type class.
Definition: UpdateType.hh:60
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
ACG::Matrix4x4d Matrix4x4
Standard Type for a 4x4 Matrix used for scripting.
Definition: DataTypes.hh:181
DLLEXPORT QString typeName(DataType _id)
Get the name of a type with given id.
Definition: Types.cc:154
static handle cast(QString src, return_value_policy, handle)
Scalar * data()
access to Scalar array
Definition: Vector11T.hh:195
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:179
static handle cast(IdList src, return_value_policy, handle parent)
Predefined datatypes.
Definition: DataTypes.hh:83
QString updateTypeName(UpdateType _id)
Get the name of a type with given id.
Definition: UpdateType.cc:267
UpdateType updateType(QString _name)
Get the id of a type with given name.
Definition: UpdateType.cc:252
ACG::Vec3d Vector
Standard Type for 3d Vector used for scripting.
Definition: DataTypes.hh:174
static handle cast(Matrix4x4 src, return_value_policy, handle parent)
DLLEXPORT DataType typeId(QString _name)
Given a dataType Identifier string this function will return the id of the datatype.
Definition: Types.cc:139
static handle cast(DataType src, return_value_policy, handle)
static handle cast(UpdateType src, return_value_policy, handle)