...
 
Commits (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/.
*/
#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();
/**************************************************************************/
/* 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 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;
a << 1, q, q.squaredNorm();
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;
Eigen::EigenSolver<MatrixA> eig(M);
VectorA eivals = eig.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 = eig.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;
}
......@@ -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/.
*/
......@@ -34,6 +34,7 @@
// not supported on cuda
#ifndef __CUDACC__
# include "Grenaille/Core/unorientedSphereFit.h"
# include "Grenaille/Core/sphereFit.h"
#endif
......
......@@ -3,10 +3,11 @@
FittingManager::FittingManager(QObject *parent) :
QObject(parent),
_fitType(FittingManager::PLANE_COV),
_mesh(NULL),
_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,11 +113,9 @@ 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){
......@@ -131,6 +134,14 @@ FittingManager::fitPrimitive(){
std::cout << "Kappa: " << f.kappa() << std::endl;
break;
}
case SPHERE:
{
COMPUTE(SPHERE);
std::cout << "Tau: " << f.tau() << std::endl;
std::cout << "Eta: " << f.eta().transpose() << std::endl;
std::cout << "Kappa: " << f.kappa() << std::endl;
break;
}
case UNSUPPORTED:
default:
return;
......@@ -145,7 +156,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;
}
......@@ -17,6 +17,7 @@ public:
enum FIT_TYPE {
PLANE_COV,
SPHERE_ORIENTED,
SPHERE,
UNSUPPORTED
};
......@@ -25,8 +26,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 +41,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;
......@@ -66,15 +63,20 @@ struct BasketMaker {
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::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>25</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
......@@ -59,6 +59,11 @@
<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 +102,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
};
......