From 05647d928a00edae1bb18beb35706085b60b7631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 29 Nov 2016 17:40:01 +0100 Subject: [PATCH] Added Orbifold Tutte Embeddings to the polyhedron demo --- .../Plugins/Surface_mesh/CMakeLists.txt | 2 +- .../Plugins/Surface_mesh/OTE_dialog.ui | 137 ++++++++++ .../Surface_mesh/Parameterization_plugin.cpp | 209 +++++++++++++--- .../Surface_mesh_parameterization/orbital.cpp | 96 ++----- .../parameterization_tests.cpp | 9 +- .../Orbital_Tutte_parameterizer_3.h | 27 +- .../internal/orbital_cone_helper.h | 236 ++++++++++++++++++ 7 files changed, 576 insertions(+), 140 deletions(-) create mode 100644 Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/OTE_dialog.ui create mode 100644 Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/internal/orbital_cone_helper.h diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt index e8fc0239428..4a8ad74af10 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt @@ -1,6 +1,6 @@ include( polyhedron_demo_macros ) if(EIGEN3_FOUND) - qt5_wrap_ui( parameterizationUI_FILES Parameterization_widget.ui ARAP_dialog.ui) + qt5_wrap_ui( parameterizationUI_FILES Parameterization_widget.ui ARAP_dialog.ui OTE_dialog.ui) polyhedron_demo_plugin(parameterization_plugin Parameterization_plugin ${parameterizationUI_FILES}) target_link_libraries(parameterization_plugin scene_polyhedron_item scene_textured_polyhedron_item scene_polyhedron_selection_item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/OTE_dialog.ui b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/OTE_dialog.ui new file mode 100644 index 00000000000..f5ae423667a --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/OTE_dialog.ui @@ -0,0 +1,137 @@ + + + OTE_dialog + + + + 0 + 0 + 355 + 100 + + + + ArrowCursor + + + Meshing criteria + + + + + + + + Orbifold type + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + Qt::LeftToRight + + + + I (Square) + + + + + II (Diamond) + + + + + III (Triangle) + + + + + IV (Parallelogram) + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + OTE_dialog + accept() + + + 384 + 191 + + + 157 + 195 + + + + + buttonBox + rejected() + OTE_dialog + reject() + + + 384 + 191 + + + 286 + 195 + + + + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp index c0820f7c688..0a0254ba25d 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp @@ -20,18 +20,33 @@ #include #include #include + +#include +#include + #include +#include + #include #include #include #include #include #include +#include +#include #include #include +#include +#include +#include + +#include #include +#include +#include #include #include @@ -41,6 +56,7 @@ #include "ui_Parameterization_widget.h" #include "ui_ARAP_dialog.h" +#include "ui_OTE_dialog.h" namespace SMP = CGAL::Surface_mesh_parameterization; @@ -143,32 +159,44 @@ private: QPointF prev_pos; }; -typedef Kernel::FT FT; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; -typedef Kernel::Point_2 Point_2; -typedef boost::graph_traits::edge_descriptor P_edge_descriptor; -typedef boost::graph_traits::halfedge_descriptor P_halfedge_descriptor; +namespace SMP = CGAL::Surface_mesh_parameterization; +typedef Kernel::FT FT; +typedef boost::graph_traits::vertex_descriptor P_vertex_descriptor; +typedef Kernel::Point_2 Point_2; +typedef boost::graph_traits::edge_descriptor P_edge_descriptor; +typedef boost::graph_traits::halfedge_descriptor P_halfedge_descriptor; +// Textured polyhedron typedef boost::graph_traits:: - edge_descriptor T_edge_descriptor; + edge_descriptor T_edge_descriptor; typedef boost::graph_traits:: - halfedge_descriptor T_halfedge_descriptor; + halfedge_descriptor T_halfedge_descriptor; typedef boost::graph_traits:: - vertex_descriptor T_vertex_descriptor; + vertex_descriptor T_vertex_descriptor; +// Seam +typedef CGAL::Unique_hash_map UV_uhm; +typedef CGAL::Unique_hash_map Seam_edge_uhm; +typedef CGAL::Unique_hash_map Seam_vertex_uhm; -typedef CGAL::Unique_hash_map UV_uhm; -typedef CGAL::Unique_hash_map Seam_edge_uhm; -typedef CGAL::Unique_hash_map Seam_vertex_uhm; - -typedef boost::associative_property_map UV_pmap; -typedef boost::associative_property_map Seam_edge_pmap; -typedef boost::associative_property_map Seam_vertex_pmap; - +typedef boost::associative_property_map UV_pmap; +typedef boost::associative_property_map Seam_edge_pmap; +typedef boost::associative_property_map Seam_vertex_pmap; typedef CGAL::Seam_mesh Seam_mesh; -typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; + +typedef boost::graph_traits::face_iterator face_iterator; + +typedef boost::unordered_set Component; +typedef std::vector Components; + +typedef boost::unordered_set SComponent; +typedef std::vector SComponents; class UVItem : public QGraphicsItem { @@ -263,17 +291,19 @@ public: QAction* actionLSC = new QAction("Least Square Conformal Map", mw); QAction* actionDAP = new QAction("Discrete Authalic", mw); QAction* actionARAP = new QAction("As Rigid As Possible", mw); + QAction* actionOTE = new QAction("Orbifold Tutte Embedding", mw); actionMVC->setObjectName("actionMVC"); actionDCP->setObjectName("actionDCP"); actionLSC->setObjectName("actionLSC"); actionDAP->setObjectName("actionDAP"); actionARAP->setObjectName("actionARAP"); + actionOTE->setObjectName("actionOTE"); _actions << actionMVC << actionDCP << actionLSC << actionDAP - << actionARAP; + << actionOTE; autoConnectActions(); Q_FOREACH(QAction *action, _actions) action->setProperty("subMenuName", @@ -309,6 +339,7 @@ public Q_SLOTS: void on_actionLSC_triggered(); void on_actionDAP_triggered(); void on_actionARAP_triggered(); + void on_actionOTE_triggered(); void on_prevButton_pressed(); void on_nextButton_pressed(); void replacePolyline() @@ -318,8 +349,7 @@ public Q_SLOTS: int id = scene->mainSelectionIndex(); Q_FOREACH(UVItem* pl, projections) { - if(pl==NULL - || pl != projections[scene->item(id)]) + if(pl==NULL || pl != projections[scene->item(id)]) continue; current_uv_item = pl; break; @@ -363,8 +393,10 @@ public Q_SLOTS: } protected: - enum Parameterization_method { PARAM_MVC, PARAM_DCP, PARAM_LSC, PARAM_DAP, PARAM_ARAP}; + enum Parameterization_method { PARAM_MVC, PARAM_DCP, PARAM_LSC, + PARAM_DAP, PARAM_ARAP, PARAM_OTE}; void parameterize(Parameterization_method method); + private: Messages_interface *messages; QList _actions; @@ -439,10 +471,10 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio sel_item = qobject_cast(scene->item(id)); if(!sel_item) continue; - if(sel_item->selected_edges.empty() - || !sel_item->selected_facets.empty() - || !sel_item->selected_vertices.empty()) + if(sel_item->selected_edges.empty()) continue; + if(method == PARAM_OTE && sel_item->selected_vertices.empty()) + continue; is_seamed = true; } // Two property maps to store the seam edges and vertices @@ -514,9 +546,26 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio } } + // map the cones from the selection plugin to the textured polyhedron + boost::unordered_set unordered_cones; + if(method == PARAM_OTE) { + BOOST_FOREACH(P_vertex_descriptor vd, sel_item->selected_vertices) { + Polyhedron::Vertex_handle pvd(vd); + Textured_polyhedron::Vertex_iterator it = tMesh.vertices_begin(), + end = tMesh.vertices_end(); + for(; it!=end; ++it) { + Textured_polyhedron::Vertex_handle tvd(it); + if(it->id() == pvd->id()) { + unordered_cones.insert(tvd); + } + } + } + } + Seam_mesh sMesh(tMesh, seam_edge_pm, seam_vertex_pm); sMesh.set_seam_edges_number(seam_edges.size()); + // The parameterized values UV_uhm uv_uhm; UV_pmap uv_pm(uv_uhm); @@ -537,24 +586,45 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio CGAL::Polygon_mesh_processing::parameters::edge_is_constrained_map( edge_pmap)); - Components t_components(number_of_components); + + // Next is the gathering of the border halfedges of the connected component. + // It is wrong to pass the underlying mesh tMesh: a sphere split in half does + // not have any border according if border_halfedges() is run with tMesh. + // + // The proper way would be to completely redesign the plugin to use Seam meshes + // everywhere. But that's not worth it. Instead, we abuse the fact that faces + // are the same in tMesh and sMesh. + + // the SEAM MESH faces of each connected component + SComponents s_components(number_of_components); + Textured_polyhedron::Base::Facet_iterator fit; - for(fit = tMesh.facets_begin(); fit != tMesh.facets_end(); ++fit) - { - t_components.at(fccmap[fit]).insert(fit); + for(fit = tMesh.facets_begin(); fit != tMesh.facets_end(); ++fit) { + s_components.at(fccmap[fit]).insert(face_descriptor(fit)); } //once per component std::vector >uv_borders; uv_borders.resize(number_of_components); + for(int current_component=0; current_component border; - PMP::border_halfedges(t_components.at(current_component), - tMesh, - std::back_inserter(border)); + std::vector border; - BOOST_FOREACH(T_halfedge_descriptor hd, border) + // using `impl` to avoid face_index_t property maps +// PMP::internal::border_halfedges_impl(s_components.at(current_component), +// std::back_inserter(border), +// sMesh); + + PMP::internal::border_halfedges_impl(s_components.at(current_component), + std::back_inserter(border), + sMesh); + + std::cout << sMesh.number_of_seam_edges() << " seams" << std::endl; + std::cout << (s_components.at(current_component)).size() << " faces" << std::endl; + std::cout << border.size() << " border halfedges" << std::endl; + + BOOST_FOREACH(halfedge_descriptor hd, border) { uv_borders[current_component].push_back(source(hd, tMesh)->point().x()); uv_borders[current_component].push_back(source(hd, tMesh)->point().y()); @@ -569,12 +639,8 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio halfedge_descriptor bhd; // a halfedge on the (possibly virtual) border boost::unordered_set visited; FT result_len = 0; - BOOST_FOREACH(T_halfedge_descriptor thd, border) + BOOST_FOREACH(halfedge_descriptor hd, border) { - halfedge_descriptor hd(thd); - if(sMesh.has_on_seam(thd)) - hd.seam = true; // virtual border halfedge - assert(is_border(hd, sMesh)); if(visited.find(hd) == visited.end()) @@ -593,7 +659,8 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio } } } - assert(bhd != halfedge_descriptor() && is_border(bhd, sMesh)); + CGAL_postcondition(bhd != halfedge_descriptor()); + CGAL_postcondition(is_border(bhd, sMesh)); bool success = false; switch(method) @@ -660,6 +727,64 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio success = (err == SMP::OK); break; } + case PARAM_OTE: + { + new_item_name = tr("%1 (parameterized (OTE))").arg(poly_item->name()); + std::cout << "Parameterize (OTE)..."; + + // does not handle multiple connected components right now + // @todo (need to remove the assertions such as cones.size() == 4 + // and check where and when cones are used (passed by ID, for ex.?)) + CGAL_assertion(number_of_components == 1); + + CGAL_precondition(!unordered_cones.empty()); + + typedef SMP::Orbital_Tutte_parameterizer_3 Parameterizer; + + QDialog dialog(mw); + Ui::OTE_dialog ui; + ui.setupUi(&dialog); + connect(ui.buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); + connect(ui.buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); + + // Get values + QApplication::restoreOverrideCursor(); + + int i = dialog.exec(); + if (i == QDialog::Rejected) + return; + + SMP::Orbifold_type orb = static_cast(ui.OrbComboBox->currentIndex()); + std::cout << "selected orbifold type: " << ui.OrbComboBox->currentText().toStdString() << std::endl; + + QApplication::setOverrideCursor(Qt::WaitCursor); + + // Now, parameterize + Parameterizer parameterizer(orb); + + // mark cones in the seam mesh + typedef boost::unordered_map Cones; + Cones cmap; + SMP::internal::locate_unordered_cones, + Cones>(sMesh, unordered_cones, cmap); + + // vimap and uvmap + typedef boost::unordered_map Indices; + Indices indices; + CGAL::Polygon_mesh_processing::connected_component( + face(opposite(bhd, sMesh), sMesh), + sMesh, + boost::make_function_output_iterator( + SMP::internal::Index_map_filler(sMesh, indices))); + boost::associative_property_map vimap(indices); + + // Call to parameterizer + SMP::Error_code err = parameterizer.parameterize(sMesh, bhd, cmap, uv_pm, vimap); + success = (err == SMP::OK); + break; + } }//end switch QApplication::restoreOverrideCursor(); @@ -770,4 +895,10 @@ void Polyhedron_demo_parameterization_plugin::on_actionARAP_triggered() parameterize(PARAM_ARAP); } +void Polyhedron_demo_parameterization_plugin::on_actionOTE_triggered() +{ + std::cerr << "OTE..."; + parameterize(PARAM_OTE); +} + #include "Parameterization_plugin.moc" diff --git a/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/orbital.cpp b/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/orbital.cpp index 183fd7ca618..fb2dd59a430 100644 --- a/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/orbital.cpp +++ b/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/orbital.cpp @@ -46,87 +46,16 @@ typedef SurfaceMesh::Property_map UV_pmap; namespace SMP = CGAL::Surface_mesh_parameterization; -/// Read the cones from the input file. -SMP::Error_code read_cones(const SurfaceMesh& sm, const char* filename, - std::vector& cone_vds_in_sm) -{ - std::ifstream in(filename); - std::string vertices_line; - std::getline(in, vertices_line); // read the first line of the file - std::istringstream iss(vertices_line); - std::vector cones; - cones.reserve(4); - int cone_index; - while(iss >> cone_index) { - cones.push_back(cone_index); - } - - if(cones.size() < 3 || cones.size() > 4) { - std::cerr << "Error: problem loading the input cones" << std::endl; - return SMP::ERROR_WRONG_PARAMETER; - } - - std::cout << "Cones: "; - for(std::size_t i=0; i -void locate_cones(const Mesh& mesh, - const std::vector& cone_vds_in_sm, - ConeMap& cones) -{ - // property map to go from SM_vertex_descriptor to Point_3 - typedef SMP::internal::Kernel_traits::PPM SM_PPM; - const SM_PPM sm_ppmap = get(boost::vertex_point, mesh.mesh()); - - // property map to go from vertex_descriptor to Point_3 - typedef SMP::internal::Kernel_traits::PPM PPM; - const PPM ppmap = get(boost::vertex_point, mesh); - - // the cones in the underlying mesh - std::size_t cvdss = cone_vds_in_sm.size(); - for(std::size_t i=0; i2) ? argv[2] : "../data/bear.selection.txt"; // Read the cones and find the corresponding vertex_descriptor in the underlying mesh 'sm' - std::vector cone_vds_in_sm; - read_cones(sm, cone_filename, cone_vds_in_sm); + typedef std::vector Cones_in_smesh_container; + Cones_in_smesh_container cone_vds_in_sm; + SMP::internal::read_cones(sm, cone_filename, cone_vds_in_sm); // Two property maps to store the seam edges and vertices Seam_edge_pmap seam_edge_pm = sm.add_property_map("e:on_seam", false).first; @@ -185,7 +115,9 @@ int main(int argc, char * argv[]) // Mark the cones in the seam mesh typedef boost::unordered_map Cones; Cones cmap; - locate_cones(mesh, cone_vds_in_sm, cmap); + SMP::internal::locate_cones(mesh, cone_vds_in_sm, 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 diff --git a/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/parameterization_tests.cpp b/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/parameterization_tests.cpp index 9aca13e54d2..01b67c1abac 100644 --- a/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/parameterization_tests.cpp +++ b/Surface_mesh_parameterization/examples/Surface_mesh_parameterization/parameterization_tests.cpp @@ -5,16 +5,17 @@ #include #include +#include +#include + #include #include -#include -#include -#include - #include #include +#include + #include #include diff --git a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbital_Tutte_parameterizer_3.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbital_Tutte_parameterizer_3.h index a09cbbb66f9..cb726db4b62 100644 --- a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbital_Tutte_parameterizer_3.h +++ b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/Orbital_Tutte_parameterizer_3.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -58,20 +59,16 @@ // @todo checks that cones are different, are on seams, seam is one connected // component +// @todo Should the order of cones provided in entry matter ? Map the first cone +// to [-1, -1] for example ? namespace CGAL { namespace Surface_mesh_parameterization { -enum Cone_type -{ - Unique_cone, - Duplicated_cone -}; - enum Orbifold_type { - Square, + Square = 0, Diamond, Triangle, Parallelogram @@ -246,10 +243,12 @@ public: ++id_r; // current line index in A is increased } - void parameterize_seam_segment(const std::vector >& seam_segment, - NT ang, int& current_line_id_in_A, - Matrix& A, Vector& B) const + void constrain_seam_segment(const std::vector >& seam_segment, + NT ang, int& current_line_id_in_A, + Matrix& A, Vector& B) const { + std::cout << "constraining segment of length " << seam_segment.size() << std::endl; + // check that if there is a common vertex, it is at the beginning bool is_reversed = (seam_segment.back().first == seam_segment.back().second); @@ -323,7 +322,7 @@ public: // points between two cones, and the corresponding points on the opposite side of the seam std::vector > seam_segment; - int segment_index = 0; // counting the segments (3 max) + std::size_t segment_index = 0; // counting the segments (3 max) // Go through the seam, marking rotation and cone constraints while(true) { // breaking at the last cone @@ -366,7 +365,7 @@ public: CGAL_assertion(segment_index < angs.size()); NT ang = angs[segment_index]; - parameterize_seam_segment(seam_segment, ang, current_line_id_in_A, A, B); + constrain_seam_segment(seam_segment, ang, current_line_id_in_A, A, B); // the last cone of the seam is constrained if(is_in_map->second == Unique_cone) { // reached the end of the seam @@ -378,7 +377,7 @@ public: std::cout << "-------------------------" << std::endl; seam_segment.clear(); - segment_index++; + ++segment_index; } // move to the next halfedge couple (walking on the border of the seam) @@ -482,7 +481,7 @@ public: const VertexIndexMap vimap) const { std::cout << "size of X: " << X.size() << std::endl; - CGAL_assertion(X.size() == 2 * num_vertices(mesh) ); + CGAL_assertion(X.size() == static_cast(2 * num_vertices(mesh))); BOOST_FOREACH(vertex_descriptor vd, vertices(mesh)) { int index = get(vimap, vd); diff --git a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/internal/orbital_cone_helper.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/internal/orbital_cone_helper.h new file mode 100644 index 00000000000..ea0e6103f04 --- /dev/null +++ b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/internal/orbital_cone_helper.h @@ -0,0 +1,236 @@ +// Copyright (c) 2016 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$ +// +// +// Author(s) : + +#ifndef CGAL_SURFACE_MESH_PARAMETERIZATION_INTERNAL_CONE_HELPER_H +#define CGAL_SURFACE_MESH_PARAMETERIZATION_INTERNAL_CONE_HELPER_H + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +namespace Surface_mesh_parameterization { + +enum Cone_type +{ + Unique_cone, + Duplicated_cone +}; + +namespace internal { + +/// Read the cones from the input file. +template +Error_code read_cones(const Polygon_mesh& pm, const char* filename, + std::vector::vertex_descriptor>& cone_vds_in_pm) +{ + typedef typename boost::graph_traits::vertex_descriptor PM_vertex_descriptor; + + std::ifstream in(filename); + std::string vertices_line; + std::getline(in, vertices_line); // read the first line of the file + std::istringstream iss(vertices_line); + std::vector cones; + cones.reserve(4); + int cone_index; + while(iss >> cone_index) { + cones.push_back(cone_index); + } + + if(cones.size() < 3 || cones.size() > 4) { + std::cerr << "Error: Not enough or too many input cones" << std::endl; + return ERROR_WRONG_PARAMETER; + } + + std::cout << "Cones: "; + for(std::size_t i=0; i Cone_type +template +void locate_cones(const Mesh& mesh, + const Cones_in_pmesh_vector& cone_vds_in_sm, + ConeMap& cones) +{ + CGAL_precondition(cones.empty()); + + typedef typename boost::graph_traits::vertex_descriptor BM_vertex_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + // property map to go from BM_vertex_descriptor to Point_3 + typedef typename Kernel_traits::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::PPM PPM; + const PPM ppmap = get(boost::vertex_point, mesh); + + // the cones in the underlying mesh + std::size_t cvdss = cone_vds_in_sm.size(); + for(std::size_t i=0; i Cone_type +template +void locate_unordered_cones(const Mesh& mesh, + const Cones_in_pmesh_set& cone_vds_in_sm, + ConeMap& cones) +{ + CGAL_precondition(cones.empty()); + + typedef typename boost::graph_traits::vertex_descriptor BM_vertex_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::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 BM_vertex_descriptor to Point_3 + typedef typename Kernel_traits::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::PPM PPM; + const PPM ppmap = get(boost::vertex_point, mesh); + + // walk on the seam and mark if we encounter a cone + vertex_descriptor end = vertex_on_seam; + do { + BOOST_FOREACH(BM_vertex_descriptor smvd, cone_vds_in_sm) { + 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 = (target(hd, mesh) == source(other_hd, mesh)) ? Unique_cone + : Duplicated_cone; + + std::cout << "new cone with type: " << ct << std::endl; + + 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); + + CGAL_postcondition((cone_vds_in_sm.size() == 3 && cones.size() == 4) || + (cone_vds_in_sm.size() == 4 && cones.size() == 6)); + + std::cout << cone_vds_in_sm.size() << " cones in sm" << std::endl; + std::cout << cones.size() << " cones in mesh" << std::endl; +} + +} // namespace internal + +} // namespace Surface_mesh_parameterization + +} // namespace CGAL + +#endif // CGAL_SURFACE_MESH_PARAMETERIZATION_INTERNAL_CONE_HELPER_H