diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 543e5631..ae97f100 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,6 +4,9 @@ on: [push] env: CUDA_BIN: /usr/local/cuda/bin + CC: gcc-12 + CXX: g++-12 + CUDAHOSTCXX: g++-12 jobs: build: @@ -33,6 +36,7 @@ jobs: libglew-dev \ libglfw3-dev \ cimg-dev \ + g++-12 \ wget wget http://mirrors.kernel.org/ubuntu/pool/universe/f/flann/libflann-dev_1.9.2+dfsg-1_amd64.deb wget http://mirrors.kernel.org/ubuntu/pool/universe/f/flann/libflann1.9_1.9.2+dfsg-1_amd64.deb diff --git a/README.md b/README.md index a0ecce16..4581251d 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,17 @@ finally execute: ./gproshan [mesh_paths.(off,obj,ply)] -### Dependencies (Linux) -g++ >= 9.4, cuda >= 11.8, cmake >= 3.24, armadillo, eigen3, cgal, suitesparse, openblas, glew, glfw3, cimg, gnuplot, embree >= 3.13 -In Ubuntu you can install them with: +### Dependencies (Linux/MacOS) +g++ >= 12.3, cuda >= 12.4, cmake >= 3.28, embree >= 4.3, glew, glfw3, armadillo, suitesparse, openblas, flann, cimg + +On Ubuntu you can install them with: + + sudo apt install cmake libglew-dev libglfw3-dev libarmadillo-dev libsuitesparse-dev libopenblas-dev libflann-dev cimg-dev + +Install Cuda if available to enable Cuda-based modules. +Export environment variable `OptiX_INSTALL_DIR` with the path to the OptiX library to enable it. - sudo apt install cmake libarmadillo-dev libeigen3-dev libcgal-dev libsuitesparse-dev libopenblas-dev libglew-dev libglfw3-dev cimg-dev gnuplot #### Installing Intel Embree diff --git a/cmake/FindOptiX.cmake b/cmake/FindOptiX.cmake index 0aff2abd..9b3f6611 100644 --- a/cmake/FindOptiX.cmake +++ b/cmake/FindOptiX.cmake @@ -1,5 +1,5 @@ # -# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/cmake/FindSuiteSparse.cmake b/cmake/FindSuiteSparse.cmake index 0793a17a..a58cdefd 100644 --- a/cmake/FindSuiteSparse.cmake +++ b/cmake/FindSuiteSparse.cmake @@ -1,8 +1,8 @@ ## CMake file to locate SuiteSparse and its useful composite projects -## The first developpement of this file was made fro Windows users who -## use: +## The first development of this file was done by Windows users who +## used: ## https://github.com/jlblancoc/suitesparse-metis-for-windows -## Anyway, it chould be work also on linux (tested on fedora 17 when you installed suitesparse from yum) +## Anyway, it could work also on linux (tested on fedora 17 when you installed suitesparse from yum) ## ## ## Inputs variables this file can process (variable must be given before find_package(SUITESPARES ...) command) : @@ -11,7 +11,7 @@ ## Note: SuiteSparse lib usually requires linking to a blas and lapack library. ## ## -## Help variables this file handle internaly : +## Help variables this file handle internally : ## * SuiteSparse_SEARCH_LIB_POSTFIX Is set in cache (as advanced) to look into the right lib/lib64 dir for libraries (user can change) ## ## @@ -20,19 +20,19 @@ ## * SuiteSparse_INCLUDE_DIRS Paths containing SuiteSparse needed headers (depend on which COMPONENTS you gave) ## * SuiteSparse_LIBRARIES Absolute paths of SuiteSparse libs found (depend on which COMPONENTS you gave) ## If SuiteSparse_USE_LAPACK_BLAS is set to ON : -## * SuiteSparse_LAPACK_BLAS_LIBRARIES Which contain the libblas and liblapack libraries +## * SuiteSparse_LAPACK_BLAS_LIBRARIES Which contain the libblas and liblapack libraries ## On windows: -## * SuiteSparse_LAPACK_BLAS_DLL Which contain all requiered binaries for use libblas and liblapack +## * SuiteSparse_LAPACK_BLAS_DLL Which contain all required binaries for use libblas and liblapack ## ## ## Detailed variables this file provide : ## * SuiteSparse__FOUND True if the given component to look for is found (INCLUDE DIR and LIBRARY) -## * SuiteSparse__INCLUDE_DIR The path directory where we can found all compenent header files +## * SuiteSparse__INCLUDE_DIR The path directory where all component header files can be found ## * SuiteSparse__LIBRARY The file path to the component library ## Note: If a component is not found, a SuiteSparse__DIR cache variable is set to allow user set the search directory. ## ## -## Possible componnents to find are (maybe some others can be available): +## Possible components to find are (maybe some others can be available): ## * AMD ## * CAMD ## * COLAMD @@ -125,13 +125,13 @@ endif() ## we can use a generic way to find all of these with simple cmake lines of code macro(SuiteSparse_FIND_COMPONENTS ) - ## On windows : we absolutly need SuiteSparse_config.h every time for all projects + ## On windows : we absolutely need SuiteSparse_config.h every time for all projects if(WIN32) list(FIND SuiteSparse_FIND_COMPONENTS "suitesparseconfig" SS_config_index) if(${SS_config_index} MATCHES "-1") list(APPEND SuiteSparse_FIND_COMPONENTS suitesparseconfig) if(SuiteSparse_VERBOSE) - message(STATUS " On windows, we absolutly need SuiteSparse_config.h every time for all projects : add suitesparseconfig component to look for") + message(STATUS " On windows, we absolutely need SuiteSparse_config.h every time for all projects : add suitesparseconfig component to look for") endif() endif() endif() @@ -292,7 +292,7 @@ macro(SuiteSparse_FIND_COMPONENTS ) endif() if(NOT ${componentToCheck}) set(SuiteSparse_FOUND OFF) - break() ## one component not found is enought to failed + break() ## one component not found is enough to failed endif() endforeach() endmacro() diff --git a/gproshanConfig.cmake.in b/gproshanConfig.cmake.in index 11ff78c7..cb668b3f 100644 --- a/gproshanConfig.cmake.in +++ b/gproshanConfig.cmake.in @@ -2,6 +2,8 @@ include(CMakeFindDependencyMacro) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") + find_package(CUDAToolkit 12) find_dependency(embree 4) diff --git a/include/gproshan/features/descriptor.h b/include/gproshan/features/descriptor.h index 28a98683..6cbd7269 100644 --- a/include/gproshan/features/descriptor.h +++ b/include/gproshan/features/descriptor.h @@ -2,7 +2,8 @@ #define DESCRIPTOR_H #include -#include + +#include // geometry processing and shape analysis framework @@ -15,10 +16,10 @@ class descriptor enum signature { GPS, HKS, WKS }; private: - a_sp_mat L, A; - a_vec eigval; - a_mat eigvec; - a_mat features; + arma::sp_mat L, A; + arma::vec eigval; + arma::mat eigvec; + arma::mat features; public: descriptor(const signature & sig, const che * mesh, const size_t n_eigs); diff --git a/include/gproshan/geodesics/heat_method.h b/include/gproshan/geodesics/heat_method.h index cd8468f0..51134c65 100644 --- a/include/gproshan/geodesics/heat_method.h +++ b/include/gproshan/geodesics/heat_method.h @@ -13,7 +13,6 @@ #include #include -#include // geometry processing and shape analysis framework @@ -31,21 +30,10 @@ double heat_method(real_t * dist, const che * mesh, const std::vector & arma::vec compute_divergence(const che * mesh, const arma::vec & u); -/// cholmod Keenan implementation -/// base on the code https://github.com/larc/dgpdec-course/tree/master/Geodesics -double solve_positive_definite(arma::mat & x, const arma::sp_mat & A, const arma::mat & b, cholmod_common * context); - -cholmod_dense * arma_2_cholmod(const arma::mat & m, cholmod_common * context); - -cholmod_sparse * arma_2_cholmod(const arma::sp_mat & m, cholmod_common * context); #ifdef GPROSHAN_CUDA -/// double solve_positive_definite_gpu(arma::mat & x, const arma::sp_mat & A, const arma::mat & b); - -/// host and device support -/// https://docs.nvidia.com/cuda/cusolver/index.html#cusolver-lt-t-gt-csrlsvchol double solve_positive_definite_cusolver(const int m, const int nnz, const double * hA_values, const int * hA_col_ptrs, const int * hA_row_indices, const double * hb, double * hx, const bool host = 0); #endif // GPROSHAN_CUDA diff --git a/include/gproshan/geometry/mat.h b/include/gproshan/geometry/mat.h index a4b0d170..418d9f03 100644 --- a/include/gproshan/geometry/mat.h +++ b/include/gproshan/geometry/mat.h @@ -3,6 +3,10 @@ #include +#ifndef __CUDACC__ + #include +#endif // __CUDACC__ + // geometry processing and shape analysis framework namespace gproshan { @@ -73,26 +77,34 @@ class mat } __host_device__ - static mat identity() + mat t() const { - mat res; - for(index_t i = 0; i < N; ++i) - res[i][i] = 1; - return res; + return transpose(*this); } __host_device__ - static mat transpose(const mat & m) + static mat identity() { mat res; for(index_t i = 0; i < N; ++i) - for(index_t j = 0; j < N; ++j) - res[i][j] = m[j][i]; + res[i][i] = 1; return res; } }; -///< std std::ostream + +template +__host_device__ +mat transpose(const mat & m) +{ + mat res; + for(index_t i = 0; i < N; ++i) + for(index_t j = 0; j < N; ++j) + res[i][j] = m[j][i]; + return res; +} + + template std::ostream & operator << (std::ostream & os, const mat & m) { @@ -101,7 +113,6 @@ std::ostream & operator << (std::ostream & os, const mat & m) return os; } -///< std std::istream template std::istream & operator >> (std::istream & is, mat & m) { @@ -111,12 +122,27 @@ std::istream & operator >> (std::istream & is, mat & m) } +#ifndef __CUDACC__ +template +mat inverse(const mat & m) +{ + mat inv; + mat mt = m.t(); + + arma::Mat ainv((T *) &inv, N, N, false, true); + arma::Mat amt((T *) &mt, N, N, false, true); + + arma::inv(ainv, amt); + + return inv.t(); +} +#endif // __CUDACC__ + + using mat2 = mat; using mat3 = mat; using mat4 = mat; -mat4 inverse(const mat4 & m); - } // namespace gproshan diff --git a/include/gproshan/include_arma.h b/include/gproshan/include_arma.h deleted file mode 100644 index a1ab9303..00000000 --- a/include/gproshan/include_arma.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef INCLUDE_ARMA_H -#define INCLUDE_ARMA_H - -#include - -#define ARMA_ALLOW_FAKE_GCC -#include - -#ifdef NDEBUG - #define ARMA_NO_DEBUG -#endif - - -// geometry processing and shape analysis framework -namespace gproshan { - - -#ifdef GPROSHAN_FLOAT - typedef arma::fmat a_mat; - typedef arma::fvec a_vec; - typedef arma::frowvec a_rowvec; - typedef arma::sp_fmat a_sp_mat; -#else - typedef arma::mat a_mat; - typedef arma::vec a_vec; - typedef arma::rowvec a_rowvec; - typedef arma::sp_mat a_sp_mat; -#endif - - -} // namespace gproshan - -#endif // INCLUDE_ARMA_H - diff --git a/include/gproshan/mdict/basis.h b/include/gproshan/mdict/basis.h index 4031f714..066f57bb 100644 --- a/include/gproshan/mdict/basis.h +++ b/include/gproshan/mdict/basis.h @@ -2,10 +2,11 @@ #define BASIS_H #include -#include #include +#include + // geometry processing and shape analysis framework // mesh dictionary learning and sparse coding namespace @@ -21,18 +22,18 @@ class basis public: basis(const real_t r, const size_t d); virtual ~basis() = default; - virtual void discrete(a_mat & phi, const a_vec & x, const a_vec & y) = 0; - virtual void d_discrete(a_mat & phi, const a_vec & x, const a_vec & y, const bool b) = 0; + virtual void discrete(arma::fmat & phi, const arma::fvec & x, const arma::fvec & y) = 0; + virtual void d_discrete(arma::fmat & phi, const arma::fvec & x, const arma::fvec & y, const bool b) = 0; virtual real_t freq(const index_t idx) = 0; real_t & radio(); size_t dim() const; void plot_basis(); - void plot_atoms(const a_mat & A); - void plot_patch(const a_mat & A, const a_mat & xyz, const index_t p); + void plot_atoms(const arma::fmat & A); + void plot_patch(const arma::fmat & A, const arma::fmat & xyz, const index_t p); private: virtual void plot_basis(std::ostream & os) = 0; - virtual void plot_atoms(std::ostream & os, const a_vec & A) = 0; + virtual void plot_atoms(std::ostream & os, const arma::fvec & A) = 0; }; diff --git a/include/gproshan/mdict/basis_cosine.h b/include/gproshan/mdict/basis_cosine.h index 45ea49e7..1dc12813 100644 --- a/include/gproshan/mdict/basis_cosine.h +++ b/include/gproshan/mdict/basis_cosine.h @@ -17,12 +17,12 @@ class basis_cosine: public basis public: basis_cosine(const size_t nr, const size_t nf, const real_t r = 0); - void discrete(a_mat & phi, const a_vec & x, const a_vec & y); + void discrete(arma::fmat & phi, const arma::fvec & x, const arma::fvec & y); private: void plot_basis(std::ostream & os); - void plot_atoms(std::ostream & os, const a_vec & A); - a_vec cosine(const a_vec & x, const a_vec & y, const real_t c, const real_t alpha); + void plot_atoms(std::ostream & os, const arma::fvec & A); + arma::fvec cosine(const arma::fvec & x, const arma::fvec & y, const real_t c, const real_t alpha); void cosine(std::ostream & os, const real_t c, const real_t alpha); }; diff --git a/include/gproshan/mdict/basis_dct.h b/include/gproshan/mdict/basis_dct.h index 1c08b12c..1abfefd8 100644 --- a/include/gproshan/mdict/basis_dct.h +++ b/include/gproshan/mdict/basis_dct.h @@ -16,15 +16,15 @@ class basis_dct: public basis public: basis_dct(const size_t n, const real_t r = 1); - void discrete(a_mat & phi, const a_vec & x, const a_vec & y); - void d_discrete(a_mat & phi, const a_vec & x, const a_vec & y, const bool b); + void discrete(arma::fmat & phi, const arma::fvec & x, const arma::fvec & y); + void d_discrete(arma::fmat & phi, const arma::fvec & x, const arma::fvec & y, const bool b); real_t freq(const index_t idx); private: void plot_basis(std::ostream & os); - void plot_atoms(std::ostream & os, const a_vec & A); - a_vec dct(const a_vec & x, const a_vec & y, const index_t nx, const index_t ny); - a_vec d_dct(const a_vec & x, const a_vec & y, const index_t nx, const index_t ny); + void plot_atoms(std::ostream & os, const arma::fvec & A); + arma::fvec dct(const arma::fvec & x, const arma::fvec & y, const index_t nx, const index_t ny); + arma::fvec d_dct(const arma::fvec & x, const arma::fvec & y, const index_t nx, const index_t ny); void dct(std::ostream & os, const index_t nx, const index_t ny); }; diff --git a/include/gproshan/mdict/mdict.h b/include/gproshan/mdict/mdict.h index 91a3ff09..ecd40a6d 100644 --- a/include/gproshan/mdict/mdict.h +++ b/include/gproshan/mdict/mdict.h @@ -4,7 +4,6 @@ #include #include #include -#include // geometry processing and shape analysis framework @@ -21,44 +20,44 @@ struct locval_t }; -void OMP(std::vector & alpha, const a_vec & x, const index_t i, const a_mat & D, const size_t L); +void OMP(std::vector & alpha, const arma::fvec & x, const index_t i, const arma::fmat & D, const size_t L); -a_sp_mat OMP_all(std::vector & locval, const a_mat & X, const a_mat & D, const size_t L); +arma::sp_fmat OMP_all(std::vector & locval, const arma::fmat & X, const arma::fmat & D, const size_t L); -void sp_KSVD(a_mat & D, const a_mat & X, const size_t L, size_t k); +void sp_KSVD(arma::fmat & D, const arma::fmat & X, const size_t L, size_t k); // DENSE -std::tuple _OMP(const a_vec & x, const a_mat & D, const size_t L); +std::tuple _OMP(const arma::fvec & x, const arma::fmat & D, const size_t L); -a_vec OMP(const a_vec & x, const a_mat & D, const size_t L); -a_vec OMP(const a_vec & x, const a_mat & D, const size_t L, const arma::uchar_vec & mask); +arma::fvec OMP(const arma::fvec & x, const arma::fmat & D, const size_t L); +arma::fvec OMP(const arma::fvec & x, const arma::fmat & D, const size_t L, const arma::uchar_vec & mask); -a_mat OMP_all(const a_mat & X, const a_mat & D, const size_t L); +arma::fmat OMP_all(const arma::fmat & X, const arma::fmat & D, const size_t L); -void KSVD(a_mat & D, const a_mat & X, const size_t L, size_t k); +void KSVD(arma::fmat & D, const arma::fmat & X, const size_t L, size_t k); // MESH DENSE -a_vec OMP(const patch & p, const a_mat & A, const size_t L); -a_vec OMP(const patch & p, const a_mat & A, const size_t L); +arma::fvec OMP(const patch & p, const arma::fmat & A, const size_t L); +arma::fvec OMP(const patch & p, const arma::fmat & A, const size_t L); -a_mat OMP_all(const std::vector & patches, const a_mat & A, const size_t L); -a_mat OMP_all(const std::vector & patches, basis * phi_basis, const a_mat & A, const size_t L); +arma::fmat OMP_all(const std::vector & patches, const arma::fmat & A, const size_t L); +arma::fmat OMP_all(const std::vector & patches, basis * phi_basis, const arma::fmat & A, const size_t L); -void KSVD(a_mat & A, const std::vector & patches, const size_t L, size_t k); +void KSVD(arma::fmat & A, const std::vector & patches, const size_t L, size_t k); // MESH SPARSE -void OMP(std::vector & alpha, const patch & p, const index_t i, const a_mat & A, const size_t L); +void OMP(std::vector & alpha, const patch & p, const index_t i, const arma::fmat & A, const size_t L); -a_sp_mat OMP_all(std::vector & locval, const std::vector & patches, const a_mat & A, const size_t L); +arma::sp_fmat OMP_all(std::vector & locval, const std::vector & patches, const arma::fmat & A, const size_t L); -void sp_KSVD(a_mat & A, const std::vector & patches, const size_t L, size_t k); +void sp_KSVD(arma::fmat & A, const std::vector & patches, const size_t L, size_t k); } // namespace gproshan::mdict diff --git a/include/gproshan/mdict/msparse_coding.h b/include/gproshan/mdict/msparse_coding.h index 2e98c936..614850f3 100644 --- a/include/gproshan/mdict/msparse_coding.h +++ b/include/gproshan/mdict/msparse_coding.h @@ -6,8 +6,6 @@ #include #include -#include - // geometry processing and shape analysis framework // mesh dictionary learning and sparse coding namespace @@ -38,8 +36,8 @@ class msparse_coding basis * phi_basis; ///< continuous basis. params m_params; ///< - a_mat A; ///< dictionary continuous matrix. - a_mat alpha; ///< sparse coding matrix. + arma::fmat A; ///< dictionary continuous matrix. + arma::fmat alpha; ///< sparse coding matrix. real_t s_radio; ///< sampling geodesic radio. std::vector sampling; ///< samples, center of patches if sampling. @@ -93,7 +91,7 @@ class msparse_coding ); real_t mesh_reconstruction(const fmask_t & mask = nullptr); - void update_alphas(a_mat & alpha, size_t threshold); + void update_alphas(arma::fmat & alpha, size_t threshold); void save_alpha(std::string file); index_t sample(const index_t s); diff --git a/include/gproshan/mdict/patch.h b/include/gproshan/mdict/patch.h index cfb51b1f..c5833c5b 100644 --- a/include/gproshan/mdict/patch.h +++ b/include/gproshan/mdict/patch.h @@ -9,9 +9,6 @@ #include -#include - - // geometry processing and shape analysis framework // mesh dictionary learning and sparse coding namespace namespace gproshan::mdict { @@ -27,10 +24,10 @@ class patch { public: std::vector vertices; ///< Vertices of the patch. - a_mat T; ///< Transformation matrix. - a_vec x; ///< Center point. - a_mat xyz; ///< Matrix of points. - a_mat phi; ///< Projected basis. + arma::fmat T; ///< Transformation matrix. + arma::fvec x; ///< Center point. + arma::fmat xyz; ///< Matrix of points. + arma::fmat phi; ///< Projected basis. double avg_dist; ///< Average distance between points. real_t radio; ///< Radio. size_t min_nv; ///< @@ -66,7 +63,7 @@ class patch const real_t area_mesh ); - void init_random(const vertex & c, const a_mat & T, const real_t radio, const real_t max_radio, const real_t percent, const real_t fr); + void init_random(const vertex & c, const arma::fmat & T, const real_t radio, const real_t max_radio, const real_t percent, const real_t fr); void recover_radial_disjoint(che * mesh, const real_t radio_, @@ -90,7 +87,7 @@ class patch ); void remove_extra_xyz_disjoint(size_t & max_points); void add_extra_xyz_disjoint(che * mesh, std::vector & vpatches, const index_t p); - const a_vec normal(); + const arma::fvec normal(); bool is_covered( bool * covered); // void save(const real_t radio, const size_t imsize, CImgList & imlist); diff --git a/include/gproshan/mesh/che.h b/include/gproshan/mesh/che.h index 6f760905..0f014ca1 100644 --- a/include/gproshan/mesh/che.h +++ b/include/gproshan/mesh/che.h @@ -189,6 +189,41 @@ class che return {VT[he], VT[he + 1], VT[he + 2]}; } + __host_device__ + mat3 trig_points(const index_t t) const + { + assert(t < n_trigs); + const index_t he = t * 3; + mat3 m = {GT[VT[he]], GT[VT[he + 1]], GT[VT[he + 2]]}; + return m.t(); + } + + __host_device__ + mat3 trig_normals(const index_t t) const + { + assert(t < n_trigs); + const index_t he = t * 3; + mat3 m = {VN[VT[he]], VN[VT[he + 1]], VN[VT[he + 2]]}; + return m.t(); + } + + __host_device__ + mat3 trig_colors(const index_t t) const + { + assert(t < n_trigs); + const index_t he = t * 3; + mat3 m = {VC[VT[he]], VC[VT[he + 1]], VC[VT[he + 2]]}; + return m.t(); + } + + __host_device__ + vec3 trig_heatmap(const index_t t) const + { + assert(t < n_trigs); + const index_t he = t * 3; + return {VHC[VT[he]], VHC[VT[he + 1]], VHC[VT[he + 2]]}; + } + __host_device__ index_t halfedge(const index_t he) const { @@ -214,8 +249,13 @@ class che return VHC; } - - vertex normal_trig(const index_t f) const; +/* + __host_device__ + T shading(const real_t u, const real_t v) + { + } +*/ + vertex normal_trig(const index_t t) const; vertex normal_he(const index_t he) const; vertex gradient_he(const index_t he, const real_t * f) const; dvec3 gradient_he(const index_t he, const double * f) const; diff --git a/include/gproshan/mesh/che_fill_hole.h b/include/gproshan/mesh/che_fill_hole.h index 8c9063ee..76866dd2 100644 --- a/include/gproshan/mesh/che_fill_hole.h +++ b/include/gproshan/mesh/che_fill_hole.h @@ -2,9 +2,9 @@ #define CHE_FILL_HOLE_H #include -#include #include +#include // geometry processing and shape analysis framework @@ -18,7 +18,7 @@ struct border_t border_t() = default; - border_t(const std::vector & V, const index_t _v, const std::array & neighbors, const bool o): + border_t(const std::vector & V, const index_t _v, const std::array & neighbors, const bool o): v(_v) { index_t p_v = neighbors[!o]; @@ -30,25 +30,25 @@ struct border_t return; } - a_vec a = V[p_v] - V[v]; - a_vec b = V[n_v] - V[v]; + arma::fvec a = V[p_v] - V[v]; + arma::fvec b = V[n_v] - V[v]; a[2] = b[2] = 0; theta = atan2(b[1], b[0]) - atan2(a[1], a[0]); if(theta < 0) theta += 2 * M_PI; } - a_vec new_vertex(const std::vector & V, real_t div, const real_t length, const std::array & neighbors, const bool o) + arma::fvec new_vertex(const std::vector & V, real_t div, const real_t length, const std::array & neighbors, const bool o) { index_t p_v = neighbors[!o]; index_t n_v = neighbors[o]; - a_vec a = V[p_v] - V[v]; - a_vec b = V[n_v] - V[v]; + arma::fvec a = V[p_v] - V[v]; + arma::fvec b = V[n_v] - V[v]; a(2) = b(2) = 0; - a_vec r = div * a + (1 - div) * b; + arma::fvec r = div * a + (1 - div) * b; r = length * normalise(r) + V[v]; r(2) = 0; @@ -56,19 +56,19 @@ struct border_t return r; } - border_t(const std::vector & V, const index_t _v, const std::array & neighbors, const bool o, const a_vec & normal): + border_t(const std::vector & V, const index_t _v, const std::array & neighbors, const bool o, const arma::fvec & normal): v(_v) { index_t p_v = neighbors[!o]; index_t n_v = neighbors[o]; - a_vec a = V[p_v] - V[v]; - a_vec b = V[n_v] - V[v]; + arma::fvec a = V[p_v] - V[v]; + arma::fvec b = V[n_v] - V[v]; a -= dot(a, normal) * normal; b -= dot(a, normal) * normal; - a_mat E(3,3); + arma::fmat E(3,3); E.col(0) = normalise(a); E.col(1) = normalise(cross(normal, a)); E.col(2) = normal; @@ -81,18 +81,18 @@ struct border_t if(theta < 0) theta += 2 * M_PI; } - a_vec new_vertex(const std::vector & V, real_t div, const real_t length, const std::array & neighbors, const bool o, const a_vec & normal) + arma::fvec new_vertex(const std::vector & V, real_t div, const real_t length, const std::array & neighbors, const bool o, const arma::fvec & normal) { index_t p_v = neighbors[!o]; index_t n_v = neighbors[o]; - a_vec a = V[p_v] - V[v]; - a_vec b = V[n_v] - V[v]; + arma::fvec a = V[p_v] - V[v]; + arma::fvec b = V[n_v] - V[v]; a -= dot(a, normal) * normal; b -= dot(a, normal) * normal; - a_mat E(3,3); + arma::fmat E(3,3); E.col(0) = normalise(a); E.col(1) = normalise(cross(normal, a)); E.col(2) = normal; @@ -100,7 +100,7 @@ struct border_t a = E.t() * a; b = E.t() * b; - a_vec r(3); + arma::fvec r(3); r[0] = cos(theta * div); r[1] = sin(theta * div); r[2] = 0; diff --git a/include/gproshan/mesh/simplification.h b/include/gproshan/mesh/simplification.h index 855ef509..972d70fd 100644 --- a/include/gproshan/mesh/simplification.h +++ b/include/gproshan/mesh/simplification.h @@ -2,9 +2,9 @@ #define SIMPLIFICATION_H #include -#include #include +#include // geometry processing and shape analysis framework @@ -14,7 +14,7 @@ namespace gproshan { class simplification { private: - a_mat * Q; + arma::fmat * Q; che * mesh; index_t levels; diff --git a/include/gproshan/raytracing/optix.h b/include/gproshan/raytracing/optix.h index 683b2d0e..e60dfd58 100644 --- a/include/gproshan/raytracing/optix.h +++ b/include/gproshan/raytracing/optix.h @@ -53,7 +53,7 @@ class optix : public raytracing public: optix(const std::string & ptx = "/src/optix.ptx"); - optix(const std::vector & meshes, const std::vector & model_mats); + optix(const std::vector & meshes, const std::vector & model_mats); ~optix(); void render(vec4 * img, const render_params & params, const bool flat); @@ -64,7 +64,7 @@ class optix : public raytracing void create_hitgroup_programs(); void create_pipeline(); void build_sbt(); - OptixTraversableHandle build_as(const std::vector & meshes, const std::vector & model_mats); + OptixTraversableHandle build_as(const std::vector & meshes, const std::vector & model_mats); void add_mesh(OptixBuildInput & optix_mesh, CUdeviceptr & d_vertex_ptr, uint32_t & optix_trig_flags, const che * mesh, const mat4 & model_mat); }; diff --git a/include/gproshan/raytracing/utils.h b/include/gproshan/raytracing/utils.h index a5cf9ae6..03718c4b 100644 --- a/include/gproshan/raytracing/utils.h +++ b/include/gproshan/raytracing/utils.h @@ -106,18 +106,11 @@ struct t_eval_hit } const uvec3 trig = mesh.trig(primID); + const vec3 uv = {1.f - u - v, u, v}; - Kd = (1.f - u - v) * mesh.color(trig.x()) - + u * mesh.color(trig.y()) - + v * mesh.color(trig.z()); - normal = (1.f - u - v) * mesh.normal(trig.x()) - + u * mesh.normal(trig.y()) - + v * mesh.normal(trig.z()); - heatmap = (1.f - u - v) * mesh.heatmap(trig.x()) - + u * mesh.heatmap(trig.y()) - + v * mesh.heatmap(trig.z()); - - normal = normalize(normal); + Kd = mesh.trig_colors(primID) * uv; + normal = normalize(mesh.trig_normals(primID) * uv); + heatmap = dot(mesh.trig_heatmap(primID), uv); if(!sc.trig_mat) return; if(sc.trig_mat[primID] == NIL) return; diff --git a/include/gproshan/util.h b/include/gproshan/util.h index 5f2cae8e..b6d420cf 100644 --- a/include/gproshan/util.h +++ b/include/gproshan/util.h @@ -88,7 +88,7 @@ T normalize(T * data, const size_t n_elem) { T max = 0; - #pragma omp parallel for reduction(std::max: max) + #pragma omp parallel for reduction(max: max) for(index_t i = 0; i < n_elem; ++i) max = std::max(max, data[i]); diff --git a/src/gproshan/CMakeLists.txt b/src/gproshan/CMakeLists.txt index 815f72ab..9f40dbbf 100644 --- a/src/gproshan/CMakeLists.txt +++ b/src/gproshan/CMakeLists.txt @@ -77,6 +77,8 @@ write_basic_package_version_file( install(FILES ${CMAKE_CURRENT_BINARY_DIR}/gproshanConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/gproshanConfigVersion.cmake + ${gproshan_SOURCE_DIR}/cmake/FindSuiteSparse.cmake + ${gproshan_SOURCE_DIR}/cmake/FindOptiX.cmake DESTINATION lib/cmake/gproshan ) diff --git a/src/gproshan/app_viewer.cpp b/src/gproshan/app_viewer.cpp index 76001140..b9dbd5b7 100644 --- a/src/gproshan/app_viewer.cpp +++ b/src/gproshan/app_viewer.cpp @@ -348,7 +348,7 @@ bool app_viewer::process_gaussian_curvature(viewer * p_view) real_t g, g_max = -INFINITY, g_min = INFINITY; vertex a, b; - a_vec gv(mesh->n_vertices); + arma::fvec gv(mesh->n_vertices); #pragma omp parallel for private(g, a, b) reduction(max: g_max) reduction(min: g_min) for(index_t v = 0; v < mesh->n_vertices; ++v) @@ -747,7 +747,7 @@ bool app_viewer::process_mask(viewer * p_view) mesh->update_heatmap(msc); std::string f_points = tmp_file_path(std::string(msc) + ".rsampl"); - a_vec points_out; + arma::fvec points_out; gproshan_debug_var(f_points); points_out.load(f_points); gproshan_debug_var(size(points_out)); @@ -807,9 +807,9 @@ bool app_viewer::process_eigenfuntions(viewer * p_view) if(ImGui::Button("Run")) { - a_sp_mat L, A; - a_vec eigval; - a_mat eigvec; + arma::sp_fmat L, A; + arma::fvec eigval; + arma::fmat eigvec; TIC(view->time) n_eigs = eigs_laplacian(mesh, eigval, eigvec, L, A, n_eigs); diff --git a/src/gproshan/features/descriptor.cpp b/src/gproshan/features/descriptor.cpp index b396966e..2e55c76d 100644 --- a/src/gproshan/features/descriptor.cpp +++ b/src/gproshan/features/descriptor.cpp @@ -57,11 +57,11 @@ void descriptor::compute_hks() void descriptor::compute_wks() { eigvec = eigvec % eigvec; // element wise product - eigval = log(eigval); + double max_ev = log(std::max(max(abs(eigval)), 1e-6)); - a_vec e = arma::linspace(eigval(1), eigval(eigval.n_elem - 1), eigval.n_elem); - real_t sigma = (e(1) - e(0)) * 6; // 6 is wks variance see reference - real_t sigma_2 = 2 * sigma * sigma; + arma::vec e = arma::linspace(eigval(1), max_ev, eigval.n_elem); + double sigma = (e(1) - e(0)) * 6; // 6 is wks variance see reference + double sigma_2 = 2 * sigma * sigma; features.zeros(eigvec.n_rows, e.n_elem); diff --git a/src/gproshan/geodesics/heat_method.cpp b/src/gproshan/geodesics/heat_method.cpp index 9742591b..bf139681 100644 --- a/src/gproshan/geodesics/heat_method.cpp +++ b/src/gproshan/geodesics/heat_method.cpp @@ -4,12 +4,17 @@ #include #include +#include // geometry processing and shape analysis framework namespace gproshan { +/// cholmod Keenan implementation +/// base on the code https://github.com/larc/dgpdec-course/tree/master/Geodesics +double solve_positive_definite(arma::mat & x, const arma::sp_mat & A, const arma::mat & b, cholmod_common * context); + double heat_method(real_t * dist, const che * mesh, const std::vector & sources, const heat_method_opt & opt) { if(!size(sources)) return 0; @@ -114,6 +119,10 @@ arma::vec compute_divergence(const che * mesh, const arma::vec & u) return div; } + +cholmod_dense * arma_2_cholmod(const arma::mat & m, cholmod_common * context); +cholmod_sparse * arma_2_cholmod(const arma::sp_mat & m, cholmod_common * context); + double solve_positive_definite(arma::mat & x, const arma::sp_mat & A, const arma::mat & b, cholmod_common * context) { cholmod_sparse * cA = arma_2_cholmod(A, context); diff --git a/src/gproshan/geometry/mat.cpp b/src/gproshan/geometry/mat.cpp deleted file mode 100644 index 25287f2a..00000000 --- a/src/gproshan/geometry/mat.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include - -#include - - -// geometry processing and shape analysis framework -namespace gproshan { - - -mat4 inverse(const mat4 & m) -{ - mat4 inv; - mat4 mt = mat4::transpose(m); - - a_mat a_inv((real_t *) &inv, 4, 4, false, true); - a_mat a_m((real_t *) &mt, 4, 4, false, true); - - arma::inv(a_inv, a_m); - - return mat4::transpose(inv); -} - - -} // namespace gproshan - diff --git a/src/gproshan/mdict/basis.cpp b/src/gproshan/mdict/basis.cpp index e57da9e2..ee5925e1 100644 --- a/src/gproshan/mdict/basis.cpp +++ b/src/gproshan/mdict/basis.cpp @@ -44,7 +44,7 @@ void basis::plot_basis() system(file.c_str()); } -void basis::plot_atoms(const a_mat & A) +void basis::plot_atoms(const arma::fmat & A) { size_t K = A.n_rows; size_t m = A.n_cols; @@ -81,9 +81,9 @@ void basis::plot_atoms(const a_mat & A) system(file.c_str()); } -void basis::plot_patch(const a_mat & A, const a_mat & xyz, const index_t p) +void basis::plot_patch(const arma::fmat & A, const arma::fmat & xyz, const index_t p) { - a_mat tmp = xyz.t(); + arma::fmat tmp = xyz.t(); std::string data = tmp_file_path("xyz_" + std::to_string(p) + ".dat"); tmp.save(data.c_str(), arma::arma_ascii); diff --git a/src/gproshan/mdict/basis_cosine.cpp b/src/gproshan/mdict/basis_cosine.cpp index a09faedf..5eb1c44b 100644 --- a/src/gproshan/mdict/basis_cosine.cpp +++ b/src/gproshan/mdict/basis_cosine.cpp @@ -10,7 +10,7 @@ namespace gproshan::mdict { basis_cosine::basis_cosine(const size_t nr, const size_t nf, const real_t r): basis(r, r * nf), n_rot(nr), n_freq(nf) {} -void basis_cosine::discrete(a_mat & phi, const a_vec & x, const a_vec & y) +void basis_cosine::discrete(arma::fmat & phi, const arma::fvec & x, const arma::fvec & y) { assert(phi.n_cols == _dim); @@ -40,7 +40,7 @@ void basis_cosine::plot_basis(std::ostream & os) } } -void basis_cosine::plot_atoms(std::ostream & os, const a_vec & A) +void basis_cosine::plot_atoms(std::ostream & os, const arma::fvec & A) { real_t d = 1.0 / (n_rot - 1); real_t c; @@ -53,7 +53,7 @@ void basis_cosine::plot_atoms(std::ostream & os, const a_vec & A) } } -a_vec basis_cosine::cosine(const a_vec & x, const a_vec & y, const real_t c, const real_t alpha) +arma::fvec basis_cosine::cosine(const arma::fvec & x, const arma::fvec & y, const real_t c, const real_t alpha) { return cos(c * (alpha * x + (1 - alpha) * y)); } diff --git a/src/gproshan/mdict/basis_dct.cpp b/src/gproshan/mdict/basis_dct.cpp index 6bcf8d42..97cfd13d 100644 --- a/src/gproshan/mdict/basis_dct.cpp +++ b/src/gproshan/mdict/basis_dct.cpp @@ -10,7 +10,7 @@ namespace gproshan::mdict { basis_dct::basis_dct(const size_t n, const real_t r): basis(r, n * n), n_freq(n) {} -void basis_dct::discrete(a_mat & phi, const a_vec & x, const a_vec & y) +void basis_dct::discrete(arma::fmat & phi, const arma::fvec & x, const arma::fvec & y) { assert(phi.n_cols == _dim); @@ -19,7 +19,7 @@ void basis_dct::discrete(a_mat & phi, const a_vec & x, const a_vec & y) phi.col(k) = dct(x, y, nx, ny); } -void basis_dct::d_discrete(a_mat & phi, const a_vec & x, const a_vec & y, const bool b) +void basis_dct::d_discrete(arma::fmat & phi, const arma::fvec & x, const arma::fvec & y, const bool b) { assert(phi.n_cols == _dim); @@ -39,7 +39,7 @@ void basis_dct::plot_basis(std::ostream & os) } } -void basis_dct::plot_atoms(std::ostream & os, const a_vec & A) +void basis_dct::plot_atoms(std::ostream & os, const arma::fvec & A) { for(index_t k = 0, nx = 0; nx < n_freq; ++nx) for(index_t ny = 0; ny < n_freq; ++ny, ++k) @@ -48,13 +48,13 @@ void basis_dct::plot_atoms(std::ostream & os, const a_vec & A) } } -a_vec basis_dct::dct(const a_vec & x, const a_vec & y, const index_t nx, const index_t ny) +arma::fvec basis_dct::dct(const arma::fvec & x, const arma::fvec & y, const index_t nx, const index_t ny) { return cos(M_PI * nx * x / _radio ) % cos(M_PI * ny * y / _radio); } -a_vec basis_dct::d_dct(const a_vec & x, const a_vec & y, const index_t nx, const index_t ny) +arma::fvec basis_dct::d_dct(const arma::fvec & x, const arma::fvec & y, const index_t nx, const index_t ny) { return - (M_PI * nx / _radio) * (sin(M_PI * nx * x / _radio) % cos(M_PI * ny * y / _radio)); } diff --git a/src/gproshan/mdict/image_denoising.cpp b/src/gproshan/mdict/image_denoising.cpp index 3df9215f..c6a8c62e 100644 --- a/src/gproshan/mdict/image_denoising.cpp +++ b/src/gproshan/mdict/image_denoising.cpp @@ -32,7 +32,7 @@ void test_image_denoising(const std::string & file) size_t L = 10; // sparsity OMP norm L_0 size_t K = 10; // KSVD iterations - a_mat X(n, M); + arma::fmat X(n, M); for(index_t x = 0; x < rows; ++x) for(index_t y = 0; y < cols; ++y) @@ -45,10 +45,10 @@ void test_image_denoising(const std::string & file) X(k++, i) = image(a, b); } - a_mat D(n, m, arma::fill::randu); + arma::fmat D(n, m, arma::fill::randu); D = normalise(D); - a_mat spD = D; + arma::fmat spD = D; CImg imdict; for(index_t i = 0; i < 16; ++i) @@ -94,14 +94,14 @@ void test_image_denoising(const std::string & file) gproshan_log(OMP); TIC(time) - a_mat Y = D * OMP_all(X, D, L); + arma::fmat Y = D * OMP_all(X, D, L); TOC(time) gproshan_log_var(time); TIC(time) std::vector locval; - a_mat spY = D * OMP_all(locval, X, D, L); + arma::fmat spY = D * OMP_all(locval, X, D, L); TOC(time) gproshan_log_var(time); diff --git a/src/gproshan/mdict/mdict.cpp b/src/gproshan/mdict/mdict.cpp index f1ba6551..826238d3 100644 --- a/src/gproshan/mdict/mdict.cpp +++ b/src/gproshan/mdict/mdict.cpp @@ -22,7 +22,7 @@ std::ostream & operator << (std::ostream & os, const locval_t & lc) return os << '(' << lc.i << ',' << lc.j << ") = " << lc.val; } -void OMP(std::vector & alpha, const a_vec & x, const index_t i, const a_mat & D, const size_t L) +void OMP(std::vector & alpha, const arma::fvec & x, const index_t i, const arma::fmat & D, const size_t L) { const auto & [aa, selected_atoms] = _OMP(x, D, L); @@ -33,7 +33,7 @@ void OMP(std::vector & alpha, const a_vec & x, const index_t i, const } } -a_sp_mat OMP_all(std::vector & locval, const a_mat & X, const a_mat & D, const size_t L) +arma::sp_fmat OMP_all(std::vector & locval, const arma::fmat & X, const arma::fmat & D, const size_t L) { locval.clear(); @@ -42,7 +42,7 @@ a_sp_mat OMP_all(std::vector & locval, const a_mat & X, const a_mat & OMP(locval, X.col(i), i, D, L); arma::umat DI(2, size(locval)); - a_vec DV(size(locval)); + arma::fvec DV(size(locval)); #pragma omp parallel for for(index_t k = 0; k < size(locval); ++k) @@ -52,17 +52,17 @@ a_sp_mat OMP_all(std::vector & locval, const a_mat & X, const a_mat & DV(k) = locval[k].val; } - return a_sp_mat(DI, DV, D.n_cols, X.n_cols); + return arma::sp_fmat(DI, DV, D.n_cols, X.n_cols); } -void sp_KSVD(a_mat & D, const a_mat & X, const size_t L, size_t k) +void sp_KSVD(arma::fmat & D, const arma::fmat & X, const size_t L, size_t k) { size_t m = D.n_cols; size_t M = X.n_cols; arma::uvec omega(M); - a_mat R, E, U, V; - a_vec s; + arma::fmat R, E, U, V; + arma::fvec s; std::vector locval; std::vector rows; @@ -70,7 +70,7 @@ void sp_KSVD(a_mat & D, const a_mat & X, const size_t L, size_t k) while(k--) { - a_sp_mat alpha = OMP_all(locval, X, D, L); + arma::sp_fmat alpha = OMP_all(locval, X, D, L); std::ranges::sort(locval, [](const locval_t & a, const locval_t & b) { @@ -108,13 +108,13 @@ void sp_KSVD(a_mat & D, const a_mat & X, const size_t L, size_t k) // DENSE -std::tuple _OMP(const a_vec & x, const a_mat & D, const size_t L) +std::tuple _OMP(const arma::fvec & x, const arma::fmat & D, const size_t L) { arma::uvec selected_atoms(L); real_t threshold = norm(x) * sigma; - a_mat DD; - a_vec aa, r = x; + arma::fmat DD; + arma::fvec aa, r = x; index_t l = 0; while(norm(r) > threshold && l < L) @@ -129,7 +129,7 @@ std::tuple _OMP(const a_vec & x, const a_mat & D, const size_ return {aa, selected_atoms.head(l)}; } -arma::uword max_index(const a_vec & V,const arma::uchar_vec & mask) +arma::uword max_index(const arma::fvec & V,const arma::uchar_vec & mask) { arma::uvec indices = arma::sort_index(V, "descend"); @@ -139,14 +139,14 @@ arma::uword max_index(const a_vec & V,const arma::uchar_vec & mask) return NIL; } -std::tuple _OMP(const a_vec & x, const a_mat & D, const size_t L, const arma::uchar_vec & mask) +std::tuple _OMP(const arma::fvec & x, const arma::fmat & D, const size_t L, const arma::uchar_vec & mask) { arma::uvec selected_atoms(L); real_t threshold = norm(x) * sigma; - a_mat DD; - a_vec aa, r = x; + arma::fmat DD; + arma::fvec aa, r = x; index_t l = 0; while(norm(r) > threshold && l < L) @@ -162,9 +162,9 @@ std::tuple _OMP(const a_vec & x, const a_mat & D, const size_ return {aa, selected_atoms.head(l)}; } -a_vec OMP(const a_vec & x, const a_mat & D, const size_t L) +arma::fvec OMP(const arma::fvec & x, const arma::fmat & D, const size_t L) { - a_vec alpha(D.n_cols, arma::fill::zeros); + arma::fvec alpha(D.n_cols, arma::fill::zeros); const auto & [aa, selected_atoms] = _OMP(x, D, L); alpha.elem(selected_atoms) = aa; @@ -172,9 +172,9 @@ a_vec OMP(const a_vec & x, const a_mat & D, const size_t L) return alpha; } -a_vec OMP(const a_vec & x, const a_mat & D, const size_t L, const arma::uchar_vec & mask) +arma::fvec OMP(const arma::fvec & x, const arma::fmat & D, const size_t L, const arma::uchar_vec & mask) { - a_vec alpha(D.n_cols, arma::fill::zeros); + arma::fvec alpha(D.n_cols, arma::fill::zeros); const auto & [aa, selected_atoms] = _OMP(x, D, L, mask); alpha.elem(selected_atoms) = aa; @@ -182,9 +182,9 @@ a_vec OMP(const a_vec & x, const a_mat & D, const size_t L, const arma::uchar_ve return alpha; } -a_mat OMP_all(const a_mat & X, const a_mat & D, const size_t L) +arma::fmat OMP_all(const arma::fmat & X, const arma::fmat & D, const size_t L) { - a_mat alpha(D.n_cols, X.n_cols); + arma::fmat alpha(D.n_cols, X.n_cols); #pragma omp parallel for for(index_t i = 0; i < X.n_cols; ++i) { @@ -194,11 +194,11 @@ a_mat OMP_all(const a_mat & X, const a_mat & D, const size_t L) return alpha; } -void KSVD(a_mat & D, const a_mat & X, const size_t L, size_t k) +void KSVD(arma::fmat & D, const arma::fmat & X, const size_t L, size_t k) { arma::uvec omega; - a_mat alpha, R, E, U, V; - a_vec s; + arma::fmat alpha, R, E, U, V; + arma::fvec s; while(k--) { @@ -224,12 +224,12 @@ void KSVD(a_mat & D, const a_mat & X, const size_t L, size_t k) // MESH DENSE -a_vec OMP(const patch & p, const a_mat & A, const size_t L) +arma::fvec OMP(const patch & p, const arma::fmat & A, const size_t L) { return OMP(p.xyz.row(2).t(), p.phi * A, L); } -a_vec OMP(const patch & p, basis * phi_basis, const a_mat & A, const size_t L) +arma::fvec OMP(const patch & p, basis * phi_basis, const arma::fmat & A, const size_t L) { arma::uchar_vec mask(A.n_cols); @@ -239,9 +239,9 @@ a_vec OMP(const patch & p, basis * phi_basis, const a_mat & A, const size_t L) return OMP(p.xyz.row(2).t(), p.phi * A, L, mask); } -a_mat OMP_all(const std::vector & patches, basis * phi_basis, const a_mat & A, const size_t L) +arma::fmat OMP_all(const std::vector & patches, basis * phi_basis, const arma::fmat & A, const size_t L) { - a_mat alpha(A.n_cols, size(patches)); + arma::fmat alpha(A.n_cols, size(patches)); #pragma omp parallel for for(index_t i = 0; i < size(patches); ++i) @@ -250,9 +250,9 @@ a_mat OMP_all(const std::vector & patches, basis * phi_basis, const a_mat return alpha; } -a_mat OMP_all(const std::vector & patches, const a_mat & A, const size_t L) +arma::fmat OMP_all(const std::vector & patches, const arma::fmat & A, const size_t L) { - a_mat alpha(A.n_cols, size(patches)); + arma::fmat alpha(A.n_cols, size(patches)); #pragma omp parallel for for(index_t i = 0; i < size(patches); ++i) @@ -261,15 +261,15 @@ a_mat OMP_all(const std::vector & patches, const a_mat & A, const size_t return alpha; } -void KSVD(a_mat & A, const std::vector & patches, const size_t L, size_t k) +void KSVD(arma::fmat & A, const std::vector & patches, const size_t L, size_t k) { size_t K = A.n_rows; arma::uvec omega; - a_mat new_A = A; - a_mat alpha, D, sum, sum_error; - a_vec a, e; + arma::fmat new_A = A; + arma::fmat alpha, D, sum, sum_error; + arma::fvec a, e; real_t aj; @@ -313,12 +313,12 @@ void KSVD(a_mat & A, const std::vector & patches, const size_t L, size_t // MESH SPARSE -void OMP(std::vector & alpha, const patch & p, const index_t i, const a_mat & A, const size_t L) +void OMP(std::vector & alpha, const patch & p, const index_t i, const arma::fmat & A, const size_t L) { OMP(alpha, p.xyz.row(2).t(), i, p.phi * A, L); } -a_sp_mat OMP_all(std::vector & locval, const std::vector & patches, const a_mat & A, const size_t L) +arma::sp_fmat OMP_all(std::vector & locval, const std::vector & patches, const arma::fmat & A, const size_t L) { locval.clear(); @@ -327,7 +327,7 @@ a_sp_mat OMP_all(std::vector & locval, const std::vector & patc OMP(locval, patches[i], i, A, L); arma::umat DI(2, size(locval)); - a_vec DV(size(locval)); + arma::fvec DV(size(locval)); #pragma omp parallel for for(index_t k = 0; k < size(locval); ++k) @@ -337,16 +337,16 @@ a_sp_mat OMP_all(std::vector & locval, const std::vector & patc DV(k) = locval[k].val; } - return a_sp_mat(DI, DV, A.n_cols, size(patches)); + return arma::sp_fmat(DI, DV, A.n_cols, size(patches)); } -void sp_KSVD(a_mat & A, const std::vector & patches, const size_t L, size_t k) +void sp_KSVD(arma::fmat & A, const std::vector & patches, const size_t L, size_t k) { size_t K = A.n_rows; - a_mat new_A = A; - a_mat D, sum, sum_error; - a_vec a, e; + arma::fmat new_A = A; + arma::fmat D, sum, sum_error; + arma::fvec a, e; real_t aj; @@ -356,7 +356,7 @@ void sp_KSVD(a_mat & A, const std::vector & patches, const size_t L, size while(k--) { - a_sp_mat alpha = OMP_all(locval, patches, A, L); + arma::sp_fmat alpha = OMP_all(locval, patches, A, L); std::ranges::sort(locval, [](const locval_t & a, const locval_t & b) { diff --git a/src/gproshan/mdict/msparse_coding.cpp b/src/gproshan/mdict/msparse_coding.cpp index 6f6ca0a1..85206c9d 100644 --- a/src/gproshan/mdict/msparse_coding.cpp +++ b/src/gproshan/mdict/msparse_coding.cpp @@ -163,7 +163,7 @@ void msparse_coding::load_sampling() size_t count = 0; real_t area_mesh = mesh->area_surface(); - a_vec S; + arma::fvec S; if(S.load(tmp_file_path(key_name + ".rsampl"))) { gproshan_debug(loading sampling); @@ -273,7 +273,7 @@ void msparse_coding::load_sampling() if(!covered[i]) outliers.push_back(i); - a_vec outlv(size(outliers)); + arma::fvec outlv(size(outliers)); for(index_t i = 0; i < size(outliers); ++i) outlv(i) = outliers[i]; @@ -336,7 +336,7 @@ void msparse_coding::init_radial_feature_patches() bool save_all = true; if(save_all) { - a_mat AS; + arma::fmat AS; AS.resize(m_params.n_patches, 13); for(index_t i = 0; i < m_params.n_patches; ++i) { @@ -522,8 +522,8 @@ real_t msparse_coding::execute() che * msparse_coding::point_cloud_reconstruction(real_t per, real_t fr) { - a_mat S; - a_mat alpha; + arma::fmat S; + arma::fmat alpha; S.load(tmp_file_path(key_name + ".smp")); alpha.load(tmp_file_path(key_name + ".alpha")); @@ -546,7 +546,7 @@ che * msparse_coding::point_cloud_reconstruction(real_t per, real_t fr) #pragma omp parallel for for(index_t i = 0; i < m_params.n_patches; ++i) { - a_mat T(3,3); + arma::fmat T(3,3); T(0,0) = S(i,4); T(1,0) = S(i,5); T(2,0) = S(i,6); @@ -563,7 +563,7 @@ che * msparse_coding::point_cloud_reconstruction(real_t per, real_t fr) p.phi.set_size(p.xyz.n_cols, phi_basis->dim()); phi_basis->discrete(p.phi, p.xyz.row(0).t(), p.xyz.row(1).t()); - a_vec x = p.phi * A * alpha.col(i); + arma::fvec x = p.phi * A * alpha.col(i); p.xyz.row(2) = x.t(); p.iscale_xyz(phi_basis->radio()); @@ -595,16 +595,16 @@ che * msparse_coding::point_cloud_reconstruction(real_t per, real_t fr) che * new_mesh = new che(point_cloud.data(), size(point_cloud), nullptr, 0); new_mesh->update_normals(); - a_vec n; + arma::fvec n; for(index_t v = 0, i = 0; i < m_params.n_patches; ++i) { patch & p = patches[i]; phi_basis->d_discrete(p.phi, p.xyz.row(0).t(), p.xyz.row(1).t(), 0); - a_vec dx = p.phi * A * alpha.col(i); + arma::fvec dx = p.phi * A * alpha.col(i); phi_basis->d_discrete(p.phi, p.xyz.row(0).t(), p.xyz.row(1).t(), 1); - a_vec dy = p.phi * A * alpha.col(i); + arma::fvec dy = p.phi * A * alpha.col(i); for(index_t j = 0; j < patches[i].xyz.n_cols; ++j, ++v) { @@ -680,8 +680,8 @@ void msparse_coding::learning() //random //arma::uvec r_ind = arma::randi(m, arma::distr_param(0, M)); //A = alpha.cols(r_ind); - a_mat R, E, U, V; - a_vec s; + arma::fmat R, E, U, V; + arma::fvec s; svd(U, s, V, alpha); gproshan_debug(svd done!); A = U.cols(0, m_params.n_atoms); @@ -868,7 +868,7 @@ void msparse_coding::init_patches(const bool reset, const fmask_t & mask) for(index_t s = 0; s < m_params.n_patches; ++s) { viewer::vectors.push_back({patches[s].x(0), patches[s].x(1), patches[s].x(2)}); - a_vec r = patches[s].x() + 0.02 * patches[s].normal(); + arma::fvec r = patches[s].x() + 0.02 * patches[s].normal(); viewer::vectors.push_back({r(0), r(1), r(2)}); } */ @@ -880,7 +880,7 @@ real_t msparse_coding::mesh_reconstruction(const fmask_t & mask) assert(n_vertices == mesh->n_vertices); - a_mat V(3, mesh->n_vertices, arma::fill::zeros); + arma::fmat V(3, mesh->n_vertices, arma::fill::zeros); patches_error.resize(m_params.n_patches); @@ -889,7 +889,7 @@ real_t msparse_coding::mesh_reconstruction(const fmask_t & mask) { patch & rp = patches[p]; - a_vec x = rp.phi * A * alpha.col(p); + arma::fvec x = rp.phi * A * alpha.col(p); patches_error[p] = { accu(abs(x - rp.xyz.row(2).t())) / size(rp.vertices), p }; @@ -921,7 +921,7 @@ real_t msparse_coding::mesh_reconstruction(const fmask_t & mask) // simple means vertex if(size(patches_map[v]) && (!mask || mask(v))) { - a_vec mv = arma::zeros(3); + arma::fvec mv = arma::zeros(3); for(auto p: patches_map[v]) mv += patches[p.first].xyz.col(p.second); @@ -962,7 +962,7 @@ real_t msparse_coding::mesh_reconstruction(const fmask_t & mask) return max_error; } -void msparse_coding::update_alphas(a_mat & alpha, size_t threshold) +void msparse_coding::update_alphas(arma::fmat & alpha, size_t threshold) { size_t np_new = m_params.n_patches - threshold; bool patches_covered[np_new]; @@ -978,7 +978,7 @@ void msparse_coding::update_alphas(a_mat & alpha, size_t threshold) if(!patches_covered[s-threshold]) { - a_vec sum; + arma::fvec sum; sum.zeros(); size_t c = 0; // Here updating alphas, we need a structure between patches and neighboor patches diff --git a/src/gproshan/mdict/patch.cpp b/src/gproshan/mdict/patch.cpp index fb09387f..dd9d20ff 100644 --- a/src/gproshan/mdict/patch.cpp +++ b/src/gproshan/mdict/patch.cpp @@ -124,7 +124,7 @@ bool patch::add_vertex_by_trigs(vertex & n, std::vector & N, double thr_ return added; } -void patch::init_random(const vertex & c, const a_mat & T, const real_t radio, const real_t max_radio, const real_t percent, const real_t fr) +void patch::init_random(const vertex & c, const arma::fmat & T, const real_t radio, const real_t max_radio, const real_t percent, const real_t fr) { this->radio = radio; this->T = T; @@ -226,7 +226,7 @@ void patch::init_radial_disjoint( real_t & euc_radio, normal_fit_directions(mesh, v); - a_vec vn = T.col(2); + arma::fvec vn = T.col(2); vertex n = { vn(0), vn(1), vn(2) }; vertices.push_back(v); @@ -369,7 +369,7 @@ void patch::add_extra_xyz_disjoint(che * mesh, std::vector & vpatche // create a random point real_t a = abs(dis(gen)) * 2 * M_PI; real_t r = abs(dis(gen)); - a_vec np = { r * std::cos(a), r * std::sin(a), 0 }; + arma::fvec np = { r * std::cos(a), r * std::sin(a), 0 }; //gproshan_debug_var(np); // find the closest point @@ -377,7 +377,7 @@ void patch::add_extra_xyz_disjoint(che * mesh, std::vector & vpatche double min_d = INFINITY; for(index_t v: vertices) { - a_vec aux = xyz.col(vpatches[v][p]); + arma::fvec aux = xyz.col(vpatches[v][p]); aux(2) = 0; if(norm(np - aux) < min_d) @@ -394,7 +394,7 @@ void patch::add_extra_xyz_disjoint(che * mesh, std::vector & vpatche } // forstar to find closest trinagle - a_mat abc(3,3); + arma::fmat abc(3,3); for(const index_t he: mesh->star(min_v)) { //discard triangles outside the patch @@ -418,10 +418,10 @@ void patch::add_extra_xyz_disjoint(che * mesh, std::vector & vpatche if(abs(A - (A1 + A2 + A3)) < std::numeric_limits::epsilon()) { - a_mat proj_abc = abc.tail_cols(2).each_col() - abc.col(0); + arma::fmat proj_abc = abc.tail_cols(2).each_col() - abc.col(0); np -= abc.col(0); - a_vec coef = arma::inv(proj_abc.head_rows(2)) * np.head(2); + arma::fvec coef = arma::inv(proj_abc.head_rows(2)) * np.head(2); np = proj_abc * coef + abc.col(0); if(!std::isnan(np(2))) @@ -500,7 +500,7 @@ void patch::iscale_xyz(const real_t radio_f) xyz = xyz / factor; } -const a_vec patch::normal() +const arma::fvec patch::normal() { return T.col(2); } @@ -541,7 +541,7 @@ void patch::gather_vertices(che * mesh, const index_t v, const real_t radio, ind memset(toplevel, -1, sizeof(index_t) * mesh->n_vertices); - a_vec p(3); + arma::fvec p(3); toplevel[v] = 0; qvertices.push({0, v}); @@ -664,8 +664,8 @@ void patch::compute_avg_distance(che * mesh, std::vector & vpatches, { if(itp.first == p) { - a_vec a = xyz.col(i); - a_vec b = xyz.col(itp.second); + arma::fvec a = xyz.col(i); + arma::fvec b = xyz.col(itp.second); a(2) = 0; b(2) = 0; distances.push_back(norm(a - b)); @@ -677,8 +677,8 @@ void patch::compute_avg_distance(che * mesh, std::vector & vpatches, /* for(size_t j = i+1; j < size(vertices); ++j) // replace for 1 ring { - a_vec a = xyz.col(i); - a_vec b = xyz.col(j); + arma::fvec a = xyz.col(i); + arma::fvec b = xyz.col(j); a(2) = 0; b(2) = 0; distances.push_back(norm(a - b)); diff --git a/src/gproshan/mesh/che.cpp b/src/gproshan/mesh/che.cpp index 34101f9b..58981b87 100644 --- a/src/gproshan/mesh/che.cpp +++ b/src/gproshan/mesh/che.cpp @@ -91,7 +91,7 @@ che::che(const che & mesh, const index_t * sorted, const che::options & opts) if(opts.colors) { - if(sorted) + if(!sorted) { memcpy(VC, mesh.VC, n_vertices * sizeof(rgb_t)); memcpy(VHC, mesh.VHC, n_vertices * sizeof(real_t)); diff --git a/src/gproshan/mesh/che_fill_hole.cpp b/src/gproshan/mesh/che_fill_hole.cpp index 50e63a2e..3ce7ad19 100644 --- a/src/gproshan/mesh/che_fill_hole.cpp +++ b/src/gproshan/mesh/che_fill_hole.cpp @@ -15,10 +15,10 @@ bool operator<(const border_t & a, const border_t & b) return a.theta > b.theta; } -a_vec normal_face(const std::vector & tmp_vertices, const index_t a_v, const index_t b_v, const index_t c_v) +arma::fvec normal_face(const std::vector & tmp_vertices, const index_t a_v, const index_t b_v, const index_t c_v) { - a_vec a = tmp_vertices[c_v] - tmp_vertices[a_v]; - a_vec b = tmp_vertices[b_v] - tmp_vertices[a_v]; + arma::fvec a = tmp_vertices[c_v] - tmp_vertices[a_v]; + arma::fvec b = tmp_vertices[b_v] - tmp_vertices[a_v]; return normalise(cross(a,b)); } @@ -26,8 +26,8 @@ che * mesh_simple_fill_hole(che * mesh, const std::vector & border_vert { std::vector vertices; vertex normal, normal_v, edge_v, v; - a_mat E(3, 3); - a_vec ve(3); + arma::fmat E(3, 3); + arma::fvec ve(3); vertices.reserve(size(border_vertices)); @@ -208,8 +208,8 @@ che * mesh_fill_hole(che * mesh, const std::vector & border_vertices, c void split_border(std::vector > & , che * mesh, const std::vector & border_vertices) { size_t n = size(border_vertices); - a_mat data(3, n); - a_mat means; + arma::fmat data(3, n); + arma::fmat means; vertex normal; for(index_t i = 0; i < n; ++i) @@ -338,8 +338,8 @@ che * fill_hole_front_angles_test(che * mesh, std::vector & front_verti for(index_t v: front_vertices) vertices.push_back(mesh->point(v)); - std::vector tmp_vertices(size(vertices)); - std::vector tmp_normals(size(vertices)); + std::vector tmp_vertices(size(vertices)); + std::vector tmp_normals(size(vertices)); vertex normal; for(index_t v = 0; v < size(vertices); ++v) @@ -389,8 +389,8 @@ che * fill_hole_front_angles_test(che * mesh, std::vector & front_verti real_t a75 = 75.0 * M_PI / 180; real_t a135 = 135.0 * M_PI / 180; - a_vec m_vec; - a_vec m_normal; + arma::fvec m_vec; + arma::fvec m_normal; while(!front.empty() && p_iter--) { @@ -551,11 +551,11 @@ che * fill_hole_front_angles_test(che * mesh, std::vector & front_verti vertices.clear(); - for(a_vec r: tmp_vertices) + for(arma::fvec r: tmp_vertices) vertices.push_back({r[0], r[1], r[2]}); for(index_t v = 0; false && v < size(tmp_vertices); ++v) - a_vec normal = tmp_vertices[v] + length * 3 * normalise(tmp_normals[v]); + arma::fvec normal = tmp_vertices[v] + length * 3 * normalise(tmp_normals[v]); gproshan_debug_var(perimeter); // gproshan_debug(filling holes); @@ -575,7 +575,7 @@ che * fill_hole_front_angles(std::vector & vertices, const real_t length // PCA -------------------------------------------------------------------------- - a_mat V(3, size(vertices)); + arma::fmat V(3, size(vertices)); for(index_t v = 0; v < size(vertices); ++v) { V(0,v) = vertices[v][0]; @@ -589,16 +589,16 @@ che * fill_hole_front_angles(std::vector & vertices, const real_t length perimeter = init_perimeter; //debug(perimeter) - a_vec avg = mean(V, 1); + arma::fvec avg = mean(V, 1); V.each_col() -= avg; - a_vec orientation(3); + arma::fvec orientation(3); orientation(0) = normal.x(); orientation(1) = normal.y(); orientation(2) = normal.z(); - a_mat E; - a_vec eigval; + arma::fmat E; + arma::fvec eigval; eig_sym(eigval, E, V * V.t()); E.swap_cols(0, 2); //debug(E) @@ -612,19 +612,19 @@ che * fill_hole_front_angles(std::vector & vertices, const real_t length //debug(dot(orientation, E.col(2))) V = E.t() * V; -// V.each_col([](a_vec & v){v(2) = 0;}); +// V.each_col([](arma::fvec & v){v(2) = 0;}); bool o = is_grow; - a_vec a = V.col(0); - a_vec b = V.col(1); + arma::fvec a = V.col(0); + arma::fvec b = V.col(1); a(2) = b(2) = 0; a = normalise(a); b = normalise(b); // END PCA ---------------------------------------------------------------------- - std::vector tmp_vertices(size(vertices)); + std::vector tmp_vertices(size(vertices)); std::vector is_border(size(vertices)); std::vector > neighbors(size(vertices)); @@ -656,7 +656,7 @@ che * fill_hole_front_angles(std::vector & vertices, const real_t length real_t a75 = 75.0 * M_PI / 180; real_t a135 = 135.0 * M_PI / 180; - a_vec m_vec; + arma::fvec m_vec; while(!front.empty() && p_iter-- && p_iter < 2000) { while(!front.empty() && @@ -815,7 +815,7 @@ che * fill_hole_front_angles(std::vector & vertices, const real_t length vertices.clear(); vertices.reserve(size(tmp_vertices)); - for(a_vec r: tmp_vertices) + for(arma::fvec r: tmp_vertices) { r = E * r + avg; vertices.push_back({r[0], r[1], r[2]}); diff --git a/src/gproshan/mesh/che_poisson.cpp b/src/gproshan/mesh/che_poisson.cpp index 612ab747..b441ac5b 100644 --- a/src/gproshan/mesh/che_poisson.cpp +++ b/src/gproshan/mesh/che_poisson.cpp @@ -1,7 +1,8 @@ #include #include -#include + +#include // geometry processing and shape analysis framework @@ -12,7 +13,7 @@ void poisson(che * mesh, const size_t old_n_vertices, index_t k) { if(!k) return; - a_mat B(mesh->n_vertices, 3); + arma::fmat B(mesh->n_vertices, 3); for(index_t v = 0; v < mesh->n_vertices; ++v) { if(v < old_n_vertices) @@ -24,13 +25,13 @@ void poisson(che * mesh, const size_t old_n_vertices, index_t k) else B.row(v).zeros(); } - a_sp_mat L, A; + arma::sp_fmat L, A; laplacian(mesh, L, A); for(index_t i = 0; i < mesh->n_vertices; ++i) B.row(i) *= -1 / A(i,i); - a_sp_mat M; + arma::sp_fmat M; real_t s = (k % 2) ? -1 : 1; if(k > 1) M = A * L; @@ -49,7 +50,7 @@ void poisson(che * mesh, const size_t old_n_vertices, index_t k) A.shed_cols(0, old_n_vertices - 1); B.shed_rows(0, old_n_vertices - 1); - a_mat X; + arma::fmat X; if(spsolve(X, s * L, s * B)) for(index_t v = old_n_vertices; v < mesh->n_vertices; ++v) { @@ -59,13 +60,13 @@ void poisson(che * mesh, const size_t old_n_vertices, index_t k) } } -void biharmonic_interp_2(a_mat & P, a_mat & H) +void biharmonic_interp_2(arma::fmat & P, arma::fmat & H) { size_t n = P.n_cols; real_t x; - a_mat A(n, n); - a_vec pi(2), pj(2); + arma::fmat A(n, n); + arma::fvec pi(2), pj(2); for(index_t i = 0; i < n; ++i) { @@ -78,7 +79,7 @@ void biharmonic_interp_2(a_mat & P, a_mat & H) } } - a_mat alpha = solve(A, P.row(2).t()); + arma::fmat alpha = solve(A, P.row(2).t()); for(index_t i = 0; i < H.n_cols; ++i) { @@ -116,7 +117,7 @@ void biharmonic_interp_2(che * mesh, const size_t old_n_vertices, const size_t n delete [] rings; delete [] sorted; - a_mat P(3, size(sub_mesh_hole)); + arma::fmat P(3, size(sub_mesh_hole)); index_t i = 0; for(index_t & b: sub_mesh_hole) { @@ -126,7 +127,7 @@ void biharmonic_interp_2(che * mesh, const size_t old_n_vertices, const size_t n ++i; } - a_mat H(3, n_vertices - old_n_vertices); + arma::fmat H(3, n_vertices - old_n_vertices); for(index_t i = 0, v = old_n_vertices; v < n_vertices; ++i, ++v) { @@ -135,13 +136,13 @@ void biharmonic_interp_2(che * mesh, const size_t old_n_vertices, const size_t n H(2, i) = mesh->point(v).z(); } - a_vec avg = mean(H, 1); + arma::fvec avg = mean(H, 1); P.each_col() -= avg; H.each_col() -= avg; - a_mat E; - a_vec eval; + arma::fmat E; + arma::fvec eval; eig_sym(eval, E, H * H.t()); E.swap_cols(0,2); diff --git a/src/gproshan/mesh/simplification.cpp b/src/gproshan/mesh/simplification.cpp index 26f21a43..2ab6cec0 100644 --- a/src/gproshan/mesh/simplification.cpp +++ b/src/gproshan/mesh/simplification.cpp @@ -9,7 +9,7 @@ simplification::simplification(che * mesh_, const index_t levels_) { mesh = mesh_; levels = levels_; - Q = new a_mat[mesh->n_vertices]; + Q = new arma::fmat[mesh->n_vertices]; execute(); } @@ -33,7 +33,7 @@ void simplification::compute_quadrics() { Q[v].resize(4,4); Q[v].zeros(); - a_vec p(4); + arma::fvec p(4); for(const index_t he: mesh->star(v)) { @@ -68,7 +68,7 @@ void simplification::order_edges(index_t * sort_edges, real_t * error_edges) real_t simplification::compute_error(const index_t e) { vertex ve = create_vertex(e); - a_vec v(4); + arma::fvec v(4); v(0) = ve.x(); v(1) = ve.y(); diff --git a/src/gproshan/raytracing/optix.cpp b/src/gproshan/raytracing/optix.cpp index a68b2c92..cd4b27e6 100644 --- a/src/gproshan/raytracing/optix.cpp +++ b/src/gproshan/raytracing/optix.cpp @@ -94,7 +94,7 @@ optix::optix(const std::string & ptx) cudaMalloc(&optix_params_buffer, sizeof(launch_params)); } -optix::optix(const std::vector & meshes, const std::vector & model_mats): optix() +optix::optix(const std::vector & meshes, const std::vector & model_mats): optix() { // build as optix_params.traversable = build_as(meshes, model_mats); @@ -333,7 +333,7 @@ void optix::build_sbt() sbt.hitgroupRecordCount = size(hitgroup_records); } -OptixTraversableHandle optix::build_as(const std::vector & meshes, const std::vector & model_mats) +OptixTraversableHandle optix::build_as(const std::vector & meshes, const std::vector & model_mats) { OptixTraversableHandle optix_as_handle = {}; diff --git a/src/gproshan/scenes/scanner.cpp b/src/gproshan/scenes/scanner.cpp index efa6f5a2..05b96f89 100644 --- a/src/gproshan/scenes/scanner.cpp +++ b/src/gproshan/scenes/scanner.cpp @@ -46,7 +46,7 @@ che * scanner_ptx(const rt::raytracing * rt, const size_t n_rows, const size_t n real_t max_dist = 0; - #pragma omp parallel for reduction(std::max: max_dist) + #pragma omp parallel for reduction(max: max_dist) for(index_t v = 0; v < mesh_ptx->n_vertices; ++v) max_dist = std::max(max_dist, mesh_ptx->heatmap(v)); @@ -64,8 +64,7 @@ che * scanner_ptx_jpg(const rt::raytracing * rt, const size_t n_rows, const size CImg img((unsigned char *) &mesh_ptx->rgb(0), 3, n_cols, n_rows); img.permute_axes("zycx"); - std::string img_filename = file_jpg + ".jpg"; - img.save(img_filename.c_str()); + img.save((file_jpg + "_scan.jpg").c_str()); std::thread([](const CImg & img) { img.display(); }, img).detach();