From b0bf663ff7d04e6648859b460e79d58305af0637 Mon Sep 17 00:00:00 2001 From: Otto Link Date: Fri, 16 Aug 2024 16:02:31 +0200 Subject: [PATCH] Add read array from numpy file and write array to numpy file --- .gitmodules | 3 ++ HighMap/CMakeLists.txt | 1 + HighMap/include/highmap/array.hpp | 20 ++++++++++++ HighMap/src/array/array_io.cpp | 40 ++++++++++++++++++++++++ examples/ex_from_numpy/CMakeLists.txt | 2 ++ examples/ex_from_numpy/ex_from_numpy.cpp | 19 +++++++++++ examples/ex_to_numpy/CMakeLists.txt | 2 ++ examples/ex_to_numpy/ex_to_numpy.cpp | 24 ++++++++++++++ external/CMakeLists.txt | 1 + external/libnpy | 1 + 10 files changed, 113 insertions(+) create mode 100644 examples/ex_from_numpy/CMakeLists.txt create mode 100644 examples/ex_from_numpy/ex_from_numpy.cpp create mode 100644 examples/ex_to_numpy/CMakeLists.txt create mode 100644 examples/ex_to_numpy/ex_to_numpy.cpp create mode 160000 external/libnpy diff --git a/.gitmodules b/.gitmodules index 6a8a8eaf..f4becad4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,3 +20,6 @@ [submodule "external/Noise"] path = external/Noise url = git@github.com:otto-link/Noise.git +[submodule "external/libnpy"] + path = external/libnpy + url = git@github.com:llohse/libnpy.git diff --git a/HighMap/CMakeLists.txt b/HighMap/CMakeLists.txt index 088f0f4f..f2d610b9 100644 --- a/HighMap/CMakeLists.txt +++ b/HighMap/CMakeLists.txt @@ -31,6 +31,7 @@ target_link_libraries( FastNoiseLite::FastNoiseLite hmm::hmm libInterpolate::libInterpolate + libnpy::libnpy macro-logger::macro-logger NoiseLib OpenMP::OpenMP_CXX diff --git a/HighMap/include/highmap/array.hpp b/HighMap/include/highmap/array.hpp index 045c3899..d2fc65fc 100644 --- a/HighMap/include/highmap/array.hpp +++ b/HighMap/include/highmap/array.hpp @@ -673,6 +673,16 @@ class Array */ void from_file(std::string fname); + /** + * @brief Import array data from a numpy binary file. + * + * @param fname The name of the file to import data from. + * + * **Example** + * @include ex_from_numpy.cpp + */ + void from_numpy(std::string fname); + /** * @brief Display various information about the array. * @@ -865,6 +875,16 @@ class Array */ void to_file(std::string fname); + /** + * @brief Export the array to a numpy binary file. + * + * @param fname The name of the file to which the array data will be written. + * + * **Example** + * @include ex_to_numpy.cpp + */ + void to_numpy(std::string fname); + /** * @brief Export the array as a PNG image file with a specified colormap and * hillshading. diff --git a/HighMap/src/array/array_io.cpp b/HighMap/src/array/array_io.cpp index c20a88af..0c58ba7a 100644 --- a/HighMap/src/array/array_io.cpp +++ b/HighMap/src/array/array_io.cpp @@ -4,6 +4,7 @@ #include #include "macrologger.h" +#include "npy.hpp" #include "highmap/array.hpp" #include "highmap/io.hpp" @@ -22,6 +23,35 @@ void Array::from_file(std::string fname) f.close(); } +void Array::from_numpy(std::string fname) +{ + npy::npy_data d = npy::read_npy(fname); + + // update array shape + Vec2 new_shape = {(int)d.shape[0], (int)d.shape[1]}; + this->set_shape(new_shape); + + // copy the data + if (d.fortran_order) + { + for (int i = 0; i < this->shape.x; i++) + for (int j = 0; j < this->shape.y; j++) + { + int k = j * this->shape.x + i; + (*this)(i, j) = d.data[k]; + } + } + else + { + for (int i = 0; i < this->shape.x; i++) + for (int j = 0; j < this->shape.y; j++) + { + int k = i * this->shape.y + j; + (*this)(i, j) = d.data[k]; + } + } +} + void Array::infos(std::string msg) const { std::cout << "Array: " << msg << " "; @@ -58,6 +88,16 @@ void Array::to_file(std::string fname) f.close(); } +void Array::to_numpy(std::string fname) +{ + npy::npy_data_ptr d; + d.data_ptr = this->vector.data(); + d.shape = {(uint)this->shape.x, (uint)this->shape.y}; + d.fortran_order = false; + + npy::write_npy(fname, d); +} + void Array::to_png(std::string fname, int cmap, bool hillshading) { std::vector img(3 * this->shape.x * this->shape.y); diff --git a/examples/ex_from_numpy/CMakeLists.txt b/examples/ex_from_numpy/CMakeLists.txt new file mode 100644 index 00000000..72562d4b --- /dev/null +++ b/examples/ex_from_numpy/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(ex_from_numpy ex_from_numpy.cpp) +target_link_libraries(ex_from_numpy highmap) diff --git a/examples/ex_from_numpy/ex_from_numpy.cpp b/examples/ex_from_numpy/ex_from_numpy.cpp new file mode 100644 index 00000000..75fbcbdf --- /dev/null +++ b/examples/ex_from_numpy/ex_from_numpy.cpp @@ -0,0 +1,19 @@ +#include + +#include "highmap.hpp" + +int main(void) +{ + hmap::Vec2 shape = {512, 256}; + hmap::Vec2 res = {4.f, 2.f}; + int seed = 1; + + hmap::Array z1 = hmap::noise_fbm(hmap::NoiseType::PERLIN, shape, res, seed); + + z1.to_numpy("out.npy"); + + hmap::Array z2; + z2.from_numpy("out.npy"); + + hmap::export_banner_png("ex_from_numpy.png", {z1, z2}, hmap::cmap::inferno); +} diff --git a/examples/ex_to_numpy/CMakeLists.txt b/examples/ex_to_numpy/CMakeLists.txt new file mode 100644 index 00000000..e363d269 --- /dev/null +++ b/examples/ex_to_numpy/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(ex_to_numpy ex_to_numpy.cpp) +target_link_libraries(ex_to_numpy highmap) diff --git a/examples/ex_to_numpy/ex_to_numpy.cpp b/examples/ex_to_numpy/ex_to_numpy.cpp new file mode 100644 index 00000000..4a3b4417 --- /dev/null +++ b/examples/ex_to_numpy/ex_to_numpy.cpp @@ -0,0 +1,24 @@ +#include + +#include "highmap.hpp" + +int main(void) +{ + hmap::Vec2 shape = {512, 256}; + hmap::Vec2 res = {4.f, 2.f}; + int seed = 1; + + hmap::Array z = hmap::noise_fbm(hmap::NoiseType::PERLIN, shape, res, seed); + + std::cout << z(10, 12) << std::endl; + + z.to_numpy("out.npy"); + z.to_png("ex_to_numpy.png", hmap::cmap::jet); + + // --- python script to check this + + // import numpy as np + // z = np.load('out.npy') + // print(z.shape) + // print(z[10, 12]) +} diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 34278d43..0d563473 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -3,6 +3,7 @@ include(dkm.cmake) include(FastNoiseLite.cmake) include(hmm.cmake) include(libInterpolate.cmake) +include(libnpy.cmake) include(macro-logger.cmake) include(xsimd.cmake) diff --git a/external/libnpy b/external/libnpy new file mode 160000 index 00000000..471fe480 --- /dev/null +++ b/external/libnpy @@ -0,0 +1 @@ +Subproject commit 471fe480d5f1082fd8fd0e746eaf10084a2fb82b