Refactor Iterative Authalic parameterization

This commit is contained in:
Mael Rouxel-Labbé 2020-07-09 17:37:46 +02:00
parent d9debb99fb
commit 07b9e89be5
3 changed files with 859 additions and 1184 deletions

View File

@ -1,743 +0,0 @@
// This file has been adopted from CGAL, to integrate the below mentioned paper
//
// Paper : Learning to Reconstruct Symmetric Shapes using Planar Parameterization of 3D Surface
// Author(s) : Hardik Jain, Manuel Wöllhaf, Olaf Hellwich
// Conference : IEEE International Conference on Computer Vision Workshops (ICCVW) 2019
//
#ifndef CGAL_SURFACE_MESH_PARAMETERIZATION_FIXED_BORDER_ITERATIVE_PARAMETERIZER_3_H
#define CGAL_SURFACE_MESH_PARAMETERIZATION_FIXED_BORDER_ITERATIVE_PARAMETERIZER_3_H
#define DEBUG_L0 1
#include <CGAL/license/Surface_mesh_parameterization.h>
#include <CGAL/Surface_mesh_parameterization/internal/angles.h>
#include <CGAL/Surface_mesh_parameterization/internal/Containers_filler.h>
#include <CGAL/Surface_mesh_parameterization/internal/kernel_traits.h>
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
#include <CGAL/Surface_mesh_parameterization/Square_border_parameterizer_3.h>
#include <CGAL/boost/graph/properties.h>
#include <CGAL/circulator.h>
#include <CGAL/Default.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/squared_distance_2.h> //for 2D functions
#include <CGAL/squared_distance_3.h> //for 3D functions
#if defined(CGAL_EIGEN3_ENABLED)
#include <CGAL/Eigen_solver_traits.h>
#endif
#include <boost/function_output_iterator.hpp>
#include <iostream>
#include <iomanip>
/// \file Fixed_border_iterative_parameterizer_3.h
namespace CGAL {
namespace Surface_mesh_parameterization {
// ------------------------------------------------------------------------------------
// Declaration
// ------------------------------------------------------------------------------------
/// \ingroup PkgSurfaceMeshParameterizationMethods
///
/// The class `Fixed_border_iterative_parameterizer_3`
/// is the base class of fixed border parameterization methods (Tutte, Floater, ...).
///
/// A one-to-one mapping is guaranteed if the border of the surface is mapped onto a convex polygon.
///
/// This class is a pure virtual class and thus cannot be instantiated.
/// Nevertheless, it implements most of the parameterization algorithm `parameterize()`.
/// Subclasses are *Strategies* \cgalCite{cgal:ghjv-dpero-95} that modify the behavior of this algorithm:
/// - They provide the template parameters `BorderParameterizer_` and `SolverTraits_`.
/// - They implement `compute_w_ij()` to compute w_ij = (i, j), coefficient of matrix A
/// for j neighbor vertex of i.
///
/// \cgalModels `Parameterizer_3`
///
/// \tparam TriangleMesh_ must be a model of `FaceGraph`.
///
/// \tparam BorderParameterizer_ is a Strategy to parameterize the surface border
/// and must be a model of `Parameterizer_3`.<br>
/// <b>%Default:</b>
/// \code
/// Square_border_arc_length_parameterizer_3<TriangleMesh_>
/// \endcode
///
/// \tparam SolverTraits_ must be a model of `SparseLinearAlgebraTraits_d`.<br>
/// Note that the system is *not* symmetric because `Fixed_border_iterative_parameterizer_3`
/// does not remove border vertices from the system.<br>
/// <b>%Default:</b> If \ref thirdpartyEigen "Eigen" 3.1 (or greater) is available
/// and `CGAL_EIGEN3_ENABLED` is defined, then an overload of `Eigen_solver_traits`
/// is provided as default parameter:
/// \code
/// CGAL::Eigen_solver_traits<
/// Eigen::BiCGSTAB<Eigen_sparse_matrix<double>::EigenType,
/// Eigen::IncompleteLUT< double > > >
/// \endcode
///
/// \sa `CGAL::Surface_mesh_parameterization::Iterative_authalic_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
///
template <typename TriangleMesh_,
typename BorderParameterizer_ = Default,
typename SolverTraits_ = Default>
class Fixed_border_iterative_parameterizer_3
{
public:
#ifndef DOXYGEN_RUNNING
typedef typename Default::Get<BorderParameterizer_,
Square_border_arc_length_parameterizer_3<TriangleMesh_> >::type Border_parameterizer;
typedef typename Default::Get<SolverTraits_,
#if defined(CGAL_EIGEN3_ENABLED)
CGAL::Eigen_solver_traits<
Eigen::BiCGSTAB<Eigen_sparse_matrix<double>::EigenType,
Eigen::IncompleteLUT<double> > >
#else
#pragma message("Error: You must either provide 'SolverTraits_' or link CGAL with the Eigen library");
SolverTraits_ // no parameter provided, and Eigen is not enabled: so don't compile!
#endif
>::type Solver_traits;
#else // DOXYGEN_RUNNING
typedef Border_parameterizer_ Border_parameterizer;
typedef SolverTraits_ Solver_traits;
#endif
typedef TriangleMesh_ TriangleMesh;
// Private types
private:
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::face_descriptor face_descriptor;
typedef CGAL::Vertex_around_target_circulator<TriangleMesh> vertex_around_target_circulator;
typedef CGAL::Face_around_target_circulator<TriangleMesh> face_around_target_circulator;
typedef CGAL::Vertex_around_face_circulator<TriangleMesh> vertex_around_face_circulator;
// Protected types
protected:
// Traits subtypes:
typedef typename internal::Kernel_traits<TriangleMesh>::Kernel Kernel;
typedef typename internal::Kernel_traits<TriangleMesh>::PPM PPM;
typedef typename Kernel::FT NT;
typedef typename Kernel::Point_2 Point_2;
typedef typename Kernel::Point_3 Point_3;
typedef typename Kernel::Vector_3 Vector_3;
typedef std::unordered_set<vertex_descriptor> Vertex_set;
// Solver traits subtypes:
typedef typename Solver_traits::Vector Vector;
typedef typename Solver_traits::Matrix Matrix;
typedef CGAL::dynamic_face_property_t<double> Face_double_tag;
typedef typename boost::property_map<TriangleMesh, Face_double_tag>::type Face_Double_map;
typedef CGAL::dynamic_vertex_property_t<double> Vertex_double_tag;
typedef typename boost::property_map<TriangleMesh, Vertex_double_tag>::type Vertex_Double_map;
typedef CGAL::dynamic_vertex_property_t<int> Vertex_int_tag;
typedef typename boost::property_map<TriangleMesh, Vertex_int_tag>::type Vertex_Int_map;
typedef CGAL::dynamic_vertex_property_t<Point_2> Vertex_point2_tag;
typedef typename boost::property_map<TriangleMesh, Vertex_point2_tag>::type Vertex_point2_map;
// Public operations
public:
/// Constructor
///
/// \param border_param %Object that maps the surface's border to 2D space
/// \param sparse_la Traits object to access a sparse linear system
Fixed_border_iterative_parameterizer_3(Border_parameterizer border_param = Border_parameterizer(),
Solver_traits sparse_la = Solver_traits())
: m_borderParameterizer(border_param), m_linearAlgebra(sparse_la), LScounter(0)
{ }
/// Destructor of base class should be virtual.
virtual ~Fixed_border_iterative_parameterizer_3() { }
// Default copy constructor and operator =() are fine
/// Compute a one-to-one mapping from a triangular 3D surface mesh
/// to a piece of the 2D space.
/// The mapping is piecewise linear (linear in each triangle).
/// The result is the (u,v) pair image of each vertex of the 3D surface.
///
/// \tparam VertexUVmap must be a model of `ReadWritePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `TriangleMesh` using `Kernel_traits`)
/// as value type.
/// \tparam VertexIndexMap must be a model of `ReadablePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor` as key type and
/// a unique integer as value type.
/// \tparam VertexParameterizedMap must be a model of `ReadWritePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor` as key type and
/// a Boolean as value type.
///
/// \param mesh a triangulated surface.
/// \param bhd a halfedge descriptor on the boundary of `mesh`.
/// \param uvmap an instanciation of the class `VertexUVmap`.
/// \param vimap an instanciation of the class `VertexIndexMap`.
/// \param vpmap an instanciation of the class `VertexParameterizedMap`.
/// \param iterations an integer number of iterations to run the parameterization.
/// \param error return error value of the iterative process.
///
/// \pre `mesh` must be a triangular mesh.
/// \pre The mesh border must be mapped onto a convex polygon.
/// \pre The vertices must be indexed (`vimap` must be initialized)
///
template <typename VertexUVmap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code parameterize(TriangleMesh& mesh,
halfedge_descriptor bhd,
VertexUVmap uvmap1,
VertexIndexMap vimap1,
VertexParameterizedMap vpmap,
int& iterations,
double& error)
{
Error_code status = OK;
Vertex_set vertices;
internal::Containers_filler<TriangleMesh, Vertex_set> fc(mesh, vertices);
Polygon_mesh_processing::connected_component(face(opposite(bhd, mesh), mesh), mesh,
boost::make_function_output_iterator(fc));
int nbVertices = static_cast<int>(vertices.size());
if(nbVertices == 0)
return ERROR_EMPTY_MESH;
// Compute (u,v) for border vertices and mark them as "parameterized"
status = get_border_parameterizer().parameterize(mesh, bhd, uvmap1, vimap1, vpmap);
if (status != OK)
return status;
// Create two sparse linear systems "A*Xu = Bu" and "A*Xv = Bv" (one line/column per vertex)
Matrix A(nbVertices, nbVertices);
Matrix A_prev(nbVertices, nbVertices);
Vector Xu(nbVertices), Xv(nbVertices), Bu(nbVertices), Bv(nbVertices);
double err[iterations];
// Initialize A, Xu, Xv, Bu and Bv after border parameterization
// Fill the border vertices' lines in both linear systems:
// "u = constant" and "v = constant"
//
initialize_system_from_mesh_border(A, Bu, Bv, mesh, bhd, uvmap1, vimap1);
// Fill the matrix for the inner vertices v_i: compute A's coefficient
// w_ij for each neighbor j; then w_ii = - sum of w_ijs
std::unordered_set<vertex_descriptor> main_border;
for(vertex_descriptor v : vertices_around_face(bhd, mesh))
main_border.insert(v);
// create new uvmap & vimap
Vertex_point2_map uvmap = get(Vertex_point2_tag(), mesh);
Vertex_Int_map vimap = get(Vertex_int_tag(), mesh);
for(vertex_descriptor v : vertices)
{
put(uvmap, v, get(uvmap1, v));
put(vimap, v, get(vimap1, v));
}
// update last best uvmap wrt the border
lastBestuvmap = get(Vertex_point2_tag(), mesh);
for(vertex_descriptor v : vertices)
{
// border vertices only
if(main_border.find(v) != main_border.end())
put(lastBestuvmap, v, get(uvmap, v));
}
int lastBesti = 0;
compute_faceArea(mesh);
compute_borderLength_3D(mesh);
double gamma = 1;
bool isChanged = false;
// iterate it with the new weights
if(DEBUG_L0)
std::cout << std::endl;
int i = 0;
while(i <= iterations)
{
if(DEBUG_L0)
std::cout << "Iteration " << i << std::flush;
// update weights for inner vertices
for(vertex_descriptor v : vertices)
{
// inner vertices only
if(main_border.find(v) == main_border.end())
{
// Compute the line i of matrix A for i inner vertex
if(i == 0)
{
//status = setup_inner_vertex_relations(A, A_prev, Bu, Bv, mesh, v, vimap);
status = setup_inner_vertex_relations_cotangent(A, Bu, Bv, mesh, v, vimap);
if(status != OK)
return status;
}
else
{
status = setup_iter_inner_vertex_relations(A, A_prev, Bu, Bv, mesh, v, vimap, uvmap, gamma);
if(status != OK)
return status;
}
}
}
// solve linear equations
// Solve "A*Xu = Bu". On success, solution is (1/Du) * Xu.
// Solve "A*Xv = Bv". On success, solution is (1/Dv) * Xv.
NT Du = 0, Dv = 0;
if(!get_linear_algebra_traits().linear_solver(A, Bu, Xu, Du) ||
!get_linear_algebra_traits().linear_solver(A, Bv, Xv, Dv))
{
status = ERROR_CANNOT_SOLVE_LINEAR_SYSTEM;
}
else
{
LScounter = 0;
}
if(status != OK)
{
if(LScounter < 4)
{
// modify the weights and re-try the linear solver
++LScounter;
gamma /= 2;
continue;
}
else
{
status = OK;
break;
}
}
// WARNING: this package does not support homogeneous coordinates!
CGAL_assertion(Du == 1.0);
CGAL_assertion(Dv == 1.0);
// Copy A to A_prev, it is a computationally inefficient task but neccesary
copy_sparse_matrix(mesh, vertices, vimap, A, A_prev);
// Copy Xu and Xv coordinates into the (u,v) pair of each vertex
for(vertex_descriptor v : vertices)
{
// inner vertices only
if(main_border.find(v) == main_border.end())
{
int index = get(vimap,v);
put(uvmap, v, Point_2(Xu[index], Xv[index]));
put(vpmap, v, true);
}
}
compute_faceWise_L2(mesh, uvmap);
compute_vertexWise_L2(mesh, vertices);
err[i] = compute_area_distortion(mesh, vertices, main_border, uvmap);
if(DEBUG_L0)
std::cout << " err " << err[i] << std::flush;
if(err[i] <= err[lastBesti])
{
update_uv(vertices, main_border, uvmap);
lastBesti = i;
isChanged = false;
if(DEBUG_L0)
std::cout << " *****" << std::flush;
}
else if(err[i] > 100)
{
break;
}
else
{
if(!isChanged)
{
gamma /= 2;
isChanged = true;
}
}
++i;
std::cout << std::endl;
}
// Check postconditions
if(status != OK)
return status;
if(i == 0 && i != iterations)
{
// means that the computation terminated for the first iteration may be because system was unsolvable
return ERROR_CANNOT_SOLVE_LINEAR_SYSTEM;
}
for(vertex_descriptor v : vertices)
{
put(uvmap1, v, get(lastBestuvmap, v));
put(vimap1, v, get(vimap, v));
}
iterations = lastBesti;
error = err[lastBesti];
return status;
}
void update_uv(const Vertex_set& vertices,
const std::unordered_set<vertex_descriptor>& main_border,
Vertex_point2_map uvmap)
{
for(vertex_descriptor v : vertices)
{
// inner vertices only
if(main_border.find(v) == main_border.end())
put(lastBestuvmap, v, get(uvmap, v));
}
}
/// Initialize A, Bu and Bv after border parameterization.
/// Fill the border vertices' lines in both linear systems:
/// "u = constant" and "v = constant".
///
/// \tparam VertexUVmap must be a model of `ReadWritePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `TriangleMesh` using `Kernel_traits`)
/// as value type.
/// \tparam VertexIndexMap must be a model of `ReadablePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor` as key type and
/// a unique integer as value type.
///
/// \param A the matrix in both linear system
/// \param Bu the right hand side vector in the linear system of x coordinates
/// \param Bv the right hand side vector in the linear system of y coordinates
/// \param mesh a triangulated surface.
/// \param bhd a halfedge descriptor on the boundary of `mesh`.
/// \param uvmap an instanciation of the class `VertexUVmap`.
/// \param vimap an instanciation of the class `VertexIndexMap`.
///
/// \pre Vertices must be indexed (`vimap` must be initialized).
/// \pre A, Bu and Bv must be allocated.
/// \pre Border vertices must be parameterized.
template <typename VertexUVmap, typename VertexIndexMap>
void initialize_system_from_mesh_border(Matrix& A, Vector& Bu, Vector& Bv,
const TriangleMesh& mesh,
halfedge_descriptor bhd,
VertexUVmap uvmap,
VertexIndexMap vimap) const
{
for(halfedge_descriptor hd : halfedges_around_face(bhd, mesh))
{
// Get vertex index in sparse linear system
int index = get(vimap, target(hd, mesh));
// Write a diagonal coefficient of A
A.set_coef(index, index, 1, true /*new*/);
// get the halfedge uv
// Write constant in Bu and Bv
const Point_2& uv = get(uvmap, target(hd, mesh));
Bu[index] = uv.x();
Bv[index] = uv.y();
}
}
/// Compute w_ij, coefficient of matrix A for j neighbor vertex of i.
/// Implementation note: Subclasses must at least implement compute_w_ij().
///
/// \param mesh a triangulated surface.
/// \param main_vertex_v_i the vertex of `mesh` with index `i`
/// \param neighbor_vertex_v_j the vertex of `mesh` with index `j`
virtual NT compute_w_ij(const TriangleMesh& mesh,
vertex_descriptor main_vertex_v_i,
vertex_around_target_circulator neighbor_vertex_v_j) const = 0;
virtual Error_code setup_inner_vertex_relations(Matrix& A, Matrix& A_prev,
Vector&, Vector&,
const TriangleMesh& mesh,
vertex_descriptor vertex,
Vertex_Int_map& vimap)
{
return OK; // TODO: Need to check
}
virtual Error_code setup_inner_vertex_relations_cotangent(Matrix& A,
Vector&, Vector&,
const TriangleMesh& mesh,
vertex_descriptor vertex,
Vertex_Int_map& vimap)
{
return OK; // TODO: Need to check
}
template <typename VertexIndexMap>
Error_code setup_iter_inner_vertex_relations(Matrix& A, Matrix& A_prev,
Vector&, Vector&,
TriangleMesh& mesh,
vertex_descriptor vertex,
VertexIndexMap vimap,
Vertex_point2_map& uvmap,
double gamma)
{
int i = get(vimap, vertex);
// circulate over vertices around 'vertex' to compute w_ii and w_ijs
NT w_ii = 0;
int vertexIndex = 0;
//const double sigma = getvL2(mesh, vertex, fL2Map, areaMap);
vertex_around_target_circulator v_j(halfedge(vertex, mesh), mesh), end = v_j;
CGAL_For_all(v_j, end)
{
// Get j index
int j = get(vimap, *v_j);
// Call to virtual method to do the actual coefficient computation
//NT w_ij = A_prev.get_coef(i,j) / compute_sig_ij(vertex, *v_j) / gamma;
NT w_ij = A_prev.get_coef(i,j) / pow(compute_sig_ij(mesh, uvmap, vertex, *v_j, 1.0),gamma);
// w_ii = - sum of w_ijs
w_ii -= w_ij;
// Set w_ij in matrix
A.set_coef(i,j, w_ij, false);
//A_prev.set_coef(i,j, w_ij, false);
++vertexIndex;
}
if(vertexIndex < 2)
return ERROR_NON_TRIANGULAR_MESH;
// Set w_ii in matrix
A.set_coef(i,i, w_ii, true /*new*/);
return OK;
}
virtual NT compute_faceArea(TriangleMesh& mesh) = 0;
virtual NT compute_faceWise_L2(TriangleMesh& mesh, Vertex_point2_map &uvmap) = 0;
virtual NT compute_vertexWise_L2(TriangleMesh& mesh, Vertex_set& vertices) = 0;
virtual double compute_sig_ij(TriangleMesh& mesh, Vertex_point2_map &uvmap, vertex_descriptor v_i, vertex_descriptor v_j, double gamma) = 0;
virtual NT compute_borderLength_3D(TriangleMesh& mesh) = 0;
virtual double distError(TriangleMesh& mesh) = 0;
// Measure L2 stretch
template <typename VertexUVmap>
double compute_dist_errors(const TriangleMesh& mesh, Vertex_set& vertices,
const std::unordered_set<vertex_descriptor>& main_border,
const VertexUVmap uvmap)
{
// iterate fpr all inner vertices and for each vertex
std::vector<double> area_3D;
std::vector<double> area_2D;
std::vector<double> area_dist;
double A_3D = Polygon_mesh_processing::area(mesh);
double A_2D = 1.;
for(vertex_descriptor v : vertices)
{
// inner vertices only
if(main_border.find(v) == main_border.end())
{
double a_2D = 0;
double a_3D = 0;
// find the area of all the adjacent faces to this vertex
face_around_target_circulator f_j(halfedge(v, mesh), mesh), end = f_j;
CGAL_For_all(f_j, end)
{
// get area in original mesh
a_3D += (Polygon_mesh_processing::face_area(*f_j, mesh)/A_3D);
// get area in parameterised mesh
// iterate for all the vertices of this face and compute area
std::vector<Point_2> uv_points;
for(vertex_descriptor vd : vertices_around_face(halfedge(v, mesh), mesh))
uv_points.push_back(get(uvmap, vd));
a_2D += (abs(CGAL::area(uv_points[0], uv_points[1],uv_points[2])) / A_2D);
}
area_3D.push_back(a_3D);
area_2D.push_back(a_2D);
area_dist.push_back(square((a_3D/a_2D) - 1));
}
}
return sqrt(sum_vector(area_dist));
}
template <typename VertexUVmap>
double compute_area_distortion(TriangleMesh& mesh,
const Vertex_set& vertices,
const std::unordered_set<vertex_descriptor>& main_border,
const VertexUVmap uvmap)
{
// iterate for all inner vertices and for each vertex
Face_Double_map area_3DMap = get(Face_double_tag(), mesh);
Face_Double_map area_2DMap = get(Face_double_tag(), mesh);;
std::vector<double> area_dist;
std::vector<face_descriptor> innerFaces;
double A_3D = 0.0;
double A_2D = 0.0;
for(face_descriptor fd : faces(mesh))
{
put(area_3DMap, fd, Polygon_mesh_processing::face_area(fd, mesh));
// get area in parameterised mesh
std::vector<Point_2> uv_points;
for(vertex_descriptor vd : vertices_around_face(halfedge(fd, mesh), mesh))
uv_points.push_back(get(uvmap,vd));
put(area_2DMap, fd, abs(CGAL::area(uv_points[0], uv_points[1], uv_points[2])));
}
for(face_descriptor fd : faces(mesh))
{
A_3D += get(area_3DMap, fd);
A_2D += get(area_2DMap, fd);
}
for(face_descriptor fd : faces(mesh))
{
double a_3D = get(area_3DMap, fd);
double a_2D = get(area_2DMap, fd);
area_dist.push_back(abs(a_3D/A_3D - a_2D/A_2D));
}
return sum_vector(area_dist);
}
template <typename T>
T sum_vector(typename std::vector<T> vec)
{
T sum = 0;
for(typename std::vector<T>::iterator it=vec.begin(); it!= vec.end(); ++it)
sum += *it;
return sum;
}
template <typename VertexIndexMap>
void copy_sparse_matrix(TriangleMesh& mesh,
Vertex_set& vertices,
VertexIndexMap& vimap,
const Matrix& src,
Matrix& dest)
{
CGAL_assertion(src.row_dimension()==dest.row_dimension());
CGAL_assertion(src.column_dimension()==dest.column_dimension());
for(vertex_descriptor vertex : vertices)
{
int i = get(vimap, vertex);
vertex_around_target_circulator v_j(halfedge(vertex, mesh), mesh), end = v_j;
CGAL_For_all(v_j, end)
{
int j = get(vimap, *v_j);
dest.set_coef(i,j, src.get_coef(i,j), false);
}
}
}
template <typename VertexIndexMap>
void print_matrix(const Vertex_set& vertices,
const VertexIndexMap vimap,
const Matrix &A,
const std::string name)
{
std::cout << "Matrix " << name << "(" << A.row_dimension() << "x" << A.column_dimension() << ")" << std::endl;
Matrix A1(A.row_dimension(), A.column_dimension());
int r=0, c=0;
for(vertex_descriptor v1 : vertices)
{
int i = get(vimap, v1);
for(vertex_descriptor v2 : vertices)
{
int j = get(vimap, v2);
A1.set_coef(r, c, A.get_coef(i, j));
++c;
}
++r;
c = 0;
}
for(int r = 0; r < A.row_dimension(); ++r)
for(int c = 0; c < A.column_dimension(); ++c)
std::cout << std::setw(10) << A1.get_coef(r,c) << "\t" << std::flush;
std::cout << std::endl;
}
template <typename VertexIndexMap>
void print_vector(const Vertex_set& vertices,
const VertexIndexMap vimap,
const Vector& A,
const std::string name)
{
std::cout << "Vector " << name << "(" << A.size() << ")" << std::endl;
Vector A1(A.size());
int r = 0;
for(vertex_descriptor v1 : vertices)
{
int i = get(vimap,v1);
A1.set(r, A(i));
++r;
}
for(int r=0; r<A.size(); ++r)
std::cout << A1(r) << std::endl;
}
void print(Matrix& A, Vector& Xu, Vector& Bu)
{
std::cout << "Matrix " << "(" << A.row_dimension() << "x" << A.column_dimension() << ")" << std::endl;
for(int r=0; r<A.row_dimension(); ++r)
{
for(int c=0; c<A.column_dimension(); ++c)
std::cout << std::setw(10) << A.get_coef(r,c) << "\t" << std::flush;
std::cout << "\t\t" << Xu(r) << "\t\t" << Bu(r) << std::endl;
}
}
// Protected accessors
protected:
/// Get the object that maps the surface's border onto a 2D space.
Border_parameterizer& get_border_parameterizer() { return m_borderParameterizer; }
/// Get the sparse linear algebra (traits object to access the linear system).
Solver_traits& get_linear_algebra_traits() { return m_linearAlgebra; }
// Fields
private:
// Object that maps the surface's border onto a 2D space.
Border_parameterizer m_borderParameterizer;
// Traits object to solve a sparse linear system
Solver_traits m_linearAlgebra;
// Object that keeps the last best UV Map
Vertex_point2_map lastBestuvmap;
// Counter to keep track of failure of Linear solver
int LScounter;
};
} // namespace Surface_mesh_parameterization
} // namespace CGAL
#endif // CGAL_SURFACE_MESH_PARAMETERIZATION_FIXED_BORDER_ITERATIVE_PARAMETERIZER_3_H

View File

@ -1,142 +0,0 @@
// This file has been adopted from CGAL, to integrate the below mentioned paper
//
// Paper : Learning to Reconstruct Symmetric Shapes using Planar Parameterization of 3D Surface
// Author(s) : Hardik Jain, Manuel Wöllhaf, Olaf Hellwich
// Conference : IEEE International Conference on Computer Vision Workshops (ICCVW) 2019
//
#ifndef CGAL_SURFACE_MESH_PARAMETERIZATION_ITERATIVE_PARAMETERIZE_H
#define CGAL_SURFACE_MESH_PARAMETERIZATION_ITERATIVE_PARAMETERIZE_H
#include <CGAL/license/Surface_mesh_parameterization.h>
#include <CGAL/disable_warnings.h>
#include <CGAL/Surface_mesh_parameterization/internal/Bool_property_map.h>
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
#include <CGAL/Surface_mesh_parameterization/Mean_value_coordinates_parameterizer_3.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <boost/function_output_iterator.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
/// \file Iterative_parameterize.h
namespace CGAL {
namespace Surface_mesh_parameterization {
/// \ingroup PkgSurfaceMeshParameterizationMainFunction
///
/// Compute a one-to-one mapping from a 3D triangle surface `mesh` to a
/// simple 2D domain.
/// The mapping is piecewise linear on the triangle mesh.
/// The result is a pair `(u,v)` of parameter coordinates for each vertex of the input mesh.
///
/// A one-to-one mapping may be guaranteed or not, depending on
/// the chosen Parameterizer algorithm.
///
/// \tparam TriangleMesh must be a model of `FaceGraph`.
/// \tparam Parameterizer must be a model of `Parameterizer_3`.
/// \tparam HD must be the halfedge_descriptor type corresponding to the graph
/// traits of TriangleMesh.
/// \tparam VertexUVmap must be a model of `ReadWritePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `TriangleMesh` using `Kernel_traits`)
/// as value type.
///
/// \param mesh a triangulated surface.
/// \param parameterizer a parameterizer.
/// \param bhd a halfedge descriptor on the boundary of `mesh`.
/// \param uvm an instanciation of the class `VertexUVmap`.
/// \param iterations an integer number of iterations to run the parameterization.
/// \param error return error value of the iterative process.
///
/// \pre `mesh` must be a triangular mesh.
/// \pre The mesh border must be mapped onto a convex polygon
/// (for fixed border parameterizations).
/// \pre The vertices must be indexed (vimap must be initialized).
///
template <class TriangleMesh, class Parameterizer, class HD, class VertexUVmap>
Error_code parameterize(TriangleMesh& mesh,
Parameterizer parameterizer,
HD bhd,
VertexUVmap uvm,
int& iterations,
double& error)
{
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef boost::unordered_map<vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(bhd, mesh), mesh),
mesh,
boost::make_function_output_iterator(
internal::Index_map_filler<TriangleMesh, Indices>(mesh, indices)));
boost::associative_property_map<Indices> vipm(indices);
boost::unordered_set<vertex_descriptor> vs;
internal::Bool_property_map<boost::unordered_set<vertex_descriptor> > vpm(vs);
return parameterizer.parameterize(mesh, bhd, uvm, vipm, vpm, iterations, error);
}
template <class TriangleMesh, class Parameterizer, class HD, class VertexUVmap>
Error_code parameterize(TriangleMesh& mesh,
Parameterizer parameterizer,
HD bhd,
VertexUVmap uvm,
int& iterations)
{
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef boost::unordered_map<vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(bhd, mesh), mesh),
mesh,
boost::make_function_output_iterator(
internal::Index_map_filler<TriangleMesh, Indices>(mesh, indices)));
boost::associative_property_map<Indices> vipm(indices);
boost::unordered_set<vertex_descriptor> vs;
internal::Bool_property_map<boost::unordered_set<vertex_descriptor> > vpm(vs);
double error;
return parameterizer.parameterize(mesh, bhd, uvm, vipm, vpm, iterations, error);
}
template <class TriangleMesh, class Parameterizer, class HD, class VertexUVmap>
Error_code parameterize(TriangleMesh& mesh,
Parameterizer parameterizer,
HD bhd,
VertexUVmap uvm)
{
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef boost::unordered_map<vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(bhd, mesh), mesh),
mesh,
boost::make_function_output_iterator(
internal::Index_map_filler<TriangleMesh, Indices>(mesh, indices)));
boost::associative_property_map<Indices> vipm(indices);
boost::unordered_set<vertex_descriptor> vs;
internal::Bool_property_map<boost::unordered_set<vertex_descriptor> > vpm(vs);
int iterations = 0;
double error;
return parameterizer.parameterize(mesh, bhd, uvm, vipm, vpm, iterations, error);
}
} // namespace Surface_mesh_parameterization
} // namespace CGAL
#include <CGAL/enable_warnings.h>
#endif // CGAL_ITERATIVE_PARAMETERIZE_H