aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2021-04-16 09:46:28 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2021-04-21 13:20:08 +0200
commitdb52b6e6ec926f48679d091f7afa42f514b5e71c (patch)
treeab1a07975038ddc642e2911905f7965a600ff9d4 /sources
parent4cde4075f97fc9f8d349591291289127666b35e5 (diff)
libpyside: Add helpers for numpy
Add utility functions for converting numpy vectors containing x,y data to list of QPoint, QPointF, respectively along with helpers for type checking and initialization. Task-number: PYSIDE-1540 Task-number: PYSIDE-1503 Change-Id: Idde5084434a36ec31eb87bf65dec3d637cff728b Reviewed-by: Christian Tismer <tismer@stackless.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'sources')
-rw-r--r--sources/pyside6/libpyside/CMakeLists.txt7
-rw-r--r--sources/pyside6/libpyside/pyside.cpp2
-rw-r--r--sources/pyside6/libpyside/pyside_numpy.cpp191
-rw-r--r--sources/pyside6/libpyside/pyside_numpy.h89
4 files changed, 289 insertions, 0 deletions
diff --git a/sources/pyside6/libpyside/CMakeLists.txt b/sources/pyside6/libpyside/CMakeLists.txt
index 50cc3108f..78be0c082 100644
--- a/sources/pyside6/libpyside/CMakeLists.txt
+++ b/sources/pyside6/libpyside/CMakeLists.txt
@@ -53,6 +53,7 @@ set(libpyside_SRC
pysideqflags.cpp
pysideweakref.cpp
pyside.cpp
+ pyside_numpy.cpp
pysidestaticstrings.cpp
)
@@ -94,6 +95,12 @@ target_include_directories(pyside6 PUBLIC
$<INSTALL_INTERFACE:include/PySide6>
)
+if (NOT "${NUMPY_INCLUDE_DIR}" STREQUAL "")
+ target_include_directories(pyside6 PRIVATE ${NUMPY_INCLUDE_DIR})
+ target_compile_definitions(pyside6 PRIVATE -DHAVE_NUMPY
+ PRIVATE -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION)
+endif()
+
target_link_libraries(pyside6
PRIVATE Shiboken6::libshiboken
PRIVATE ${QML_LIBRARIES}
diff --git a/sources/pyside6/libpyside/pyside.cpp b/sources/pyside6/libpyside/pyside.cpp
index 80f0e1b7e..7efe49b68 100644
--- a/sources/pyside6/libpyside/pyside.cpp
+++ b/sources/pyside6/libpyside/pyside.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "pyside.h"
+#include "pyside_numpy.h"
#include "pyside_p.h"
#include "signalmanager.h"
#include "pysideclassinfo_p.h"
@@ -86,6 +87,7 @@ namespace PySide
void init(PyObject *module)
{
qobjectNextAddr = nullptr;
+ Numpy::init();
ClassInfo::init(module);
Signal::init(module);
Slot::init(module);
diff --git a/sources/pyside6/libpyside/pyside_numpy.cpp b/sources/pyside6/libpyside/pyside_numpy.cpp
new file mode 100644
index 000000000..344137b4c
--- /dev/null
+++ b/sources/pyside6/libpyside/pyside_numpy.cpp
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifdef HAVE_NUMPY
+// Include numpy first to get the proper PyArray_Check
+# include <numpy/arrayobject.h>
+# include "pyside_numpy.h"
+
+// Convert X,Y of type T data to a list of points (QPoint, PointF)
+template <class T, class Point>
+static QList<Point>
+ xyDataToQPointHelper(PyArrayObject *pyX, PyArrayObject *pyY,
+ qsizetype size)
+{
+ auto *x = reinterpret_cast<const T *>(PyArray_DATA(pyX));
+ auto *y = reinterpret_cast<const T *>(PyArray_DATA(pyY));
+ QList<Point> result;
+ result.reserve(size);
+ for (auto xEnd = x + size; x < xEnd; ++x, ++y)
+ result.append(Point(*x, *y));
+ return result;
+}
+
+// Convert X,Y of double/float type data to a list of QPoint (rounding)
+template <class T>
+static QList<QPoint>
+ xyFloatDataToQPointHelper(PyArrayObject *pyX, PyArrayObject *pyY,
+ qsizetype size)
+{
+ auto *x = reinterpret_cast<const T *>(PyArray_DATA(pyX));
+ auto *y = reinterpret_cast<const T *>(PyArray_DATA(pyY));
+ QList<QPoint> result;
+ result.reserve(size);
+ for (auto xEnd = x + size; x < xEnd; ++x, ++y)
+ result.append(QPoint(qRound(*x), qRound(*y)));
+ return result;
+}
+
+
+namespace PySide::Numpy
+{
+
+bool init()
+{
+ import_array1(false);
+ return true;
+}
+
+bool check(PyObject *pyIn)
+{
+ return PyArray_Check(pyIn);
+}
+
+struct XyCheck
+{
+ qsizetype size;
+ int numpytype;
+};
+
+// Check whether pyXIn and pyYIn are 1 dimensional vectors of the same size.
+// Return -1, -1 on failure.
+static XyCheck checkXyData(PyArrayObject *pyX, PyArrayObject *pyY)
+{
+ XyCheck result{-1, -1};
+ if (PyArray_NDIM(pyX) != 1 || (PyArray_FLAGS(pyX) & NPY_ARRAY_C_CONTIGUOUS) == 0)
+ return result;
+ if (PyArray_NDIM(pyY) != 1 || (PyArray_FLAGS(pyY) & NPY_ARRAY_C_CONTIGUOUS) == 0)
+ return result;
+ const int xType = PyArray_TYPE(pyX);
+ const int yType = PyArray_TYPE(pyY);
+ if (xType != yType)
+ return result;
+ result.numpytype = xType;
+ result.size = qMin(PyArray_DIMS(pyX)[0], PyArray_DIMS(pyY)[0]);
+ return result;
+}
+
+QList<QPointF> xyDataToQPointFList(PyObject *pyXIn, PyObject *pyYIn)
+{
+ auto *pyX = reinterpret_cast<PyArrayObject *>(pyXIn);
+ auto *pyY = reinterpret_cast<PyArrayObject *>(pyYIn);
+ XyCheck check = checkXyData(pyX, pyY);
+ if (check.size <= 0)
+ return {};
+ switch (check.numpytype) {
+ case NPY_INT:
+ return xyDataToQPointHelper<int, QPointF>(pyX, pyY, check.size);
+ case NPY_UINT:
+ return xyDataToQPointHelper<unsigned, QPointF>(pyX, pyY, check.size);
+ case NPY_FLOAT:
+ return xyDataToQPointHelper<float, QPointF>(pyX, pyY, check.size);
+ case NPY_DOUBLE:
+ return xyDataToQPointHelper<double, QPointF>(pyX, pyY, check.size);
+ default:
+ break;
+ }
+ return {};
+}
+
+QList<QPoint> xyDataToQPointList(PyObject *pyXIn, PyObject *pyYIn)
+{
+ auto *pyX = reinterpret_cast<PyArrayObject *>(pyXIn);
+ auto *pyY = reinterpret_cast<PyArrayObject *>(pyYIn);
+ XyCheck check = checkXyData(pyX, pyY);
+ if (check.size <= 0)
+ return {};
+ switch (check.numpytype) {
+ case NPY_INT:
+ return xyDataToQPointHelper<int, QPoint>(pyX, pyY, check.size);
+ case NPY_UINT:
+ return xyDataToQPointHelper<unsigned, QPoint>(pyX, pyY, check.size);
+ case NPY_FLOAT:
+ return xyFloatDataToQPointHelper<float>(pyX, pyY, check.size);
+ case NPY_DOUBLE:
+ return xyFloatDataToQPointHelper<double>(pyX, pyY, check.size);
+ default:
+ break;
+ }
+
+ return {};
+}
+
+} //namespace PySide::Numpy
+
+#else // HAVE_NUMPY
+# include "pyside_numpy.h"
+namespace PySide::Numpy
+{
+
+bool init()
+{
+ return true;
+}
+
+bool check(PyObject *)
+{
+ return false;
+}
+
+QList<QPointF> xyDataToQPointFList(PyObject *, PyObject *)
+{
+ qWarning("Unimplemented function %s, (numpy was not found).", __FUNCTION__);
+ return {};
+}
+
+QList<QPoint> xyDataToQPointList(PyObject *, PyObject *)
+{
+ qWarning("Unimplemented function %s, (numpy was not found).", __FUNCTION__);
+ return {};
+}
+
+} //namespace PySide::Numpy
+
+#endif // !HAVE_NUMPY
diff --git a/sources/pyside6/libpyside/pyside_numpy.h b/sources/pyside6/libpyside/pyside_numpy.h
new file mode 100644
index 000000000..158865c1d
--- /dev/null
+++ b/sources/pyside6/libpyside/pyside_numpy.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PYSIDE_NUMPY_H
+#define PYSIDE_NUMPY_H
+
+#include <sbkpython.h>
+
+#include <pysidemacros.h>
+
+#include <QtCore/QList>
+#include <QtCore/QPoint>
+#include <QtCore/QPointF>
+
+// This header provides a PyArray_Check() definition that can be used to avoid
+// having to include the numpy headers. When using numpy headers, make sure
+// to include this header after them to skip the definition. Also remember
+// that import_array() must then be called to initialize numpy.
+
+namespace PySide::Numpy
+{
+
+bool init();
+
+/// Check whether the object is a PyArrayObject
+/// \param pyIn object
+/// \return Whether it is a PyArrayObject
+PYSIDE_API bool check(PyObject *pyIn);
+
+/// Create a list of QPointF from 2 equally sized numpy array of x and y data
+/// (float,double).
+/// \param pyXIn X data array
+/// \param pyYIn Y data array
+/// \return List of QPointF
+
+PYSIDE_API QList<QPointF> xyDataToQPointFList(PyObject *pyXIn, PyObject *pyYIn);
+
+/// Create a list of QPoint from 2 equally sized numpy array of x and y data
+/// (int).
+/// \param pyXIn X data array
+/// \param pyYIn Y data array
+/// \return List of QPoint
+
+PYSIDE_API QList<QPoint> xyDataToQPointList(PyObject *pyXIn, PyObject *pyYIn);
+
+
+} //namespace PySide::Numpy
+
+#ifndef PyArray_Check
+# define PyArray_Check(op) PySide::Numpy::check(op)
+#endif
+
+#endif // PYSIDE_NUMPY_H