diff --git a/CHANGELOG b/CHANGELOG index a39a220bd..dee448522 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,7 @@ improved doc. - [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) diff --git a/Ponca/src/Fitting/mean.h b/Ponca/src/Fitting/mean.h index f037dc1ea..c70ab81cf 100644 --- a/Ponca/src/Fitting/mean.h +++ b/Ponca/src/Fitting/mean.h @@ -122,6 +122,56 @@ namespace Ponca { }; //class MeanPositionDer + template + 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/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: