diff --git a/CHANGELOG b/CHANGELOG index 7d2368994..dee448522 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,9 +10,12 @@ improved doc. - API - [spatialPartitioning] Add kd-tree traits type (#80) - [fitting] Add Primitive::getNumNeighbors (#86) + - [fitting] Change naming convention and rational for principal curvatures in CurvatureEstimatorBase (#94) + - [fitting] Add class MeanNormalDer to compute derivatives of the mean normal vector (#78) - Bug-fixes and code improvements - [spatialPartitioning] Fix unwanted function hiding with DryFit::setWeightFunc (#86) + - [spatialPartitioning] Fix missing include directive in kdTreeTraits.h (#92) - [fitting] Fix a potential bug when using multi-pass fitting (#89) - [fitting] Fix a bug in CovarianceFit (#93) - [fitting] Remove deadcode in Basket (#86) @@ -22,7 +25,7 @@ improved doc. - Fix WeightKernel test (failing on windows due to finite differences) (#91) -Docs - - [spatialPartitioning] Update module page with a minimal doc and examples (#86) + - [spatialPartitioning] Update module page with a minimal doc and examples (#86, #92) - [spatialPartitioning] Add NanoFlann example (#86) -------------------------------------------------------------------------------- diff --git a/Ponca/src/Fitting/curvature.h b/Ponca/src/Fitting/curvature.h index 3d485d058..2d91a8139 100644 --- a/Ponca/src/Fitting/curvature.h +++ b/Ponca/src/Fitting/curvature.h @@ -16,7 +16,8 @@ namespace Ponca template < class DataPoint, class _WFunctor, int DiffType, typename T> /** * - * \brief Base class for any 3d curvature estimator: holds \f$k_1\f$, \f$k_2\f$ and associated vectors + * \brief Base class for any 3d curvature estimator: holds \f$k_{\min}\f$, \f$k_{\max}\f$ and associated vectors, + * such that \f$ k_{\min} <= k_{\max} \f$ */ class CurvatureEstimatorBase : public T { @@ -30,14 +31,14 @@ namespace Ponca }; private: - /// \brief Principal curvature with highest absolute magnitude - Scalar m_k1 {0}, - /// \brief Principal curvature with smallest absolute magnitude - m_k2 {0}; - /// \brief Direction associated to the principal curvature with highest absolute magnitude - VectorType m_v1 {VectorType::Zero()}, - /// \brief Direction associated to the principal curvature with highest smallest magnitude - m_v2 {VectorType::Zero()}; + /// \brief Minimal principal curvature + Scalar m_kmin {0}, + /// \brief Maximal principal curvature + m_kmax {0}; + /// \brief Direction associated to the minimal principal curvature + VectorType m_vmin {VectorType::Zero()}, + /// \brief Direction associated to the maximal principal curvature + m_vmax {VectorType::Zero()}; /// \brief Internal state indicating if the curvature are set to default (false), or have been computed (true) bool m_isValid {false}; @@ -54,38 +55,32 @@ namespace Ponca /**************************************************************************/ /* Use results */ /**************************************************************************/ - //! \brief Returns an estimate of the first principal curvature value - //! - //! It is the greatest curvature in absolute value. - PONCA_MULTIARCH inline Scalar k1() const { return m_k1; } - - //! \brief Returns an estimate of the second principal curvature value - //! - //! It is the smallest curvature in absolute value. - PONCA_MULTIARCH inline Scalar k2() const { return m_k2; } - - //! \brief Returns an estimate of the first principal curvature direction - //! - //! It is the greatest curvature in absolute value. - PONCA_MULTIARCH inline VectorType k1Direction() const { return m_v1; } - - //! \brief Returns an estimate of the second principal curvature direction - //! - //! It is the smallest curvature in absolute value. - PONCA_MULTIARCH inline VectorType k2Direction() const { return m_v2; } + //! \brief Returns an estimate of the minimal principal curvature value + PONCA_MULTIARCH inline Scalar kmin() const { return m_kmin; } + + //! \brief Returns an estimate of the maximal principal curvature value + PONCA_MULTIARCH inline Scalar kmax() const { return m_kmax; } + + //! \brief Returns an estimate of the minimal principal curvature direction + PONCA_MULTIARCH inline VectorType kminDirection() const { return m_vmin; } + + //! \brief Returns an estimate of the maximal principal curvature direction + PONCA_MULTIARCH inline VectorType kmaxDirection() const { return m_vmax; } //! \brief Returns an estimate of the mean curvature - PONCA_MULTIARCH inline Scalar kMean() const { return (m_k1 + m_k2)/Scalar(2);} + PONCA_MULTIARCH inline Scalar kMean() const { return (m_kmin + m_kmax)/Scalar(2);} //! \brief Returns an estimate of the Gaussian curvature - PONCA_MULTIARCH inline Scalar GaussianCurvature() const { return m_k1 * m_k2;} + PONCA_MULTIARCH inline Scalar GaussianCurvature() const { return m_kmin * m_kmax;} protected: /// \brief Set curvature values. To be called in finalize() by child classes /// - /// Principal curvatures are re-ordered depending on their magnitude, - /// such that \f$ |k_1| > |k_2| \f$ - PONCA_MULTIARCH inline void setCurvatureValues(Scalar k1, Scalar k2, const VectorType& v1, const VectorType& v2); + /// If the given parameters are such that \f$ k_{\min} > k_{\max} \f$, then this + /// method swap the two curvature values and directions and store them such that + /// \f$ k_{\min} <= k_{\max} \f$. + /// + PONCA_MULTIARCH inline void setCurvatureValues(Scalar kmin, Scalar kmax, const VectorType& vmin, const VectorType& vmax); }; } //namespace Ponca diff --git a/Ponca/src/Fitting/curvature.hpp b/Ponca/src/Fitting/curvature.hpp index bd0fd180f..8f34082e3 100644 --- a/Ponca/src/Fitting/curvature.hpp +++ b/Ponca/src/Fitting/curvature.hpp @@ -1,14 +1,13 @@ -#include PONCA_MULTIARCH_INCLUDE_STD(cmath) //abs namespace Ponca { template void CurvatureEstimatorBase::init(const VectorType &_evalPos) { Base::init(_evalPos); - m_k1 = 0; - m_k2 = 0; - m_v1 = VectorType::Zero(); - m_v2 = VectorType::Zero(); + m_kmin = 0; + m_kmax = 0; + m_vmin = VectorType::Zero(); + m_vmax = VectorType::Zero(); m_isValid = false; } @@ -16,21 +15,18 @@ namespace Ponca { template void CurvatureEstimatorBase::setCurvatureValues( - Scalar k1, Scalar k2, const VectorType &v1, const VectorType &v2) { - PONCA_MULTIARCH_STD_MATH(abs) - - if (abs(k1) < abs(k2)) { - m_k1 = k2; - m_k2 = k1; - m_v1 = v2; - m_v2 = v1; + Scalar kmin, Scalar kmax, const VectorType &vmin, const VectorType &vmax) { + if(kmin <= kmax) { + m_kmin = kmin; + m_kmax = kmax; + m_vmin = vmin; + m_vmax = vmax; } else { - m_k1 = k1; - m_k2 = k2; - m_v1 = v1; - m_v2 = v2; + m_kmin = kmax; + m_kmax = kmin; + m_vmin = vmax; + m_vmax = vmin; } - m_isValid = true; } } \ No newline at end of file diff --git a/Ponca/src/Fitting/curvatureEstimation.hpp b/Ponca/src/Fitting/curvatureEstimation.hpp index e896386ad..8fda0329f 100644 --- a/Ponca/src/Fitting/curvatureEstimation.hpp +++ b/Ponca/src/Fitting/curvatureEstimation.hpp @@ -148,19 +148,19 @@ NormalCovarianceCurvatureEstimator::finalize m_solver.computeDirect(m_cov); - Scalar k1 = m_solver.eigenvalues()(1); - Scalar k2 = m_solver.eigenvalues()(2); + Scalar kmin = m_solver.eigenvalues()(1); + Scalar kmax = m_solver.eigenvalues()(2); - VectorType v1 = m_solver.eigenvectors().col(1); - VectorType v2 = m_solver.eigenvectors().col(2); + VectorType vmin = m_solver.eigenvectors().col(1); + VectorType vmax = m_solver.eigenvectors().col(2); // fallback // TODO(thib) which epsilon value should be chosen ? Scalar epsilon = Scalar(1e-3); - if(k1::finalize n.rowwise().squaredNorm().minCoeff(&i0); i1 = (i0+1)%3; i2 = (i0+2)%3; - v1[i0] = 0; - v1[i1] = n[i2]; - v1[i2] = -n[i1]; - v2[i0] = n[i1]*n[i1] + n[i2]*n[i2]; - v2[i1] = -n[i1]*n[i0]; - v2[i2] = -n[i2]*n[i0]; + vmin[i0] = 0; + vmin[i1] = n[i2]; + vmin[i2] = -n[i1]; + vmax[i0] = n[i1]*n[i1] + n[i2]*n[i2]; + vmax[i1] = -n[i1]*n[i0]; + vmax[i2] = -n[i2]*n[i0]; } - Base::setCurvatureValues(k1, k2, v1, v2); + Base::setCurvatureValues(kmin, kmax, vmin, vmax); } return res; } @@ -259,8 +259,8 @@ ProjectedNormalCovarianceCurvatureEstimator:: m_solver.computeDirect(m_cov); - Base::m_k1 = m_solver.eigenvalues()(0); - Base::m_k2 = m_solver.eigenvalues()(1); + Base::m_kmin = m_solver.eigenvalues()(0); + Base::m_kmax = m_solver.eigenvalues()(1); // transform from local plane coordinates to world coordinates Base::m_v1 = m_tframe * m_solver.eigenvectors().col(0); @@ -269,10 +269,10 @@ ProjectedNormalCovarianceCurvatureEstimator:: //TODO(thib) which epsilon value should be chosen ? // Scalar epsilon = Eigen::NumTraits::dummy_precision(); Scalar epsilon = Scalar(1e-3); - if(Base::m_k1 + class MeanNormalDer : public T { + PONCA_FITTING_DECLARE_DEFAULT_TYPES + PONCA_FITTING_DECLARE_DEFAULT_DER_TYPES + + protected: + enum { + Check = Base::PROVIDES_PRIMITIVE_DERIVATIVE && + Base::PROVIDES_MEAN_NORMAL, + PROVIDES_MEAN_NORMAL_DERIVATIVE, /*!< \brief Provides derivative of the mean normal*/ + }; + + private: + /*! \brief Derivatives of the input normals of the input points vectors*/ + VectorArray m_dSumN {VectorArray::Zero()}; + + public: + + PONCA_EXPLICIT_CAST_OPERATORS_DER(MeanNormalDer,meanNormalDer) + PONCA_FITTING_DECLARE_INIT + PONCA_FITTING_DECLARE_ADDNEIGHBOR_DER + + /// \brief Compute the derivative of the mean normal vector of the input points. + /// + /// ### Step-by-step derivation of the mean normal : + /// Given the definition of the mean normal \f$ n(\mathbf{x}) = \frac{\sum_i w_\mathbf{x}(\mathbf{n_i}) \mathbf{n_i}}{\sum_i w_\mathbf{x}(\mathbf{n_i})} \f$, + /// where \f$\left[\mathbf{n_i} \in \text{neighborhood}(\mathbf{x})\right]\f$ are all the normal samples in \f$\mathbf{x}\f$'s neighborhood. + /// + /// We denote \f$ t(\mathbf{x}) = \sum_i w_\mathbf{x}(\mathbf{n_i}) \mathbf{n_i} \f$ and \f$ s(\mathbf{x}) = \sum_i w_\mathbf{x}(\mathbf{n_i})\f$, + /// such that \f$ n(\mathbf{x}) = \frac{t(\mathbf{x})}{s(\mathbf{x})}\f$. + /// + /// By definition, \f$ n'(\mathbf{x}) = \frac{s(\mathbf{x})t'(\mathbf{x}) - t(\mathbf{x})s'(\mathbf{x})}{s(\mathbf{x})^2}\f$. + /// + /// Assuming the weight of each normal is dependent on the position, we have \f$ s'(\mathbf{x}) = \sum_i w'_\mathbf{x}(\mathbf{n_i}) \f$. + /// + /// We rewrite \f$ t(\mathbf{x}) = \sum u(\mathbf{x})v(\mathbf{x}) \f$, with \f$ u(\mathbf{x}) = w_\mathbf{x}(\mathbf{n_i}) \f$ and \f$ v(\mathbf{x}) = \mathbf{n_i} \f$. + /// + /// Assuming the normal vectors themselves do not change with position, \f$v(\mathbf{x})\f$ is constant, its derivative is null, + /// and so \f$ t'(\mathbf{x}) = \sum_i u'(\mathbf{x}) v(\mathbf{x}) = \sum_i w'_\mathbf{x}(\mathbf{n_i}) \mathbf{n_i} \f$. + /// + /// Which leads to \f$ n'(\mathbf{x}) = \frac{\sum_i w'\mathbf{x}(\mathbf{n_i}) \mathbf{n_i} - n(\mathbf{x})\sum w'(\mathbf{x})}{\sum_i w\mathbf{x}(\mathbf{n_i})} \f$. + /// \note This code is not directly tested. + + PONCA_MULTIARCH inline const VectorArray& dMeanNormal() const + { + return m_dSumN; + } + + }; //class MeanNormalDer + #include "mean.hpp" } //namespace Ponca diff --git a/Ponca/src/Fitting/mean.hpp b/Ponca/src/Fitting/mean.hpp index 3369581b5..2f4e19ed9 100644 --- a/Ponca/src/Fitting/mean.hpp +++ b/Ponca/src/Fitting/mean.hpp @@ -68,3 +68,25 @@ MeanPositionDer::addLocalNeighbor(Scalar w, return false; } + + +template +void +MeanNormalDer::init(const VectorType &_evalPos) { + Base::init(_evalPos); + m_dSumN.setZero(); +} + +template +bool +MeanNormalDer::addLocalNeighbor(Scalar w, + const VectorType &localQ, + const DataPoint &attributes, + ScalarArray &dw) { + if (Base::addLocalNeighbor(w, localQ, attributes, dw)) { + m_dSumN += attributes.normal() * dw; + return true; + } + + return false; +} diff --git a/Ponca/src/Fitting/orientedSphereFit.h b/Ponca/src/Fitting/orientedSphereFit.h index 065fe5fae..f07ba75c8 100644 --- a/Ponca/src/Fitting/orientedSphereFit.h +++ b/Ponca/src/Fitting/orientedSphereFit.h @@ -135,7 +135,7 @@ class OrientedSphereDerImpl : public T }; //class OrientedSphereDerImpl -/// \brief Helper alias for Plane fitting on 3D points using CovariancePlaneFitImpl +/// \brief Helper alias for Oriented Sphere fitting on 3D points using OrientedSphereDerImpl template < class DataPoint, class _WFunctor, int DiffType, typename T> using OrientedSphereDer = OrientedSphereDerImpl + namespace Ponca { #ifndef PARSED_WITH_DOXYGEN namespace internal diff --git a/doc/src/example.mdoc b/doc/src/example.mdoc index 02b225bb9..fd86d8a11 100644 --- a/doc/src/example.mdoc +++ b/doc/src/example.mdoc @@ -18,6 +18,7 @@ - \subpage example_cu_ssc_page : Calculate Screen Space Curvature using CUDA/C++. - \subpage example_python_ssc_page : Calculate Screen Space Curvature using CUDA/Python. - @ref spatialpartitioning "Spatial Partitioning Module" + - \subpage example_cxx_neighbor_search : Nearest, k-nearest and range neighbor searches using Ponca::KdTree. - \subpage example_cxx_nanoflann_page : Comparison between Nanoflann and Ponca KdTree APIs. */ diff --git a/doc/src/example_cxx_neighbor_search.mdoc b/doc/src/example_cxx_neighbor_search.mdoc new file mode 100644 index 000000000..d982686b2 --- /dev/null +++ b/doc/src/example_cxx_neighbor_search.mdoc @@ -0,0 +1,14 @@ +/* + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + + +/*! + \page example_cxx_neighbor_search Ponca::KdTree neighbor searches + + This is an example of how to use Ponca::KdTree to perform nearest, k-nearest and range neighbor search. + + \include cpp/ponca_neighbor_search.cpp +*/ diff --git a/doc/src/ponca.mdoc b/doc/src/ponca.mdoc index faff972e6..40750b357 100644 --- a/doc/src/ponca.mdoc +++ b/doc/src/ponca.mdoc @@ -46,14 +46,14 @@ \section ponca_credits_sec Credits \subsection ponca_credits_subsection_crew Developers and contributors + Main contributors - Nicolas Mellado : conception, implementation, documentation and examples
- - Aniket Agarwalla (Google Summer of Code 2021) : add new fitting primitives
- - Matthieu Gomiero, Dorian Ferreira, Sacha Vincent : port KdTree code in Spatial Partitioning module
- - Nicolas Dupont, Carl Delrieu, Dorian Verge: add Wendland and Singular weight kernels, as described in \cite Alexa:2009:Hermite
- Thibault Lejemble : implementation of several fitting primitives, differential estimators, and original version of the Spatial Partitioning code
- - Jules Vidal, Antoine Lafon : bug fixes
- - Amael Marquez : KdTree API improvements
+ + Other contributors + - Fitting module : Aniket Agarwalla, Nicolas Dupont, Carl Delrieu, Dorian Verge, Jules Vidal, Antoine Lafon, Anais Bains + - SpatialPartitioning module : Amael Marquez, Matthieu Gomiero, Dorian Ferreira, Sacha Vincent \subsection ponca_credits_subsection_grenaille Patate/Grenaille crew and contributors Ponca is a fork of Patate, module Grenaille, which is now deprecated, and which was developed by: diff --git a/doc/src/ponca_module_fitting.mdoc b/doc/src/ponca_module_fitting.mdoc index a1ac7adbd..aa9f633fb 100644 --- a/doc/src/ponca_module_fitting.mdoc +++ b/doc/src/ponca_module_fitting.mdoc @@ -252,7 +252,7 @@ namespace Ponca \note There is currently no formal description of the API provided by each capability. This will be fixed in upcoming releases. These relations are currently implicitly defined (and used), but not documented. For instance, a tool with the capability `PROVIDES_PRINCIPAL_CURVATURES` provides the following methods: - `k1()`, `k2()`, `k1Direction()`, `k2Direction()`, `kMean()`, `GaussianCurvature()`, see CurvatureEstimatorBase. + `kmin()`, `kmax()`, `kminDirection()`, `kmaxDirection()`, `kMean()`, `GaussianCurvature()`, see CurvatureEstimatorBase. In order to ease tools combinations, each class declare a set of *required* and *provided* capabilities, as listed in the two following table: diff --git a/doc/src/ponca_module_spatialpartitioning.mdoc b/doc/src/ponca_module_spatialpartitioning.mdoc index ea77c9cd1..74e519374 100644 --- a/doc/src/ponca_module_spatialpartitioning.mdoc +++ b/doc/src/ponca_module_spatialpartitioning.mdoc @@ -42,8 +42,12 @@ namespace Ponca \note As queries are objets that are independent from the KdTree, they can be created and used in parallel from multiple threads. + \warning Queries from an index (KdTreeKNearestIndexQuery, KdTreeNearestIndexQuery and KdTreeRangeIndexQuery) do not iterate on the queried index. + \subsection spatialpartitioning_kdtree_examples Examples - KdTree usage is demonstrated both in tests and examples: + + Several KdTree queries are illustrated in the example \ref example_cxx_neighbor_search. + KdTree usage is also demonstrated both in tests and examples: - `tests/src/basket.cpp` - `tests/src/kdtree_knearest.cpp` - `tests/src/kdtree_nearest.cpp` @@ -54,6 +58,16 @@ namespace Ponca Ponca::KdTreeBase is a customizable version of Ponca::KdTree, which can be controlled using `Traits`. See KdTreeDefaultTraits for customization API. + \subsection spatialpartitioning_kdtree_implementation Implementation details + + The kd-tree is a binary search tree that + - is balanced (cuts at the median at each node) + - cuts along the dimension that extends the most at each node + - has a maximal depth (KdTreeDefaultTraits::MAX_DEPTH) + - has a minimal number of points per leaf (KdTreeBase::m_min_cell_size) + - only stores points in the leafs + - uses depth-first search with a static stack for queries + - keeps the initial order of points
[\ref user_manual_page "Go back to user manual"]
*/ diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 53070e5a2..48ecf31c2 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -34,5 +34,13 @@ target_include_directories(ponca_fit_line PRIVATE ${PONCA_src_ROOT}) add_dependencies(ponca-examples ponca_fit_line) ponca_handle_eigen_dependency(ponca_fit_line) +set(ponca_neighbor_search_SRCS + ponca_neighbor_search.cpp +) +add_executable(ponca_neighbor_search ${ponca_neighbor_search_SRCS}) +target_include_directories(ponca_neighbor_search PRIVATE ${PONCA_src_ROOT}) +add_dependencies(ponca-examples ponca_neighbor_search) +ponca_handle_eigen_dependency(ponca_neighbor_search) + add_subdirectory(pcl) add_subdirectory(nanoflann) diff --git a/examples/cpp/ponca_basic_cpu.cpp b/examples/cpp/ponca_basic_cpu.cpp index a592079ae..a45f092e1 100644 --- a/examples/cpp/ponca_basic_cpu.cpp +++ b/examples/cpp/ponca_basic_cpu.cpp @@ -152,10 +152,10 @@ int main() if(fit3.isStable()) { cout << "eigen values: "<< endl; - cout << fit3.k1() << endl; - cout << fit3.k2() << endl; + cout << fit3.kmin() << endl; + cout << fit3.kmax() << endl; cout << "eigen vectors: "<< endl; - cout << fit3.k1Direction() << endl << endl; - cout << fit3.k2Direction() << endl; + cout << fit3.kminDirection() << endl << endl; + cout << fit3.kmaxDirection() << endl; } } diff --git a/examples/cpp/ponca_neighbor_search.cpp b/examples/cpp/ponca_neighbor_search.cpp new file mode 100644 index 000000000..d871689bd --- /dev/null +++ b/examples/cpp/ponca_neighbor_search.cpp @@ -0,0 +1,74 @@ +/* +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#include +#include +#include + +struct DataPoint +{ + enum {Dim = 3}; + using Scalar = float; + using VectorType = Eigen::Vector; + inline const auto& pos() const {return m_pos;} + VectorType m_pos; +}; + +int main() +{ + // generate N random points + constexpr int N = 1e5; + std::vector points(N); + std::generate(points.begin(), points.end(), [](){ + return DataPoint{100 * DataPoint::VectorType::Random()};}); + + // build the k-d tree + const Ponca::KdTree kdtree(points); + + // neighbor searches are done below from these arbitrary index and point + const int query_idx = 10; + const DataPoint::VectorType query_pt{-10.0, 0.5, 75.0}; + + // + // nearest neighbor search + // + std::cout << "the nearest neighbor of the point at index " << query_idx << " is at index " + << *kdtree.nearest_neighbor(query_idx).begin() << std::endl; + std::cout << "the nearest neighbor of the point (" << query_pt.transpose() << ") is at index " + << *kdtree.nearest_neighbor(query_pt).begin() << std::endl; + + // + // k-nearest neighbor search + // + constexpr int k = 10; + std::cout << "the " << k << "-nearest neighbors of the point at index " << query_idx << " are at indices: "; + for(int neighbor_idx : kdtree.k_nearest_neighbors(query_idx, k)) { + std::cout << neighbor_idx << ", "; + } + std::cout << std::endl; + std::cout << "the " << k << "-nearest neighbors of the point (" << query_pt.transpose() << ") are at indices: "; + for(auto neighbor_idx : kdtree.k_nearest_neighbors(query_pt, k)) { + std::cout << neighbor_idx << ", "; + } + std::cout << std::endl; + + // + // range neighbor search + // + constexpr DataPoint::Scalar radius = 5.25; + std::cout << "the neighbors of the point at index " << query_idx << " at a distance " << radius << " are at indices: "; + for(int neighbor_idx : kdtree.range_neighbors(query_idx, radius)) { + std::cout << neighbor_idx << ", "; + } + std::cout << std::endl; + std::cout << "the neighbors of the point (" << query_pt.transpose() << ") at a distance " << radius << " are at indices: "; + for(auto neighbor_idx : kdtree.range_neighbors(query_pt, radius)) { + std::cout << neighbor_idx << ", "; + } + std::cout << std::endl; + + return 1; +} diff --git a/tests/src/algebraicsphere_primitive.cpp b/tests/src/algebraicsphere_primitive.cpp index e2c40ed91..3a5358df4 100644 --- a/tests/src/algebraicsphere_primitive.cpp +++ b/tests/src/algebraicsphere_primitive.cpp @@ -7,7 +7,7 @@ /*! \file test/Grenaille/okabe_primitive.cpp - \brief Test validity Plane Primitive + \brief Test validity Algebraic Sphere Primitive */ #include "../common/testing.h" diff --git a/tests/src/curvature_plane.cpp b/tests/src/curvature_plane.cpp index 6e9d60708..525881797 100644 --- a/tests/src/curvature_plane.cpp +++ b/tests/src/curvature_plane.cpp @@ -64,12 +64,12 @@ void testFunction(bool _bAddPositionNoise = false, bool _bAddNormalNoise = false if( fit.isStable() ){ // Check if principal curvature values are null - VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.k1()), Scalar(1.), epsilon) ); - VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.k2()), Scalar(1.), epsilon) ); + VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.kmin()), Scalar(1.), epsilon) ); + VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.kmax()), Scalar(1.), epsilon) ); // Check if principal curvature directions lie on the plane - VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.k1Direction().dot(direction)), Scalar(1.), epsilon) ); - VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.k2Direction().dot(direction)), Scalar(1.), epsilon) ); + VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.kminDirection().dot(direction)), Scalar(1.), epsilon) ); + VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.kmaxDirection().dot(direction)), Scalar(1.), epsilon) ); } else { VERIFY(FITTING_FAILED); diff --git a/tests/src/curvature_sphere.cpp b/tests/src/curvature_sphere.cpp index 4a2fdee07..357c39816 100644 --- a/tests/src/curvature_sphere.cpp +++ b/tests/src/curvature_sphere.cpp @@ -60,23 +60,23 @@ void testFunction(bool _bAddPositionNoise = false, bool _bAddNormalNoise = false if( fit.isStable() ) { // Check if principal curvature values are equal to the inverse radius -// VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.k1()-curvature), Scalar(1.), epsilon) ); -// VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.k2()-curvature), Scalar(1.), epsilon) ); +// VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.kmin()-curvature), Scalar(1.), epsilon) ); +// VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.kmax()-curvature), Scalar(1.), epsilon) ); // Check if principal curvature directions are tangent to the sphere VectorType normal = (vectorPoints[i].pos()-center).normalized(); - if(!Eigen::internal::isMuchSmallerThan(std::abs(fit.k1Direction().dot(normal)), Scalar(1.), epsilon) || - !Eigen::internal::isMuchSmallerThan(std::abs(fit.k2Direction().dot(normal)), Scalar(1.), epsilon)) + if(!Eigen::internal::isMuchSmallerThan(std::abs(fit.kminDirection().dot(normal)), Scalar(1.), epsilon) || + !Eigen::internal::isMuchSmallerThan(std::abs(fit.kmaxDirection().dot(normal)), Scalar(1.), epsilon)) { - Scalar dot1 = std::abs(fit.k1Direction().dot(normal)); - Scalar dot2 = std::abs(fit.k2Direction().dot(normal)); + Scalar dot1 = std::abs(fit.kminDirection().dot(normal)); + Scalar dot2 = std::abs(fit.kmaxDirection().dot(normal)); cout << "dot1 = " << dot1 << endl; cout << "dot2 = " << dot2 << endl; } - VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.k1Direction().dot(normal)), Scalar(1.), epsilon) ); - VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.k2Direction().dot(normal)), Scalar(1.), epsilon) ); + VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.kminDirection().dot(normal)), Scalar(1.), epsilon) ); + VERIFY( Eigen::internal::isMuchSmallerThan(std::abs(fit.kmaxDirection().dot(normal)), Scalar(1.), epsilon) ); } else { VERIFY(FITTING_FAILED); diff --git a/tests/src/dnormal_sphere.cpp b/tests/src/dnormal_sphere.cpp index 17f482e39..5a0910fa9 100644 --- a/tests/src/dnormal_sphere.cpp +++ b/tests/src/dnormal_sphere.cpp @@ -25,7 +25,7 @@ void testFunction(bool _bAddPositionNoise = false, bool _bAddNormalNoise = false typedef typename DataPoint::VectorType VectorType; typedef typename DataPoint::MatrixType MatrixType; - //generate sampled plane + //generate sampled sphere int nbPoints = Eigen::internal::random(100, 1000); Scalar radius = Eigen::internal::random(1,10); diff --git a/tests/src/fit_radius_curvature_center.cpp b/tests/src/fit_radius_curvature_center.cpp index 15bcddcaa..21e5c26a3 100644 --- a/tests/src/fit_radius_curvature_center.cpp +++ b/tests/src/fit_radius_curvature_center.cpp @@ -51,9 +51,9 @@ subTestSpatial::eval(const Fit& _fit, Scalar /*_fitRadiusKappa*/, Scalar /*_fitRadiusAlgebraic*/){ - Scalar k1 = _fit.k1(); - Scalar k2 = _fit.k2(); - Scalar kmean = (k1 + k2) / Scalar (2.); + Scalar kmin = _fit.kmin(); + Scalar kmax = _fit.kmax(); + Scalar kmean = (kmin + kmax) / Scalar (2.); Scalar radius = Scalar(1.) / kmean; //Test value diff --git a/tests/src/gls_paraboloid_der.cpp b/tests/src/gls_paraboloid_der.cpp index fa4bc2593..2af71cc0c 100644 --- a/tests/src/gls_paraboloid_der.cpp +++ b/tests/src/gls_paraboloid_der.cpp @@ -204,8 +204,11 @@ void testFunction(bool isSigned = true) VectorType normal = flip_fit * fit.primitiveGradient().template cast(); // Scalar kmean = fit.kappa(); - Scalar kappa1 = flip_fit * fit.k1(); - Scalar kappa2 = flip_fit * fit.k2(); + // principal curvatures k1,k2 are used here such that |k1| > |k2| (instead of kmin < kmax) + Scalar kmin = fit.kmin(); + Scalar kmax = fit.kmax(); + Scalar kappa1 = flip_fit * (std::abs(kmin)