Files
igl/external/lim/LIMSolverInterface.h
T
schuellc 52e7231cee Added new serialize function
Modified xml serialization
Updated Embree ray intersection checks
Updateded LIM
Various bug fixes
2015-01-28 15:41:51 +01:00

457 lines
16 KiB
C++

// Copyright 2013 - Christian Schüller 2013, schuellc@inf.ethz.ch
// Interactive Geometry Lab - ETH Zurich
//----------------------------------------------------------------------------------------
// LIMSolverInterface.h
// Date: 07.06.13
// Author: Christian Schüller
//----------------------------------------------------------------------------------------
#pragma once
#ifndef LIM_SOLVER_INTERFACE_H
#define LIM_SOLVER_INTERFACE_H
#include "TriangleMesh.h"
#include "TetrahedronMesh.h"
#include "LIMSolver2D.h"
#include "LIMSolver3D.h"
#include "Identity_LIMSolver2D.h"
#include "Dirichlet_LIMSolver2D.h"
#include "UniformLaplacian_LIMSolver2D.h"
#include "Laplacian_LIMSolver2D.h"
#include "GreenStrain_LIMSolver2D.h"
#include "LGARAP_LIMSolver2D.h"
#include "LSConformal_LIMSolver2D.h"
#include "Poisson_LIMSolver2D.h"
#include "Identity_LIMSolver3D.h"
#include "Dirichlet_LIMSolver3D.h"
#include "UniformLaplacian_LIMSolver3D.h"
#include "Laplacian_LIMSolver3D.h"
#include "GreenStrain_LIMSolver3D.h"
#include "LGARAP_LIMSolver3D.h"
#include <Eigen/Dense>
#include <Eigen/Sparse>
// LIM data structure
struct LIMData
{
bool isTetMesh;
DeformableMesh* mesh;
LIMSolver* solver;
int iteration;
};
//----------------------------------------------------------------------------------------
// Function: FreeLIMData
//----------------------------------------------------------------------------------------
// Description:
// Releases given LIM data object
//----------------------------------------------------------------------------------------
// Input:
// data Pointer to LIMData instance
//----------------------------------------------------------------------------------------
void FreeLIMData(LIMData* data)
{
delete data->mesh->InitalVertices;
delete data->mesh->DeformedVertices;
delete data->mesh->PredictedVertices;
if(data->isTetMesh)
delete static_cast<TetrahedronMesh*>(data->mesh)->Tetrahedra;
else
delete static_cast<TriangleMesh*>(data->mesh)->Triangles;
delete data->mesh->BorderVertices;
delete data->mesh->ConstraintMatrix;
delete data->mesh->ConstraintTargets;
delete data->mesh;
delete data->solver;
}
//----------------------------------------------------------------------------------------
// Function: InitLIM
//----------------------------------------------------------------------------------------
// Description:
// Initializes the LIM Solver data before calling the function ComputeLIM_Step
//----------------------------------------------------------------------------------------
// Input:
// vertices vx3 matrix containing vertex position of the mesh
// initialVertices vx3 matrix containing vertex position of initial rest pose mesh
// elements exd matrix containing vertex indices of all elements
// borderVertices (optional) only needed for 2D LSCM) vector containing indices of border vertices
// gradients (optional) only needed for 2D Poisson) vector containing partial derivatives of target element gradients (structure is: [xx_1, xy_1, xx_2, xy_2, ..., xx_v, xy_v, yx_1, yy_1, yx_2, yy_2, ..., yx_v, yy_v]')
// constraintMatrix C: (c)x(3xv) sparse linear positional constraint matrix
// X,Y,Z-coordinates are alternatingly stacked per row (structure for triangles: [x_1, y_1, z_1, x_2, y_2, z_2, ..., x_v,y_v,z_v])
// and each row of C belongs to a linear constraint.
// constraintTargets d: c vector target positions
// energyType type of used energy: 0=Dirichlet,1=Laplacian,2=Green,3=ARAP,4=LSCM,5=Poisson
// enableOutput (optional) enables the output (#iteration / hessian correction / step size / positional constraints squared error / barrier constraints energy / deformation energy)
// enableBarriers (optional) enables the non-flip constraints (default = true)
// enableAlphaUpdate (optional) enables dynamic alpha weight adjustment (default = true)
// beta (optional) steepness factor of barrier slopes (default: ARAP/LSCM = 0.01, Green = 1)
// eps (optional) smallest valid triangle area (default: 1e-5 * smallest triangle)
//
// where:
// v : # vertices
// c : # linear constraints
// e : # elements of mesh
// d : # vetices per element (triangle = 3, tet = 4)
//----------------------------------------------------------------------------------------
// Return value:
// data a pointer to the LIM data object
//----------------------------------------------------------------------------------------
LIMData* InitLIM(
Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
const std::vector<int>& borderVertices,
const Eigen::Matrix<double,Eigen::Dynamic,1>& gradients,
const Eigen::SparseMatrix<double>& constraintMatrix,
const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
int energyType,
bool enableOuput = true,
bool enableBarriers = true,
bool enableAlphaUpdate = true,
double beta = -1,
double eps = -1)
{
LIMData* data = new LIMData();
data->isTetMesh = (elements.cols() == 4);
//------------------------------------------------------------------------------------
// Init mesh object
//------------------------------------------------------------------------------------
DeformableMesh* mesh = NULL;
if(data->isTetMesh)
{
TetrahedronMesh* tetMesh = new TetrahedronMesh();
mesh = tetMesh;
tetMesh->Tetrahedra = new Eigen::Matrix<int,Eigen::Dynamic,4>(elements);
}
else
{
TriangleMesh* triMesh = new TriangleMesh();
mesh = triMesh;
triMesh->Triangles = new Eigen::Matrix<int,Eigen::Dynamic,3>(elements);
triMesh->BorderVertices = new Eigen::Matrix<int,Eigen::Dynamic,1>();
triMesh->IsCorotatedTriangles = false;
triMesh->BorderVertices->resize(borderVertices.size(),1);
for(int i=0;i<(int)borderVertices.size();i++)
triMesh->BorderVertices->coeffRef(i) = borderVertices[i];
}
mesh->InitalVertices = new Eigen::Matrix<double,Eigen::Dynamic,3>(initialVertices);
mesh->DeformedVertices = new Eigen::Matrix<double,Eigen::Dynamic,3>(vertices);
mesh->PredictedVertices = new Eigen::Matrix<double,Eigen::Dynamic,3>(vertices);
mesh->ConstraintMatrix = new Eigen::SparseMatrix<double>(constraintMatrix);
mesh->ConstraintTargets = new Eigen::Matrix<double,Eigen::Dynamic,1>(constraintTargets);
mesh->InitMesh();
if(eps != -1) mesh->EPS3 = eps;
//------------------------------------------------------------------------------------
// Intit solver
//------------------------------------------------------------------------------------
LIMSolver* solver = NULL;
if(data->isTetMesh)
{
switch(energyType)
{
case 0:
solver = new Dirichlet_LIMSolver3D();
break;
case 1:
solver = new Laplacian_LIMSolver3D();
break;
case 2:
solver = new GreenStrain_LIMSolver3D();
break;
case 3:
solver = new LGARAP_LIMSolver3D();
break;
default:
solver = new GreenStrain_LIMSolver2D();
break;
}
}
else
{
switch(energyType)
{
case 0:
solver = new Dirichlet_LIMSolver2D();
break;
case 1:
solver = new Laplacian_LIMSolver2D();
break;
case 2:
solver = new GreenStrain_LIMSolver2D();
break;
case 3:
solver = new LGARAP_LIMSolver2D();
break;
case 4:
solver = new LSConformal_LIMSolver2D();
break;
case 5:
{
Poisson_LIMSolver2D* psolver = new Poisson_LIMSolver2D();
psolver->b = gradients;
solver = psolver;
}
break;
default:
new GreenStrain_LIMSolver2D();
break;
}
}
solver->Init(mesh);
solver->EnableBarriers = enableBarriers;
if(beta != -1) solver->Beta = beta;
data->mesh = mesh;
data->solver = solver;
data->iteration = 0;
return data;
}
LIMData* InitLIM(
Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
const Eigen::SparseMatrix<double>& constraintMatrix,
const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
int energyType,
bool enableOuput = true,
bool enableBarriers = true,
bool enableAlphaUpdate = true,
double beta = -1,
double eps = -1)
{
vector<int> borderVertices;
Eigen::VectorXd gradients;
return InitLIM(
vertices,
initialVertices,
elements,
borderVertices,
gradients,
constraintMatrix,
constraintTargets,
energyType,
enableOuput,
enableBarriers,
enableAlphaUpdate,
beta,
eps);
}
//----------------------------------------------------------------------------------------
// Function: ComputeLIM
//----------------------------------------------------------------------------------------
// Description:
// Computes a locally injective mapping of a triangle or tet-mesh based on a deformation energy
// subject to some provided linear positional constraints Cv-d.
//----------------------------------------------------------------------------------------
// Input:
// vertices vx3 matrix containing vertex position of the mesh
// initialVertices vx3 matrix containing vertex position of initial rest pose mesh
// elements exd matrix containing vertex indices of all elements
// borderVertices (optional) (only needed for 2D LSCM) vector containing indices of border vertices
// gradients (optional) (only needed for 2D Poisson) vector containing partial derivatives of target element gradients (structure is: [xx_1, xy_1, xx_2, xy_2, ..., xx_v, xy_v, yx_1, yy_1, yx_2, yy_2, ..., yx_v, yy_v]')
// constraintMatrix C: (c)x(3xv) sparse linear positional constraint matrix
// X,Y,Z-coordinates are alternatingly stacked per row (structure for triangles: [x_1, y_1, z_1, x_2, y_2, z_2, ..., x_v,y_v,z_v])
// and each row of C belongs to a linear constraint.
// constraintTargets d: c vector target positions
// energyType type of used energy: 0=Dirichlet,1=Laplacian,2=Green,3=ARAP,4=LSCM
// tolerance max squared positional constraints error
// maxIteration max number of iterations
// findLocalMinima iterating until a local minima is found. If not enabled only tolerance must be fulfilled.
// enableOutput (optional) enables the output (#itaration / hessian correction / step size / positional constraints / barrier constraints / deformation energy) (default : true)
// enableBarriers (optional) enables the non-flip constraints (default = true)
// enableAlphaUpdate (optional) enables dynamic alpha weight adjustment (default = true)
// beta (optional) steepness factor of barrier slopes (default: ARAP/LSCM = 0.01, Green = 1)
// eps (optional) smallest valid triangle area (default: 1e-5 * smallest triangle)
//
// where:
// v : # vertices
// c : # linear constraints
// e : # elements of mesh
// d : # vetices per element (triangle = 3, tet = 4)
//----------------------------------------------------------------------------------------
// Output:
// vertices vx3 matrix containing resulting vertex position of the mesh
//----------------------------------------------------------------------------------------
// Return values:
// 1 : Successful optimization with fulfilled tolerance
// -1 : Max iteration reached before tolerance was fulfilled
// -2 : not feasible -> has inverted elements (may want to decrease eps?)
//----------------------------------------------------------------------------------------
int ComputeLIM(
Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
const std::vector<int>& borderVertices,
const Eigen::Matrix<double,Eigen::Dynamic,1>& gradients,
const Eigen::SparseMatrix<double>& constraintMatrix,
const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
int energyType,
double tolerance,
int maxIteration,
bool findLocalMinima,
bool enableOuput = true,
bool enableBarriers = true,
bool enableAlphaUpdate = true,
double beta = -1,
double eps = -1)
{
LIMData* data = InitLIM(vertices, initialVertices, elements, borderVertices, gradients, constraintMatrix, constraintTargets, energyType, enableOuput, enableBarriers, enableAlphaUpdate, beta, eps);
int result = 0;
while(result == 0)
{
if(data->solver->CurrentStepSize < 1e-15 || (data->solver->CurrentPositionalEnergy <= tolerance && (findLocalMinima == false || data->solver->CurrentStepSize < 1e-15)))
result = 1; // termination criteria fulfilled
if(data->iteration >= maxIteration)
result = -1; // max iteration reached
if(result == 0)
{
if(data->solver->Solve() == -1)
result = -2; // state not feasible -> inverted elements
else
{
// swap vertex buffers
Eigen::Matrix<double,Eigen::Dynamic,3>* temp = data->mesh->DeformedVertices;
data->mesh->DeformedVertices = data->mesh->PredictedVertices;
data->mesh->PredictedVertices = temp;
data->iteration++;
}
}
}
// assign resulting vertices
vertices = *data->mesh->DeformedVertices;
// release solver data
FreeLIMData(data);
return result;
}
int ComputeLIM(
Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
const Eigen::SparseMatrix<double>& constraintMatrix,
const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
int energyType,
double tolerance,
int maxIteration,
bool findLocalMinima,
bool enableOuput = true,
bool enableBarriers = true,
bool enableAlphaUpdate = true,
double beta = -1,
double eps = -1)
{
vector<int> borderVertices;
Eigen::VectorXd gradients;
return ComputeLIM(
vertices,
initialVertices,
elements,
borderVertices,
gradients,
constraintMatrix,
constraintTargets,
energyType,
tolerance,
maxIteration,
findLocalMinima,
enableOuput,
enableBarriers,
enableAlphaUpdate,
beta,
eps);
}
//----------------------------------------------------------------------------------------
// Function: ComputeLIM_Step
//----------------------------------------------------------------------------------------
// Description:
// Computes one minimization step for the given LIM problem. Use InitLim to initialize LIM data.
//----------------------------------------------------------------------------------------
// Input:
// data LIM data structure
//----------------------------------------------------------------------------------------
// Output:
// vertices vx3 matrix containing resulting vertex position of the mesh
//----------------------------------------------------------------------------------------
// Return values:
// 1 : Successful optimization step
// -1 : Lim data is not initialized
// -2 : not feasible -> has inverted elements (may want to decrease eps?)
//----------------------------------------------------------------------------------------
int ComputeLIM_Step(
LIMData*& data,
Eigen::Matrix<double,Eigen::Dynamic,3>& vertices)
{
if(data == NULL)
{
cerr << "LIM data is not initialized." << endl;
return -1;
}
int result = 0;
if(data->solver->Solve() == -1)
result = -2; // state not feasible -> inverted elements
else
{
// swap vertex buffers
Eigen::Matrix<double,Eigen::Dynamic,3>* temp = data->mesh->DeformedVertices;
data->mesh->DeformedVertices = data->mesh->PredictedVertices;
data->mesh->PredictedVertices = temp;
data->iteration++;
}
// assign resulting vertices
vertices = *data->mesh->DeformedVertices;
return result;
}
#endif