...
 
Commits (17)
......@@ -86,6 +86,11 @@ public:
resetPrimitive();
}
/*! \brief Explicit conversion to AlgebraicSphere, to access methods potentially hidden by inheritage */
MULTIARCH inline
AlgebraicSphere<DataPoint, WFunctor, T>& algebraicSphere()
{ return * static_cast<AlgebraicSphere<DataPoint, WFunctor, T>*>(this); }
/*! \brief Set the scalar field values to 0 and reset the isNormalized() status
\warning Set m_ul to Zero(), which leads to nans in OrientedSphere::normal()
......@@ -206,12 +211,18 @@ public:
//! \brief Value of the scalar field at the location \f$ \mathbf{q} \f$
MULTIARCH inline Scalar potential (const VectorType& _q) const;
/*! \brief Value of the scalar field at the evaluation point */
MULTIARCH inline Scalar potential() const { return m_uc; }
//! \brief Project a point on the sphere
MULTIARCH inline VectorType project (const VectorType& _q) const;
//! \brief Approximation of the scalar field gradient at \f$ \mathbf{q} (not normalized) \f$
MULTIARCH inline VectorType primitiveGradient (const VectorType& _q) const;
/*! \brief Approximation of the scalar field gradient at the evaluation point */
MULTIARCH inline VectorType primitiveGradient () const { return m_ul.normalized(); }
/*!
\brief Used to know if the fitting result to a plane
\return true if finalize() have been called and the fitting result to a plane
......
......@@ -37,7 +37,14 @@ private:
protected:
enum
{
Check = Base::PROVIDES_PLANE
Check = Base::PROVIDES_PLANE,
/*!
* \brief Expose a method worldToTangentPlane(VectorType), which turns a point
* in ambient 3D space to the tangent plane.
* \see worldToTangentPlane
* \see tangentPlaneToWorld
*/
PROVIDES_TANGENT_PLANE_BASIS
};
public:
......@@ -57,8 +64,7 @@ public:
// computation data
Scalar m_sumW; /*!< \brief Sum of queries weight.*/
VectorType m_cog, /*!< \brief Gravity center of the neighborhood */
m_evalPos; /*!< \brief Center of the evaluation basis */
VectorType m_cog; /*!< \brief Gravity center of the neighborhood */
MatrixType m_cov; /*!< \brief Covariance matrix */
Solver m_solver; /*!<\brief Solver used to analyse the covariance matrix */
......@@ -70,6 +76,11 @@ public:
/*! \brief Default constructor */
MULTIARCH inline CovariancePlaneFit() : Base() {}
/*! \brief Explicit conversion to CovariancePlaneFit, to access methods potentially hidden by inheritage */
MULTIARCH inline
CovariancePlaneFit<DataPoint, WFunctor, T>& covariancePlaneFit()
{ return * static_cast<CovariancePlaneFit<DataPoint, WFunctor, T>*>(this); }
/**************************************************************************/
/* Initialization */
/**************************************************************************/
......@@ -94,12 +105,6 @@ public:
using Base::potential;
/*! \brief Value of the scalar field at the evaluation point */
MULTIARCH inline Scalar potential() const { return Base::potential(m_evalPos); }
/*! \brief Value of the normal of the primitive at the evaluation point */
MULTIARCH inline VectorType normal() const { return Base::m_p.template head<DataPoint::Dim>(); }
/*! \brief Reading access to the Solver used to analyse the covariance
matrix */
MULTIARCH inline const Solver& solver() const { return m_solver; }
......@@ -111,6 +116,22 @@ public:
\return 0 for invalid fits
*/
MULTIARCH inline Scalar surfaceVariation() const;
/*!
* \brief Express a point in ambiant space relatively to the tangent plane.
* Output vector is: [h, u, v]^T, where u, v are 2d coordinates on the plane,
* and h the height of the sample.
* \tparam ignoreTranslation must be set to true when passing vectors instead of points
*/
template <bool ignoreTranslation = false>
MULTIARCH inline VectorType worldToTangentPlane(const VectorType &_q) const;
/*!
* \brief Transform a point from the tangent plane [h, u, v]^T to ambiant space
* \tparam ignoreTranslation must be set to true when passing vectors instead of points
*/
template <bool ignoreTranslation = false>
MULTIARCH inline VectorType tangentPlaneToWorld(const VectorType &_q) const;
}; //class CovariancePlaneFit
namespace internal {
......
......@@ -14,11 +14,10 @@ CovariancePlaneFit<DataPoint, _WFunctor, T>::init(const VectorType& _evalPos)
{
// Setup primitive
Base::resetPrimitive();
// Base::basisCenter() = _evalPos;
Base::basisCenter() = _evalPos;
// Setup fitting internal values
m_sumW = Scalar(0.0);
m_evalPos = _evalPos;
m_cog = VectorType::Zero();
m_cov = MatrixType::Zero();
}
......@@ -27,7 +26,7 @@ template < class DataPoint, class _WFunctor, typename T>
bool
CovariancePlaneFit<DataPoint, _WFunctor, T>::addNeighbor(const DataPoint& _nei)
{
VectorType q = _nei.pos() - m_evalPos;
VectorType q = _nei.pos() - Base::basisCenter();
// compute weight
Scalar w = m_w.w(q, _nei);
......@@ -57,26 +56,26 @@ CovariancePlaneFit<DataPoint, _WFunctor, T>::finalize ()
return Base::m_eCurrentState;
}
// Finalize the centroid (still expressed in local basis)
m_cog = m_cog/m_sumW;
// Center the covariance on the centroid:
m_cov -= m_cog * m_cog.transpose() / m_sumW;
m_cov += - Scalar(2) * m_cov/m_sumW + m_cog * m_cog.transpose();
// \note The covariance matrix should be here normalized by m_sumW.
// As it does not affect the eigen decomposition, we skip this normalization
// to save computation.
// Finalize the centroid
m_cog = m_cog/m_sumW + m_evalPos;
#ifdef __CUDACC__
m_solver.computeDirect(m_cov);
#else
m_solver.compute(m_cov);
#endif
Base::m_eCurrentState = ( m_solver.info() == Eigen::Success ? STABLE : UNDEFINED );
Base::setPlane(m_solver.eigenvectors().col(0), m_cog);
// \todo Use the output of the solver to check stability
Base::m_eCurrentState = STABLE;
return Base::m_eCurrentState;
}
......@@ -85,12 +84,35 @@ template < class DataPoint, class _WFunctor, typename T>
typename CovariancePlaneFit<DataPoint, _WFunctor, T>::Scalar
CovariancePlaneFit<DataPoint, _WFunctor, T>::surfaceVariation () const
{
if( Base::m_eCurrentState == UNDEFINED )
return 0;
return m_solver.eigenvalues()(0) / m_solver.eigenvalues().mean();
}
template < class DataPoint, class _WFunctor, typename T>
template <bool ignoreTranslation>
typename CovariancePlaneFit<DataPoint, _WFunctor, T>::VectorType
CovariancePlaneFit<DataPoint, _WFunctor, T>::worldToTangentPlane (const VectorType& _q) const
{
if (ignoreTranslation)
return m_solver.eigenvectors().transpose() * _q;
else {
// apply rotation and translation to get uv coordinates
return m_solver.eigenvectors().transpose() * (_q - Base::basisCenter());
}
}
template < class DataPoint, class _WFunctor, typename T>
template <bool ignoreTranslation>
typename CovariancePlaneFit<DataPoint, _WFunctor, T>::VectorType
CovariancePlaneFit<DataPoint, _WFunctor, T>::tangentPlaneToWorld (const VectorType& _lq) const
{
if (ignoreTranslation)
return m_solver.eigenvectors().transpose().inverse() * _lq;
else {
return m_solver.eigenvectors().transpose().inverse() * _lq + Base::basisCenter();
}
}
namespace internal
{
......@@ -121,7 +143,7 @@ CovariancePlaneDer<DataPoint, _WFunctor, T, Type>::addNeighbor(const DataPoint
ScalarArray dw;
// centered basis
VectorType q = _nei.pos()-Base::m_evalPos;
VectorType q = _nei.pos()-Base::basisCenter();
// compute weight
if (Type & FitScaleDer)
......@@ -162,22 +184,15 @@ CovariancePlaneDer<DataPoint, _WFunctor, T, Type>::finalize()
for(int k=0; k<NbDerivatives; ++k)
{
// Finalize the computation of dCov.
// Note that at this stage m_dCog = sum_i dw_i * (p_i-c).
// Since the covariance matrix is translation invariant,
// this step natuarally cancels the centered basis.
VectorType shifted_cog = Base::m_cog - Base::m_evalPos;
m_dCov[k] = m_dCov[k]
- shifted_cog * m_dCog.col(k).transpose()
- m_dCog.col(k) * shifted_cog.transpose()
+ m_dSumW[k] * shifted_cog * shifted_cog.transpose();
// cancel centered basis of dCog:
m_dCog.col(k) += m_dSumW[k] * Base::m_evalPos;
- Base::m_cog * m_dCog.col(k).transpose()
- m_dCog.col(k) * Base::m_cog.transpose()
+ m_dSumW[k] * Base::m_cog * Base::m_cog.transpose();
// apply normalization by sumW:
m_dCog.col(k) = (m_dCog.col(k) - m_dSumW(k) * Base::m_cog) / Base::m_sumW;
VectorType normal = Base::normal();
VectorType normal = Base::primitiveGradient();
// The derivative of 'normal' is the derivative of the smallest eigenvector.
// Since the covariance matrix is real and symmetric, it is equal to:
// n' = - (C - lambda_0 I)^+ C' n
......@@ -194,7 +209,10 @@ CovariancePlaneDer<DataPoint, _WFunctor, T, Type>::finalize()
VectorType dDiff = -m_dCog.col(k);
if(k>0 || !isScaleDer())
dDiff(isScaleDer() ? k-1 : k) += 1;
m_dDist(k) = m_dNormal.col(k).dot(Base::m_evalPos-Base::m_cog) + normal.dot(dDiff);
m_dDist(k) = m_dNormal.col(k).dot(Base::m_cog) + normal.dot(dDiff);
// \fixme we shouldn't need this normalization, however currently the derivatives are overestimated by a factor 2
m_dNormal /= Scalar(2.);
}
}
......
......@@ -91,7 +91,7 @@ CurvatureEstimator<DataPoint, _WFunctor, T>::tangentPlane(bool useNormal) const
if(useNormal)
{
VectorType n = Base::normal();
VectorType n = Base::primitiveGradient();
n.minCoeff(&i0);
i1 = (i0+1)%3;
i2 = (i0+2)%3;
......
......@@ -4,8 +4,6 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <Eigen/Eigenvalues>
#ifndef _GRENAILLE_GLS_
#define _GRENAILLE_GLS_
......@@ -100,7 +98,7 @@ public:
}
/*! \brief Compute and return \f$ \eta \f$ */
MULTIARCH inline VectorType eta() const { return Base::normal(); }
MULTIARCH inline VectorType eta() const { return Base::primitiveGradient(); }
/*! \brief Compute and return \f$ \kappa \f$ */
MULTIARCH inline Scalar kappa() const
......
/*
Copyright (C) 2018 Nicolas Mellado <nmellado0@gmail.com>
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/.
*/
#ifndef _GRENAILLE_MEAN_PLANE_FIT_
#define _GRENAILLE_MEAN_PLANE_FIT_
#include "enums.h"
namespace Grenaille
{
/*!
\brief Plane fitting procedure computing the mean position and orientation
from oriented points
\inherit Concept::FittingProcedureConcept
\see CompactPlane
\todo Add derivatives
*/
template < class DataPoint, class _WFunctor, typename T >
class MeanPlaneFit : public CompactPlane<DataPoint, _WFunctor>
{
private:
typedef CompactPlane<DataPoint, _WFunctor> Base;
protected:
enum
{
Check = Base::PROVIDES_PLANE
};
public:
/*! \brief Scalar type inherited from DataPoint*/
typedef typename Base::Scalar Scalar;
/*! \brief Vector type inherited from DataPoint*/
typedef typename Base::VectorType VectorType;
/*! \brief Vector type inherited from DataPoint*/
typedef typename Base::MatrixType MatrixType;
/*! \brief Weight Function*/
typedef _WFunctor WFunctor;
protected:
// computation data
Scalar m_sumW; /*!< \brief Sum of queries weight.*/
VectorType m_sumN, /*!< \brief Sum of the normal vectors */
m_sumP; /*!< \brief Sum of the relative positions */
WFunctor m_w; /*!< \brief Weight function (must inherits BaseWeightFunc) */
public:
/*! \brief Default constructor */
MULTIARCH inline MeanPlaneFit() : Base() {}
/**************************************************************************/
/* Initialization */
/**************************************************************************/
/*! \copydoc Concept::FittingProcedureConcept::setWeightFunc() */
MULTIARCH inline void setWeightFunc (const WFunctor& _w) { m_w = _w; }
/*! \copydoc Concept::FittingProcedureConcept::init() */
MULTIARCH inline void init (const VectorType& _evalPos);
/**************************************************************************/
/* Processing */
/**************************************************************************/
/*! \copydoc Concept::FittingProcedureConcept::addNeighbor() */
MULTIARCH inline bool addNeighbor(const DataPoint &_nei);
/*! \copydoc Concept::FittingProcedureConcept::finalize() */
MULTIARCH inline FIT_RESULT finalize();
}; //class MeanPlaneFit
#include "meanPlaneFit.hpp"
} //namespace Grenaille
#endif
/*
Copyright (C) 2018 Nicolas Mellado <nmellado0@gmail.com>
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/.
*/
template < class DataPoint, class _WFunctor, typename T>
void
MeanPlaneFit<DataPoint, _WFunctor, T>::init(const VectorType& _evalPos)
{
// Setup primitive
Base::resetPrimitive();
Base::basisCenter() = _evalPos;
// Setup fitting internal values
m_sumP = VectorType::Zero();
m_sumN = VectorType::Zero();
m_sumW = Scalar(0.0);
}
template < class DataPoint, class _WFunctor, typename T>
bool
MeanPlaneFit<DataPoint, _WFunctor, T>::addNeighbor(const DataPoint& _nei)
{
VectorType q = _nei.pos() - Base::basisCenter();
// compute weight
Scalar w = m_w.w(q, _nei);
if (w > Scalar(0.))
{
m_sumP += q * w;
m_sumN += _nei.normal() * w;
m_sumW += w;
++(Base::m_nbNeighbors);
return true;
}
return false;
}
template < class DataPoint, class _WFunctor, typename T>
FIT_RESULT
MeanPlaneFit<DataPoint, _WFunctor, T>::finalize ()
{
// handle specific configurations
// With less than 3 neighbors the fitting is undefined
if(m_sumW == Scalar(0.) || Base::m_nbNeighbors == 0)
{
Base::resetPrimitive();
Base::m_eCurrentState = UNDEFINED;
return Base::m_eCurrentState;
}
Base::setPlane(m_sumN / m_sumW, m_sumP / m_sumW);
return Base::m_eCurrentState = STABLE;
}
/*
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/.
*/
#ifndef _GRENAILLE_MONGE_PATCH_
#define _GRENAILLE_MONGE_PATCH_
#include <iostream>
namespace Grenaille
{
/*!
* \brief Extension to compute the best fit quadric on 3d points expressed as f(u,v)=h
*
* \note This procedure requires at least two passes, the first one for plane fitting,
* the second one for quadric fitting.
* \warning This class is valid only in 3D.
*/
template < class DataPoint, class _WFunctor, typename T>
class MongePatch : public T
{
private:
using Base = T;
protected:
enum
{
Check = Base::PROVIDES_PLANE && Base::PROVIDES_TANGENT_PLANE_BASIS
};
public:
typedef typename Base::Scalar Scalar; /*!< \brief Inherited scalar type*/
typedef typename Base::VectorType VectorType; /*!< \brief Inherited vector type*/
typedef typename DataPoint::MatrixType MatrixType; /*!< \brief Matrix type inherited from DataPoint*/
typedef _WFunctor WFunctor; /*!< \brief Weight Function */
typedef Eigen::Matrix<Scalar,2,1> Vector2;
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorX;
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixX;
protected:
MatrixX m_A; /*!< \brief Quadric input samples */
MatrixX m_x; /*!< \brief Quadric parameters */
VectorX m_b; /*!< \brief Obervations */
int m_neiIdx; /*!< \brief Counter of observations, used in addNeighhor() */
bool m_planeIsReady;
public:
/*! \brief Explicit conversion to MongePatch, to access methods potentially hidden by inheritage */
MULTIARCH inline
MongePatch<DataPoint, WFunctor, T>& mongePatch()
{ return * static_cast<MongePatch<DataPoint, WFunctor, T>*>(this); }
/**************************************************************************/
/* Initialization */
/**************************************************************************/
/*! \copydoc Concept::FittingProcedureConcept::init() */
MULTIARCH inline void init (const VectorType& _evalPos);
/**************************************************************************/
/* Processing */
/**************************************************************************/
/*! \copydoc Concept::FittingProcedureConcept::addNeighbor() */
MULTIARCH inline bool addNeighbor(const DataPoint &_nei);
/*! \copydoc Concept::FittingProcedureConcept::finalize() */
MULTIARCH inline FIT_RESULT finalize();
//! \brief Returns an estimate of the mean curvature
MULTIARCH inline Scalar kMean() const;
//! \brief Returns an estimate of the Gaussian curvature
MULTIARCH inline Scalar GaussianCurvature() const;
MULTIARCH inline Scalar evalUV(Scalar u, Scalar v) const {
return h_uu()*u*u + h_vv()*v*v + h_uv()*u*v + h_u()*u + h_v()*v + h_c();
}
/*! \brief Value of the scalar field at the evaluation point */
MULTIARCH inline Scalar potential(const VectorType& _q) const {
VectorType x = Base::worldToTangentPlane(_q);
return evalUV(*(x.data()+1),*(x.data()+2)) - *(x.data());
}
//! \brief Orthogonal projecting on the patch, such that h = f(u,v)
MULTIARCH inline VectorType project (const VectorType& _q) const
{
VectorType x = Base::worldToTangentPlane(_q);
*(x.data()) = evalUV(*(x.data()+1),*(x.data()+2));
return Base::tangentPlaneToWorld(x);
}
MULTIARCH inline const Scalar & h_uu () const { return *(m_x.data()); }
MULTIARCH inline const Scalar & h_vv () const { return *(m_x.data()+1); }
MULTIARCH inline const Scalar & h_uv () const { return *(m_x.data()+2); }
MULTIARCH inline const Scalar & h_u () const { return *(m_x.data()+3); }
MULTIARCH inline const Scalar & h_v () const { return *(m_x.data()+4); }
MULTIARCH inline const Scalar & h_c () const { return *(m_x.data()+5); }
};
#include "mongePatch.hpp"
} //namespace Grenaille
#endif

#include <Eigen/SVD>
#include <Eigen/Geometry>
template < class DataPoint, class _WFunctor, typename T>
void
MongePatch<DataPoint, _WFunctor, T>::init(const VectorType& _evalPos)
{
Base::init(_evalPos);
m_x.setZero();
m_planeIsReady = false;
}
template < class DataPoint, class _WFunctor, typename T>
bool
MongePatch<DataPoint, _WFunctor, T>::addNeighbor(const DataPoint& _nei)
{
if(! m_planeIsReady)
{
return Base::addNeighbor(_nei);
}
else // base plane is ready, we can now fit the patch
{
VectorType q = _nei.pos() - Base::basisCenter();
Scalar w = Base::m_w.w(q, _nei);
if (w > Scalar(0.))
{
// express neighbor in local coordinate frame
VectorType local = Base::worldToTangentPlane(_nei.pos());
const Scalar& h = *(local.data());
const Scalar& u = *(local.data()+1);
const Scalar& v = *(local.data()+2);
Eigen::Matrix<Scalar, 6, 1 > p;
p << u*u, v*v, u*v, u, v, 1;
m_A += w*p*p.transpose();
m_b += w*h*p;
return true;
}
}
return false;
}
template < class DataPoint, class _WFunctor, typename T>
FIT_RESULT
MongePatch<DataPoint, _WFunctor, T>::finalize ()
{
// end of the fitting process, check plane is ready
if (! m_planeIsReady) {
FIT_RESULT res = Base::finalize();
if(res == STABLE) { // plane is ready
m_planeIsReady = true;
m_A = MatrixX(6,6/*5*/);
m_A.setZero();
m_b = VectorX(6);
m_b.setZero();
m_neiIdx = 0;
return Base::m_eCurrentState = NEED_OTHER_PASS;
}
return res;
}
// end of the monge patch fitting process
else {
// we use BDCSVD as the matrix size is 36
// http://eigen.tuxfamily.org/dox/classEigen_1_1BDCSVD.html
m_x = m_A.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(m_b);
return Base::m_eCurrentState = STABLE;
}
}
template < class DataPoint, class _WFunctor, typename T>
typename MongePatch<DataPoint, _WFunctor, T>::Scalar
MongePatch<DataPoint, _WFunctor, T>::kMean() const {
MULTIARCH_STD_MATH(pow);
static const Scalar one (1);
static const Scalar two (2);
static const Scalar threeOverTwo (Scalar(3)/Scalar(2));
return ((one + pow(h_v(),two) ) * h_uu() * two*h_u()*h_v()*h_uv() + (one+pow(h_u(),two))*h_vv()) /
(two * pow(one +pow(h_u(),two) + pow(h_v(),two),threeOverTwo));
}
template < class DataPoint, class _WFunctor, typename T>
typename MongePatch<DataPoint, _WFunctor, T>::Scalar
MongePatch<DataPoint, _WFunctor, T>::GaussianCurvature() const {
MULTIARCH_STD_MATH(pow);
static const Scalar one (1);
static const Scalar two (2);
return (h_uu()*h_vv() - pow(h_uv(),two)) /
pow((one + pow(h_u(),two) + pow(h_v(),two) ), two);
}
......@@ -76,19 +76,6 @@ public:
/*! \copydoc Concept::FittingProcedureConcept::finalize() */
MULTIARCH inline FIT_RESULT finalize();
/**************************************************************************/
/* Results */
/**************************************************************************/
using Base::potential;
/*! \brief Value of the scalar field at the evaluation point */
MULTIARCH inline Scalar potential() const { return Base::m_uc; }
/*! \brief Value of the normal of the primitive at the evaluation point */
MULTIARCH inline VectorType normal() const { return Base::m_ul.normalized(); }
}; //class OrientedSphereFit
......
......@@ -11,6 +11,8 @@
#define _GRENAILLE_PLANE_
#include "primitive.h" // PrimitiveBase
#include <Eigen/Geometry>
#include <iostream>
namespace Grenaille
{
......@@ -24,28 +26,27 @@ namespace Grenaille
\f$ s_\mathbf{u}(\mathbf{x}) =
\left[ \mathbf{x}^T \; 1 \;\right]^T \cdot \mathbf{p} \f$.
This class uses a compact storage of n+1 scalars in n-dimensionnal space. It
can be sensitive to the data scale, leading to potential instabilities
due to round errors at large scales.
\todo Add standard plane storing 2n scalars (direction and center).
This class inherits Eigen::Hyperplane.
This primitive requires the definition of n-dimensionnal vectors
(VectorType) and homogeneous n-dimensionnal vectors (HVectorType) in
Concept::PointConcept.
(VectorType) in Concept::PointConcept.
This primitive provides:
\verbatim PROVIDES_PLANE \endverbatim
\note The first n-components of the plane must define a normalized vector
*/
template < class DataPoint, class _WFunctor, typename T = void >
class CompactPlane : public PrimitiveBase<DataPoint, _WFunctor>
class CompactPlane : public PrimitiveBase<DataPoint, _WFunctor>,
public Eigen::Hyperplane<typename DataPoint::Scalar, DataPoint::Dim >
{
private:
typedef PrimitiveBase<DataPoint, _WFunctor> Base;
using Base = PrimitiveBase<DataPoint, _WFunctor>;
public:
/// \brief Specialization of Eigen::Hyperplane inherited by Grenaille::CompactPlane
using EigenBase = Eigen::Hyperplane<typename DataPoint::Scalar, DataPoint::Dim >;
protected:
......@@ -62,35 +63,41 @@ public:
typedef typename DataPoint::VectorType VectorType;
/*! \brief Matrix type inherited from DataPoint */
typedef typename DataPoint::MatrixType MatrixType;
/*! \brief Homogeneous vector type inherited from DataPoint */
typedef typename DataPoint::HVectorType HVectorType;
/*! \brief Weight Function */
typedef _WFunctor WFunctor;
// results
public:
private:
//! \brief Evaluation position (needed for centered basis)
VectorType m_p;
HVectorType m_p; /*!< \brief Homogeneous plane representation */
public:
/*! \brief Default constructor */
MULTIARCH inline CompactPlane()
: Base()
: Base(), EigenBase()
{
m_p = VectorType::Zero();
resetPrimitive();
}
/*! \brief Set the scalar field values to 0 and reset the isNormalized()
/*! \brief Explicit conversion to CompactPlane, to access methods potentially hidden by inheritage */
MULTIARCH inline
CompactPlane<DataPoint, WFunctor, T>& compactPlane()
{ return * static_cast<CompactPlane<DataPoint, WFunctor, T>*>(this); }
/*! \brief Set the scalar field values to 0
status */
MULTIARCH inline void resetPrimitive()
{
Base::resetPrimitive();
m_p = HVectorType::Zero();
EigenBase* cc = static_cast<EigenBase*>(this);
*cc = EigenBase();
}
MULTIARCH inline bool operator==(const CompactPlane<DataPoint, WFunctor, T>& other) const{
return m_p == other.m_p;
return EigenBase::isApprox(other);
}
/*! \brief Comparison operator, convenience function */
......@@ -98,37 +105,54 @@ public:
return ! ((*this) == other);
}
/*! \brief Reading access to the basis center (evaluation position) */
MULTIARCH inline const VectorType& basisCenter () const { return m_p; }
/*! \brief Writing access to the (evaluation position) */
MULTIARCH inline VectorType& basisCenter () { return m_p; }
/* \brief Init the plane from a direction and a position
\param _dir Orientation of the plane
\param _dir Orientation of the plane, does not need to be normalized
\param _pos Position of the plane
*/
MULTIARCH inline void setPlane (const VectorType& _dir,
const VectorType& _pos)
{
m_p.template head<DataPoint::Dim>() = _dir.normalized();
m_p.template tail<1>()<< -_pos.dot(m_p.template head<DataPoint::Dim>());
EigenBase* cc = static_cast<EigenBase*>(this);
*cc = EigenBase(_dir.normalized(), _pos);
}
/*! \brief Value of the scalar field at the evaluation point */
MULTIARCH inline Scalar potential ( ) const
{
return EigenBase::signedDistance(VectorType::Zero());
}
//! \brief Value of the scalar field at the location \f$ \mathbf{q} \f$
MULTIARCH inline Scalar potential (const VectorType& _q) const
{
// Project on the normal vector and add the offset value
return m_p.template head<DataPoint::Dim>().dot(_q) +
*( m_p.template tail<1>().data() );
// The potential is the distance from the point to the plane
return EigenBase::signedDistance(_q - m_p);
}
//! \brief Project a point on the plane
MULTIARCH inline VectorType project (const VectorType& _q) const
{
// The potential is the distance from the point to the plane
return _q - potential(_q) * m_p.template head<DataPoint::Dim>();
// Project on the normal vector and add the offset value
return EigenBase::projection(_q - m_p) + m_p;
}
//! \brief Scalar field gradient direction at the evaluation point
MULTIARCH inline VectorType primitiveGradient () const
{
// Uniform gradient defined only by the orientation of the plane
return EigenBase::normal();
}
//! \brief Scalar field gradient direction at \f$ \mathbf{q}\f$
MULTIARCH inline VectorType primitiveGradient (const VectorType&) const
{
// Uniform gradient defined only by the orientation of the plane
return m_p.template head<DataPoint::Dim>();
return EigenBase::normal();
}
......
/*
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/.
*/
#ifndef _GRENAILLE_SPHERE_FIT_
#define _GRENAILLE_SPHERE_FIT_
#include "algebraicSphere.h"
namespace Grenaille
{
/*!
\brief Algebraic Sphere fitting procedure on point sets without normals
Method published in \cite Guennebaud:2007:APSS.
\inherit Concept::FittingProcedureConcept
\see AlgebraicSphere
*/
template < class DataPoint, class _WFunctor, typename T = void >
class SphereFit : public AlgebraicSphere<DataPoint, _WFunctor>
{
private:
typedef AlgebraicSphere<DataPoint, _WFunctor> Base;
public:
/*! \brief Scalar type inherited from DataPoint*/
typedef typename Base::Scalar Scalar;
/*! \brief Vector type inherited from DataPoint*/
typedef typename Base::VectorType VectorType;
/*! \brief Weight Function*/
typedef _WFunctor WFunctor;
protected:
typedef Eigen::Matrix<Scalar, DataPoint::Dim+2, 1> VectorA;
typedef Eigen::Matrix<Scalar, DataPoint::Dim+2, DataPoint::Dim+2> MatrixA;
// computation data
MatrixA m_matA; /*!< \brief Covariance matrix of [1, p, p^2] */
Scalar m_sumW; /*!< \brief Sum of queries weight */
WFunctor m_w; /*!< \brief Weight function (must inherits BaseWeightFunc) */
public:
/*! \brief Default constructor */
MULTIARCH inline SphereFit()
: Base(){}
/**************************************************************************/
/* Initialization */
/**************************************************************************/
/*! \copydoc Concept::FittingProcedureConcept::setWeightFunc() */
MULTIARCH inline void setWeightFunc (const WFunctor& _w) { m_w = _w; }
/*! \copydoc Concept::FittingProcedureConcept::init() */
MULTIARCH inline void init (const VectorType& _evalPos);
/**************************************************************************/
/* Processing */
/**************************************************************************/
/*! \copydoc Concept::FittingProcedureConcept::addNeighbor() */
MULTIARCH inline bool addNeighbor(const DataPoint &_nei);
/*! \copydoc Concept::FittingProcedureConcept::finalize() */
MULTIARCH inline FIT_RESULT finalize();
}; //class SphereFit
#include "sphereFit.hpp"
} //namespace Grenaille
#endif
/*
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/.
*/
template < class DataPoint, class _WFunctor, typename T>
void
SphereFit<DataPoint, _WFunctor, T>::init(const VectorType& _evalPos)
{
// Setup primitive
Base::resetPrimitive();
Base::basisCenter() = _evalPos;
// Setup fitting internal values
m_sumW = Scalar(0.0);
m_matA.setZero();
}
template < class DataPoint, class _WFunctor, typename T>
bool
SphereFit<DataPoint, _WFunctor, T>::addNeighbor(const DataPoint& _nei)
{
// centered basis
VectorType q = _nei.pos() - Base::basisCenter();
// compute weight
Scalar w = m_w.w(q, _nei);
if (w > Scalar(0.))
{
VectorA a;
#ifdef __CUDACC__
a(0) = 1;
a.template segment<DataPoint::Dim>(1) = q;
a(DataPoint::Dim+1) = q.squaredNorm();
#else
a << 1, q, q.squaredNorm();
#endif
m_matA += w * a * a.transpose();
m_sumW += w;
++(Base::m_nbNeighbors);
return true;
}
return false;
}
template < class DataPoint, class _WFunctor, typename T>
FIT_RESULT
SphereFit<DataPoint, _WFunctor, T>::finalize ()
{
// handle specific configurations
// With less than 3 neighbors the fitting is undefined
if(m_sumW == Scalar(0.) || Base::m_nbNeighbors < 3)
{
Base::m_ul.setZero();
Base::m_uc = Scalar(0.);
Base::m_uq = Scalar(0.);
Base::m_isNormalized = false;
Base::m_eCurrentState = UNDEFINED;
return Base::m_eCurrentState;
}
MatrixA matC;
matC.setIdentity();
matC.template topRightCorner<1,1>() << -2;
matC.template bottomLeftCorner<1,1>() << -2;
matC.template topLeftCorner<1,1>() << 0;
matC.template bottomRightCorner<1,1>() << 0;
MatrixA invCpratt;
invCpratt.setIdentity();
invCpratt.template topRightCorner<1,1>() << -0.5;
invCpratt.template bottomLeftCorner<1,1>() << -0.5;
invCpratt.template topLeftCorner<1,1>() << 0;
invCpratt.template bottomRightCorner<1,1>() << 0;
MatrixA M = invCpratt * m_matA;
// go to positive semi-definite matrix to be compatible with
// SelfAdjointEigenSolver requirements
// Note: This does not affect the eigen vectors order
Eigen::SelfAdjointEigenSolver<MatrixA> solver;
#ifdef __CUDACC__
solver.computeDirect(M.transpose() * M);
#else
solver.compute(M.transpose() * M);
#endif
VectorA eivals = solver.eigenvalues().real();
int minId = -1;
for(int i=0 ; i<DataPoint::Dim+2 ; ++i)
{
Scalar ev = eivals(i);
if((ev>0) && (minId==-1 || ev<eivals(minId)))
minId = i;
}
//mLambda = eivals(minId);
VectorA vecU = solver.eigenvectors().col(minId).real();
Base::m_uq = vecU[1+DataPoint::Dim];
Base::m_ul = vecU.template segment<DataPoint::Dim>(1);
Base::m_uc = vecU[0];
Base::m_isNormalized = false;
if(Base::m_nbNeighbors < 6)
{
Base::m_eCurrentState = UNSTABLE;
}
else
{
Base::m_eCurrentState = STABLE;
}
return Base::m_eCurrentState;
}
......@@ -80,14 +80,6 @@ public:
/*! \copydoc Concept::FittingProcedureConcept::finalize() */
MULTIARCH inline FIT_RESULT finalize();
using Base::potential;
/*! \brief Value of the scalar field at the evaluation point */
MULTIARCH inline Scalar potential() const { return Base::m_uc; }
/*! \brief Value of the normal of the primitive at the evaluation point */
MULTIARCH inline VectorType normal() const { return Base::m_ul.normalized(); }
}; // class UnorientedSphereFit
......
......@@ -16,9 +16,11 @@ namespace Grenaille
This is just the tip of the iceberg though, as we also provide methods for dealing with points equipped with non-oriented normals \cite Chen:2013:NOMG, techniques to analyze
points clouds in scale-space to discover salient structures \cite Mellado:2012:GLS, methods to compute multi-scale principal curvatures \cite Mellado:2013:SSC and methods to compute surface variation using a plane instead of a sphere for the fitting \cite Pauly:2002:PSSimplification. See the table below:
Primitive | Supported Input | Fitting techniques | Analysis/Tools | Other usages |
Primitive | Required Input | Fitting techniques | Analysis/Tools | Other usages |
----------------- | ------------------- | --------------------------------------------- | -------------------------------------------------- | ------------ |
Plane | Points | CovariancePlaneFit | Surface Variation\cite Pauly:2002:PSSimplification | |
Plane | Points only | CovariancePlaneFit | Surface Variation\cite Pauly:2002:PSSimplification | |
Plane | Oriented points | MeanPlaneFit | | |
Monge Patch | Points only | MongePatchFit | | |
Algebraic Sphere | Oriented points | OrientedSphereFit \cite Guennebaud:2007:APSS | GLS\cite Mellado:2012:GLS | Ray Traced Curvature\cite Mellado:2013:SSC |
Algebraic Sphere | Non-oriented points | UnorientedSphereFit \cite Chen:2013:NOMG | | |
......
......@@ -141,6 +141,7 @@ public:
inline faceIterator faceEnd();
inline GLTri3DMesh();
inline void setFrom(const GLTri3DMesh& input);
inline void initVBO(bool initForPicking = true);
inline void clearVBO();
inline void draw();
......
......@@ -181,6 +181,12 @@ GLTri3DMesh::GLTri3DMesh()
}
void GLTri3DMesh::setFrom(const GLTri3DMesh &input){
_init = false;
_faces = input._faces;
_vertices = input._vertices;
}
void GLTri3DMesh::addFace(const std::vector<Vertex> &vertices){
assert(vertices.size() == 3);
......
/*
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/.
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
......@@ -22,8 +22,11 @@
#include "Grenaille/Core/weightFunc.h"
#include "Grenaille/Core/plane.h"
#include "Grenaille/Core/meanPlaneFit.h"
#include "Grenaille/Core/covariancePlaneFit.h"
#include "Grenaille/Core/mongePatch.h"
#include "Grenaille/Core/sphereFit.h"
#include "Grenaille/Core/orientedSphereFit.h"
#include "Grenaille/Core/mlsSphereFitDer.h"
#include "Grenaille/Core/curvature.h"
......
......@@ -52,14 +52,17 @@
\section patate_credits_sec Credits
\subsection patate_credits_subsection_crew Crew
\subsection patate_credits_subsection_crew Active crew
- <b> Nicolas Mellado </b>: conception, implementation and examples <br/>
- <b> Gautier Ciaudo </b>: testing, documentation, refactoring and examples <br/>
- <b> Simon Boyé </b>: conception, implementation, documentation and examples <br/>
- <b> Gael Guennebaud </b>: conception and implementation <br/>
- <b> Pascal Barla </b>: conception and documentation <br/>
- <b> Noam Kremen </b>: implementation <br/>
- <b> Thibault Lejemble </b>: implementation (Grenaille) <br/>
\subsection patate_credits_subsection_contributors Contributors
- <b> Gautier Ciaudo </b>: testing, documentation, refactoring and examples <br/>
- <b> Simon Boyé </b>: conception, implementation, documentation and examples (Vitelotte) <br/>
- <b> Noam Kremen </b>: implementation (Grenaille)<br/>
\subsection patate_credits_subsection_citation Citation
......@@ -69,7 +72,7 @@
author = {Nicolas Mellado and Gautier Ciaudo and Simon Boy\'{e} and Ga\"{e}l Guennebaud and Pascal Barla},
title = {Patate Lib},
howpublished = {http://patate.gforge.inria.fr/},
year = {2013}
year = {2018}
}
\endverbatim
......
......@@ -79,9 +79,9 @@ if(CMAKE_COMPILER_IS_GNUCXX)
if(CMAKE_SYSTEM_NAME MATCHES Linux)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_FLAGS} -g2")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COVERAGE_FLAGS} -O2 -g2")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COVERAGE_FLAGS} -O2 -g2 -DEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COVERAGE_FLAGS} -fno-inline-functions")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COVERAGE_FLAGS} -O0 -g3")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COVERAGE_FLAGS} -O0 -g3 -DEBUG")
endif(CMAKE_SYSTEM_NAME MATCHES Linux)
elseif(MSVC)
......
......@@ -31,7 +31,6 @@ public:
enum {Dim = 3};
typedef double Scalar;
typedef Eigen::Matrix<Scalar, Dim, 1> VectorType;
typedef Eigen::Matrix<Scalar, Dim+1, 1> HVectorType;
typedef Eigen::Matrix<Scalar, Dim, Dim> MatrixType;
MULTIARCH inline MyPoint( const VectorType& _pos = VectorType::Zero(),
......
......@@ -2,11 +2,12 @@
FittingManager::FittingManager(QObject *parent) :
QObject(parent),
_fitType(FittingManager::PLANE_COV),
_mesh(NULL),
_fitType(FittingManager::PLANE_MEAN),
_mesh(nullptr),
_neiApproximation(new Mesh()),
_scale(0.02),
_evalPos(Mesh::Vector::Zero()),
_stateUpdateNei(false)
_stateUpdateNei(true)
{
}
void
......@@ -20,6 +21,7 @@ FittingManager::setBasketType(FIT_TYPE type){
void
FittingManager::setEvaluationPoint(const PatateCommon::GLTri3DMesh::Vector &pos){
_evalPos = pos;
_stateUpdateNei = true;
std::cout << __PRETTY_FUNCTION__ << std::endl;
emit evaluationPointChanged();
......@@ -30,6 +32,7 @@ FittingManager::setEvaluationPoint(const PatateCommon::GLTri3DMesh::Vector &pos)
void
FittingManager::setScale(float scale){
_scale = scale;
_stateUpdateNei = true;
std::cout << __PRETTY_FUNCTION__ << std::endl;
emit scaleChanged();
......@@ -40,6 +43,7 @@ FittingManager::setScale(float scale){
void
FittingManager::setScale(double scale){
_scale = scale;
_stateUpdateNei = true;
std::cout << __PRETTY_FUNCTION__ << std::endl;
emit scaleChanged();
......@@ -62,9 +66,9 @@ FittingManager::fitPrimitive(){
// - fit primitive
// - project nei vertices on primitive
//
_neiApproximation = Mesh();
if (_stateUpdateNei){
Mesh nei;
// accessing using UNSUPPORTED returns default params
typedef typename fittingmanagerspace::BasketMaker<UNSUPPORTED>::WeightFunc WFunc;
typedef typename Mesh::Vector VectorType;
......@@ -88,15 +92,16 @@ FittingManager::fitPrimitive(){
if (add){
_neiApproximation.addVertex(list[0].pos());
_neiApproximation.addVertex(list[1].pos());
_neiApproximation.addVertex(list[2].pos());
nei.addVertex(list[0].pos());
nei.addVertex(list[1].pos());
nei.addVertex(list[2].pos());
_neiApproximation.addFace(vertexId, vertexId+1, vertexId+2);
nei.addFace(vertexId, vertexId+1, vertexId+2);
vertexId += 3;
}
}
_neiApproximation->setFrom(nei);
}
......@@ -108,24 +113,45 @@ FittingManager::fitPrimitive(){
f.setWeightFunc(WFunc(_scale)); \
f.init(_evalPos); \
f.compute(_mesh->begin(), _mesh->end()); \
if (_stateUpdateNei){ \
for (Mesh::posIterator it = _mesh->vertexBegin(); \
it != _mesh->vertexEnd(); ++it) \
*it = f.project(*it); \
}
for (Mesh::posIterator it = _neiApproximation->vertexBegin(); \
it != _neiApproximation->vertexEnd(); ++it) \
*it = f.project(*it);
switch(_fitType){
case PLANE_COV:
case PLANE_MEAN:
{
COMPUTE(PLANE_MEAN);
std::cout << "Normal vector: " << f.primitiveGradient(_evalPos).transpose() << std::endl;
break;
}
case PLANE_COV:
{
COMPUTE(PLANE_COV);
std::cout << "Normal vector: " << f.primitiveGradient(_evalPos).transpose() << std::endl;
std::cout << "Surface variation: " << f.surfaceVariation() << std::endl;
break;
}
case MONGE_PATCH:
{
COMPUTE(MONGE_PATCH);
std::cout << "Mean Curvature: " << f.kMean() << std::endl;
break;
}
case SPHERE_ORIENTED:
{
COMPUTE(PLANE_COV);
COMPUTE(SPHERE_ORIENTED);
std::cout << "Normal vector: " << f.primitiveGradient(_evalPos).transpose() << std::endl;
std::cout << "Surface variation: " << f.surfaceVariation() << std::endl;
std::cout << "Tau: " << f.tau() << std::endl;
std::cout << "Eta: " << f.eta().transpose() << std::endl;
std::cout << "Kappa: " << f.kappa() << std::endl;
break;
}
case SPHERE_ORIENTED:
case SPHERE:
{
COMPUTE(SPHERE_ORIENTED);
COMPUTE(SPHERE);
std::cout << "Normal vector: " << f.primitiveGradient(_evalPos).transpose() << std::endl;
std::cout << "Tau: " << f.tau() << std::endl;
std::cout << "Eta: " << f.eta().transpose() << std::endl;
std::cout << "Kappa: " << f.kappa() << std::endl;
......@@ -145,7 +171,7 @@ FittingManager::fitPrimitive(){
* Internally, the weighting function is created, and used to select the vertices
* having an influence on the fit
*/
FittingManager::Mesh
FittingManager::computeNeighborhoodMeshApprox() const {
FittingManager::Mesh *
FittingManager::getNeighborhoodMeshApprox() {
return _neiApproximation;
}
......@@ -15,8 +15,11 @@ public:
//! Type of supported fit types, used to generate Baskets.
//! \warning Must be aligned with UI
enum FIT_TYPE {
PLANE_MEAN,
PLANE_COV,
MONGE_PATCH,
SPHERE_ORIENTED,
SPHERE,
UNSUPPORTED
};
......@@ -25,8 +28,8 @@ public:
inline void setMesh(Mesh* mesh) { _mesh = mesh; }
//! \brief Generate a new mesh that is an approximation of the current nei.
Mesh computeNeighborhoodMeshApprox() const;
//! \brief Getter on the projected mesh.
Mesh *getNeighborhoodMeshApprox();
signals:
//! \brief Signal emitted when the basket has been applied to the input data.
......@@ -40,15 +43,11 @@ public slots:
void setScale(float scale);
void setScale(double scale);
void fitPrimitive();
void setNeighborhoodApproxUpdate(bool update) {
_stateUpdateNei = update;
if(update) fitPrimitive();
}
private:
FIT_TYPE _fitType;
PatateCommon::GLTri3DMesh *_mesh;
PatateCommon::GLTri3DMesh _neiApproximation;
PatateCommon::GLTri3DMesh *_neiApproximation;
Scalar _scale;
typename Mesh::Vector _evalPos;
......@@ -63,18 +62,35 @@ struct BasketMaker {
typedef Grenaille::DistWeightFunc<MyPoint,Grenaille::SmoothWeightKernel<MyPoint::Scalar> > WeightFunc;
};
template <>
struct BasketMaker<FittingManager::PLANE_MEAN>{
typedef Grenaille::DistWeightFunc<MyPoint,Grenaille::SmoothWeightKernel<MyPoint::Scalar> > WeightFunc;
typedef Grenaille::Basket<MyPoint,WeightFunc, Grenaille::MeanPlaneFit> Basket;
};
template <>
struct BasketMaker<FittingManager::PLANE_COV>{
typedef Grenaille::DistWeightFunc<MyPoint,Grenaille::SmoothWeightKernel<MyPoint::Scalar> > WeightFunc;
typedef Grenaille::Basket<MyPoint,WeightFunc, Grenaille::CompactPlane,
Grenaille::CovariancePlaneFit> Basket;
typedef Grenaille::Basket<MyPoint,WeightFunc, Grenaille::CovariancePlaneFit> Basket;
};
template <>
struct BasketMaker<FittingManager::MONGE_PATCH>{
typedef Grenaille::DistWeightFunc<MyPoint,Grenaille::SmoothWeightKernel<MyPoint::Scalar> > WeightFunc;
typedef Grenaille::Basket<MyPoint,WeightFunc, Grenaille::CovariancePlaneFit, Grenaille::MongePatch> Basket;
};
template <>
struct BasketMaker<FittingManager::SPHERE_ORIENTED>{
typedef Grenaille::DistWeightFunc<MyPoint,Grenaille::SmoothWeightKernel<MyPoint::Scalar> > WeightFunc;
typedef Grenaille::Basket<MyPoint,WeightFunc, Grenaille::AlgebraicSphere,
Grenaille::OrientedSphereFit,
typedef Grenaille::Basket<MyPoint,WeightFunc, Grenaille::OrientedSphereFit,
Grenaille::GLSParam> Basket;
};
template <>
struct BasketMaker<FittingManager::SPHERE>{
typedef Grenaille::DistWeightFunc<MyPoint,Grenaille::SmoothWeightKernel<MyPoint::Scalar> > WeightFunc;
typedef Grenaille::Basket<MyPoint,WeightFunc, Grenaille::SphereFit,
Grenaille::GLSParam> Basket;
};
......
......@@ -36,8 +36,7 @@ MainWindow::MainWindow(QWidget *parent) :
connect(&_manager, SIGNAL(fitPerformed()),
this, SLOT(updateNeighborhoodMesh()));
connect(ui->_paramDisplayProjectedNei, SIGNAL(clicked(bool)),
&_manager, SLOT(setNeighborhoodApproxUpdate(bool)));
ui->_viewer->setNeighborhoodMesh(_manager.getNeighborhoodMeshApprox());
}
MainWindow::~MainWindow()
......@@ -78,5 +77,5 @@ void MainWindow::on__paramBasketType_currentIndexChanged(int index)
}
void MainWindow::updateNeighborhoodMesh(){
ui->_viewer->setNeighborhoodMesh(_manager.computeNeighborhoodMeshApprox());
ui->_viewer->update();
}
......@@ -20,7 +20,7 @@
<x>0</x>
<y>0</y>
<width>800</width>
<height>19</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
......@@ -49,16 +49,31 @@
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QComboBox" name="_paramBasketType">
<item>
<property name="text">
<string>Mean Plane</string>
</property>
</item>
<item>
<property name="text">
<string>Covariance Plane Fit</string>
</property>
</item>
<item>
<property name="text">
<string>Monge Patch</string>
</property>
</item>
<item>
<property name="text">
<string>Oriented Sphere Fit</string>
</property>
</item>
<item>
<property name="text">
<string>Sphere Fit</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
......@@ -97,25 +112,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="_paramDisplayGroup">
<property name="title">
<string>Display</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="_paramDisplayProjectedNei">
<property name="toolTip">
<string>May slow down performances</string>
</property>
<property name="text">
<string>Show projected neighborhood</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
......
......@@ -200,13 +200,18 @@ void Viewer::paintGL()
{
qglClearColor(Qt::white);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_CULL_FACE);
if (_mesh != NULL){
draw(_mesh, _meshAttribs);
if(_pickedPointId != -1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw(&_neighborhoodMesh, _sphereAttribs);
if(_pickedPointId != -1) drawPicked();
{
draw(_mesh, _sphereAttribs);
glClear(/*GL_COLOR_BUFFER_BIT |*/ GL_DEPTH_BUFFER_BIT);
draw(_neighborhoodMesh, _meshAttribs);
} else {
draw(_mesh, _meshAttribs);
}
//if(_pickedPointId != -1) drawPicked();
}
}
......
......@@ -68,7 +68,7 @@ public:
public slots:
void setScale(double scale) { _scale = scale; update(); }
void setNeighborhoodMesh (const Mesh& mesh) { _neighborhoodMesh = mesh; update(); }
void setNeighborhoodMesh (Mesh* mesh) { _neighborhoodMesh = mesh; update(); }
signals:
void selectedPointChanged(const PatateCommon::GLTri3DMesh::Vector& point);
......@@ -118,8 +118,8 @@ private:
double _scale;
Mesh *_mesh;
Mesh _unitSphere, _neighborhoodMesh;
Mesh *_mesh, *_neighborhoodMesh;
Mesh _unitSphere;
MeshAttributesValues _meshAttribs, _sphereAttribs;
QTimer *_refreshTimer; // automatically update the view
};
......
......@@ -14,4 +14,5 @@ add_multi_test(fit_unoriented.cpp)
add_multi_test(gls_compare.cpp)
add_multi_test(plane_primitive.cpp)
add_multi_test(fit_plane.cpp)
add_multi_test(fit_monge_patch.cpp)
add_multi_test(basket.cpp)
/*
Copyright (C) 2014 Nicolas Mellado <nmellado0@gmail.com>
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/.