Merge pull request #4885 from MaelRL/Iterative_authalic_parameterization

This commit is contained in:
Laurent Rineau 2020-10-29 14:21:42 +01:00 committed by GitHub
commit a6c5402dc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 2169 additions and 557 deletions

View File

@ -24,6 +24,7 @@
#include <boost/unordered_set.hpp>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <utility>
@ -32,6 +33,7 @@
namespace CGAL {
#ifndef DOXYGEN_RUNNING
template <typename HD>
class Seam_mesh_halfedge_descriptor
{
@ -86,8 +88,92 @@ public:
return 2 * hash_value(hd.tmhd) + static_cast<std::size_t>(hd.seam);
}
};
template <typename HD>
class Seam_mesh_vertex_descriptor
{
public:
Seam_mesh_halfedge_descriptor<HD> hd;
Seam_mesh_vertex_descriptor() { }
Seam_mesh_vertex_descriptor(const Seam_mesh_halfedge_descriptor<HD>& h)
: hd(h)
{ }
bool operator==(const Seam_mesh_vertex_descriptor& other) const
{
return (hd == other.hd);
}
bool operator!=(const Seam_mesh_vertex_descriptor& other) const
{
return (hd != other.hd);
}
bool operator<(const Seam_mesh_vertex_descriptor& other) const
{
return hd < other.hd;
}
operator HD() const
{
return hd;
}
#ifdef CGAL_SEAM_MESH_INSERT_OPERATOR
friend std::ostream& operator<<(std::ostream& os, const Seam_mesh_vertex_descriptor vd)
{
os << "seam mesh vertex: " << vd.hd;
return os;
}
#endif
friend std::size_t hash_value(const Seam_mesh_vertex_descriptor& vd)
{
return hash_value(vd.hd.tmhd);
}
};
template <typename HD, typename SM>
class Seam_mesh_edge_descriptor
{
public:
Seam_mesh_halfedge_descriptor<HD> hd;
const SM* mesh_;
Seam_mesh_edge_descriptor() : mesh_(nullptr) { }
Seam_mesh_edge_descriptor(const Seam_mesh_halfedge_descriptor<HD>& hd, const SM* m)
: hd(hd), mesh_(m)
{}
friend bool operator==(Seam_mesh_edge_descriptor e1, Seam_mesh_edge_descriptor e2)
{
return (e1.hd == e2.hd) || (e1.hd == e2.mesh_->opposite(e2.hd));
}
friend bool operator!=(Seam_mesh_edge_descriptor e1, Seam_mesh_edge_descriptor e2)
{
return ! (e1 == e2);
}
#ifdef CGAL_SEAM_MESH_INSERT_OPERATOR
friend std::ostream& operator<<(std::ostream& os, const Seam_mesh_edge_descriptor& ed)
{
os << ed.hd;
return os;
}
#endif
friend std::size_t hash_value(const Seam_mesh_edge_descriptor& ed)
{
return hash_value((std::min)(ed.hd, ed.mesh_->opposite(ed.hd)));
}
};
#endif // DOXYGEN_RUNNING
/// \ingroup PkgBGLAdaptors
///
/// This class is a data structure that takes a triangle mesh, further refered
@ -112,6 +198,10 @@ class Seam_mesh
typedef Seam_mesh<TM, SEM, SVM> Self;
public:
/// The underlying mesh type
typedef TM Triangle_mesh;
// backward compatibility
typedef TM TriangleMesh;
public:
@ -187,23 +277,15 @@ public:
class halfedge_descriptor
{
public:
TM_halfedge_descriptor tmhd;
bool seam;
/// %Default constructor
halfedge_descriptor() : tmhd(), seam(false) { }
halfedge_descriptor();
halfedge_descriptor(TM_halfedge_descriptor tmhd, bool seam = false)
: tmhd(tmhd), seam(seam)
{ }
/// Constructor from a halfedge of the underlying mesh
halfedge_descriptor(TM_halfedge_descriptor tmhd, bool seam = false);
#ifdef CGAL_SEAM_MESH_INSERT_OPERATOR
/// Print the halfedge and if it is on a seam.
friend std::ostream& operator<<(std::ostream& os, const halfedge_descriptor& hd)
{
os << hd.tmhd << ((hd.seam)?" on seam":"");
return os;
}
friend std::ostream& operator<<(std::ostream& os, const halfedge_descriptor& hd);
#endif
};
#else
@ -265,13 +347,13 @@ public:
return halfedge_descriptor(*hd, seam);
}
};
#endif
#endif // DOXYGEN_RUNNING
#ifdef DOXYGEN_RUNNING
/// This class represents a vertex of the seam mesh.
///
/// Implementation note: to properly duplicate vertices that are on seams,
/// a vertex_descriptor is in fact represented as a halfedge of the underlying
/// mesh.
/// a vertex_descriptor is in fact represented as a halfedge of the seam mesh.
///
/// \cgalModels `Descriptor`
/// \cgalModels `LessThanComparable`
@ -280,48 +362,20 @@ public:
class vertex_descriptor
{
public:
halfedge_descriptor hd;
/// %Default constructor
vertex_descriptor() { }
vertex_descriptor();
vertex_descriptor(const halfedge_descriptor& h)
: hd(h)
{ }
bool operator==(const vertex_descriptor& other) const
{
return (hd == other.hd);
}
bool operator!=(const vertex_descriptor& other) const
{
return (hd != other.hd);
}
bool operator<(const vertex_descriptor& other) const
{
return hd < other.hd;
}
operator TM_halfedge_descriptor() const
{
return hd;
}
/// Constructor from a seam mesh halfedge
vertex_descriptor(const halfedge_descriptor& h);
#ifdef CGAL_SEAM_MESH_INSERT_OPERATOR
friend std::ostream& operator<<(std::ostream& os, const vertex_descriptor vd)
{
os << "seam mesh vertex: " << vd.hd;
return os;
}
/// Print the seam mesh vertex.
friend std::ostream& operator<<(std::ostream& os, const vertex_descriptor vd);
#endif
friend std::size_t hash_value(const vertex_descriptor& vd)
{
return hash_value(vd.hd.tmhd);
}
};
#else
typedef Seam_mesh_vertex_descriptor<TM_halfedge_descriptor> vertex_descriptor;
#endif
// iterator
#ifndef DOXYGEN_RUNNING
@ -403,48 +457,24 @@ public:
};
#endif
#ifdef DOXYGEN_RUNNING
/// This class represents an edge of the seam mesh.
///
/// \cgalModels `Descriptor`
/// \cgalModels `Hashable`
///
class edge_descriptor
{
public:
halfedge_descriptor hd;
const Self* mesh_;
/// %Default constructor
edge_descriptor();
#ifdef CGAL_SEAM_MESH_INSERT_OPERATOR
friend
std::ostream& operator<<(std::ostream& os, const edge_descriptor& ed)
{
os << ed.hd;
return os;
}
friend std::ostream& operator<<(std::ostream& os, const edge_descriptor& ed);
#endif
edge_descriptor()
: mesh_(nullptr)
{}
edge_descriptor(const halfedge_descriptor& hd, const Self* m)
: hd(hd), mesh_(m)
{}
friend bool operator==(edge_descriptor e1, edge_descriptor e2)
{
return (e1.hd == e2.hd) || (e1.hd == e2.mesh_->opposite(e2.hd));
}
friend bool operator!=(edge_descriptor e1, edge_descriptor e2)
{
return ! (e1 == e2);
}
friend std::size_t hash_value(const edge_descriptor& ed)
{
return hash_value((std::min)(ed.hd, ed.mesh_->opposite(ed.hd)));
}
};
#else
typedef Seam_mesh_edge_descriptor<TM_halfedge_descriptor, Self> edge_descriptor;
#endif
#ifndef DOXYGEN_RUNNING
// iterator
@ -1120,6 +1150,46 @@ public:
} // namespace CGAL
#ifndef CGAL_CFG_NO_STD_HASH
namespace std {
template <typename HD>
struct hash<CGAL::Seam_mesh_vertex_descriptor<HD> >
: public CGAL::cpp98::unary_function<CGAL::Seam_mesh_vertex_descriptor<HD>, std::size_t>
{
std::size_t operator()(const CGAL::Seam_mesh_vertex_descriptor<HD>& v) const
{
return hash_value(v);
}
};
template <typename HD>
struct hash<CGAL::Seam_mesh_halfedge_descriptor<HD> >
: public CGAL::cpp98::unary_function<CGAL::Seam_mesh_halfedge_descriptor<HD>, std::size_t>
{
std::size_t operator()(const CGAL::Seam_mesh_halfedge_descriptor<HD>& h) const
{
return hash_value(h);
}
};
template <typename HD, typename SM>
struct hash<CGAL::Seam_mesh_edge_descriptor<HD, SM> >
: public CGAL::cpp98::unary_function<CGAL::Seam_mesh_edge_descriptor<HD, SM>, std::size_t>
{
std::size_t operator()(const CGAL::Seam_mesh_edge_descriptor<HD, SM>& e) const
{
return hash_value(e);
}
};
// Seam_mesh::face_descriptor is equal to TM_face_descriptor so nothing to do
} // namespace std
#endif // CGAL_CFG_NO_STD_HASH
#include <CGAL/enable_warnings.h>
#endif //CGAL_SEAM_MESH_H

View File

@ -135,7 +135,7 @@ struct Index_map_initializer<IndexPropertyMap, Graph, false>
void operator()(const PropertyTag, IndexPropertyMap, const Graph&)
{
// The property map is not writable; should never be here.
CGAL_assertion_msg(false, "You are trying to initialize a non-writable property map");
CGAL_assertion_msg(false, "Initialization of a non-writable property map is impossible");
}
};
@ -171,7 +171,7 @@ IndexMap get_initialized_index_map_const(const IndexMap index_map,
CGAL_USE(g);
CGAL_USE(p);
// If you are passing a pmap via NPs, it must be initialized
// If a pmap is passed via NPs, it must be initialized
CGAL_assertion(is_index_map_valid(p, index_map, g));
return index_map;
@ -185,7 +185,7 @@ IndexMap get_initialized_index_map(const IndexMap index_map,
CGAL_USE(g);
CGAL_USE(p);
// If you are passing a pmap via NPs, it must be initialized
// If a pmap is passed via NPs, it must be initialized
CGAL_assertion(is_index_map_valid(p, index_map, g));
return index_map;

View File

@ -1153,6 +1153,12 @@ Teillaud"
URL = {https://hal.inria.fr/hal-01568002},
}
@inproceedings{cgal:j-lrsspp-19,
title={Learning to Reconstruct Symmetric Shapes using Planar Parameterization of 3D Surface},
author={Jain, Hardik and Wollhaf, Manuel and Hellwich, Olaf},
booktitle={Proceedings of the IEEE International Conference on Computer Vision Workshops},
year={2019}
}
@book{ cgal:j-csl-99
,author = "Nicolai M. Josuttis"
@ -1964,6 +1970,14 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio
update = "09.11 penarand"
}
@inproceedings{cgal:ssgh-tmpm-01,
title={Texture mapping progressive meshes},
author={Sander, Pedro V and Snyder, John and Gortler, Steven J and Hoppe, Hugues},
booktitle={Proceedings of the 28th annual conference on Computer graphics and interactive techniques},
pages={409--416},
year={2001}
}
@inproceedings{ cgal:s-cgehd-98
,author = "Jonathan R. Shewchuk"
,title = "A Condition Guaranteeing the Existence of Higher-Dimensional

View File

@ -77,7 +77,6 @@ Release date: December 2020
- Added the functions `set_recycle_garbage()` and `does_recycle_garbage()` to the class `Surface_mesh`.
### [dD Geometry Kernel](https://doc.cgal.org/5.2/Manual/packages.html#PkgKernelD)
- The kernels [`Epick_d`](https://doc.cgal.org/5.2/Kernel_d/structCGAL_1_1Epick__d.html)
@ -87,6 +86,10 @@ Release date: December 2020
to deal with weighted points.
### [Surface Mesh Parameterization](https://doc.cgal.org/5.2/Manual/packages.html#PkgSurfaceMeshParameterization)
- Added a new parameterization method, Iterative Authalic Parameterization. It is based on the work of Jain, Hardik, Manuel Wollhaf, and Olaf Hellwich,
"Learning to Reconstruct Symmetric Shapes using Planar Parameterization of 3D Surface." (IEEE International Conference on Computer Vision Workshops, 2019).
[Release 5.1](https://github.com/CGAL/cgal/releases/tag/v5.1)
-----------

View File

@ -29,6 +29,7 @@
#include <CGAL/Surface_mesh_parameterization/Barycentric_mapping_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Discrete_authalic_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Discrete_conformal_map_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Iterative_authalic_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
#include <CGAL/Surface_mesh_parameterization/LSCM_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Two_vertices_parameterizer_3.h>
@ -342,6 +343,7 @@ public:
QAction* actionDCP = new QAction ("Discrete Conformal Map", mw);
QAction* actionLSC = new QAction("Least Square Conformal Map", mw);
QAction* actionDAP = new QAction("Discrete Authalic", mw);
QAction* actionIAP = new QAction("Iterative Authalic", mw);
QAction* actionARAP = new QAction("As Rigid As Possible", mw);
QAction* actionOTE = new QAction("Orbifold Tutte Embedding", mw);
QAction* actionBTP = new QAction("Tutte Barycentric", mw);
@ -349,6 +351,7 @@ public:
actionDCP->setObjectName("actionDCP");
actionLSC->setObjectName("actionLSC");
actionDAP->setObjectName("actionDAP");
actionIAP->setObjectName("actionIAP");
actionARAP->setObjectName("actionARAP");
actionOTE->setObjectName("actionOTE");
actionBTP->setObjectName("actionBTP");
@ -356,6 +359,7 @@ public:
_actions << actionARAP
<< actionBTP
<< actionDAP
<< actionIAP
<< actionDCP
<< actionLSC
<< actionMVC
@ -413,6 +417,7 @@ public Q_SLOTS:
void on_actionDCP_triggered();
void on_actionLSC_triggered();
void on_actionDAP_triggered();
void on_actionIAP_triggered();
void on_actionARAP_triggered();
void on_actionOTE_triggered();
void on_actionBTP_triggered();
@ -485,8 +490,8 @@ public Q_SLOTS:
}
protected:
enum Parameterization_method { PARAM_MVC, PARAM_DCP, PARAM_LSC,
PARAM_DAP, PARAM_ARAP, PARAM_OTE, PARAM_BTP};
enum Parameterization_method { PARAM_MVC, PARAM_DCP, PARAM_LSC, PARAM_DAP,
PARAM_IAP, PARAM_ARAP, PARAM_OTE, PARAM_BTP};
void parameterize(Parameterization_method method);
private:
@ -804,6 +809,15 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio
status = SMP::parameterize(sMesh, Parameterizer(), bhd, uv_pm);
break;
}
case PARAM_IAP:
{
new_item_name = tr("%1 (parameterized (IAP))").arg(poly_item->name());
std::cout << "Parameterize (IAP)..." << std::endl;
typedef SMP::Iterative_authalic_parameterizer_3<Seam_mesh> Parameterizer;
Parameterizer parameterizer;
status = parameterizer.parameterize(sMesh, bhd, uv_pm, 15 /*iterations*/);
break;
}
case PARAM_ARAP:
{
new_item_name = tr("%1 (parameterized (ARAP))").arg(poly_item->name());
@ -1014,6 +1028,12 @@ void Polyhedron_demo_parameterization_plugin::on_actionDAP_triggered()
parameterize(PARAM_DAP);
}
void Polyhedron_demo_parameterization_plugin::on_actionIAP_triggered()
{
std::cerr << "IAP...";
parameterize(PARAM_IAP);
}
void Polyhedron_demo_parameterization_plugin::on_actionARAP_triggered()
{
std::cerr << "ARAP...";

View File

@ -19,11 +19,11 @@ Construction and destruction are undefined.
\cgalHasModel `CGAL::Surface_mesh_parameterization::Discrete_conformal_map_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
\cgalHasModel `CGAL::Surface_mesh_parameterization::LSCM_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
\cgalHasModel `CGAL::Surface_mesh_parameterization::Mean_value_coordinates_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
\cgalHasModel `CGAL::Surface_mesh_parameterization::Orbifold_Tutte_parameterizer_3<SeamMesh, SolverTraits>`
\cgalHasModel `CGAL::Surface_mesh_parameterization::Circular_border_parameterizer_3<TriangleMesh>`
\cgalHasModel `CGAL::Surface_mesh_parameterization::Square_border_parameterizer_3<TriangleMesh>`
\cgalHasModel `CGAL::Surface_mesh_parameterization::Two_vertices_parameterizer_3<TriangleMesh>`
\sa `CGAL::Surface_mesh_parameterization::Orbifold_Tutte_parameterizer_3<SeamMesh, SolverTraits>`
*/
class Parameterizer_3

View File

@ -2,8 +2,10 @@
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - Planar Parameterization of Triangulated Surface Meshes"
EXTRACT_ALL = false
HIDE_UNDOC_MEMBERS = true
HIDE_UNDOC_CLASSES = true
WARN_IF_UNDOCUMENTED = false
HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/nefertiti.jpg \
${CGAL_PACKAGE_DOC_DIR}/fig/ARAP_new.jpg \
${CGAL_PACKAGE_DOC_DIR}/fig/orbifold_new.jpg \

View File

@ -6,7 +6,7 @@
\cgalPkgDescriptionBegin{Triangulated Surface Mesh Parameterization,PkgSurfaceMeshParameterization}
\cgalPkgPicture{bimbaDetail.png}
\cgalPkgSummaryBegin
\cgalPkgAuthors{Laurent Saboret, Pierre Alliez, Bruno Lévy, Mael Rouxel-Labbé, and Andreas Fabri}
\cgalPkgAuthors{Laurent Saboret, Pierre Alliez, Bruno Lévy, Mael Rouxel-Labbé, Andreas Fabri, and Hardik Jain}
\cgalPkgDesc{Parameterizing a surface amounts to finding a one-to-one mapping from
a suitable domain to the surface. In this package, we focus on triangulated surfaces
that are homeomorphic to a disk and on piecewise linear mappings into a planar domain.
@ -49,9 +49,10 @@ This \cgal package implements several parameterization methods:
Conditionally guaranteed if all weights are positive and border is convex.
- Floater Mean Value Coordinates \cgalCite{cgal:f-mvc-03} :
One-to-one mapping is guaranteed for convex border.
- Iterative Authalic Parameterization \cgalCite{cgal:j-lrsspp-19}.
- Free border:
- As Rigid As Possible Parameterization \cgalCite{liu2008local}
- Least Squares Conformal Maps \cgalCite{cgal:lprm-lscm-02}.
- Least Squares Conformal Maps (LSCM) \cgalCite{cgal:lprm-lscm-02}.
- Borderless:
- Orbifold Tutte Embeddings \cgalCite{aigerman2015orbifold}.
@ -60,6 +61,7 @@ The following classes implement the methods listed above:
- `CGAL::Surface_mesh_parameterization::Barycentric_mapping_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
- `CGAL::Surface_mesh_parameterization::Discrete_authalic_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
- `CGAL::Surface_mesh_parameterization::Discrete_conformal_map_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
- `CGAL::Surface_mesh_parameterization::Iterative_authalic_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
- `CGAL::Surface_mesh_parameterization::LSCM_parameterizer_3<TriangleMesh, BorderParameterizer>`
- `CGAL::Surface_mesh_parameterization::Mean_value_coordinates_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
- `CGAL::Surface_mesh_parameterization::Orbifold_Tutte_parameterizer_3<TriangleMesh, SolverTraits>`

View File

@ -7,13 +7,7 @@ namespace CGAL {
\anchor chapsurface_mesh_parameterization
\cgalAutoToc
\authors Laurent Saboret, Pierre Alliez, Bruno L&eacute;vy, Andreas Fabri, and
Mael Rouxel-Labbé
\warning The API and structure of this package have greatly changed with CGAL 4.11.
Users who wish to use the former API must use a version prior to 4.11.
Section \ref Surface_mesh_parameterizationBasics gives a gentle introduction to
the new, much simpler, API.
\authors Laurent Saboret, Pierre Alliez, Bruno L&eacute;vy, Mael Rouxel-Labb&eacute;, Andreas Fabri and Hardik Jain
\section Surface_mesh_parameterizationIntroduction Introduction
@ -218,7 +212,7 @@ convex combination condition. This algorithm amounts to solve one
sparse linear system for each set of parameter coordinates, with a
\#vertices x \#vertices sparse and symmetric positive definite matrix
(if the border vertices are eliminated from the linear system).
A coefficient \f$ (i, j)\f$ of the matrix is set to 1 for an edge linking
A coefficient \f$ (i,j)\f$ of the matrix is set to 1 for an edge linking
the vertex \f$ v_i\f$ to the vertex \f$ v_j\f$, to minus the degree of the
vertex \f$ v_i\f$ for a diagonal element, and to 0 for any other matrix
entry. Although a bijective mapping is guaranteed when the border is convex,
@ -299,6 +293,29 @@ for both systems) is asymmetric.
Floater Mean Value Coordinates. Rightmost: parameter space.
\cgalFigureCaptionEnd
\subsubsection Surface_mesh_parameterizationIterativeAuthalic Iterative Authalic Parameterization
`Surface_mesh_parameterization::Iterative_authalic_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
The Iterative Authalic parameterization method has been introduced by
Jain et al. \cgalCite{cgal:j-lrsspp-19}. This parameterization
is a fixed border parameterization and is part of the authalic parameterization family,
meaning that it aims to minimize area distortion between the input surface mesh and the parameterized output.
More precisely, the approach used by this parameterizer is to iteratively redistribute
the \f$ L_2\f$ stretch - as defined by Sander et al. \cgalCite{cgal:ssgh-tmpm-01} - over the mesh.
\cgalFigureAnchor{Surface_mesh_parameterizationfigiterativeauthalic}
<center>
<img src="iterative_authalic.jpg" style="max-width:70%;"/>
</center>
\cgalFigureCaptionBegin{Surface_mesh_parameterizationfigiterativeauthalic}
Iterative Authalic Parameterization (the blue line depicts the cut graph). Rightmost: parameter space.
\cgalFigureCaptionEnd
Although this is a fixed border parameterization method, it does not guarantee a one-to-one mapping.
However, it will in practice yield valid results with less distortion than other authalic
parameterization methods.
\subsubsection secBorderParameterizationsforFixedMethods Border Parameterizations for Fixed Methods
Parameterization methods for borders are used as traits classes modifying the
@ -475,55 +492,43 @@ underlying (input) mesh.
\subsection Surface_mesh_parameterizationParameterization Parameterization Methods and Guarantees
<UL>
<LI>Fixed boundaries
<UL>
<LI>One-to-one mapping
Tutte's theorem guarantees a one-to-one mapping provided that the weights are all positive
and the border is convex.
It is the case for Tutte Barycentric Mapping and Floater Mean Value Coordinates.
It is not always the case for Discrete Conformal Map (cotangents) and
Discrete Authalic parameterization.
<LI>Non-singularity of the matrix
Geshorgin's theorem guarantees the convergence of the solver if the matrix is diagonal dominant.
This is the case with positive weights (Tutte Barycentric Mapping and Floater Mean Value Coordinates).
</UL>
<LI>Free boundaries
<UL>
<LI>One-to-one mapping
No guarantee is provided by either LSCM or ARAP parameterizations (both global
overlaps and triangle flips can occur).
<LI>Non-singularity of the matrix
For LSCM, the matrix of the system is the Gram matrix of a matrix with maximal rank,
and is therefore non-singular (Gram theorem).
</UL>
<LI> Boundary-less
<UL>
<LI>One-to-one mapping
The Orbifold-Tutte embedding is guaranteed to exist and to be computable
via a sparse linear system.
</UL>
</UL>
<ul>
<li><b>Fixed boundaries</b>
<ul>
<li><em>One-to-one mapping</em><br>
Tutte's theorem guarantees a one-to-one mapping provided that the weights are all positive
and the border is convex.
It is the case for Tutte Barycentric Mapping and Floater Mean Value Coordinates.
It is not always the case for Discrete Conformal Map (cotangents), Discrete Authalic,
and Iterative Authalic parameterizations.
</li>
<li><em>Non-singularity of the matrix</em><br>
Geshorgin's theorem guarantees the convergence of the solver if the matrix is diagonal dominant.
This is the case with positive weights (Tutte Barycentric Mapping and Floater Mean Value Coordinates).
</li>
</ul>
</li>
<li><b>Free boundaries</b>
<ul>
<li><em>One-to-one mapping</em><br>
No guarantee is provided by either LSCM or ARAP parameterizations (both global overlaps
and triangle flips can occur).
</li>
<li><em>Non-singularity of the matrix</em><br>
For LSCM, the matrix of the system is the Gram matrix of a matrix with maximal rank,
and is therefore non-singular (Gram theorem).
</li>
</ul>
</li>
<li><b>Boundary-less</b>
<ul>
<li><em>One-to-one mapping</em><br>
The Orbifold-Tutte embedding is guaranteed to exist and to be computable
via a sparse linear system.
</li>
</ul>
</li>
</ul>
\section Surface_mesh_parameterizationExtendingthe Implementation History
@ -539,6 +544,9 @@ and Yaron Lipman. Finally, the class `Seam_mesh` was introduced to handle
virtual borders. The class `Seam_mesh` is also a model of a `FaceGraph`,
and replaces a wrapper which had a more complicated API.
Iterative authalic parameterization was added in CGAL 5.2 by Mael Rouxel-Labbé,
based on a prototype developed by Hardik Jain.
*/
} /* namespace CGAL */

View File

@ -5,4 +5,5 @@
\example Surface_mesh_parameterization/seam_Polyhedron_3.cpp
\example Surface_mesh_parameterization/simple_parameterization.cpp
\example Surface_mesh_parameterization/square_border_parameterizer.cpp
\example Surface_mesh_parameterization/iterative_authalic_parameterizer.cpp
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 KiB

View File

@ -63,6 +63,8 @@ if ( CGAL_FOUND )
target_link_libraries(simple_parameterization PUBLIC CGAL::Eigen_support)
create_single_source_cgal_program( "square_border_parameterizer.cpp" )
target_link_libraries(square_border_parameterizer PUBLIC CGAL::Eigen_support)
create_single_source_cgal_program( "iterative_authalic_parameterizer.cpp" )
target_link_libraries(iterative_authalic_parameterizer PUBLIC CGAL::Eigen_support)
if(SuiteSparse_FOUND)
target_link_libraries(orbifold PRIVATE ${SuiteSparse_LIBRARIES})

View File

@ -0,0 +1,66 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Surface_mesh_parameterization/IO/File_off.h>
#include <CGAL/Surface_mesh_parameterization/Square_border_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Circular_border_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Iterative_authalic_parameterizer_3.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/Unique_hash_map.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
typedef boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Surface_mesh>::halfedge_descriptor halfedge_descriptor;
typedef CGAL::Unique_hash_map<vertex_descriptor, Point_2> UV_uhm;
typedef boost::associative_property_map<UV_uhm> UV_pmap;
namespace SMP = CGAL::Surface_mesh_parameterization;
int main(int argc, char** argv)
{
std::ifstream in((argc>1) ? argv[1] : "data/nefertiti.off");
if(!in)
{
std::cerr << "Error: problem loading the input data" << std::endl;
return EXIT_FAILURE;
}
Surface_mesh sm;
in >> sm;
halfedge_descriptor bhd = CGAL::Polygon_mesh_processing::longest_border(sm).first;
// The 2D points of the uv parametrisation will be written into this map
UV_uhm uv_uhm;
UV_pmap uv_map(uv_uhm);
typedef SMP::Circular_border_arc_length_parameterizer_3<Surface_mesh> Border_parameterizer;
Border_parameterizer border_parameterizer; // the border parameterizer will automatically compute the corner vertices
typedef SMP::Iterative_authalic_parameterizer_3<Surface_mesh, Border_parameterizer> Parameterizer;
Parameterizer parameterizer(border_parameterizer);
const unsigned int iterations = (argc > 2) ? std::atoi(argv[2]) : 15;
SMP::Error_code err = parameterizer.parameterize(sm, bhd, uv_map, iterations);
if(err != SMP::OK)
{
std::cerr << "Error: " << SMP::get_error_message(err) << std::endl;
return EXIT_FAILURE;
}
std::ofstream out("iterative_result.off");
SMP::IO::output_uvmap_to_off(sm, bhd, uv_map, out);
return EXIT_SUCCESS;
}

View File

@ -129,7 +129,7 @@ namespace Surface_mesh_parameterization {
/// a random vertex is pinned.
///
/// If flips are present in the initial parameterization, a post-processing step
/// is applied using `CGAL::Surface_mesh_parameterization::MVC_post_processor_3<TriangleMesh, SolverTraits_>`
/// is applied using `CGAL::Surface_mesh_parameterization::MVC_post_processor_3<TriangleMesh_, SolverTraits_>`
/// to attempt to obtain a valid final embedding.
///
/// A one-to-one mapping is *not* guaranteed.
@ -162,6 +162,7 @@ namespace Surface_mesh_parameterization {
/// \endcode
///
/// \sa `CGAL::Surface_mesh_parameterization::Fixed_border_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Iterative_authalic_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
///
template < class TriangleMesh_,
class BorderParameterizer_ = Default,
@ -194,28 +195,39 @@ public:
#endif
>::type Solver_traits;
#else
/// Border parameterizer type
typedef Border_parameterizer_ Border_parameterizer;
/// Solver traits type
typedef SolverTraits_ Solver_traits;
/// Number type, deduced from the internal vertex point map of `Triangle_mesh`
typedef unspecified_type NT;
#endif
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef TriangleMesh_ TriangleMesh;
/// Mesh halfedge type
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
// 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 typename boost::graph_traits<TriangleMesh>::face_iterator face_iterator;
typedef typename boost::graph_traits<TriangleMesh>::vertex_iterator vertex_iterator;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Triangle_mesh>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<Triangle_mesh>::face_iterator face_iterator;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_iterator vertex_iterator;
typedef CGAL::Halfedge_around_target_circulator<TriangleMesh> halfedge_around_target_circulator;
typedef CGAL::Halfedge_around_face_circulator<TriangleMesh> halfedge_around_face_circulator;
typedef CGAL::Halfedge_around_target_circulator<Triangle_mesh> halfedge_around_target_circulator;
typedef CGAL::Halfedge_around_face_circulator<Triangle_mesh> halfedge_around_face_circulator;
typedef boost::unordered_set<vertex_descriptor> Vertex_set;
typedef std::vector<face_descriptor> Faces_vector;
// Traits subtypes:
typedef typename internal::Kernel_traits<TriangleMesh>::Kernel Kernel;
typedef typename internal::Kernel_traits<Triangle_mesh>::Kernel Kernel;
typedef typename Kernel::FT NT;
typedef typename Kernel::Point_2 Point_2;
typedef typename Kernel::Point_3 Point_3;
@ -277,7 +289,7 @@ private:
template <typename VertexUVMap,
typename VertexIndexMap>
void output_uvmap(const std::string filename,
const TriangleMesh& mesh,
const Triangle_mesh& mesh,
const Vertex_set& vertices,
const Faces_vector& faces,
const VertexUVMap uvmap,
@ -292,7 +304,7 @@ private:
typename VertexIndexMap>
void output_uvmap(const std::string filename,
const unsigned int iter,
const TriangleMesh& mesh,
const Triangle_mesh& mesh,
const Vertex_set& vertices,
const Faces_vector& faces,
const VertexUVMap uvmap,
@ -331,12 +343,12 @@ private:
// Private operations
private:
// Store the vertices and faces of the mesh in memory.
Error_code initialize_containers(const TriangleMesh& mesh,
Error_code initialize_containers(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
Vertex_set& vertices,
Faces_vector& faces) const
{
internal::Containers_filler<TriangleMesh> fc(mesh, vertices, &faces);
internal::Containers_filler<Triangle_mesh> fc(mesh, vertices, &faces);
Polygon_mesh_processing::connected_component(
face(opposite(bhd, mesh), mesh),
mesh,
@ -351,7 +363,7 @@ private:
// Initialize the UV values with a first parameterization of the input.
template <typename VertexUVMap,
typename VertexIndexMap>
Error_code compute_initial_uv_map(TriangleMesh& mesh,
Error_code compute_initial_uv_map(Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexUVMap uvmap,
VertexIndexMap vimap) const
@ -372,11 +384,11 @@ private:
// According to the paper, MVC is better for single border and LSCM is better
// when there are multiple borders
if(number_of_borders == 1) {
typedef Mean_value_coordinates_parameterizer_3<TriangleMesh> MVC_parameterizer;
typedef Mean_value_coordinates_parameterizer_3<Triangle_mesh> MVC_parameterizer;
MVC_parameterizer mvc_parameterizer;
status = mvc_parameterizer.parameterize(mesh, bhd, uvmap, vimap, vpmap);
} else {
typedef LSCM_parameterizer_3<TriangleMesh, Border_parameterizer> LSCM_parameterizer;
typedef LSCM_parameterizer_3<Triangle_mesh, Border_parameterizer> LSCM_parameterizer;
LSCM_parameterizer lscm_parameterizer;
status = lscm_parameterizer.parameterize(mesh, bhd, uvmap, vimap, vpmap);
}
@ -389,7 +401,7 @@ private:
template <typename VertexUVMap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code parameterize_border(const TriangleMesh& mesh,
Error_code parameterize_border(const Triangle_mesh& mesh,
const Vertex_set& vertices,
halfedge_descriptor bhd,
VertexIndexMap vimap,
@ -422,14 +434,14 @@ private:
}
// Compute the cotangent of the angle between the vectors ij and ik.
void compute_cotangent_angle(const TriangleMesh& mesh,
void compute_cotangent_angle(const Triangle_mesh& mesh,
halfedge_descriptor hd,
vertex_descriptor vi,
vertex_descriptor vj,
vertex_descriptor vk,
Cot_map ctmap) const
{
typedef typename boost::property_map<TriangleMesh,
typedef typename boost::property_map<Triangle_mesh,
boost::vertex_point_t>::const_type PPmap;
const PPmap ppmap = get(vertex_point, mesh);
@ -442,7 +454,7 @@ private:
}
// Fill the map 'ctmap' with the cotangents of the angles of the faces of 'mesh'.
Error_code compute_cotangent_angles(const TriangleMesh& mesh,
Error_code compute_cotangent_angles(const Triangle_mesh& mesh,
const Faces_vector& faces,
Cot_map ctmap) const
{
@ -468,8 +480,8 @@ private:
return OK;
}
// Compute w_ij = (i, j) coefficient of matrix A for j neighbor vertex of i.
NT compute_w_ij(const TriangleMesh& mesh,
// computes `w_ij`, the `(i,j)`-coefficient of matrix `A` for `j` neighbor vertex of `i`.
NT compute_w_ij(const Triangle_mesh& mesh,
halfedge_descriptor hd,
const Cot_map ctmap) const
{
@ -496,7 +508,7 @@ private:
// \pre Line i of A must contain only zeros.
template <typename VertexIndexMap>
Error_code fill_linear_system_matrix(Matrix& A,
const TriangleMesh& mesh,
const Triangle_mesh& mesh,
vertex_descriptor vertex,
const Cot_map ct_map,
VertexIndexMap vimap) const
@ -538,7 +550,7 @@ private:
// after (at least two) border vertices parameterization.
template <typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code initialize_matrix_A(const TriangleMesh& mesh,
Error_code initialize_matrix_A(const Triangle_mesh& mesh,
const Vertex_set& vertices,
const Cot_map ctmap,
VertexIndexMap vimap,
@ -695,7 +707,7 @@ private:
// Compute the root that gives the lowest face energy.
template <typename VertexUVMap>
std::size_t compute_root_with_lowest_energy(const TriangleMesh& mesh,
std::size_t compute_root_with_lowest_energy(const Triangle_mesh& mesh,
face_descriptor fd,
const Cot_map ctmap,
const Local_points& lp,
@ -722,7 +734,7 @@ private:
// Compute the root that gives the lowest face energy.
template <typename VertexUVMap>
std::size_t compute_root_with_lowest_energy(const TriangleMesh& mesh,
std::size_t compute_root_with_lowest_energy(const Triangle_mesh& mesh,
face_descriptor fd,
const Cot_map ctmap,
const Local_points& lp,
@ -748,7 +760,7 @@ private:
// Compute the optimal values of the linear transformation matrices Lt.
template <typename VertexUVMap>
Error_code compute_optimal_Lt_matrices(const TriangleMesh& mesh,
Error_code compute_optimal_Lt_matrices(const Triangle_mesh& mesh,
const Faces_vector& faces,
const Cot_map ctmap,
const Local_points& lp,
@ -874,13 +886,13 @@ private:
}
// Compute the local parameterization (2D) of a face and store it in memory.
void project_face(const TriangleMesh& mesh,
void project_face(const Triangle_mesh& mesh,
vertex_descriptor vi,
vertex_descriptor vj,
vertex_descriptor vk,
Local_points& lp) const
{
typedef typename boost::property_map<TriangleMesh,
typedef typename boost::property_map<Triangle_mesh,
boost::vertex_point_t>::const_type PPmap;
const PPmap ppmap = get(vertex_point, mesh);
@ -900,7 +912,7 @@ private:
// Utility for fill_linear_system_rhs():
// Compute the local isometric parameterization (2D) of the faces of the mesh.
Error_code compute_local_parameterization(const TriangleMesh& mesh,
Error_code compute_local_parameterization(const Triangle_mesh& mesh,
const Faces_vector& faces,
Local_points& lp,
Lp_map lpmap) const
@ -936,9 +948,9 @@ private:
return OK;
}
// Compute the coefficient b_ij = (i, j) of the right hand side vector B,
// Compute the coefficient b_ij = (i,j) of the right hand side vector B,
// for j neighbor vertex of i.
void compute_b_ij(const TriangleMesh& mesh,
void compute_b_ij(const Triangle_mesh& mesh,
halfedge_descriptor hd,
const Cot_map ctmap,
const Local_points& lp,
@ -1009,7 +1021,7 @@ private:
// \pre Vertex i musn't be already parameterized.
// \pre Lines i of Bu and Bv must be zero.
template <typename VertexIndexMap>
Error_code fill_linear_system_rhs(const TriangleMesh& mesh,
Error_code fill_linear_system_rhs(const Triangle_mesh& mesh,
vertex_descriptor vertex,
const Cot_map ctmap,
const Local_points& lp,
@ -1053,7 +1065,7 @@ private:
template <typename VertexUVMap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code compute_rhs(const TriangleMesh& mesh,
Error_code compute_rhs(const Triangle_mesh& mesh,
const Vertex_set& vertices,
const Cot_map ctmap,
const Local_points& lp,
@ -1091,7 +1103,7 @@ private:
template <typename VertexUVMap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code update_solution(const TriangleMesh& mesh,
Error_code update_solution(const Triangle_mesh& mesh,
const Vertex_set& vertices,
const Cot_map ctmap,
const Local_points& lp,
@ -1147,7 +1159,7 @@ private:
// Compute the current energy of a face, given a linear transformation matrix.
template <typename VertexUVMap>
NT compute_current_face_energy(const TriangleMesh& mesh,
NT compute_current_face_energy(const Triangle_mesh& mesh,
face_descriptor fd,
const Cot_map ctmap,
const Local_points& lp,
@ -1190,7 +1202,7 @@ private:
// Compute the current energy of a face.
template <typename VertexUVMap>
NT compute_current_face_energy(const TriangleMesh& mesh,
NT compute_current_face_energy(const Triangle_mesh& mesh,
face_descriptor fd,
const Cot_map ctmap,
const Local_points& lp,
@ -1207,7 +1219,7 @@ private:
// Compute the current energy of the parameterization.
template <typename VertexUVMap>
NT compute_current_energy(const TriangleMesh& mesh,
NT compute_current_energy(const Triangle_mesh& mesh,
const Faces_vector& faces,
const Cot_map ctmap,
const Local_points& lp,
@ -1232,14 +1244,14 @@ private:
// the (hopefully few) flips in the result.
template <typename VertexUVMap,
typename VertexIndexMap>
Error_code post_process(const TriangleMesh& mesh,
Error_code post_process(const Triangle_mesh& mesh,
const Vertex_set& vertices,
const Faces_vector& faces,
halfedge_descriptor bhd,
VertexUVMap uvmap,
const VertexIndexMap vimap) const
{
typedef MVC_post_processor_3<TriangleMesh> Post_processor;
typedef MVC_post_processor_3<Triangle_mesh> Post_processor;
Post_processor p;
Error_code status = p.parameterize(mesh, vertices, faces, bhd, uvmap, vimap);
@ -1255,28 +1267,28 @@ private:
// Public operations
public:
/// Check if the 3D -> 2D mapping is one-to-one.
template <typename VertexUVMap>
bool is_one_to_one_mapping(const TriangleMesh& mesh,
const Faces_vector& faces,
/// returns whether the 3D -> 2D mapping is one-to-one.
template <typename FaceRange, typename VertexUVMap>
bool is_one_to_one_mapping(const Triangle_mesh& mesh,
const FaceRange& faces,
const VertexUVMap uvmap) const
{
return internal::is_one_to_one_mapping(mesh, faces, uvmap);
}
/// Compute a mapping from a triangular 3D surface mesh to a piece of the 2D space.
/// computes a 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`)
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `Triangle_mesh` 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
/// `boost::graph_traits<Triangle_mesh>::%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
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// a Boolean as value type.
///
/// \param mesh a triangulated surface.
@ -1291,12 +1303,16 @@ public:
template <typename VertexUVMap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code parameterize(TriangleMesh& mesh,
Error_code parameterize(Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexUVMap uvmap,
VertexIndexMap vimap,
VertexParameterizedMap vpmap)
{
CGAL_precondition(is_valid_polygon_mesh(mesh));
CGAL_precondition(is_triangle_mesh(mesh));
CGAL_precondition(bhd != boost::graph_traits<Triangle_mesh>::null_halfedge() && is_border(bhd, mesh));
Error_code status = OK;
// vertices and faces containers

View File

@ -21,6 +21,7 @@
#include <CGAL/Surface_mesh_parameterization/Fixed_border_parameterizer_3.h>
#include <CGAL/Default.h>
#include <CGAL/iterator.h>
#if defined(CGAL_EIGEN3_ENABLED)
#include <CGAL/Eigen_solver_traits.h>
@ -43,8 +44,8 @@ namespace Surface_mesh_parameterization {
/// This class is a strategy called by the main
/// parameterization algorithm `Fixed_border_parameterizer_3::parameterize()` and it:
/// - provides the template parameters `BorderParameterizer_` and `SolverTraits_`.
/// - implements compute_w_ij() to compute `w_ij = (i,j)`, coefficient of
/// the matrix A for `j` neighbor vertex of `i`, based on Tutte Barycentric
/// - implements compute_w_ij() to compute `w_ij`, the `(i,j)`-coefficient of
/// the matrix `A` for `j` neighbor vertex of `i`, based on Tutte Barycentric
/// Mapping method.
///
/// \cgalModels `Parameterizer_3`
@ -108,24 +109,32 @@ public:
#endif
>::type Solver_traits;
#else
/// Border parameterizer type
typedef Border_parameterizer_ Border_parameterizer;
typedef SolverTraits_ SolverTraits;
/// Solver traits type
typedef SolverTraits_ Solver_traits;
#endif
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef TriangleMesh_ TriangleMesh;
/// Mesh vertex type
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
/// Mesh halfedge type
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
private:
// Superclass
typedef Fixed_border_parameterizer_3<TriangleMesh_,
typedef Fixed_border_parameterizer_3<Triangle_mesh,
Border_parameterizer,
Solver_traits> Base;
// Private types
private:
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
typedef CGAL::Vertex_around_target_circulator<TriangleMesh> vertex_around_target_circulator;
typedef typename Base::NT NT;
// Solver traits subtypes:
@ -139,24 +148,24 @@ public:
///< %Object that maps the surface's border to 2D space.
Solver_traits sparse_la = Solver_traits())
///< Traits object to access a sparse linear system.
: Fixed_border_parameterizer_3<TriangleMesh,
: Fixed_border_parameterizer_3<Triangle_mesh,
Border_parameterizer,
Solver_traits>(border_param, sparse_la)
{ }
// Default copy constructor and operator =() are fine
/// Check if the 3D -> 2D mapping is one-to-one.
/// returns whether the 3D -> 2D mapping is one-to-one.
template <typename VertexUVMap,
typename Faces_Container>
bool is_one_to_one_mapping(const TriangleMesh& mesh,
bool is_one_to_one_mapping(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
const VertexUVMap uvmap) const
{
/// Theorem: A one-to-one mapping is guaranteed if all w_ij coefficients
/// are > 0 (for j vertex neighbor of i) and if the surface
/// Theorem: A one-to-one mapping is guaranteed if all `w_ij` coefficients
/// are > 0 (for `j` vertex neighbor of `i`) and if the surface
/// border is mapped onto a 2D convex polygon.
/// Here, all w_ij coefficients = 1 (for j vertex neighbor of i), thus a
/// Here, all `w_ij` coefficients are equal to `1` (for `j` vertex neighbor of `i`), thus a
/// valid embedding is guaranteed if the surface border is mapped
/// onto a 2D convex polygon.
return (Base::get_border_parameterizer().is_border_convex() ||
@ -165,13 +174,12 @@ public:
// Protected operations
protected:
/// Compute w_ij = (i,j), coefficient of matrix A for j neighbor vertex of i.
virtual NT compute_w_ij(const TriangleMesh& /* mesh */,
/// computes `w_ij`, the coefficient of matrix `A` for `j` neighbor vertex of `i`.
virtual NT compute_w_ij(const Triangle_mesh& /* mesh */,
vertex_descriptor /* main_vertex_v_i */,
vertex_around_target_circulator /* neighbor_vertex_v_j */ ) const
Vertex_around_target_circulator<Triangle_mesh> /* neighbor_vertex_v_j */ ) const
{
/// In the Tutte Barycentric Mapping algorithm, we have w_ij = 1,
/// for j neighbor vertex of i.
/// In the Tutte Barycentric Mapping algorithm, we have `w_ij = 1`, for `j` neighbor vertex of `i`.
return 1.;
}
};

View File

@ -62,29 +62,33 @@ class Circular_border_parameterizer_3
{
// Public types
public:
typedef TriangleMesh_ TriangleMesh;
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
/// Mesh vertex type
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
/// Mesh halfedge type
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
// Protected types
protected:
typedef typename internal::Kernel_traits<TriangleMesh_>::PPM PPM;
typedef typename internal::Kernel_traits<TriangleMesh_>::Kernel Kernel;
typedef typename internal::Kernel_traits<Triangle_mesh>::PPM PPM;
typedef typename internal::Kernel_traits<Triangle_mesh>::Kernel Kernel;
typedef typename Kernel::FT NT;
typedef typename Kernel::Point_2 Point_2;
typedef typename Kernel::Vector_3 Vector_3;
// Protected operations
protected:
virtual NT compute_edge_length(const TriangleMesh& mesh,
virtual NT compute_edge_length(const Triangle_mesh& mesh,
vertex_descriptor source,
vertex_descriptor target) const = 0;
// Private operations
private:
// Compute the total length of the border
NT compute_border_length(const TriangleMesh& mesh,
NT compute_border_length(const Triangle_mesh& mesh,
halfedge_descriptor bhd) const
{
NT len = 0.0;
@ -96,21 +100,21 @@ private:
// Public operations
public:
/// Assign to the mesh's border vertices a 2D position (i.e.\ a (u,v) pair)
/// assigns to the mesh's border vertices a 2D position (i.e.\ a `(u,v)` pair)
/// on the circle. Mark them as <i>parameterized</i>.
///
/// The distribution of vertices over the circle depends on the function
/// `compute_edge_length()`.
///
/// \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`)
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `Triangle_mesh` 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
/// `boost::graph_traits<Triangle_mesh>::%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
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// a Boolean as value type.
///
/// \param mesh a triangulated surface.
@ -124,7 +128,7 @@ public:
template <typename VertexUVmap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code parameterize(const TriangleMesh& mesh,
Error_code parameterize(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexUVmap uvmap,
VertexIndexMap /* vimap */,
@ -159,7 +163,7 @@ public:
return OK;
}
/// Indicate if border's shape is convex.
/// indicates if border's shape is convex.
bool is_border_convex() const { return true; }
virtual ~Circular_border_parameterizer_3() { }
@ -192,20 +196,18 @@ class Circular_border_uniform_parameterizer_3
// Public types
public:
// We have to repeat the types exported by superclass
/// @cond SKIP_IN_MANUAL
typedef TriangleMesh_ TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
/// @endcond
typedef TriangleMesh_ Triangle_mesh;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
// Private types
private:
typedef Circular_border_parameterizer_3<TriangleMesh> Base;
typedef Circular_border_parameterizer_3<Triangle_mesh> Base;
typedef typename Base::NT NT;
// Protected operations
protected:
/// Compute the length of an edge.
virtual NT compute_edge_length(const TriangleMesh& /* mesh */,
/// computes the length of an edge.
virtual NT compute_edge_length(const Triangle_mesh& /* mesh */,
vertex_descriptor /* source */,
vertex_descriptor /* target */) const
{
@ -243,24 +245,22 @@ class Circular_border_arc_length_parameterizer_3
// Public types
public:
// We have to repeat the types exported by superclass
/// @cond SKIP_IN_MANUAL
typedef TriangleMesh_ TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
/// @endcond
typedef TriangleMesh_ Triangle_mesh;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
// Private types
private:
typedef Circular_border_parameterizer_3<TriangleMesh> Base;
typedef Circular_border_parameterizer_3<Triangle_mesh> Base;
typedef typename Base::PPM PPM;
typedef typename Base::NT NT;
typedef typename Base::Vector_3 Vector_3;
typedef typename Base::PPM PPM;
typedef typename Base::NT NT;
typedef typename Base::Vector_3 Vector_3;
// Protected operations
protected:
/// Compute the length of an edge.
virtual NT compute_edge_length(const TriangleMesh& mesh,
/// computes the length of an edge.
virtual NT compute_edge_length(const Triangle_mesh& mesh,
vertex_descriptor source,
vertex_descriptor target) const
{

View File

@ -48,8 +48,8 @@ namespace Surface_mesh_parameterization {
/// This class is a strategy called by the main
/// parameterization algorithm `Fixed_border_parameterizer_3::parameterize()` and it:
/// - provides the template parameters `BorderParameterizer_` and `SolverTraits_`.
/// - implements `compute_w_ij()` to compute w_ij = (i, j), coefficient of the matrix A
/// for j neighbor vertex of i, based on Discrete Authalic Parameterization algorithm.
/// - implements `compute_w_ij()` to compute `w_ij`, the `(i,j)`-coefficient of the matrix `A`
/// for `j` neighbor vertex of `i`, based on Discrete Authalic Parameterization algorithm.
///
/// \cgalModels `Parameterizer_3`
///
@ -75,6 +75,8 @@ namespace Surface_mesh_parameterization {
/// \endcode
///
/// \sa `CGAL::Surface_mesh_parameterization::Fixed_border_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::ARAP_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::Iterative_authalic_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
///
template < class TriangleMesh_,
class BorderParameterizer_ = Default,
@ -112,23 +114,31 @@ public:
#endif
>::type Solver_traits;
#else
/// Border parameterizer type
typedef Border_parameterizer_ Border_parameterizer;
/// Solver traits type
typedef SolverTraits_ Solver_traits;
#endif
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef TriangleMesh_ TriangleMesh;
/// Mesh vertex type
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
// Private types
private:
// Superclass
typedef Fixed_border_parameterizer_3<TriangleMesh,
typedef Fixed_border_parameterizer_3<Triangle_mesh,
Border_parameterizer,
Solver_traits> Base;
// Private types
private:
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef CGAL::Vertex_around_target_circulator<TriangleMesh> vertex_around_target_circulator;
typedef CGAL::Vertex_around_target_circulator<Triangle_mesh> vertex_around_target_circulator;
// Traits subtypes:
typedef typename Base::PPM PPM;
@ -148,7 +158,7 @@ public:
///< %Object that maps the surface's border to 2D space.
Solver_traits sparse_la = Solver_traits())
///< Traits object to access a sparse linear system.
: Fixed_border_parameterizer_3<TriangleMesh,
: Fixed_border_parameterizer_3<Triangle_mesh,
Border_parameterizer,
Solver_traits>(border_param, sparse_la)
{ }
@ -157,14 +167,14 @@ public:
// Protected operations
protected:
/// Compute w_ij = (i, j), coefficient of matrix A for j neighbor vertex of i.
/// computes `w_ij`, the (i,j), coefficient of matrix `A` for `j` neighbor vertex of `i`.
///
/// \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,
virtual NT compute_w_ij(const Triangle_mesh& mesh,
vertex_descriptor main_vertex_v_i,
vertex_around_target_circulator neighbor_vertex_v_j) const
Vertex_around_target_circulator<Triangle_mesh> neighbor_vertex_v_j) const
{
const PPM ppmap = get(vertex_point, mesh);

View File

@ -48,8 +48,8 @@ namespace Surface_mesh_parameterization {
/// This class is a strategy called by the main
/// parameterization algorithm `Fixed_border_parameterizer_3::parameterize()` and it:
/// - provides the template parameters `BorderParameterizer_` and `SolverTraits_`.
/// - implements `compute_w_ij()` to compute w_ij = (i, j), coefficient of matrix A
/// for j neighbor vertex of i, based on Discrete Conformal Map method.
/// - implements `compute_w_ij()` to compute `w_ij`, the `(i,j)`-coefficient of matrix `A`,
/// for `j` neighbor vertex of `i`, based on Discrete Conformal Map method.
///
/// \cgalModels `Parameterizer_3`
///
@ -112,23 +112,29 @@ public:
#endif
>::type Solver_traits;
#else
/// Border parameterizer type
typedef Border_parameterizer_ Border_parameterizer;
/// Solver traits type
typedef SolverTraits_ Solver_traits;
#endif
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef TriangleMesh_ TriangleMesh;
// Private types
private:
// Superclass
typedef Fixed_border_parameterizer_3<TriangleMesh,
typedef Fixed_border_parameterizer_3<Triangle_mesh,
Border_parameterizer,
Solver_traits> Base;
// Private types
private:
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef CGAL::Vertex_around_target_circulator<TriangleMesh> vertex_around_target_circulator;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
typedef CGAL::Vertex_around_target_circulator<Triangle_mesh> vertex_around_target_circulator;
// Traits subtypes:
typedef typename Base::Kernel Kernel;
@ -148,7 +154,7 @@ public:
///< %Object that maps the surface's border to 2D space.
Solver_traits sparse_la = Solver_traits())
///< Traits object to access a sparse linear system.
: Fixed_border_parameterizer_3<TriangleMesh,
: Fixed_border_parameterizer_3<Triangle_mesh,
Border_parameterizer,
Solver_traits>(border_param, sparse_la)
{ }
@ -157,14 +163,14 @@ public:
// Protected operations
protected:
/// Compute w_ij = (i,j) coefficient of matrix A for j neighbor vertex of i.
/// computes `w_ij`, the `(i,j)`-coefficient of matrix `A`, for `j` neighbor vertex of `i`.
///
/// \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,
virtual NT compute_w_ij(const Triangle_mesh& mesh,
vertex_descriptor main_vertex_v_i,
vertex_around_target_circulator neighbor_vertex_v_j) const // its target is main_vertex_v_i
Vertex_around_target_circulator<Triangle_mesh> neighbor_vertex_v_j) const // its target is main_vertex_v_i
{
const PPM ppmap = get(vertex_point, mesh);

View File

@ -58,8 +58,8 @@ namespace Surface_mesh_parameterization {
/// 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.
/// - They implement `compute_w_ij()` to compute `w_ij`, the `(i,j)`-coefficient of matrix `A`
/// for `j` neighbor vertex of `i`.
///
// @todo `Fixed_border_parameterizer_3` should remove border vertices
// from the linear systems in order to have a symmetric positive definite
@ -88,7 +88,6 @@ namespace Surface_mesh_parameterization {
/// Eigen::IncompleteLUT< double > > >
/// \endcode
///
/// \sa `CGAL::Surface_mesh_parameterization::ARAP_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::Barycentric_mapping_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::Discrete_authalic_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::Discrete_conformal_map_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
@ -121,34 +120,44 @@ public:
#endif
>::type Solver_traits;
#else
/// Border parameterizer type
typedef Border_parameterizer_ Border_parameterizer;
/// Solver traits type
typedef SolverTraits_ Solver_traits;
#endif
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef TriangleMesh_ TriangleMesh;
/// Mesh vertex type
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
/// Mesh halfedge type
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
/// Solver vector type
typedef typename Solver_traits::Vector Vector;
/// Solver matrix type
typedef typename Solver_traits::Matrix Matrix;
// Private types
private:
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
typedef CGAL::Vertex_around_target_circulator<TriangleMesh> vertex_around_target_circulator;
typedef CGAL::Vertex_around_face_circulator<TriangleMesh> vertex_around_face_circulator;
typedef CGAL::Vertex_around_target_circulator<Triangle_mesh> vertex_around_target_circulator;
// Protected types
protected:
// Traits subtypes:
typedef typename internal::Kernel_traits<TriangleMesh>::Kernel Kernel;
typedef typename internal::Kernel_traits<TriangleMesh>::PPM PPM;
typedef typename internal::Kernel_traits<Triangle_mesh>::Kernel Kernel;
typedef typename internal::Kernel_traits<Triangle_mesh>::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;
// Solver traits subtypes:
typedef typename Solver_traits::Vector Vector;
typedef typename Solver_traits::Matrix Matrix;
// Public operations
public:
/// Constructor
@ -164,20 +173,20 @@ public:
// Default copy constructor and operator =() are fine
/// Compute a one-to-one mapping from a triangular 3D surface mesh
/// computes 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.
/// 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`)
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `Triangle_mesh` 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
/// `boost::graph_traits<Triangle_mesh>::%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
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// a Boolean as value type.
///
/// \param mesh a triangulated surface.
@ -193,18 +202,22 @@ public:
template <typename VertexUVmap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code parameterize(TriangleMesh& mesh,
Error_code parameterize(Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexUVmap uvmap,
VertexIndexMap vimap,
VertexParameterizedMap vpmap)
{
CGAL_precondition(is_valid_polygon_mesh(mesh));
CGAL_precondition(is_triangle_mesh(mesh));
CGAL_precondition(bhd != boost::graph_traits<Triangle_mesh>::null_halfedge() && is_border(bhd, mesh));
Error_code status = OK;
typedef boost::unordered_set<vertex_descriptor> Vertex_set;
Vertex_set vertices;
internal::Containers_filler<TriangleMesh> fc(mesh, vertices);
internal::Containers_filler<Triangle_mesh> fc(mesh, vertices);
Polygon_mesh_processing::connected_component(
face(opposite(bhd, mesh), mesh),
mesh,
@ -294,16 +307,16 @@ public:
// Protected operations
protected:
/// Initialize A, Bu and Bv after border parameterization.
/// initializes `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`)
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `Triangle_mesh` 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
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// a unique integer as value type.
///
/// \param A the matrix in both linear system
@ -315,11 +328,11 @@ protected:
/// \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 `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,
const Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexUVmap uvmap,
VertexIndexMap vimap) const
@ -337,16 +350,15 @@ protected:
}
}
/// Compute w_ij, coefficient of matrix A for j neighbor vertex of i.
/// computes `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,
virtual NT compute_w_ij(const Triangle_mesh& mesh,
vertex_descriptor main_vertex_v_i,
vertex_around_target_circulator neighbor_vertex_v_j) const
= 0;
Vertex_around_target_circulator<Triangle_mesh> neighbor_vertex_v_j) const = 0;
/// Compute the line i of matrix A for i inner vertex:
/// - call compute_w_ij() to compute the A coefficient w_ij for each neighbor v_j.
@ -361,7 +373,7 @@ protected:
Error_code setup_inner_vertex_relations(Matrix& A,
Vector&,
Vector&,
const TriangleMesh& mesh,
const Triangle_mesh& mesh,
vertex_descriptor vertex,
VertexIndexMap vimap) const
{

View File

@ -75,7 +75,7 @@ namespace Surface_mesh_parameterization {
/// 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::SparseMatrix<double> > >
/// CGAL::Eigen_solver_traits<Eigen::SimplicialLDLT< Eigen::SparseMatrix<double> > >
/// \endcode
/// Otherwise, it uses CGAL's wrapping function to the OpenNL library:
/// \code
@ -100,12 +100,7 @@ public:
#if defined(CGAL_EIGEN3_ENABLED)
// WARNING: at the moment, the choice of SolverTraits_ is completely
// ignored (see LeastSquaresSolver typedef) and `OpenNL::LinearSolver<SolverTraits_>`
// is used anyway. If Eigen solver traits were to be used again, there is a bug
// in the line below to be first fixed:
// `Eigen_sparse_symmetric_matrix<double>::EigenType` is a NON SYMMETRIC
// Eigen sparse matrix, and thus SolverTraits_::Matrix will be a NON SYMMETRIC matrix
// and the whole symmetry aspect will be completely ignored.
// @fixme
// is always used...
CGAL::Eigen_solver_traits<
Eigen::SimplicialLDLT<Eigen_sparse_symmetric_matrix<double>::EigenType> >
#else
@ -113,24 +108,29 @@ public:
#endif
>::type Solver_traits;
#else
/// The border parameterizer
typedef Border_parameterizer_ Border_parameterizer;
/// Solver traits type
typedef SolverTraits_ Solver_traits;
#endif
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef TriangleMesh_ TriangleMesh;
/// Mesh halfedge type
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
// 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 typename boost::graph_traits<TriangleMesh>::vertex_iterator vertex_iterator;
typedef typename boost::graph_traits<TriangleMesh>::face_iterator face_iterator;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Triangle_mesh>::face_descriptor face_descriptor;
// Traits subtypes:
typedef typename internal::Kernel_traits<TriangleMesh>::PPM PPM;
typedef typename internal::Kernel_traits<TriangleMesh>::Kernel Kernel;
typedef typename internal::Kernel_traits<Triangle_mesh>::PPM PPM;
typedef typename internal::Kernel_traits<Triangle_mesh>::Kernel Kernel;
typedef typename Kernel::FT NT;
typedef typename Kernel::Point_2 Point_2;
typedef typename Kernel::Point_3 Point_3;
@ -155,29 +155,29 @@ public:
// Default copy constructor and operator =() are fine
/// Check if the 3D -> 2D mapping is one-to-one.
/// returns whether the 3D -> 2D mapping is one-to-one.
template <typename VertexUVMap>
bool is_one_to_one_mapping(const TriangleMesh& mesh,
bool is_one_to_one_mapping(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
const VertexUVMap uvmap) const
{
return internal::is_one_to_one_mapping(mesh, bhd, uvmap);
}
/// Compute a one-to-one mapping from a triangular 3D surface mesh
/// computes 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.
/// 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`)
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `Triangle_mesh` 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
/// `boost::graph_traits<Triangle_mesh>::%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
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// a Boolean as value type.
///
/// \param mesh a triangulated surface.
@ -190,17 +190,21 @@ public:
/// \pre The vertices must be indexed (`vimap` must be initialized).
///
template <typename VertexUVmap, typename VertexIndexMap, typename VertexParameterizedMap>
Error_code parameterize(TriangleMesh& mesh,
Error_code parameterize(Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexUVmap uvmap,
VertexIndexMap vimap,
VertexParameterizedMap vpmap)
{
CGAL_precondition(is_valid_polygon_mesh(mesh));
CGAL_precondition(is_triangle_mesh(mesh));
CGAL_precondition(bhd != boost::graph_traits<Triangle_mesh>::null_halfedge() && is_border(bhd, mesh));
// Fill containers
boost::unordered_set<vertex_descriptor> ccvertices;
std::vector<face_descriptor> ccfaces;
internal::Containers_filler<TriangleMesh> fc(mesh, ccvertices, &ccfaces);
internal::Containers_filler<Triangle_mesh> fc(mesh, ccvertices, &ccfaces);
Polygon_mesh_processing::connected_component(
face(opposite(bhd, mesh), mesh),
mesh,
@ -340,7 +344,7 @@ private:
// in presence of degenerate triangles
template <typename VertexIndexMap >
Error_code setup_triangle_relations(LeastSquaresSolver& solver,
const TriangleMesh& mesh,
const Triangle_mesh& mesh,
face_descriptor facet,
VertexIndexMap vimap) const
{

View File

@ -14,6 +14,7 @@
#include <CGAL/license/Surface_mesh_parameterization.h>
#include <CGAL/Surface_mesh_parameterization/internal/Bool_property_map.h>
#include <CGAL/Surface_mesh_parameterization/internal/Containers_filler.h>
#include <CGAL/Surface_mesh_parameterization/internal/kernel_traits.h>
@ -93,29 +94,33 @@ public:
#endif
>::type Solver_traits;
#else
/// Solver traits type
typedef SolverTraits_ Solver_traits;
#endif
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef TriangleMesh_ TriangleMesh;
// Private types
private:
// This class
typedef MVC_post_processor_3<TriangleMesh, Solver_traits> Self;
typedef MVC_post_processor_3<Triangle_mesh, Solver_traits> Self;
// 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 typename boost::graph_traits<TriangleMesh>::face_iterator face_iterator;
typedef typename boost::graph_traits<TriangleMesh>::vertex_iterator vertex_iterator;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<Triangle_mesh>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<Triangle_mesh>::face_iterator face_iterator;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_iterator vertex_iterator;
typedef boost::unordered_set<vertex_descriptor> Vertex_set;
typedef std::vector<face_descriptor> Faces_vector;
// Traits subtypes:
typedef typename internal::Kernel_traits<TriangleMesh>::Kernel Kernel;
typedef typename internal::Kernel_traits<Triangle_mesh>::Kernel Kernel;
typedef typename Kernel::FT NT;
typedef typename Kernel::Point_2 Point_2;
typedef typename Kernel::Vector_2 Vector_2;
@ -189,12 +194,12 @@ private:
// Private operations
private:
// Store the vertices and faces of the mesh in memory.
void initialize_containers(const TriangleMesh& mesh,
void initialize_containers(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
Vertex_set& vertices,
Faces_vector& faces) const
{
internal::Containers_filler<TriangleMesh> fc(mesh, vertices, &faces);
internal::Containers_filler<Triangle_mesh> fc(mesh, vertices, &faces);
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(bhd, mesh), mesh),
mesh,
@ -203,7 +208,7 @@ private:
// Checks whether the polygon's border is simple.
template <typename VertexUVMap>
bool is_polygon_simple(const TriangleMesh& mesh,
bool is_polygon_simple(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
const VertexUVMap uvmap) const
{
@ -273,7 +278,7 @@ private:
// Triangulate the convex hull of the border of the parameterization.
template <typename CT,
typename VertexUVMap>
Error_code triangulate_convex_hull(const TriangleMesh& mesh,
Error_code triangulate_convex_hull(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
const VertexUVMap uvmap,
CT& ct) const
@ -506,7 +511,7 @@ private:
template <typename VertexUVMap,
typename VertexIndexMap,
typename VertexParameterizedMap>
void fill_linear_system_matrix_mvc_from_mesh_halfedge(const TriangleMesh& mesh,
void fill_linear_system_matrix_mvc_from_mesh_halfedge(const Triangle_mesh& mesh,
halfedge_descriptor hd,
const VertexUVMap uvmap,
const VertexIndexMap vimap,
@ -539,7 +544,7 @@ private:
template <typename VertexUVMap,
typename VertexIndexMap,
typename VertexParameterizedMap>
void fill_linear_system_matrix_mvc_from_mesh_face(const TriangleMesh& mesh,
void fill_linear_system_matrix_mvc_from_mesh_face(const Triangle_mesh& mesh,
face_descriptor fd,
const VertexUVMap uvmap,
const VertexIndexMap vimap,
@ -562,7 +567,7 @@ private:
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code compute_mvc_matrix(const CT& ct,
const TriangleMesh& mesh,
const Triangle_mesh& mesh,
const Faces_vector& faces,
const VertexUVMap uvmap,
const VertexIndexMap vimap,
@ -660,7 +665,7 @@ private:
typename VertexUVMap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code parameterize_convex_hull_with_MVC(const TriangleMesh& mesh,
Error_code parameterize_convex_hull_with_MVC(const Triangle_mesh& mesh,
const Vertex_set& vertices,
const Faces_vector& faces,
const CT& ct,
@ -707,7 +712,7 @@ private:
public:
template <typename VertexUVMap,
typename VertexIndexMap>
Error_code parameterize(const TriangleMesh& mesh,
Error_code parameterize(const Triangle_mesh& mesh,
const Vertex_set& vertices,
const Faces_vector& faces,
halfedge_descriptor bhd,
@ -741,15 +746,15 @@ public:
return OK;
}
/// Compute a one-to-one mapping from a triangular 2D surface mesh
/// computes a one-to-one mapping from a triangular 2D surface mesh
/// that is not necessarily embedded to a piece of the 2D space.
///
/// \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`)
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `Triangle_mesh` 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
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// a unique integer as value type.
///
/// \param mesh a triangulated surface.
@ -759,7 +764,7 @@ public:
///
template <typename VertexUVMap,
typename VertexIndexMap>
Error_code parameterize(const TriangleMesh& mesh,
Error_code parameterize(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexUVMap uvmap,
const VertexIndexMap vimap)

View File

@ -45,8 +45,8 @@ namespace Surface_mesh_parameterization {
/// `Fixed_border_parameterizer_3::parameterize()`.
/// - It provides default `BorderParameterizer_` and `SolverTraits_` template
/// parameters.
/// - It implements `compute_w_ij()` to compute w_ij = (i, j) coefficient of matrix A
/// for j neighbor vertex of i based on Floater Mean Value Coordinates parameterization.
/// - It implements `compute_w_ij()` to compute `w_ij`, the `(i,j)` coefficient of matrix `A`
/// for `j` neighbor vertex of `i` based on Floater Mean Value Coordinates parameterization.
/// - It implements an optimized version of `is_one_to_one_mapping()`.
///
/// \cgalModels `Parameterizer_3`
@ -110,39 +110,48 @@ public:
#endif
>::type Solver_traits;
#else
/// The border parameterizer
typedef Border_parameterizer_ Border_parameterizer;
/// Solver traits type
typedef SolverTraits_ Solver_traits;
#endif
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef TriangleMesh_ TriangleMesh;
/// Mesh vertex type
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
/// Mesh halfedge type
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
// Private types
private:
// Superclass
typedef Fixed_border_parameterizer_3<TriangleMesh,
Border_parameterizer,
Solver_traits> Base;
typedef Fixed_border_parameterizer_3<Triangle_mesh,
Border_parameterizer,
Solver_traits> Base;
// 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 typename boost::graph_traits<Triangle_mesh>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::vertex_iterator vertex_iterator;
typedef typename boost::graph_traits<TriangleMesh>::face_iterator face_iterator;
typedef CGAL::Vertex_around_target_circulator<TriangleMesh> vertex_around_target_circulator;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_iterator vertex_iterator;
typedef typename boost::graph_traits<Triangle_mesh>::face_iterator face_iterator;
typedef CGAL::Vertex_around_target_circulator<Triangle_mesh> vertex_around_target_circulator;
// Mesh_TriangleMesh_3 subtypes:
typedef typename Base::PPM PPM;
typedef typename Base::Kernel Kernel;
typedef typename Base::NT NT;
typedef typename Base::Point_3 Point_3;
typedef typename Base::Vector_3 Vector_3;
typedef typename Base::PPM PPM;
typedef typename Base::Kernel Kernel;
typedef typename Base::NT NT;
typedef typename Base::Point_3 Point_3;
typedef typename Base::Vector_3 Vector_3;
// Solver traits subtypes:
typedef typename Solver_traits::Vector Vector;
typedef typename Solver_traits::Matrix Matrix;
typedef typename Solver_traits::Vector Vector;
typedef typename Solver_traits::Matrix Matrix;
// Public operations
public:
@ -151,16 +160,16 @@ public:
///< Object that maps the surface's border to 2D space.
Solver_traits sparse_la = Solver_traits())
///< Traits object to access a sparse linear system.
: Fixed_border_parameterizer_3<TriangleMesh,
: Fixed_border_parameterizer_3<Triangle_mesh,
Border_parameterizer,
Solver_traits>(border_param, sparse_la)
{ }
// Default copy constructor and operator =() are fine
/// Check if the 3D -> 2D mapping is one-to-one.
/// returns whether the 3D -> 2D mapping is one-to-one.
template <typename VertexUVMap>
bool is_one_to_one_mapping(const TriangleMesh& mesh,
bool is_one_to_one_mapping(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
const VertexUVMap uvmap) const
{
@ -176,14 +185,14 @@ public:
// Protected operations
protected:
/// Compute w_ij = (i, j) coefficient of matrix A for j neighbor vertex of i.
/// computes `w_ij`, the `(i, j)`-coefficient of matrix A for j neighbor vertex of i.
///
/// \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,
virtual NT compute_w_ij(const Triangle_mesh& mesh,
vertex_descriptor main_vertex_v_i,
vertex_around_target_circulator neighbor_vertex_v_j) const
Vertex_around_target_circulator<Triangle_mesh> neighbor_vertex_v_j) const
{
const PPM ppmap = get(vertex_point, mesh);

View File

@ -67,7 +67,7 @@ namespace Surface_mesh_parameterization {
/// \ingroup PkgSurfaceMeshParameterizationOrbifoldHelperFunctions
///
/// Read a serie of cones from an input stream. Cones are passed as an
/// reads a serie of cones from an input stream. Cones are passed as an
/// integer value that is the index of a vertex handle in the mesh tm`, using
/// the vertex index property map `vpmap` for correspondency.
///
@ -192,7 +192,7 @@ Error_code read_cones(const TriangleMesh& tm, const char* filename, ConeOutputIt
/// \ingroup PkgSurfaceMeshParameterizationOrbifoldHelperFunctions
///
/// Locate the cones on the seam mesh (that is, find the corresponding seam mesh
/// locates the cones on the seam mesh (that is, find the corresponding seam mesh
/// `vertex_descriptor`) and mark them with a tag to indicate whether the cone is a
/// simple cone or a duplicated cone (see \link PkgSurfaceMeshParameterizationEnums Cone_type \endlink).
///
@ -202,7 +202,7 @@ Error_code read_cones(const TriangleMesh& tm, const char* filename, ConeOutputIt
/// but is passed here as a template parameter for convenience, to avoid
/// having to pass the multiple template parameters of the class `CGAL::Seam_mesh`.
/// \tparam ConeInputBidirectionalIterator must be a model of `BidirectionalIterator`
/// with value type `boost::graph_traits<SeamMesh::TriangleMesh>::%vertex_descriptor`.
/// with value type `boost::graph_traits<SeamMesh::Triangle_mesh>::%vertex_descriptor`.
/// \tparam ConeMap must be a model of `AssociativeContainer`
/// with `boost::graph_traits<SeamMesh>::%vertex_descriptor` as key type and
/// \link PkgSurfaceMeshParameterizationEnums Cone_type \endlink as value type.
@ -216,13 +216,13 @@ bool locate_cones(const SeamMesh& mesh,
ConeInputBidirectionalIterator first, ConeInputBidirectionalIterator beyond,
ConeMap& cones)
{
typedef typename SeamMesh::TriangleMesh TriangleMesh;
typedef typename SeamMesh::Triangle_mesh Triangle_mesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor TM_vertex_descriptor;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor TM_vertex_descriptor;
typedef typename boost::graph_traits<SeamMesh>::vertex_descriptor vertex_descriptor;
// property map to go from TM_vertex_descriptor to Point_3
typedef typename internal::Kernel_traits<TriangleMesh>::PPM PM_PPM;
typedef typename internal::Kernel_traits<Triangle_mesh>::PPM PM_PPM;
const PM_PPM pm_ppmap = get(boost::vertex_point, mesh.mesh());
// property map to go from vertex_descriptor to Point_3
@ -264,9 +264,9 @@ bool locate_unordered_cones(const SeamMesh& mesh,
CGAL_precondition(cones.empty());
CGAL_precondition(std::distance(first, beyond) == 3 || std::distance(first, beyond) == 4);
typedef typename SeamMesh::TriangleMesh TriangleMesh;
typedef typename SeamMesh::Triangle_mesh Triangle_mesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor TM_vertex_descriptor;
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor TM_vertex_descriptor;
typedef typename boost::graph_traits<SeamMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<SeamMesh>::halfedge_descriptor halfedge_descriptor;
@ -282,7 +282,7 @@ bool locate_unordered_cones(const SeamMesh& mesh,
CGAL_assertion(vertex_on_seam != vertex_descriptor());
// property map to go from TM_vertex_descriptor to Point_3
typedef typename internal::Kernel_traits<TriangleMesh>::PPM PM_PPM;
typedef typename internal::Kernel_traits<Triangle_mesh>::PPM PM_PPM;
const PM_PPM pm_ppmap = get(boost::vertex_point, mesh.mesh());
// property map to go from vertex_descriptor to Point_3
@ -358,7 +358,8 @@ bool locate_unordered_cones(const SeamMesh& mesh,
/// shows how to select cones on the input mesh and automatically construct
/// the seams and the cones on the `Seam_mesh`.
///
/// \cgalModels `Parameterizer_3`
/// \attention The global function `CGAL::Surface_mesh_parameterization::parameterize()` cannot be used
/// with this parameterizer. Users should use this class's member function `parameterize()` instead.
///
/// \tparam SeamMesh must be a `Seam_mesh`, with underlying mesh any model of `FaceListGraph` and `HalfedgeListGraph`.
///
@ -405,12 +406,15 @@ public:
#endif
>::type Solver_traits;
#else
/// Solver traits type
typedef SolverTraits_ Solver_traits;
#endif
/// Mesh halfedge type
typedef typename boost::graph_traits<SeamMesh>::halfedge_descriptor halfedge_descriptor;
private:
typedef typename boost::graph_traits<SeamMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<SeamMesh>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<SeamMesh>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<SeamMesh>::vertex_iterator vertex_iterator;
@ -888,7 +892,7 @@ private:
}
public:
/// Compute a one-to-one mapping from a triangular 3D surface mesh
/// computes 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.
@ -936,6 +940,8 @@ public:
VertexUVMap uvmap,
VertexIndexMap vimap) const
{
CGAL_precondition(is_valid_polygon_mesh(mesh));
CGAL_precondition(is_triangle_mesh(mesh));
CGAL_USE(bhd);
Error_code status;

View File

@ -50,6 +50,10 @@ namespace Surface_mesh_parameterization {
/// The user can provide four vertices on the border of the mesh, which will be
/// mapped to the four corners of the square.
///
/// \attention The square border parameterizer may create degenerate faces in the parameterization:
/// if an input border vertex has valence `1` and if it is mapped to the same edge of the square
/// as its two adjacent (border) vertices, for example.
///
/// Implementation note:
/// To simplify the implementation, the border parameterizer knows only the
/// `TriangleMesh` class and does not know the parameterization algorithm
@ -67,18 +71,24 @@ class Square_border_parameterizer_3
{
// Public types
public:
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef TriangleMesh_ TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
/// Mesh vertex type
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
typedef Halfedge_around_face_iterator<TriangleMesh> halfedge_around_face_iterator;
/// Mesh halfedge type
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
// Protected types
protected:
typedef Halfedge_around_face_iterator<Triangle_mesh> halfedge_around_face_iterator;
// Traits subtypes:
typedef typename internal::Kernel_traits<TriangleMesh>::PPM PPM;
typedef typename internal::Kernel_traits<TriangleMesh>::Kernel Kernel;
typedef typename internal::Kernel_traits<Triangle_mesh>::PPM PPM;
typedef typename internal::Kernel_traits<Triangle_mesh>::Kernel Kernel;
typedef typename Kernel::FT NT;
typedef typename Kernel::Point_2 Point_2;
typedef typename Kernel::Vector_3 Vector_3;
@ -92,14 +102,14 @@ private:
// Protected operations
protected:
virtual double compute_edge_length(const TriangleMesh& mesh,
virtual double compute_edge_length(const Triangle_mesh& mesh,
vertex_descriptor source,
vertex_descriptor target) const = 0;
// Private operations
private:
// Compute the total length of the border.
double compute_border_length(const TriangleMesh& mesh,
double compute_border_length(const Triangle_mesh& mesh,
halfedge_descriptor bhd) const
{
double len = 0.0;
@ -111,7 +121,7 @@ private:
// Utility method for parameterize().
// Compute the mesh iterator whose offset is closest to 'value'.
halfedge_around_face_iterator closest_iterator(const TriangleMesh& mesh,
halfedge_around_face_iterator closest_iterator(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
Offset_map& offset,
double value) const
@ -138,7 +148,7 @@ private:
// Set the corners by splitting the border of the mesh in four
// approximately equal segments.
template<typename VertexParameterizedMap>
halfedge_descriptor compute_offsets_without_given_vertices(const TriangleMesh& mesh,
halfedge_descriptor compute_offsets_without_given_vertices(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexParameterizedMap vpmap,
Offset_map& offset) const
@ -185,7 +195,7 @@ private:
// the mesh. The vertices between two given vertices vi and vj are
// sent to the same side of the square.
template<typename VertexParameterizedMap>
halfedge_descriptor compute_offsets(const TriangleMesh& mesh,
halfedge_descriptor compute_offsets(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexParameterizedMap vpmap,
Offset_map& offset)
@ -245,18 +255,18 @@ private:
public:
// Default constructor, copy constructor and operator =() are fine
/// Assign to the vertices of the border of the mesh a 2D position
/// assigns to the vertices of the border of the mesh a 2D position
/// (i.e.\ a (u,v) pair) on the border's shape. Mark them as <i>parameterized</i>.
///
/// \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`)
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `Triangle_mesh` 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
/// `boost::graph_traits<Triangle_mesh>::%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
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// a Boolean as value type.
///
/// \param mesh a triangulated surface.
@ -270,7 +280,7 @@ public:
template<typename VertexUVMap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code parameterize(const TriangleMesh& mesh,
Error_code parameterize(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexUVMap uvmap,
VertexIndexMap /* vimap */,
@ -344,7 +354,7 @@ public:
return OK;
}
/// Indicate if the border's shape is convex.
/// indicates if the border's shape is convex.
bool is_border_convex() const { return true; }
public:
@ -382,6 +392,10 @@ public:
/// algorithm. This class implements only `compute_edge_length()` to compute a
/// segment's length.
///
/// \attention The square border parameterizer may create degenerate faces in the parameterization:
/// if an input border vertex has valence `1` and if it is mapped to the same edge of the square
/// as its two adjacent (border) vertices, for example.
///
/// \cgalModels `Parameterizer_3`
///
/// \sa `CGAL::Surface_mesh_parameterization::Square_border_parameterizer_3<TriangleMesh>`
@ -396,15 +410,14 @@ class Square_border_uniform_parameterizer_3
// Public types
public:
// We have to repeat the types exported by superclass
/// @cond SKIP_IN_MANUAL
typedef TriangleMesh_ TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
/// @endcond
typedef TriangleMesh_ TriangleMesh;
typedef TriangleMesh_ Triangle_mesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
// Private types
private:
typedef Square_border_parameterizer_3<TriangleMesh_> Base;
typedef typename Base::NT NT;
typedef Square_border_parameterizer_3<TriangleMesh_> Base;
typedef typename Base::NT NT;
public:
virtual ~Square_border_uniform_parameterizer_3() { }
@ -425,8 +438,8 @@ public:
// Protected operations
protected:
/// Compute the length of an edge.
virtual NT compute_edge_length(const TriangleMesh& /* mesh */,
/// computes the length of an edge.
virtual NT compute_edge_length(const Triangle_mesh& /* mesh */,
vertex_descriptor /* source */,
vertex_descriptor /* target */) const
{
@ -449,6 +462,10 @@ protected:
/// algorithm. This class implements only `compute_edge_length()` to compute a
/// segment's length.
///
/// \attention The square border parameterizer may create degenerate faces in the parameterization:
/// if an input border vertex has valence `1` and if it is mapped to the same edge of the square
/// as its two adjacent (border) vertices, for example.
///
/// \tparam TriangleMesh_ must be a model of `FaceGraph`.
///
/// \cgalModels `Parameterizer_3`
@ -462,14 +479,13 @@ class Square_border_arc_length_parameterizer_3
{
// Public types
public:
/// @cond SKIP_IN_MANUAL
typedef TriangleMesh_ TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
/// @endcond
typedef TriangleMesh_ TriangleMesh;
typedef TriangleMesh_ Triangle_mesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
// Private types
private:
typedef Square_border_parameterizer_3<TriangleMesh_> Base;
typedef Square_border_parameterizer_3<Triangle_mesh> Base;
typedef typename Base::PPM PPM;
typedef typename Base::NT NT;
typedef typename Base::Vector_3 Vector_3;
@ -494,7 +510,7 @@ public:
// Protected operations
protected:
/// Compute the length of an edge.
virtual NT compute_edge_length(const TriangleMesh& mesh,
virtual NT compute_edge_length(const Triangle_mesh& mesh,
vertex_descriptor source,
vertex_descriptor target) const
{

View File

@ -56,16 +56,22 @@ class Two_vertices_parameterizer_3
{
// Public types
public:
/// Triangle mesh type
typedef TriangleMesh_ Triangle_mesh;
typedef TriangleMesh_ TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
/// Mesh vertex type
typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor vertex_descriptor;
/// Mesh halfedge type
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
// Private types
private:
// Traits subtypes:
typedef typename internal::Kernel_traits<TriangleMesh>::PPM PPM;
typedef typename internal::Kernel_traits<TriangleMesh>::Kernel Kernel;
typedef typename internal::Kernel_traits<Triangle_mesh>::PPM PPM;
typedef typename internal::Kernel_traits<Triangle_mesh>::Kernel Kernel;
typedef typename Kernel::FT NT;
typedef typename Kernel::Point_2 Point_2;
typedef typename Kernel::Point_3 Point_3;
@ -92,7 +98,7 @@ public:
typename VertexUVmap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code parameterize(const TriangleMesh& mesh,
Error_code parameterize(const Triangle_mesh& mesh,
const VertexContainer& vertices,
VertexUVmap uvmap,
VertexIndexMap /* vimap */,
@ -267,17 +273,17 @@ public:
return OK;
}
/// Map two extreme vertices of the 3D mesh and mark them as <i>parameterized</i>.
/// maps two extreme vertices of the 3D mesh and mark them as <i>parameterized</i>.
///
/// \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`)
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `Triangle_mesh` 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
/// `boost::graph_traits<Triangle_mesh>::%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
/// `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
/// a Boolean as value type.
///
/// \param mesh a triangulated surface.
@ -292,7 +298,7 @@ public:
template <typename VertexUVmap,
typename VertexIndexMap,
typename VertexParameterizedMap>
Error_code parameterize(const TriangleMesh& mesh,
Error_code parameterize(const Triangle_mesh& mesh,
halfedge_descriptor bhd,
VertexUVmap uvmap,
VertexIndexMap vimap,
@ -300,7 +306,7 @@ public:
{
// Fill containers
boost::unordered_set<vertex_descriptor> vertices;
internal::Containers_filler<TriangleMesh> fc(mesh, vertices);
internal::Containers_filler<Triangle_mesh> fc(mesh, vertices);
Polygon_mesh_processing::connected_component(
face(opposite(bhd, mesh), mesh),
mesh,
@ -309,7 +315,7 @@ public:
return parameterize(mesh, vertices, uvmap, vimap, vpmap);
}
/// Indicate if the border's shape is convex.
/// indicates if the border's shape is convex.
/// Meaningless for free border parameterization algorithms.
bool is_border_convex() const { return false; }
};

View File

@ -14,11 +14,13 @@
#include <CGAL/license/Surface_mesh_parameterization.h>
#include <CGAL/disable_warnings.h>
#include <CGAL/boost/graph/internal/initialized_index_maps_helpers.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include "boost/tuple/tuple.hpp"
#include <boost/tuple/tuple.hpp>
#include <boost/unordered_set.hpp>
#include <boost/graph/graph_traits.hpp>
#include <vector>
namespace CGAL {
@ -56,7 +58,7 @@ public:
: mesh(mesh_), vertices(vertices_), faces(nullptr)
{ }
void operator()(face_descriptor fd)
void operator()(const face_descriptor fd)
{
halfedge_descriptor hd = halfedge(fd, mesh);
for(vertex_descriptor vd : vertices_around_face(hd, mesh)) {
@ -78,10 +80,10 @@ struct Index_map_filler
: mesh(mesh), map(&map), index(0)
{ }
void operator()(const face_descriptor& fd)
void operator()(const face_descriptor fd)
{
for(vertex_descriptor vd :
vertices_around_face(halfedge(fd, mesh), mesh)) {
for(vertex_descriptor vd : vertices_around_face(halfedge(fd, mesh), mesh))
{
typename Map::iterator it;
bool new_element;
boost::tie(it,new_element) = map->insert(std::make_pair(vd,1));
@ -96,12 +98,47 @@ struct Index_map_filler
int index;
};
template <typename TriangleMesh, typename VertexIndexMap>
void fill_index_map_of_cc(const typename boost::graph_traits<TriangleMesh>::halfedge_descriptor bhd,
const TriangleMesh& mesh,
VertexIndexMap vimap)
{
namespace PMP = CGAL::Polygon_mesh_processing;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::face_descriptor face_descriptor;
std::vector<face_descriptor> CC_faces;
// 'reserve' might cause a huge amount of memory to be used for a tiny CC,
// but if this is a problem as a user, one could simply parameterize a Face_filtered_graph instead.
CC_faces.reserve(num_faces(mesh));
PMP::connected_component(face(opposite(bhd, mesh), mesh), mesh, std::back_inserter(CC_faces));
// If all vertices are involved, avoid walking all the faces
if(CC_faces.size() == faces(mesh).size())
{
BGL::internal::Index_map_initializer<VertexIndexMap, TriangleMesh> id_initializer;
id_initializer(CGAL::internal_np::vertex_index, vimap, mesh);
}
else
{
for(vertex_descriptor v : vertices(mesh))
put(vimap, v, -1);
int index = 0;
for(face_descriptor f : CC_faces)
for(vertex_descriptor v : vertices_around_face(halfedge(f, mesh), mesh))
if(get(vimap, v) == -1)
put(vimap, v, index++);
}
}
} // namespace internal
} // namespace Surface_mesh_parameterization
} // namespace CGAL
#include <CGAL/enable_warnings.h>
#endif // CGAL_SURFACE_MESH_PARAMETERIZATION_INTERNAL_CONTAINERS_FILLER_H

View File

@ -232,7 +232,7 @@ public:
{ }
};
/// Check if the 3D -> 2D mapping is one-to-one.
/// returns whether the 3D -> 2D mapping is one-to-one.
/// This function is stronger than "has_flips()" because the parameterized
/// surface can loop over itself without creating any flips.
template <typename TriangleMesh,

View File

@ -0,0 +1,118 @@
// Copyright (c) 2020 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Mael Rouxel-Labbé
#ifndef CGAL_SURFACE_MESH_PARAMETERIZATION_INTERNAL_DISTORTION_H
#define CGAL_SURFACE_MESH_PARAMETERIZATION_INTERNAL_DISTORTION_H
#include <CGAL/license/Surface_mesh_parameterization.h>
#include <CGAL/boost/graph/iterator.h>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/boost/graph/Named_function_parameters.h>
#include <CGAL/circulator.h>
#include <CGAL/Kernel/global_functions.h>
#include <CGAL/Kernel_traits.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <vector>
namespace CGAL {
namespace Surface_mesh_parameterization {
#ifndef DOXYGEN_RUNNING
// Measure L2 stretch
template <typename VertexRange, typename FaceRange, typename TriangleMesh, typename VertexUVmap>
double compute_L2_stretch(const VertexRange& vertex_range,
const FaceRange& face_range,
const TriangleMesh& tmesh,
const VertexUVmap uvmap)
{
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::face_descriptor face_descriptor;
typedef typename boost::property_map<TriangleMesh, boost::vertex_point_t>::const_type VertexPointMap;
typedef typename boost::property_traits<VertexPointMap>::value_type Point_3;
typedef typename CGAL::Kernel_traits<Point_3>::Kernel Kernel;
typedef typename Kernel::Point_2 Point_2;
typedef CGAL::dynamic_face_property_t<double> Face_double_tag;
typedef typename boost::property_map<TriangleMesh, Face_double_tag>::const_type Face_double_map;
Face_double_map area_2D = get(Face_double_tag(), tmesh);
Face_double_map area_3D = get(Face_double_tag(), tmesh);
// iterate fpr all inner vertices and for each vertex
std::vector<double> area_dist;
double A_3D = 0.;
double A_2D = 0.;
for(face_descriptor f : face_range)
{
std::vector<Point_2> uv_points;
for(vertex_descriptor v : vertices_around_face(halfedge(f, tmesh), tmesh))
uv_points.push_back(get(uvmap, v));
const double a_2D = abs(CGAL::area(get(uvmap, target(halfedge(f, tmesh), tmesh)),
get(uvmap, source(halfedge(f, tmesh), tmesh)),
get(uvmap, target(next(halfedge(f, tmesh), tmesh), tmesh))));
const double a_3D = Polygon_mesh_processing::face_area(f, tmesh);
put(area_2D, f, a_2D);
put(area_3D, f, a_3D);
A_2D += a_2D;
A_3D += a_3D;
}
for(vertex_descriptor v : vertex_range)
{
// inner vertices only
if(CGAL::is_border(v, tmesh))
continue;
double a_2D = 0.;
double a_3D = 0.;
// find the area of all the adjacent faces to this vertex
CGAL::Face_around_target_circulator<TriangleMesh> f_j(halfedge(v, tmesh), tmesh), end = f_j;
CGAL_For_all(f_j, end)
{
if(*f_j == boost::graph_traits<TriangleMesh>::null_face())
continue;
a_2D += get(area_2D, *f_j);
a_3D += get(area_3D, *f_j);
}
a_2D /= A_2D;
a_3D /= A_3D;
area_dist.push_back(square((a_3D/a_2D) - 1.));
}
return sqrt(std::accumulate(area_dist.begin(), area_dist.end(), 0.));
}
template <typename TriangleMesh, typename VertexUVmap>
double compute_L2_stretch(const TriangleMesh& tmesh,
const VertexUVmap uvmap)
{
return compute_L2_stretch(vertices(tmesh), faces(tmesh), tmesh, uvmap);
}
#endif // DOXYGEN_RUNNING
} // namespace Surface_mesh_parameterization
} // namespace CGAL
#endif // CGAL_SURFACE_MESH_PARAMETERIZATION_INTERNAL_DISTORTION_H

View File

@ -103,7 +103,7 @@ public:
/// \ingroup PkgSurfaceMeshParameterizationOrbifoldHelperFunctions
///
/// Compute the shortest path between `source` and `target` over `mesh`, using
/// computes the shortest path between `source` and `target` over `mesh`, using
/// <a href="https://www.boost.org/doc/libs/release/libs/graph/doc/dijkstra_shortest_paths.html">
/// boost::dijkstra_shortest_paths()</a>.
///

View File

@ -15,19 +15,10 @@
#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 parameterize.h
@ -37,7 +28,7 @@ namespace Surface_mesh_parameterization {
/// \ingroup PkgSurfaceMeshParameterizationMainFunction
///
/// Compute a one-to-one mapping from a 3D triangle surface `mesh` to a
/// computes 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.
@ -57,7 +48,7 @@ namespace Surface_mesh_parameterization {
/// \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 uvmap an instanciation of the class `VertexUVmap`.
///
/// \pre `mesh` must be a triangular mesh.
/// \pre The mesh border must be mapped onto a convex polygon
@ -68,28 +59,26 @@ template <class TriangleMesh, class Parameterizer, class HD, class VertexUVmap>
Error_code parameterize(TriangleMesh& mesh,
Parameterizer parameterizer,
HD bhd,
VertexUVmap uvm)
VertexUVmap uvmap)
{
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
CGAL_precondition(is_valid_polygon_mesh(mesh));
CGAL_precondition(bhd != boost::graph_traits<TriangleMesh>::null_halfedge() && is_border(bhd, mesh));
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);
typedef CGAL::dynamic_vertex_property_t<int> Vertex_int_tag;
typedef typename boost::property_map<TriangleMesh, Vertex_int_tag>::type Vertex_int_map;
Vertex_int_map vimap = get(Vertex_int_tag(), mesh);
internal::fill_index_map_of_cc(bhd, mesh, vimap);
boost::unordered_set<vertex_descriptor> vs;
internal::Bool_property_map<boost::unordered_set<vertex_descriptor> > vpm(vs);
typedef CGAL::dynamic_vertex_property_t<bool> Vertex_bool_tag;
typedef typename boost::property_map<TriangleMesh, Vertex_bool_tag>::type Vertex_bool_map;
Vertex_bool_map vpmap = get(Vertex_bool_tag(), mesh);
return parameterizer.parameterize(mesh, bhd, uvm, vipm, vpm);
return parameterizer.parameterize(mesh, bhd, uvmap, vimap, vpmap);
}
/// \ingroup PkgSurfaceMeshParameterizationMainFunction
///
/// Compute a one-to-one mapping from a 3D triangle surface `mesh` to a
/// computes a one-to-one mapping from a 3D triangle surface `mesh` to a
/// 2D circle, using Floater Mean Value Coordinates algorithm.
/// A one-to-one mapping is guaranteed.
///
@ -106,7 +95,7 @@ Error_code parameterize(TriangleMesh& mesh,
///
/// \param mesh a triangulated surface.
/// \param bhd a halfedge descriptor on the boundary of `mesh`.
/// \param uvm an instanciation of the class `VertexUVmap`.
/// \param uvmap an instanciation of the class `VertexUVmap`.
///
/// \pre `mesh` must be a triangular mesh.
/// \pre The vertices must be indexed (vimap must be initialized).
@ -114,51 +103,14 @@ Error_code parameterize(TriangleMesh& mesh,
template <class TriangleMesh, class HD, class VertexUVmap>
Error_code parameterize(TriangleMesh& mesh,
HD bhd,
VertexUVmap uvm)
VertexUVmap uvmap)
{
Mean_value_coordinates_parameterizer_3<TriangleMesh> parameterizer;
return parameterize(mesh, parameterizer, bhd, uvm);
}
template <class TM, class SEM, class SVM>
class Seam_mesh;
template <class TM, class SEM, class SVM, class Parameterizer, class HD, class VertexUVmap>
Error_code parameterize(Seam_mesh<TM, SEM, SVM>& mesh,
Parameterizer parameterizer,
HD bhd,
VertexUVmap uvm)
{
typedef typename boost::graph_traits<Seam_mesh<TM, SEM, SVM> >::vertex_descriptor vertex_descriptor;
boost::unordered_set<vertex_descriptor> vs;
internal::Bool_property_map<boost::unordered_set<vertex_descriptor> > vpm(vs);
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<Seam_mesh<TM, SEM, SVM>,
Indices>(mesh, indices)));
boost::associative_property_map<Indices> vipm(indices);
return parameterizer.parameterize(mesh, bhd, uvm, vipm, vpm);
}
template <class TM, class SEM, class SVM, class HD, class VertexUVmap>
Error_code parameterize(Seam_mesh<TM, SEM, SVM>& mesh,
HD bhd,
VertexUVmap uvm)
{
Mean_value_coordinates_parameterizer_3<Seam_mesh<TM, SEM, SVM> > parameterizer;
return parameterize(mesh, parameterizer, bhd, uvm);
return parameterize(mesh, parameterizer, bhd, uvmap);
}
} // namespace Surface_mesh_parameterization
} // namespace CGAL
#include <CGAL/enable_warnings.h>
#endif // CGAL_PARAMETERIZE_H

View File

@ -22,12 +22,14 @@
#include <CGAL/Surface_mesh_parameterization/Barycentric_mapping_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Discrete_authalic_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Discrete_conformal_map_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Iterative_authalic_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/LSCM_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Mean_value_coordinates_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/MVC_post_processor_3.h>
#include <CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/parameterize.h>
#include <CGAL/Surface_mesh_parameterization/measure_distortion.h>
#include <CGAL/Surface_mesh_parameterization/Circular_border_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Square_border_parameterizer_3.h>

View File

@ -10,6 +10,7 @@
#include <CGAL/surface_mesh_parameterization.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <boost/functional/hash.hpp>
@ -17,6 +18,7 @@
#include <fstream>
namespace SMP = CGAL::Surface_mesh_parameterization;
namespace PMP = CGAL::Polygon_mesh_processing;
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2;
@ -29,6 +31,7 @@ typedef Kernel::Point_3 Point_3;
#define DCM_PM_SEAM_MESH
#define DAC_SM_SEAM_MESH
#define ORBIFOLD_SM_MESH
#define ITERATIVE_SURF_MESH
// POLYHEDRON_MESH
typedef CGAL::Polyhedron_3<Kernel> PMesh;
@ -94,7 +97,7 @@ int main(int, char**)
return EXIT_FAILURE;
}
PM_halfedge_descriptor hd = CGAL::Polygon_mesh_processing::longest_border(pm).first;
PM_halfedge_descriptor hd = PMP::longest_border(pm).first;
CGAL::Unique_hash_map<PM_vertex_descriptor, Point_2,
boost::hash<PM_vertex_descriptor> > uvhm;
@ -113,7 +116,7 @@ int main(int, char**)
std::cout << "Parameterized with MVC (POLY)!" << std::endl;
}
}
#endif
#endif // MVC_POLYHEDRON_MESH
// ***************************************************************************
// ARAP WITH POLYHEDRON_MESH
@ -131,7 +134,7 @@ int main(int, char**)
return EXIT_FAILURE;
}
PM_halfedge_descriptor hd = CGAL::Polygon_mesh_processing::longest_border(pm).first;
PM_halfedge_descriptor hd = PMP::longest_border(pm).first;
// UV map
CGAL::Unique_hash_map<PM_vertex_descriptor, Point_2,
@ -141,25 +144,21 @@ int main(int, char**)
boost::hash<PM_vertex_descriptor> > > uvpm(uvhm);
// Indices map
typedef boost::unordered_map<PM_vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(hd, pm), pm),
pm,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<PMesh, Indices>(pm, indices)));
boost::associative_property_map<Indices> vipm(indices);
typedef CGAL::dynamic_vertex_property_t<int> Vertex_int_tag;
typedef typename boost::property_map<PMesh, Vertex_int_tag>::type Vertex_int_map;
Vertex_int_map vipm = get(Vertex_int_tag(), pm);
CGAL::Surface_mesh_parameterization::internal::fill_index_map_of_cc(hd, pm, vipm);
// Vertex parameterized map
boost::unordered_set<PM_vertex_descriptor> vs;
SMP::internal::Bool_property_map<boost::unordered_set<PM_vertex_descriptor> > vpm(vs);
typedef CGAL::dynamic_vertex_property_t<bool> Vertex_bool_tag;
typedef typename boost::property_map<PMesh, Vertex_bool_tag>::type Vertex_bool_map;
Vertex_bool_map vpm = get(Vertex_bool_tag(), pm);
// Parameterizer
SMP::ARAP_parameterizer_3<PMesh> parameterizer;
SMP::Error_code status = parameterizer.parameterize(pm, hd, uvpm, vipm, vpm);
if(status != SMP::OK) {
SMP::Error_code status_bis = SMP::parameterize(pm, parameterizer, hd, uvpm);
if(status != SMP::OK || status_bis != SMP::OK) {
std::cout << "Encountered a problem: " << status << std::endl;
return EXIT_FAILURE;
}
@ -167,7 +166,7 @@ int main(int, char**)
std::cout << "Parameterized with ARAP (POLY)!" << std::endl;
}
}
#endif
#endif // ARAP_POLYHEDRON_MESH
// ***************************************************************************
// Barycentric mapping
@ -185,7 +184,7 @@ int main(int, char**)
return EXIT_FAILURE;
}
SM_halfedge_descriptor hd = CGAL::Polygon_mesh_processing::longest_border(sm).first;
SM_halfedge_descriptor hd = PMP::longest_border(sm).first;
assert(hd != SM_halfedge_descriptor());
// UV map
@ -195,11 +194,9 @@ int main(int, char**)
// Indices map
typedef boost::unordered_map<SM_vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(hd, sm), sm),
sm,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<SMesh, Indices>(sm, indices)));
PMP::connected_component(face(opposite(hd, sm), sm), sm,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<SMesh, Indices>(sm, indices)));
boost::associative_property_map<Indices> vipm(indices);
// Vertex parameterized map
@ -210,8 +207,9 @@ int main(int, char**)
SMP::Barycentric_mapping_parameterizer_3<SMesh> parameterizer;
SMP::Error_code status = parameterizer.parameterize(sm, hd, uvpm, vipm, vpm);
SMP::Error_code status_bis = SMP::parameterize(sm, parameterizer, hd, uvpm);
if(status != SMP::OK) {
if(status != SMP::OK || status_bis != SMP::OK) {
std::cout << "Encountered a problem: " << status << std::endl;
return EXIT_FAILURE;
}
@ -219,7 +217,7 @@ int main(int, char**)
std::cout << "Parameterized with Barycentric (SM)!" << std::endl;
}
}
#endif
#endif // BARY_SURF_MESH
// ***************************************************************************
// ARAP WITH SURF_MESH
@ -238,8 +236,7 @@ int main(int, char**)
}
// halfedge on the longest border
SM_halfedge_descriptor hd =
CGAL::Polygon_mesh_processing::longest_border(sm).first;
SM_halfedge_descriptor hd = PMP::longest_border(sm).first;
CGAL::Unique_hash_map<SM_vertex_descriptor, Point_2,
boost::hash<SM_vertex_descriptor> > uvhm;
@ -251,11 +248,9 @@ int main(int, char**)
// Indices map
typedef boost::unordered_map<SM_vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(hd, sm), sm),
sm,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<SMesh, Indices>(sm, indices)));
PMP::connected_component(face(opposite(hd, sm), sm), sm,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<SMesh, Indices>(sm, indices)));
boost::associative_property_map<Indices> vipm(indices);
// Parameterized bool pmap
@ -266,7 +261,9 @@ int main(int, char**)
SMP::ARAP_parameterizer_3<SMesh> parameterizer;
SMP::Error_code status = parameterizer.parameterize(sm, hd, uv_pm, vipm, vpm);
if(status != SMP::OK) {
SMP::Error_code status_bis = SMP::parameterize(sm, parameterizer, hd, uv_pm);
if(status != SMP::OK || status_bis != SMP::OK) {
std::cout << "Encountered a problem: " << status << std::endl;
return EXIT_FAILURE;
}
@ -274,7 +271,7 @@ int main(int, char**)
std::cout << "Parameterized with ARAP (SM)!" << std::endl;
}
}
#endif
#endif // ARAP_SURF_MESH
#ifdef DCM_PM_SEAM_MESH
{
@ -307,16 +304,14 @@ int main(int, char**)
PM_UV_pmap uv_pm(uv_hm);
// a halfedge on the (possibly virtual) border
PM_SE_halfedge_descriptor hd = CGAL::Polygon_mesh_processing::longest_border(mesh).first;
PM_SE_halfedge_descriptor hd = PMP::longest_border(mesh).first;
// Indices
typedef boost::unordered_map<PM_SE_vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(hd, mesh), mesh),
mesh,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<PM_Seam_mesh, Indices>(mesh, indices)));
PMP::connected_component(face(opposite(hd, mesh), mesh), mesh,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<PM_Seam_mesh, Indices>(mesh, indices)));
boost::associative_property_map<Indices> vipm(indices);
// Parameterized
@ -326,8 +321,9 @@ int main(int, char**)
SMP::Discrete_conformal_map_parameterizer_3<PM_Seam_mesh> parameterizer;
SMP::Error_code status = parameterizer.parameterize(mesh, hd, uv_pm, vipm, vpm);
SMP::Error_code status_bis = SMP::parameterize(mesh, parameterizer, hd, uv_pm);
if(status != SMP::OK) {
if(status != SMP::OK || status_bis != SMP::OK) {
std::cout << "Encountered a problem: " << status << std::endl;
return EXIT_FAILURE;
}
@ -335,7 +331,7 @@ int main(int, char**)
std::cout << "Parameterized with DCM (SEAM POLY)!" << std::endl;
}
}
#endif
#endif // DCM_PM_SEAM_MESH
// ***************************************************************************
// DAC WITH SEAM_MESH (SM)
@ -373,16 +369,14 @@ int main(int, char**)
Point_2>("h:uv").first;
// a halfedge on the (possibly virtual) border
SM_SE_halfedge_descriptor hd = CGAL::Polygon_mesh_processing::longest_border(mesh).first;
SM_SE_halfedge_descriptor hd = PMP::longest_border(mesh).first;
// Indices
typedef boost::unordered_map<SM_SE_vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(hd, mesh), mesh),
mesh,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<SM_Seam_mesh, Indices>(mesh, indices)));
PMP::connected_component(face(opposite(hd, mesh), mesh), mesh,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<SM_Seam_mesh, Indices>(mesh, indices)));
boost::associative_property_map<Indices> vipm(indices);
// Parameterized
@ -392,7 +386,9 @@ int main(int, char**)
SMP::Discrete_authalic_parameterizer_3<SM_Seam_mesh> parameterizer;
SMP::Error_code status = parameterizer.parameterize(mesh, hd, uv_pm, vipm, vpm);
if(status != SMP::OK) {
SMP::Error_code status_bis = SMP::parameterize(mesh, parameterizer, hd, uv_pm);
if(status != SMP::OK || status_bis != SMP::OK) {
std::cout << "Encountered a problem: " << status << std::endl;
return EXIT_FAILURE;
}
@ -400,7 +396,7 @@ int main(int, char**)
std::cout << "Parameterized with DAC (SEAM SM)!" << std::endl;
}
}
#endif
#endif // DAC_SM_SEAM_MESH
#ifdef ORBIFOLD_SM_MESH
{
@ -464,10 +460,10 @@ int main(int, char**)
// a halfedge on the (possibly virtual) border
// only used in output (will also be used to handle multiple connected components in the future)
SM_SE_halfedge_descriptor hd = CGAL::Polygon_mesh_processing::longest_border(mesh,
CGAL::Polygon_mesh_processing::parameters::all_default()).first;
SM_SE_halfedge_descriptor hd = PMP::longest_border(mesh, PMP::parameters::all_default()).first;
SMP::Error_code status = parameterizer.parameterize(mesh, hd, cmap, uvmap, vimap);
if(status != SMP::OK) {
std::cout << "Encountered a problem: " << status << std::endl;
return EXIT_FAILURE;
@ -476,7 +472,60 @@ int main(int, char**)
std::cout << "Parameterized with Orbifold (SEAM SM)!" << std::endl;
}
}
#endif
#endif // ORBIFOLD_SM_MESH
// ***************************************************************************
// ITERATIVE AUTHALIC WITH SURFACE_MESH
// ***************************************************************************
#ifdef ITERATIVE_SURF_MESH
{
std::cout << " ----------- ITERATIVE AUTHALIC SURFACE MESH ----------- " << std::endl;
std::ifstream in("data/oni.off");
SMesh sm;
in >> sm;
if(!in || num_vertices(sm) == 0) {
std::cerr << "Problem loading the input data" << std::endl;
return EXIT_FAILURE;
}
SM_halfedge_descriptor hd = PMP::longest_border(sm).first;
assert(hd != SM_halfedge_descriptor());
// UV map
typedef SMesh::Property_map<SM_vertex_descriptor, Point_2> UV_pmap;
UV_pmap uvpm = sm.add_property_map<SM_vertex_descriptor, Point_2>("h:uv").first;
// Indices map
typedef boost::unordered_map<SM_vertex_descriptor, int> Indices;
Indices indices;
PMP::connected_component(face(opposite(hd, sm), sm), sm,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<SMesh, Indices>(sm, indices)));
boost::associative_property_map<Indices> vipm(indices);
// Vertex parameterized map
boost::unordered_set<SM_vertex_descriptor> vs;
SMP::internal::Bool_property_map<boost::unordered_set<SM_vertex_descriptor> > vpm(vs);
// Parameterizer
SMP::Iterative_authalic_parameterizer_3<SMesh> parameterizer;
double error = 0;
unsigned int iterations = 15;
SMP::Error_code status = parameterizer.parameterize(sm, hd, uvpm, vipm, vpm, iterations, error);
SMP::Error_code status_bis = parameterizer.parameterize(sm, uvpm, 10);
if(status != SMP::OK || status_bis != SMP::OK) {
std::cout << "Encountered a problem: " << status << std::endl;
return EXIT_FAILURE;
}
else {
std::cout << "Parameterized with Barycentric (SM)!" << std::endl;
}
}
#endif // DAC_SM_SEAM_MESH
std::cout << "Done!" << std::endl;