From 92c0acc9a0222e74e1fdf18249e51ed41112355c Mon Sep 17 00:00:00 2001 From: tmontaigu Date: Sun, 24 Nov 2024 18:22:55 +0100 Subject: [PATCH] Adapt to sf changes --- wrapper/cccorelib/src/GenericDistribution.cpp | 2 - wrapper/cccorelib/src/ScalarField.cpp | 191 +++++++++++++++++- wrapper/cccorelib/src/wrappers.h | 4 +- wrapper/pycc/src/qcc_db/cc2DLabel.cpp | 1 + wrapper/pycc/src/qcc_db/ccGLMatrix.cpp | 4 +- wrapper/pycc/src/qcc_db/ccScalarField.cpp | 4 +- 6 files changed, 185 insertions(+), 21 deletions(-) diff --git a/wrapper/cccorelib/src/GenericDistribution.cpp b/wrapper/cccorelib/src/GenericDistribution.cpp index f30dbcb6..5cea5bda 100644 --- a/wrapper/cccorelib/src/GenericDistribution.cpp +++ b/wrapper/cccorelib/src/GenericDistribution.cpp @@ -51,6 +51,4 @@ void define_GenericDistribution(py::module &cccorelib) "Yk"_a, "numberOfClasses"_a, "histo"_a = nullptr); - - py::bind_vector(GenericDistribution, "ScalarContainer"); } diff --git a/wrapper/cccorelib/src/ScalarField.cpp b/wrapper/cccorelib/src/ScalarField.cpp index 313f9a3e..614dfa3d 100644 --- a/wrapper/cccorelib/src/ScalarField.cpp +++ b/wrapper/cccorelib/src/ScalarField.cpp @@ -21,12 +21,143 @@ #include "wrappers.h" #include +#include namespace py = pybind11; using namespace pybind11::literals; +class ScalarFieldView +{ + public: + explicit ScalarFieldView(CCCoreLib::ScalarField &field) + : m_field(field), m_start(0), m_stop(field.currentSize()), m_step(1), m_len(field.currentSize()) + { + } + + explicit ScalarFieldView(const ScalarFieldView view, const py::slice &slice) : ScalarFieldView(view) + { + applySlicing(slice); + } + + explicit ScalarFieldView(CCCoreLib::ScalarField &field, const py::slice &slice) : ScalarFieldView(field) + { + } + + py::object get_item(const py::object &index) + { + if (py::isinstance(index)) + { + return py::cast(m_field.getValue((index.cast() * m_step) + m_start)); + } + + if (py::isinstance(index)) + { + const auto slice = index.cast(); + return py::cast(ScalarFieldView(m_field, slice)); + } + + if (py::isinstance(index)) + { + const auto sequence = index.cast(); + py::array_t result(sequence.size()); + auto setter = result.mutable_unchecked<1>(); + for (size_t i = 0; i < sequence.size(); ++i) + { + setter[i] = m_field.getValue((sequence[i].cast() * m_step) + m_start); + } + return result; + } + } + + void set_item(const py::object &index, const py::object &value) + { + if (py::isinstance(index)) + { + m_field.setValue(index.cast() + m_start, value.cast()); + return; + } + + if (py::isinstance(index)) + { + const auto slice = index.cast(); + + // view[some_slice] = some_unique_value + if (py::isinstance(value) || py::isinstance(value)) + { + const auto floatValue = value.cast(); + for (size_t i = 0; i < m_len; ++i) + { + m_field.setValue((i * m_step) + m_start, floatValue); + } + return; + } + + const auto sequence = value.cast(); + if (sequence.size() != m_len) + { + throw py::index_error("Incorrect number of new values"); + } + + for (size_t i = 0; i < m_len; ++i) + { + m_field.setValue((i * m_step) + m_start, sequence[i].cast()); + } + + return; + } + + if (py::isinstance(index)) + { + const auto sequence = index.cast(); + + // view[some_sequence] = some_unique_value + if (py::isinstance(value) || py::isinstance(value)) + { + const auto floatValue = value.cast(); + for (size_t i = 0; i < m_len; ++i) + { + m_field.setValue((i * m_step) + m_start, floatValue); + } + return; + } + if (sequence.size() != m_len) + { + throw py::index_error("Incorrect number of new values"); + } + + for (size_t i = 0; i < m_len; ++i) + { + m_field.setValue((i * m_step) + m_start, sequence[i].cast()); + } + } + } + + void applySlicing(const py::slice &slice) + { + size_t start, stop, step, len = 0; + if (!slice.compute(m_len, &start, &stop, &step, &len)) + { + throw py::index_error(); + } + + m_len = len; + m_start += start; + m_stop = stop; + m_step += step; + } + + private: + CCCoreLib::ScalarField &m_field; + size_t m_start; + size_t m_stop; + size_t m_step; + size_t m_len; +}; + void define_ScalarField(py::module &cccorelib) { + py::class_(cccorelib, "ScalarFieldView").def("__getitem__", &ScalarFieldView::get_item); + py::class_>(cccorelib, "ScalarField", R"doc( @@ -89,7 +220,7 @@ void define_ScalarField(py::module &cccorelib) 'name' )doc") .def("size", - &CCCoreLib::ScalarField::size, + &CCCoreLib::ScalarField::currentSize, "Returns the number of elements (values) in the scalar field") .def("computeMeanAndVariance", &CCCoreLib::ScalarField::computeMeanAndVariance, @@ -117,7 +248,11 @@ void define_ScalarField(py::module &cccorelib) &CCCoreLib::ScalarField::fill, "fillValue"_a = 0, "Fills the scalar field with the given value") - .def("reserve", &CCCoreLib::ScalarField::reserve, "count"_a, R"doc( + .def( + "reserve", + [](CCCoreLib::ScalarField &field, const size_t size) { field.reserve(size); }, + "count"_a, + R"doc( Reserves space for ``count`` element, but does not change the size. Will raise an exception if allocation failed @@ -132,10 +267,10 @@ void define_ScalarField(py::module &cccorelib) )doc") .def( "resize", - [](CCCoreLib::ScalarField &self, size_t count, ScalarType valueForNewElements) + [](CCCoreLib::ScalarField &self, const size_t count, const ScalarType valueForNewElements) { // pybind11 will convert exceptions - self.resize(count, valueForNewElements); + self.resizeSafe(count, true /* always init values */, valueForNewElements); }, "count"_a, "valueForNewElements"_a = 0, @@ -158,8 +293,7 @@ void define_ScalarField(py::module &cccorelib) Prefer use of :meth:`cccorelib.ScalarField.resize`. )doc") .def("getValue", - static_cast( - &CCCoreLib::ScalarField::getValue), + &CCCoreLib::ScalarField::getValue, "index"_a, R"doc( Returns the value at the given index. @@ -198,7 +332,7 @@ void define_ScalarField(py::module &cccorelib) )doc") .def( "asArray", - [](CCCoreLib::ScalarField &self) { return PyCC::VectorAsNumpyArray(self); }, + [](CCCoreLib::ScalarField &self) { return ScalarFieldView(self); }, R"doc( Returns the scalar field viewed as a numpy array. @@ -221,10 +355,45 @@ void define_ScalarField(py::module &cccorelib) array[:] = 2.0 assert scalar_field[0] == 2.0 )doc") - .def("__getitem__", - static_cast( - &CCCoreLib::ScalarField::getValue)) - .def("__setitem__", &CCCoreLib::ScalarField::setValue) + .def( + "__getitem__", + [](CCCoreLib::ScalarField &self, const py::object &index) + { return ScalarFieldView(self).get_item(index); }, + py::return_value_policy::reference_internal) + .def( + "toArray", + [](const CCCoreLib::ScalarField &self) + { + py::array_t copy(self.currentSize()); + auto access = copy.mutable_unchecked<1>(); + for (size_t i = 0; i < self.currentSize(); ++i) + { + access[i] = self.getValue(i); + } + return copy; + }, + R"doc( + Copies the content into an array +)doc") + .def( + "__array__", + [](const CCCoreLib::ScalarField &self) + { + // TODO this is a copy-paste from toArray, should only have 1 definition of this + py::array_t copy(self.currentSize()); + auto access = copy.mutable_unchecked<1>(); + for (size_t i = 0; i < self.currentSize(); ++i) + { + access[i] = self.getValue(i); + } + return copy; + }, + R"doc( + Copies the content into an array +)doc") + .def("__setitem__", + [](CCCoreLib::ScalarField &self, const py::object &index, const py::object &value) + { return ScalarFieldView(self).set_item(index, value); }) .def("__repr__", [](const CCCoreLib::ScalarField &self) { return std::string(""; }); diff --git a/wrapper/cccorelib/src/wrappers.h b/wrapper/cccorelib/src/wrappers.h index 7729480c..31ba997b 100644 --- a/wrapper/cccorelib/src/wrappers.h +++ b/wrapper/cccorelib/src/wrappers.h @@ -112,7 +112,7 @@ void addPointsFromArrays(PointCloudType &self, throw py::value_error("xs, ys, zs must have the same size"); } - py::ssize_t numToReserve = self.size() + xs.size(); + const py::ssize_t numToReserve = self.size() + xs.size(); if (numToReserve > std::numeric_limits::max()) { throw std::out_of_range(std::to_string(numToReserve) + " cannot be casted to unsigned int"); @@ -258,7 +258,7 @@ static const constexpr char SIZE_SCALAR_FIELD_DOCSTRING[] = R"doc( CCCoreLib::ScalarField *sf = self.getScalarField(idx); \ for (py::ssize_t i{0}; i < values.size(); ++i) \ { \ - (*sf)[i] = values_u(i); \ + sf->setValue(i, values_u(i)); \ } \ } \ return idx; \ diff --git a/wrapper/pycc/src/qcc_db/cc2DLabel.cpp b/wrapper/pycc/src/qcc_db/cc2DLabel.cpp index ca21e7a0..cc94a0d0 100644 --- a/wrapper/pycc/src/qcc_db/cc2DLabel.cpp +++ b/wrapper/pycc/src/qcc_db/cc2DLabel.cpp @@ -65,6 +65,7 @@ void define_cc2DLabel(py::module &m) Pycc2DLabel.def("isPointLegendDisplayed", &cc2DLabel::isPointLegendDisplayed); Pycc2DLabel.def("setDisplayedIn2D", &cc2DLabel::setDisplayedIn2D, "state"_a); Pycc2DLabel.def("isDisplayedIn2D", &cc2DLabel::isDisplayedIn2D); + Pycc2DLabel.def("setRelativeMarkerScale", &cc2DLabel::setRelativeMarkerScale, "value"_a); py::class_(Pycc2DLabel, "PickedPoint") .def_readwrite( diff --git a/wrapper/pycc/src/qcc_db/ccGLMatrix.cpp b/wrapper/pycc/src/qcc_db/ccGLMatrix.cpp index 1f539dd6..3e27c7ea 100644 --- a/wrapper/pycc/src/qcc_db/ccGLMatrix.cpp +++ b/wrapper/pycc/src/qcc_db/ccGLMatrix.cpp @@ -125,9 +125,7 @@ static void define_ccGLMatrixClass(py::module &m, const char *name) .def("scaleRow", &ccGLMatrixType::scaleRow, "rowIndex"_a, "coef"_a) .def("scaleColumn", &ccGLMatrixType::scaleColumn, "rowIndex"_a, "coef"_a) .def("asArray", - [](ccGLMatrixType &self) { - return PyCC::SpanAsNumpyArray(self.data(), {4, 4}); - }); + [](ccGLMatrixType &self) { return PyCC::SpanAsNumpyArray(self.data(), {4, 4}); }); } void define_ccGLMatrix(py::module &m) diff --git a/wrapper/pycc/src/qcc_db/ccScalarField.cpp b/wrapper/pycc/src/qcc_db/ccScalarField.cpp index 63155e96..5da6b4b5 100644 --- a/wrapper/pycc/src/qcc_db/ccScalarField.cpp +++ b/wrapper/pycc/src/qcc_db/ccScalarField.cpp @@ -100,7 +100,5 @@ void define_ccScalarField(py::module &m) .def("mayHaveHiddenValues", &ccScalarField::mayHaveHiddenValues) .def("setModificationFlag", &ccScalarField::setModificationFlag, "state"_a) .def("getModificationFlag", &ccScalarField::getModificationFlag) - .def("importParametersFrom", &ccScalarField::importParametersFrom, "sf"_a) - .def("getGlobalShift", &ccScalarField::getGlobalShift) - .def("setGlobalShift", &ccScalarField::setGlobalShift, "state"_a); + .def("importParametersFrom", &ccScalarField::importParametersFrom, "sf"_a); }