Merge pull request #2772 from MaelRL/SMP-Clean_internal_from_example-GF

SMP: Documented some functions used in the Orbifold Tutte parameterizer

# Conflicts:
#	Surface_mesh_parameterization/examples/Surface_mesh_parameterization/orbifold.cpp
#	Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/orbifold_shortest_path.h
This commit is contained in:
Laurent Rineau 2018-02-19 14:27:59 +01:00
commit b0c6e37c1d
17 changed files with 494 additions and 380 deletions

View File

@ -968,12 +968,8 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio
Parameterizer parameterizer(orb);
// mark cones in the seam mesh
typedef boost::unordered_map<s_vertex_descriptor, SMP::Cone_type> Cones;
Cones cmap;
if(!SMP::internal::locate_unordered_cones<Seam_mesh,
boost::unordered_set<T_vertex_descriptor>,
Cones>(sMesh, unordered_cones, cmap))
boost::unordered_map<s_vertex_descriptor, SMP::Cone_type> cmap;
if(!SMP::locate_unordered_cones(sMesh, unordered_cones.begin(), unordered_cones.end(), cmap))
return;
// vimap and uvmap

View File

@ -112,20 +112,32 @@ The package performs the next checks:
- the input mesh is a surface with one connected component.
*/
/// \defgroup PkgSurfaceParameterizationMainFunction Main Function
/// \ingroup PkgSurfaceParameterization
/*!
\defgroup PkgSurfaceParameterizationMainFunction Main Functions
\ingroup PkgSurfaceParameterization
/// \defgroup PkgSurfaceParameterizationEnums Enums
/// \ingroup PkgSurfaceParameterization
The central functions, main entry point of the package.
*/
/// \defgroup PkgSurfaceParameterizationConcepts Concepts
/// \ingroup PkgSurfaceParameterization
/*!
\defgroup PkgSurfaceParameterizationEnums Enums
\ingroup PkgSurfaceParameterization
The enum classes defined and used in this package.
*/
/*!
\defgroup PkgSurfaceParameterizationConcepts Concepts
\ingroup PkgSurfaceParameterization
The concepts of this package.
*/
/*!
\defgroup PkgSurfaceParameterizationMethods Surface Parameterization Methods
\ingroup PkgSurfaceParameterization
This \cgal package implements several parameterization methods:
This \cgal package implements several parameterization methods:
- Fixed border:
- Tutte Barycentric Mapping \cgalCite{t-hdg-63}.
@ -162,5 +174,10 @@ This package implements common border parameterization methods:
vertices).
*/
/*!
\defgroup PkgSurfaceParameterizationOrbifoldHelperFunctions Orbifold Helper Functions
\ingroup PkgSurfaceParameterizationMethods
*/

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="454pt" height="136pt" viewBox="0 0 454 136" version="1.1">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="908pt" height="272pt" viewBox="0 0 454 136" version="1.1">
<g id="surface1">
<path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 187.643005 687.919155 L 198.615661 717.176968 " transform="matrix(1,0,0,-1,-48.62738,808.649624)"/>
<path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 169.357849 720.833218 L 136.443786 720.833218 " transform="matrix(1,0,0,-1,-48.62738,808.649624)"/>
@ -85,7 +85,7 @@
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 6.699219 43.929688 C 6.699219 39.929688 0.699219 39.929688 0.699219 43.929688 C 0.699219 47.929688 6.699219 47.929688 6.699219 43.929688 Z M 5.699219 43.929688 C 5.699219 41.261719 1.699219 41.261719 1.699219 43.929688 C 1.699219 46.597656 5.699219 46.597656 5.699219 43.929688 Z M 5.699219 43.929688 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 174.429688 32.957031 C 174.429688 29.625 169.429688 29.625 169.429688 32.957031 C 169.429688 36.289062 174.429688 36.289062 174.429688 32.957031 Z M 174.429688 32.957031 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 174.929688 32.957031 C 174.929688 28.957031 168.929688 28.957031 168.929688 32.957031 C 168.929688 36.957031 174.929688 36.957031 174.929688 32.957031 Z M 173.929688 32.957031 C 173.929688 30.289062 169.929688 30.289062 169.929688 32.957031 C 169.929688 35.625 173.929688 35.625 173.929688 32.957031 Z M 173.929688 32.957031 "/>
<path style="fill:none;stroke-width:0.8;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(54.5%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 88.900817 731.805874 L 118.15863 742.77853 L 151.072692 764.719937 L 136.443786 720.833218 L 151.072692 764.719937 L 187.643005 750.09103 L 183.986755 793.977749 " transform="matrix(1,0,0,-1,-48.62738,808.649624)"/>
<path style="fill:none;stroke-width:0.8;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(0%,75%,75%);stroke-opacity:1;stroke-miterlimit:10;" d="M 88.900817 731.805874 L 118.15863 742.77853 L 151.072692 764.719937 L 136.443786 720.833218 L 151.072692 764.719937 L 187.643005 750.09103 L 183.986755 793.977749 " transform="matrix(1,0,0,-1,-48.62738,808.649624)"/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 104.945312 43.929688 C 104.945312 40.597656 99.945312 40.597656 99.945312 43.929688 C 99.945312 47.261719 104.945312 47.261719 104.945312 43.929688 Z M 104.945312 43.929688 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 105.445312 43.929688 C 105.445312 39.929688 99.445312 39.929688 99.445312 43.929688 C 99.445312 47.929688 105.445312 47.929688 105.445312 43.929688 Z M 104.445312 43.929688 C 104.445312 41.261719 100.445312 41.261719 100.445312 43.929688 C 100.445312 46.597656 104.445312 46.597656 104.445312 43.929688 Z M 104.445312 43.929688 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 141.515625 58.558594 C 141.515625 55.226562 136.515625 55.226562 136.515625 58.558594 C 136.515625 61.890625 141.515625 61.890625 141.515625 58.558594 Z M 141.515625 58.558594 "/>
@ -179,7 +179,7 @@
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 273.675781 43.929688 C 273.675781 39.929688 267.675781 39.929688 267.675781 43.929688 C 267.675781 47.929688 273.675781 47.929688 273.675781 43.929688 Z M 272.675781 43.929688 C 272.675781 41.261719 268.675781 41.261719 268.675781 43.929688 C 268.675781 46.597656 272.675781 46.597656 272.675781 43.929688 Z M 272.675781 43.929688 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 441.410156 32.957031 C 441.410156 29.625 436.410156 29.625 436.410156 32.957031 C 436.410156 36.289062 441.410156 36.289062 441.410156 32.957031 Z M 441.410156 32.957031 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 441.910156 32.957031 C 441.910156 28.957031 435.910156 28.957031 435.910156 32.957031 C 435.910156 36.957031 441.910156 36.957031 441.910156 32.957031 Z M 440.910156 32.957031 C 440.910156 30.289062 436.910156 30.289062 436.910156 32.957031 C 436.910156 35.625 440.910156 35.625 440.910156 32.957031 Z M 440.910156 32.957031 "/>
<path style="fill:none;stroke-width:0.8;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(54.5%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 355.87738 731.805874 L 385.135193 742.77853 L 403.420349 720.837124 L 418.049255 764.723843 L 454.619568 750.094937 L 450.963318 793.981655 " transform="matrix(1,0,0,-1,-48.62738,808.649624)"/>
<path style="fill:none;stroke-width:0.8;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(0%,75%,75%);stroke-opacity:1;stroke-miterlimit:10;" d="M 355.87738 731.805874 L 385.135193 742.77853 L 403.420349 720.837124 L 418.049255 764.723843 L 454.619568 750.094937 L 450.963318 793.981655 " transform="matrix(1,0,0,-1,-48.62738,808.649624)"/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 339.007812 65.871094 C 339.007812 62.539062 334.007812 62.539062 334.007812 65.871094 C 334.007812 69.207031 339.007812 69.207031 339.007812 65.871094 Z M 339.007812 65.871094 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 339.507812 65.871094 C 339.507812 61.871094 333.507812 61.871094 333.507812 65.871094 C 333.507812 69.871094 339.507812 69.871094 339.507812 65.871094 Z M 338.507812 65.871094 C 338.507812 63.207031 334.507812 63.207031 334.507812 65.871094 C 334.507812 68.539062 338.507812 68.539062 338.507812 65.871094 Z M 338.507812 65.871094 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(54.5%,71.8%,91.8%);fill-opacity:1;" d="M 357.292969 87.816406 C 357.292969 84.484375 352.292969 84.484375 352.292969 87.816406 C 352.292969 91.148438 357.292969 91.148438 357.292969 87.816406 Z M 357.292969 87.816406 "/>

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -3,8 +3,6 @@
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/Seam_mesh.h>
#include <CGAL/Surface_mesh_parameterization/internal/shortest_path.h>
#include <CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
@ -64,10 +62,9 @@ int main(int argc, char * argv[])
// -- the third line optionally provides the seam edges indices as 'e11 e12 e21 e22 e31 e32' etc.
const char* cone_filename = (argc>2) ? argv[2] : "data/bear.selection.txt";
// Read the cones and find the corresponding vertex_descriptor in the underlying mesh 'sm'
typedef std::vector<SM_vertex_descriptor> Cones_in_smesh_container;
Cones_in_smesh_container cone_sm_vds;
SMP::internal::read_cones<SurfaceMesh>(sm, cone_filename, cone_sm_vds);
// Read the cones and compute their corresponding vertex_descriptor in the underlying mesh 'sm'
std::vector<SM_vertex_descriptor> cone_sm_vds;
SMP::read_cones<SurfaceMesh>(sm, cone_filename, std::back_inserter(cone_sm_vds));
// Two property maps to store the seam edges and vertices
Seam_edge_pmap seam_edge_pm = sm.add_property_map<SM_edge_descriptor, bool>("e:on_seam", false).first;
@ -76,12 +73,14 @@ int main(int argc, char * argv[])
// The seam mesh
Mesh mesh(sm, seam_edge_pm, seam_vertex_pm);
// Use the path provided between cones to create a seam mesh
// If provided, use the path between cones to create a seam mesh
SM_halfedge_descriptor smhd = mesh.add_seams(cone_filename);
// If not provided, compute the paths using shortest paths
if(smhd == SM_halfedge_descriptor() ) {
std::cout << "No seams were given in input, computing shortest paths between cones" << std::endl;
std::cout << "No seams given in input, computing the shortest paths between consecutive cones" << std::endl;
std::list<SM_edge_descriptor> seam_edges;
SMP::internal::compute_shortest_paths_between_cones(sm, cone_sm_vds, seam_edges);
SMP::compute_shortest_paths_between_cones(sm, cone_sm_vds.begin(), cone_sm_vds.end(), seam_edges);
// Add the seams to the seam mesh
BOOST_FOREACH(SM_edge_descriptor e, seam_edges) {
@ -101,11 +100,8 @@ int main(int argc, char * argv[])
}
// Mark the cones in the seam mesh
typedef boost::unordered_map<vertex_descriptor, SMP::Cone_type> Cones;
Cones cmap;
SMP::internal::locate_cones<Mesh,
Cones_in_smesh_container,
Cones>(mesh, cone_sm_vds, cmap);
boost::unordered_map<vertex_descriptor, SMP::Cone_type> cmap;
SMP::locate_cones(mesh, cone_sm_vds.begin(), cone_sm_vds.end(), cmap);
// The 2D points of the uv parametrisation will be written into this map
// Note that this is a halfedge property map, and that uv values

View File

@ -161,12 +161,6 @@ namespace Surface_mesh_parameterization {
/// \endcode
///
/// \sa `CGAL::Surface_mesh_parameterization::Fixed_border_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>`
/// \sa `CGAL::Surface_mesh_parameterization::LSCM_parameterizer_3<TriangleMesh, BorderParameterizer>`
/// \sa `CGAL::Surface_mesh_parameterization::Mean_value_coordinates_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::Orbifold_Tutte_parameterizer_3<SeamMesh, SolverTraits>`
///
template < class TriangleMesh_,
class BorderParameterizer_ = Default,

View File

@ -78,15 +78,9 @@ namespace Surface_mesh_parameterization {
/// Eigen::BiCGSTAB<Eigen_sparse_matrix<double>::EigenType,
/// Eigen::IncompleteLUT< double > > >
/// \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::Discrete_authalic_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
\sa `CGAL::Surface_mesh_parameterization::Discrete_conformal_map_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
\sa `CGAL::Surface_mesh_parameterization::LSCM_parameterizer_3<TriangleMesh, BorderParameterizer>`
\sa `CGAL::Surface_mesh_parameterization::Mean_value_coordinates_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
\sa `CGAL::Surface_mesh_parameterization::Orbifold_Tutte_parameterizer_3<SeamMesh, SolverTraits>`
*/
///
/// \sa `CGAL::Surface_mesh_parameterization::Fixed_border_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
///
template < typename TriangleMesh_,
typename BorderParameterizer_ = Default,
typename SolverTraits_ = Default >

View File

@ -84,12 +84,6 @@ 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::Barycentric_mapping_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::Discrete_conformal_map_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::LSCM_parameterizer_3<TriangleMesh, BorderParameterizer>`
/// \sa `CGAL::Surface_mesh_parameterization::Mean_value_coordinates_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::Orbifold_Tutte_parameterizer_3<SeamMesh, SolverTraits>`
///
template < class TriangleMesh_,
class BorderParameterizer_ = Default,

View File

@ -84,12 +84,6 @@ 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::Barycentric_mapping_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::Discrete_authalic_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::LSCM_parameterizer_3<TriangleMesh, BorderParameterizer>`
/// \sa `CGAL::Surface_mesh_parameterization::Mean_value_coordinates_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::Orbifold_Tutte_parameterizer_3<SeamMesh, SolverTraits>`
///
template < typename TriangleMesh_,
typename BorderParameterizer_ = Default,

View File

@ -45,9 +45,10 @@ enum Error_code
ERROR_WRONG_PARAMETER ///< A method received an unexpected parameter
};
/// Get message corresponding to an error code
/// \ingroup PkgSurfaceParameterizationEnums
/// \brief Get the message corresponding to an error code.
/// \param error_code The code returned by `parameterize()`
/// \return The string describing the error code
/// \return The string describing the error code.
const char* get_error_message(int error_code)
{
// Messages corresponding to Error_code list above. Must be kept in sync!

View File

@ -93,12 +93,6 @@ namespace Surface_mesh_parameterization {
/// \endcode
///
/// \sa `CGAL::Surface_mesh_parameterization::Two_vertices_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \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>`
/// \sa `CGAL::Surface_mesh_parameterization::Mean_value_coordinates_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa `CGAL::Surface_mesh_parameterization::Orbifold_Tutte_parameterizer_3<SeamMesh, SolverTraits>`
///
template < class TriangleMesh_,
class BorderParameterizer_ = Default,

View File

@ -82,12 +82,6 @@ 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::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>`
/// \sa `CGAL::Surface_mesh_parameterization::LSCM_parameterizer_3<TriangleMesh, BorderParameterizer>`
/// \sa `CGAL::Surface_mesh_parameterization::Orbifold_Tutte_parameterizer_3<SeamMesh, SolverTraits>`
///
template < class TriangleMesh_,
class BorderParameterizer_ = Default,

View File

@ -30,7 +30,9 @@
#include <CGAL/Surface_mesh_parameterization/internal/orbifold_cone_helper.h>
#include <CGAL/Surface_mesh_parameterization/IO/File_off.h>
#include <CGAL/Surface_mesh_parameterization/orbifold_enums.h>
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
#include <CGAL/Surface_mesh_parameterization/orbifold_shortest_path.h>
#include <CGAL/Polygon_mesh_processing/Weights.h>
@ -70,20 +72,276 @@ namespace CGAL {
namespace Surface_mesh_parameterization {
/// \ingroup PkgSurfaceParameterizationEnums
/// \ingroup PkgSurfaceParameterizationOrbifoldHelperFunctions
///
/// Weight type used in the parameterization computation.
/// Read 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.
///
/// MVC weights are guaranteed to generate positive edge weights, and the parameterization
/// is guaranteed to be injective.
/// \attention The mesh is here `tm`, it is the base mesh of the `CGAL::Seam_mesh`
/// that is passed in input, <i>not</i> the seam mesh itself.
///
/// In case the cotangent weights are used, the orbifold-Tutte embedding globally
/// minimizes the Dirichlet energy and approximates conformal mappings.
enum Weight_type
/// \tparam TriangleMesh A triangle mesh, model of `FaceListGraph` and `HalfedgeListGraph`.
/// \tparam VertexIndexMap must be a model of `ReadablePropertyMap` with
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor` as key type and
/// a unique integer as value type.
/// \tparam ConeOutputIterator a model of `OutputIterator` with value type
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor`.
///
/// \param tm the triangular mesh to be parameterized
/// \param in the input stream
/// \param vpmap an initialized vertex index map
/// \param out the output iterator
///
/// \pre The number of cones must match the chosen \link PkgSurfaceParameterizationEnums Orbifold_type \endlink.
/// \pre No two cones correspond to the same vertex (all cones have different index).
///
/// \return The corresponding vertex descriptors are output, in the same order as the input integers, in `out`.
/// The function checks if the input is valid (no duplicate, correct number of cones) and returns an `Error_code`.
template<typename TriangleMesh, typename VertexIndexMap, typename ConeOutputIterator>
Error_code read_cones(const TriangleMesh& tm, std::ifstream& in, VertexIndexMap vpmap, ConeOutputIterator out)
{
Cotangent = 0,
Mean_value
};
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor TM_vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::vertex_iterator TM_vertex_iterator;
std::vector<int> cones;
cones.reserve(4);
int cone_index;
while(in >> cone_index)
cones.push_back(cone_index);
std::cout << "Input cones: ";
for(std::size_t i=0; i<cones.size(); ++i)
std::cout << cones[i] << " ";
std::cout << std::endl;
if(cones.size() < 3 || cones.size() > 4) {
std::cerr << "Error: Not enough or too many input cones" << std::endl;
return ERROR_WRONG_PARAMETER;
}
if(!internal::are_cones_unique(cones)) {
std::cerr << "Error: The input cones are not unique" << std::endl;
return ERROR_WRONG_PARAMETER;
}
// Locate the cones in the underlying mesh 'tm'
std::vector<TM_vertex_descriptor> cone_vds_in_tm(cones.size()); // need this to keep the correct order
// Since the cones are unique, we only need to loop all the vertices once
TM_vertex_iterator vit, end;
boost::tie(vit, end) = vertices(tm);
for(; vit!=end; ++vit) {
for(std::size_t i=0; i<cones.size(); ++i) {
TM_vertex_descriptor vd = *vit;
if(vpmap[vd] == cones[i])
cone_vds_in_tm[i] = vd;
}
}
CGAL_postcondition_code(for(std::size_t i=0; i<cones.size(); ++i))
CGAL_postcondition(cone_vds_in_tm[i] != TM_vertex_descriptor());
for(std::size_t i=0; i<cones.size(); ++i)
*out++ = cone_vds_in_tm[i];
return OK;
}
/// \ingroup PkgSurfaceParameterizationOrbifoldHelperFunctions
///
/// Same as above, using the default indexation of the vertices of `tm`: vertices
/// are numbered from `0` to `num_vertices(tm)-1`, in the order that they appear
/// while calling `vertices(tm)`.
template<typename TriangleMesh, typename ConeOutputIterator>
Error_code read_cones(const TriangleMesh& tm, std::ifstream& in, ConeOutputIterator out)
{
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor TM_vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::vertex_iterator TM_vertex_iterator;
boost::unordered_map<TM_vertex_descriptor, int> m;
int counter = 0;
TM_vertex_iterator vit, end;
boost::tie(vit, end) = vertices(tm);
for(; vit!=end; ++vit)
{
TM_vertex_descriptor vd = *vit;
m[vd] = counter++;
}
return read_cones(tm, in, boost::make_assoc_property_map(m), out);
}
/// \ingroup PkgSurfaceParameterizationOrbifoldHelperFunctions
///
/// Same as above, but from a file instead of a stream.
template<typename TriangleMesh, typename VertexIndexMap, typename ConeOutputIterator>
Error_code read_cones(const TriangleMesh& tm, const char* filename, VertexIndexMap vpmap, ConeOutputIterator out)
{
std::ifstream in(filename);
return read_cones(tm, in, vpmap, out);
}
/// \ingroup PkgSurfaceParameterizationOrbifoldHelperFunctions
///
/// Same as above, but from a file instead of a stream. The default indexation
/// of the vertices of `tm` is used: vertices are numbered from `0` to `num_vertices(tm)-1`,
/// in the order that they appear while calling `vertices(tm)`.
template<typename TriangleMesh, typename ConeOutputIterator>
Error_code read_cones(const TriangleMesh& tm, const char* filename, ConeOutputIterator out)
{
std::ifstream in(filename);
return read_cones(tm, in, out);
}
/// \ingroup PkgSurfaceParameterizationOrbifoldHelperFunctions
///
/// Locate 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 PkgSurfaceParameterizationEnums Cone_type \endlink).
///
/// \attention The cones must be ordered: the first and last cones are the extremities of the seam.
///
/// \tparam SeamMesh is the same mesh that is passed to the parameterizer. It is an object of type`CGAL::Seam_mesh`,
/// 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`.
/// \tparam ConeMap must be a model of <a href="http://en.cppreference.com/w/cpp/concept/AssociativeContainer"><tt>AssociativeContainer</tt></a>
/// with `boost::graph_traits<SeamMesh>::%vertex_descriptor` as key type and
/// \link PkgSurfaceParameterizationEnums Cone_type \endlink as value type.
///
/// \param mesh the seam mesh
/// \param first, beyond the range of cones, as vertex descriptors of the base mesh.
/// \param cones an object of type `ConeMap`. Cones will be stored in this container
/// as vertex descriptors of the seam mesh, along with their associated cone types.
template<typename SeamMesh, typename ConeInputBidirectionalIterator, typename ConeMap>
bool locate_cones(const SeamMesh& mesh,
ConeInputBidirectionalIterator first, ConeInputBidirectionalIterator beyond,
ConeMap& cones)
{
typedef typename SeamMesh::TriangleMesh TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::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;
const PM_PPM pm_ppmap = get(boost::vertex_point, mesh.mesh());
// property map to go from vertex_descriptor to Point_3
typedef typename internal::Kernel_traits<SeamMesh>::PPM PPM;
const PPM ppmap = get(boost::vertex_point, mesh);
BOOST_FOREACH(vertex_descriptor vd, vertices(mesh)) {
for(ConeInputBidirectionalIterator cit=first; cit!=beyond; ++cit) {
ConeInputBidirectionalIterator last = (--beyond)++;
TM_vertex_descriptor smvd = *cit;
if(get(ppmap, vd) == get(pm_ppmap, smvd)) { // same geometric position
Cone_type ct;
if(cit == first)
ct = First_unique_cone;
else if(cit == last)
ct = Second_unique_cone;
else
ct = Duplicated_cone;
cones.insert(std::make_pair(vd, ct));
}
}
}
return internal::check_cone_validity(mesh, first, beyond, cones);
}
/// \ingroup PkgSurfaceParameterizationOrbifoldHelperFunctions
///
/// Same as above, but the cones are <i>not</i> ordered and we thus use seam mesh
/// information to determine which cones are extremities of the seam (so-called
/// <i>unique cones</i>) or not (so-called <i>duplicate cones</i>).
template<typename SeamMesh, typename ConeInputBidirectionalIterator, typename ConeMap>
bool locate_unordered_cones(const SeamMesh& mesh,
ConeInputBidirectionalIterator first, ConeInputBidirectionalIterator beyond,
ConeMap& cones)
{
CGAL_precondition(cones.empty());
CGAL_precondition(std::distance(first, beyond) == 3 || std::distance(first, beyond) == 4);
typedef typename SeamMesh::TriangleMesh TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::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;
// find a vertex on the seam
vertex_descriptor vertex_on_seam;
BOOST_FOREACH(vertex_descriptor vd, vertices(mesh)) {
if(mesh.has_on_seam(vd)) {
vertex_on_seam = vd;
break;
}
}
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;
const PM_PPM pm_ppmap = get(boost::vertex_point, mesh.mesh());
// property map to go from vertex_descriptor to Point_3
typedef typename internal::Kernel_traits<SeamMesh>::PPM PPM;
const PPM ppmap = get(boost::vertex_point, mesh);
bool first_cone_met = false;
// walk on the seam and mark if we encounter a cone
vertex_descriptor end = vertex_on_seam;
do {
ConeInputBidirectionalIterator current = first;
for(; current!=beyond; ++current) {
TM_vertex_descriptor smvd = *current;
if(get(ppmap, vertex_on_seam) == get(pm_ppmap, smvd)) { // the seam mesh vertex is a cone
// We have encountered a cone. Must check if the cone is a Unique_cone
// or a Duplicated_cone.
// A check is to look at the sources of two halfedges with the same direction
// on either side of the seam. If the sources are the same, it's a Unique_cone;
// if they differ, it's a duplicated_cone.
halfedge_descriptor hd = halfedge(vertex_on_seam, mesh);
halfedge_descriptor other_hd = opposite(hd, mesh);
// little trick to go from border halfedge on one side of the seam to
// interior halfedge on the other side of the seam
CGAL_assertion(other_hd.seam);
other_hd.seam = false;
Cone_type ct;
if(target(hd, mesh) == source(other_hd, mesh)) {
if(first_cone_met)
ct = Second_unique_cone;
else {
ct = First_unique_cone;
first_cone_met = true;
}
} else {
ct = Duplicated_cone;
}
cones.insert(std::make_pair(vertex_on_seam, ct));
}
}
// Move to the next vertex_descriptor on the seam
vertex_on_seam = source(halfedge(vertex_on_seam, mesh), mesh);
CGAL_assertion(mesh.has_on_seam(vertex_on_seam));
} while(vertex_on_seam != end);
return internal::check_cone_validity(mesh, first, beyond, cones);
}
/// \ingroup PkgSurfaceParameterizationMethods
///
@ -97,6 +355,10 @@ enum Weight_type
/// and a set of vertices of the mesh (the cones). The choice of cones influences
/// the resulting parameterization, but not the choice of the seam path between these cones.
///
/// Some helper functions related to the class `Orbifold_Tutte_parameterizer_3`
/// (for example to read and compute paths between cones) can be found
/// \link PkgSurfaceParameterizationOrbifoldHelperFunctions here \endlink.
///
/// The example \ref Surface_mesh_parameterization/orbifold.cpp "orbifold.cpp"
/// shows how to select cones on the input mesh and automatically construct
/// the seams and the cones on the `Seam_mesh`.
@ -120,12 +382,7 @@ enum Weight_type
/// Eigen::UmfPackLU<Eigen_sparse_matrix<double>::EigenType> >
/// \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>`
/// \sa `CGAL::Surface_mesh_parameterization::LSCM_parameterizer_3<TriangleMesh, BorderParameterizer>`
/// \sa `CGAL::Surface_mesh_parameterization::Mean_value_coordinates_parameterizer_3<TriangleMesh, BorderParameterizer, SolverTraits>`
/// \sa \ref PkgSurfaceParameterizationOrbifoldHelperFunctions
///
template < typename SeamMesh,
typename SolverTraits_ = Default>
@ -342,11 +599,11 @@ private:
// positions of the cones in the plane
typedef std::vector<Point_2> Point_container;
const Point_container& tcoords =
get_cones_parameterized_coordinates<Point_container>(orb_type);
internal::get_cones_parameterized_coordinates<Point_container>(orb_type);
// angles at the cones
typedef std::vector<NT> Angle_container;
const Angle_container& angs = get_angles_at_cones<Angle_container>(orb_type);
const Angle_container& angs = internal::get_angles_at_cones<Angle_container>(orb_type);
// The index of the line in M that we are filling next.
@ -637,6 +894,9 @@ public:
/// 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 ConeMap must be a model of <a href="http://en.cppreference.com/w/cpp/concept/AssociativeContainer"><tt>AssociativeContainer</tt></a>
/// with key type `boost::graph_traits<Seam_mesh>::%vertex_descriptor` and
/// \link PkgSurfaceParameterizationEnums Cone_type \endlink as value type.
/// \tparam VertexUVmap must be a model of `ReadWritePropertyMap` with
/// `boost::graph_traits<Seam_mesh>::%vertex_descriptor` as key type and
/// %Point_2 (type deduced from `Seam_mesh` using `Kernel_traits`)
@ -644,14 +904,12 @@ public:
/// \tparam VertexIndexMap must be a model of `ReadablePropertyMap` with
/// `boost::graph_traits<Seam_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<Seam_mesh>::%vertex_descriptor` as key type and
/// a Boolean as value type.
///
/// \param mesh a `Seam_mesh` parameterized by any model of a `FaceGraph`
/// \param bhd a halfedge on the border of the seam mesh
/// \param cmap a mapping of the `vertex_descriptor`s of `mesh` that are cones
/// to their respective `Cone_type`.
/// to their respective \link PkgSurfaceParameterizationEnums Cone_type \endlink
/// classification.
/// \param uvmap an instanciation of the class `VertexUVmap`.
/// \param vimap an instanciation of the class `VertexIndexMap`.
///
@ -667,7 +925,7 @@ public:
/// or intersect other paths (see Figure below).
///
/// \cgalFigureBegin{Surface_mesh_parameterizationfigorbifold, orbifold_path.svg}
/// Bad (left) and good (right) seam paths. The seam edges are shown in dark red.
/// Invalid (left) and valid (right) seam paths. Seam edges are drawn in teal.
/// Cones are marked in yellow and blue.
/// \cgalFigureEnd
template<typename ConeMap,
@ -675,7 +933,7 @@ public:
typename VertexUVMap>
Error_code parameterize(SeamMesh& mesh,
halfedge_descriptor bhd,
ConeMap cmap,
const ConeMap& cmap,
VertexUVMap uvmap,
VertexIndexMap vimap) const
{
@ -758,7 +1016,8 @@ public:
}
public:
/// Constructor.
/// Constructor of the parameterizer. The arguments allow to select
/// the desired orbifold and weight types.
Orbifold_Tutte_parameterizer_3(const Orbifold_type orb_type = Square,
const Weight_type weight_type = Cotangent)
:

View File

@ -25,6 +25,7 @@
#include <CGAL/Surface_mesh_parameterization/internal/kernel_traits.h>
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
#include <CGAL/Surface_mesh_parameterization/orbifold_enums.h>
#include <CGAL/boost/graph/properties.h>
@ -45,49 +46,7 @@ namespace CGAL {
namespace Surface_mesh_parameterization {
/// \ingroup PkgSurfaceParameterizationEnums
///
/// The types of cones used in Orbifold Tutte parameterization.
///
/// `Unique_cones` are found at the beginning and the end of the seam. All other
/// cones are duplicated in the sense that when the seam is `opened`, the vertex
/// is duplicated at two different positions.
enum Cone_type
{
First_unique_cone = 0,
Second_unique_cone,
Duplicated_cone
};
/// \ingroup PkgSurfaceParameterizationEnums
///
/// The four Orbifold types available in the Orbifold Tutte parameterization.
enum Orbifold_type
{
Square = 0,
Diamond,
Triangle,
Parallelogram
};
/// Get message corresponding to an error code
/// \param orb_type The integer value in the enum
/// \return The string describing the Orbifold type
const char* get_orbifold_type(int orb_type)
{
// Messages corresponding to Error_code list above. Must be kept in sync!
static const char* type[Parallelogram+1] = {
"Square",
"Diamond",
"Triangle",
"Parallelogram"
};
if(orb_type > Parallelogram || orb_type < 0)
return "Unknown orbifold type";
else
return type[orb_type];
}
namespace internal {
// Orbifold type functions
template<typename Point_container>
@ -134,8 +93,6 @@ NT_container get_angles_at_cones(const Orbifold_type orb_type)
return angs;
}
namespace internal {
template<typename Cone_container>
bool are_cones_unique(const Cone_container& cones)
{
@ -202,21 +159,24 @@ void find_start_cone(const ConeMap& cmap,
/// Check the validity of the input cones in the `Seam_mesh` mesh.
template<typename SeamMesh,
typename Cones_in_Seam_mesh_map,
typename Cones_in_Base_mesh_container>
bool check_input_validity(const SeamMesh& mesh,
const Cones_in_Seam_mesh_map& cones,
const Cones_in_Base_mesh_container& cone_tm_vds)
typename ConeInputBidirectionalIterator,
typename Cones_in_Seam_mesh_map>
bool check_cone_validity(const SeamMesh& mesh,
ConeInputBidirectionalIterator first, ConeInputBidirectionalIterator beyond,
const Cones_in_Seam_mesh_map& cones)
{
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<typename SeamMesh::TriangleMesh>::vertex_descriptor TM_vertex_descriptor;
typename std::iterator_traits<
ConeInputBidirectionalIterator>::difference_type number_of_cones_in_tm = std::distance(first, beyond);
// check cone numbers
if((cone_tm_vds.size() == 3 && cones.size() != 4) ||
(cone_tm_vds.size() == 4 && cones.size() != 6)) {
if((number_of_cones_in_tm == 3 && cones.size() != 4) ||
(number_of_cones_in_tm == 4 && cones.size() != 6)) {
std::cerr << "Error: Problem in number of cones: " << std::endl;
std::cerr << cone_tm_vds.size() << " cones in the base mesh" << std::endl;
std::cerr << number_of_cones_in_tm << " cones in the base mesh" << std::endl;
std::cerr << cones.size() << " cones in the seam mesh" << std::endl;
return false;
}
@ -255,8 +215,8 @@ bool check_input_validity(const SeamMesh& mesh,
return false;
}
if((cone_tm_vds.size() == 3 && duplicated_cone_counter != 2) ||
(cone_tm_vds.size() == 4 && duplicated_cone_counter != 4)) {
if((number_of_cones_in_tm == 3 && duplicated_cone_counter != 2) ||
(number_of_cones_in_tm == 4 && duplicated_cone_counter != 4)) {
std::cerr << "Error: Wrong number of duplicated cones" << std::endl;
return false;
}
@ -336,207 +296,6 @@ bool check_input_validity(const SeamMesh& mesh,
return true;
}
/// Read the cones from an input stream.
template<typename TriangleMesh>
Error_code read_cones(const TriangleMesh& pm, std::ifstream& in,
std::vector<typename boost::graph_traits<TriangleMesh>::vertex_descriptor>& cone_vds_in_tm)
{
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor TM_vertex_descriptor;
std::vector<int> cones;
cones.reserve(4);
int cone_index;
while(in >> cone_index) {
cones.push_back(cone_index);
}
std::cout << "Input cones: ";
for(std::size_t i=0; i<cones.size(); ++i)
std::cout << cones[i] << " ";
std::cout << std::endl;
if(cones.size() < 3 || cones.size() > 4) {
std::cerr << "Error: Not enough or too many input cones" << std::endl;
return ERROR_WRONG_PARAMETER;
}
if(!are_cones_unique(cones)) {
std::cerr << "Error: The input cones are not unique" << std::endl;
return ERROR_WRONG_PARAMETER;
}
// Locate the cones in the underlying mesh 'pm'
CGAL_assertion(cone_vds_in_tm.empty());
cone_vds_in_tm.resize(cones.size());
for(std::size_t i=0; i<cones.size(); ++i) {
int counter = 0;
BOOST_FOREACH(TM_vertex_descriptor vd, vertices(pm)) {
if(counter == cones[i]) {
cone_vds_in_tm[i] = vd;
break;
}
++counter;
}
CGAL_postcondition(cone_vds_in_tm[i] != TM_vertex_descriptor());
}
return OK;
}
/// Read the cones from an input file.
template<typename TriangleMesh>
Error_code read_cones(const TriangleMesh& pm, const char* filename,
std::vector<typename boost::graph_traits<TriangleMesh>::vertex_descriptor>& cone_vds_in_tm)
{
std::ifstream in(filename);
return read_cones(pm, in, cone_vds_in_tm);
}
/// Locate the cones on the seam mesh (find the corresponding seam mesh
/// vertex_descriptor) and mark them with a tag that indicates whether it is a
/// simple cone or a duplicated cone.
///
/// The cones are ordered: the first and last cones are the extremetities of the seam.
///
/// \tparam SeamMesh is a seam mesh
/// \tparam ConeMap a map vertex_descriptor --> Cone_type
template<typename SeamMesh,
typename Cones_in_pmesh_vector,
typename ConeMap>
bool locate_cones(const SeamMesh& mesh,
const Cones_in_pmesh_vector& cone_tm_vds,
ConeMap& cones)
{
CGAL_precondition(cones.empty());
typedef typename SeamMesh::TriangleMesh TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::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 Kernel_traits<TriangleMesh>::PPM PM_PPM;
const PM_PPM pm_ppmap = get(boost::vertex_point, mesh.mesh());
// property map to go from vertex_descriptor to Point_3
typedef typename Kernel_traits<SeamMesh>::PPM PPM;
const PPM ppmap = get(boost::vertex_point, mesh);
// the cones in the underlying mesh
std::size_t cvdss = cone_tm_vds.size();
for(std::size_t i=0; i<cvdss; ++i) {
TM_vertex_descriptor smvd = cone_tm_vds[i];
BOOST_FOREACH(vertex_descriptor vd, vertices(mesh)) {
if(get(ppmap, vd) == get(pm_ppmap, smvd)) {
Cone_type ct;
if(i == 0)
ct = First_unique_cone;
else if(i == (cvdss - 1))
ct = Second_unique_cone;
else
ct = Duplicated_cone;
cones.insert(std::make_pair(vd, ct));
}
}
}
return check_input_validity(mesh, cones, cone_tm_vds);
}
/// Same as above, but the cones are NOT ordered and we thus use seam mesh
/// information to determine which cones are Duplicate_cones and which cones
/// are unique
///
/// \tparam SeamMesh is a seam mesh
/// \tparam Cones_in_pmesh_set is a set of cones (vertex_descriptor of SeamMesh)
/// \tparam ConeMap a map vertex_descriptor of SeamMesh --> Cone_type
template<typename SeamMesh,
typename Cones_in_pmesh_set,
typename ConeMap>
bool locate_unordered_cones(const SeamMesh& mesh,
const Cones_in_pmesh_set& cone_tm_vds,
ConeMap& cones)
{
CGAL_precondition(cones.empty());
CGAL_precondition(cone_tm_vds.size() == 3 || cone_tm_vds.size() == 4);
typedef typename SeamMesh::TriangleMesh TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::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;
// find a vertex on the seam
vertex_descriptor vertex_on_seam;
BOOST_FOREACH(vertex_descriptor vd, vertices(mesh)) {
if(mesh.has_on_seam(vd)) {
vertex_on_seam = vd;
break;
}
}
CGAL_assertion(vertex_on_seam != vertex_descriptor());
// property map to go from TM_vertex_descriptor to Point_3
typedef typename Kernel_traits<TriangleMesh>::PPM PM_PPM;
const PM_PPM pm_ppmap = get(boost::vertex_point, mesh.mesh());
// property map to go from vertex_descriptor to Point_3
typedef typename Kernel_traits<SeamMesh>::PPM PPM;
const PPM ppmap = get(boost::vertex_point, mesh);
bool first_cone_met = false;
// walk on the seam and mark if we encounter a cone
vertex_descriptor end = vertex_on_seam;
do {
BOOST_FOREACH(TM_vertex_descriptor smvd, cone_tm_vds) {
if(get(ppmap, vertex_on_seam) == get(pm_ppmap, smvd)) { // the seam mesh vertex is a cone
// we have encountered a cone. Must check if the cone is a Unique_cone
// or a Duplicated_cone.
// a check is to look at the sources of two halfedges with the same direction
// on either side of the seam. If the sources are the same, it's a Unique_cone;
// if they differ, it's a duplicated_cone.
halfedge_descriptor hd = halfedge(vertex_on_seam, mesh);
halfedge_descriptor other_hd = opposite(hd, mesh);
// little trick to go from border halfedge on one side of the seam to
// interior halfedge on the other side of the seam
CGAL_assertion(other_hd.seam);
other_hd.seam = false;
Cone_type ct;
if(target(hd, mesh) == source(other_hd, mesh)) {
if(first_cone_met)
ct = Second_unique_cone;
else {
ct = First_unique_cone;
first_cone_met = true;
}
} else {
ct = Duplicated_cone;
}
cones.insert(std::make_pair(vertex_on_seam, ct));
}
}
// move to the next vertex_descriptor on the seam
vertex_on_seam = source(halfedge(vertex_on_seam, mesh), mesh);
CGAL_assertion(mesh.has_on_seam(vertex_on_seam));
} while(vertex_on_seam != end);
return check_input_validity(mesh, cones, cone_tm_vds);
}
} // namespace internal
} // namespace Surface_mesh_parameterization

View File

@ -0,0 +1,91 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
// Author(s) : Mael Rouxel-Labbé
#ifndef CGAL_SURFACE_MESH_PARAMETERIZATION_ORBIFOLD_ENUMS_H
#define CGAL_SURFACE_MESH_PARAMETERIZATION_ORBIFOLD_ENUMS_H
#include <CGAL/license/Surface_mesh_parameterization.h>
/// \file orbifold_enums.h
namespace CGAL {
namespace Surface_mesh_parameterization {
/// \ingroup PkgSurfaceParameterizationEnums
///
/// The two possible weight types available in the Orbifold Tutte parameterization.
enum Weight_type
{
Cotangent = 0, ///< When Cotangent weights are used, the orbifold-Tutte embedding
/// globally minimizes the Dirichlet energy and approximates conformal mappings.
Mean_value ///< Mean Value Coordinate weights are guaranteed to generate positive edge weights,
/// and the parameterization is guaranteed to be injective.
};
/// \ingroup PkgSurfaceParameterizationEnums
///
/// A classification type for the cones used in Orbifold Tutte parameterization.
enum Cone_type
{
First_unique_cone = 0, ///< Marker for the cone found at the beginning of the seam.
Second_unique_cone, ///< Marker for the cone found at the end of the seam.
Duplicated_cone ///< Marker for all the other cones. Cones are duplicated in the sense
/// that when the seam is "opened", the cone appears
/// at two different positions.
};
/// \ingroup PkgSurfaceParameterizationEnums
///
/// The four Orbifold types available in the Orbifold Tutte parameterization.
/// The different shapes result from the number of cones and the angle constraints
/// at the cones.
enum Orbifold_type
{
Square = 0, ///< Three cones, forming a square-shaped basic tile.
Diamond, ///< Three cones, forming a diamond-shaped basic tile.
Triangle, ///< Three cones, forming a triangle-shaped basic tile.
Parallelogram ///< Four cones, forming a parallelogram-shaped basic tile.
};
/// \ingroup PkgSurfaceParameterizationEnums
/// \brief Convert the orbifold type to a literal message.
/// \param orb_type the integer value in the enum
/// \return the string describing the Orbifold type.
const char* get_orbifold_type(int orb_type)
{
// Messages corresponding to the different orbifold types.
static const char* type[Parallelogram+1] = {
"Square",
"Diamond",
"Triangle",
"Parallelogram"
};
if(orb_type > Parallelogram || orb_type < 0)
return "Unknown orbifold type";
else
return type[orb_type];
}
} // namespace Surface_mesh_parameterization
} // namespace CGAL
#endif

View File

@ -18,8 +18,8 @@
//
// Author(s) : Mael Rouxel-Labbé
#ifndef CGAL_SURFACE_MESH_PARAMETERIZATION_INTERNAL_SHORTEST_PATH_H
#define CGAL_SURFACE_MESH_PARAMETERIZATION_INTERNAL_SHORTEST_PATH_H
#ifndef CGAL_SURFACE_MESH_PARAMETERIZATION_SHORTEST_PATH_H
#define CGAL_SURFACE_MESH_PARAMETERIZATION_SHORTEST_PATH_H
#include <CGAL/license/Surface_mesh_parameterization.h>
@ -103,11 +103,29 @@ public:
}
};
template<typename TriangleMesh, typename OutputIterator>
} // namespace internal
/// \ingroup PkgSurfaceParameterizationOrbifoldHelperFunctions
///
/// Compute the shortest path between `source` and `target` over `mesh`, using
/// <a href="http://www.boost.org/doc/libs/release/libs/graph/doc/dijkstra_shortest_paths.html">
/// boost::dijkstra_shortest_paths()</a>.
///
/// \tparam TriangleMesh A triangle mesh, model of `FaceListGraph` and `HalfedgeListGraph`.
/// \tparam EdgeOutputIterator A model of `OutputIterator` with value type
/// `boost::graph_traits<TriangleMesh>::%edge_descriptor`.
///
/// \param mesh the triangular mesh to be parameterized
/// \param source, target the extremities of the path to be computed
/// \param oi the output iterator
///
/// \pre `source` and `target` are vertices of `mesh`.
/// \pre `source != target`
template<typename TriangleMesh, typename EdgeOutputIterator>
void compute_shortest_paths_between_two_cones(const TriangleMesh& mesh,
typename boost::graph_traits<TriangleMesh>::vertex_descriptor source,
typename boost::graph_traits<TriangleMesh>::vertex_descriptor target,
OutputIterator oi)
typename boost::graph_traits<TriangleMesh>::vertex_descriptor source,
typename boost::graph_traits<TriangleMesh>::vertex_descriptor target,
EdgeOutputIterator oi)
{
if(source == target) {
std::cout << "Warning: the source and target are identical in 'shortest_path' " << std::endl;
@ -117,7 +135,7 @@ void compute_shortest_paths_between_two_cones(const TriangleMesh& mesh,
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::edge_descriptor edge_descriptor;
typedef Stop_at_target_Dijkstra_visitor<TriangleMesh> Stop_visitor;
typedef internal::Stop_at_target_Dijkstra_visitor<TriangleMesh> Stop_visitor;
typedef boost::unordered_map<vertex_descriptor, vertex_descriptor> Pred_umap;
typedef boost::associative_property_map<Pred_umap> Pred_pmap;
@ -146,27 +164,44 @@ void compute_shortest_paths_between_two_cones(const TriangleMesh& mesh,
} while (s != source);
}
template<typename TriangleMesh, typename Cones_vector, typename Seam_container>
/// \ingroup PkgSurfaceParameterizationOrbifoldHelperFunctions
///
/// Given a range `[first; beyond[` of cones (described as vertex descriptors),
/// compute the shortest path for all pairs of consecutive entries in the range
/// and add them to the container `seams`.
///
/// \tparam TriangleMesh A triangle mesh, model of `FaceListGraph` and `HalfedgeListGraph`.
/// \tparam InputConesForwardIterator A model of `ForwardIterator` with value type
/// `boost::graph_traits<TriangleMesh>::%vertex_descriptor`.
/// \tparam SeamContainer A model of <a href="http://en.cppreference.com/w/cpp/concept/SequenceContainer"><tt>SequenceContainer</tt></a>
/// with value type `boost::graph_traits<TriangleMesh>::%edge_descriptor`.
///
/// \param mesh the triangular mesh on which paths are computed
/// \param first, beyond a range of cones
/// \param seams a container that will store the paths, as a sequence of edges of the mesh.
///
/// \pre `std::distance(first,beyond) > 1`
template<typename TriangleMesh, typename InputConesForwardIterator, typename SeamContainer>
void compute_shortest_paths_between_cones(const TriangleMesh& mesh,
const Cones_vector& cones,
Seam_container& seams)
InputConesForwardIterator first, InputConesForwardIterator beyond,
SeamContainer& seams)
{
CGAL_precondition(cones.size() == 3 || cones.size() == 4);
for(std::size_t i=0; i<cones.size() - 1; ++i) {
compute_shortest_paths_between_two_cones(mesh, cones[i], cones[i+1],
std::back_inserter(seams));
CGAL_precondition(std::distance(first, beyond) == 3 || std::distance(first, beyond) == 4);
InputConesForwardIterator last = --beyond;
for(; first!=last; ++first) {
InputConesForwardIterator next = first;
++next;
compute_shortest_paths_between_two_cones(mesh, *first, *next, std::back_inserter(seams));
}
std::ofstream out("shortest_path.selection.txt");
output_shortest_paths_to_selection_file(mesh, seams, out);
internal::output_shortest_paths_to_selection_file(mesh, seams, out);
}
} // namespace internal
} // namespace Surface_mesh_parameterization
} // namespace CGAL
#include <CGAL/enable_warnings.h>
#endif // CGAL_SURFACE_MESH_PARAMETERIZATION_INTERNAL_SHORTEST_PATH_H
#endif // CGAL_SURFACE_MESH_PARAMETERIZATION_SHORTEST_PATH_H

View File

@ -26,6 +26,7 @@
* the free functions of this package.
*/
#include <CGAL/Surface_mesh_parameterization/ARAP_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Barycentric_mapping_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Discrete_authalic_parameterizer_3.h>

View File

@ -6,7 +6,6 @@
#include <CGAL/Polyhedron_3.h>
#include <CGAL/boost/graph/Seam_mesh.h>
#include <CGAL/Surface_mesh_parameterization/internal/shortest_path.h>
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
#include <CGAL/surface_mesh_parameterization.h>
@ -420,9 +419,8 @@ int main(int, char**)
const char* cone_filename = "data/fandisk.orbifold.selection.txt";
// Read the cones and find the corresponding vertex_descriptor in the underlying mesh 'sm'
typedef std::vector<SM_vertex_descriptor> Cones_in_smesh_container;
Cones_in_smesh_container cone_sm_vds;
SMP::internal::read_cones<SMesh>(sm, cone_filename, cone_sm_vds);
std::vector<SM_vertex_descriptor> cone_sm_vds;
SMP::read_cones<SMesh>(sm, cone_filename, std::back_inserter(cone_sm_vds));
// Two property maps to store the seam edges and vertices
SM_seam_edge_pmap seam_edge_pm = sm.add_property_map<SM_edge_descriptor, bool>("e:on_seam", false).first;
@ -435,7 +433,7 @@ int main(int, char**)
SM_halfedge_descriptor smhd = mesh.add_seams(cone_filename);
if(smhd == SM_halfedge_descriptor() ) {
std::list<SM_edge_descriptor> seam_edges;
SMP::internal::compute_shortest_paths_between_cones(sm, cone_sm_vds, seam_edges);
SMP::compute_shortest_paths_between_cones(sm, cone_sm_vds.begin(), cone_sm_vds.end(), seam_edges);
// Add the seams to the seam mesh
BOOST_FOREACH(SM_edge_descriptor e, seam_edges) {
@ -453,11 +451,8 @@ int main(int, char**)
}
// Mark the cones in the seam mesh
typedef boost::unordered_map<SM_SE_vertex_descriptor, SMP::Cone_type> Cones;
Cones cmap;
SMP::internal::locate_cones<SM_Seam_mesh,
Cones_in_smesh_container,
Cones>(mesh, cone_sm_vds, cmap);
boost::unordered_map<SM_SE_vertex_descriptor, SMP::Cone_type> cmap;
SMP::locate_cones(mesh, cone_sm_vds.begin(), cone_sm_vds.end(), cmap);
// The 2D points of the uv parametrisation will be written into this map
// Note that this is a halfedge property map, and that uv values