diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h index 97829194d88..69f2bd94626 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h @@ -18,6 +18,8 @@ #include #include #include +#include + #include #include #include @@ -28,6 +30,7 @@ #include #include #include +#include #include @@ -45,19 +48,19 @@ struct Face_map typedef value_type reference; typedef boost::writable_property_map_tag category; - Face_map(PM pm, const std::vector& triangle_ids) + Face_map(PM pm, const std::vector& face_ids) : pm(pm) - , triangle_ids(triangle_ids) + , face_ids(face_ids) {} friend void put(Face_map m, key_type k, value_type v) { - put(m.pm, v, m.triangle_ids[k]); + put(m.pm, v, m.face_ids[k]); } PM pm; - const std::vector& triangle_ids; + const std::vector& face_ids; }; template @@ -86,11 +89,11 @@ struct Default_visitor }; template -struct Triangle_index_tracker_base +struct Face_index_tracker_base { typedef boost::graph_traits GT; - Triangle_index_tracker_base(VertexCornerMapOut vertex_corner_map) + Face_index_tracker_base(VertexCornerMapOut vertex_corner_map) : m_v2v2_map(vertex_corner_map) {} @@ -103,36 +106,36 @@ struct Triangle_index_tracker_base }; template -struct Triangle_index_tracker_base +struct Face_index_tracker_base { typedef boost::graph_traits GT; using Vmap = Constant_property_map::vertex_descriptor>; - Triangle_index_tracker_base(internal_np::Param_not_found) {} + Face_index_tracker_base(internal_np::Param_not_found) {} Vmap v2v_map() { return Vmap(); } }; template -struct Triangle_index_tracker - : public Triangle_index_tracker_base +struct Face_index_tracker + : public Face_index_tracker_base { typedef boost::graph_traits GT; - Triangle_index_tracker(VertexCornerMapOut vertex_corner_map, FacePatchMapOut face_patch_map) - : Triangle_index_tracker_base(vertex_corner_map) - , m_f2f_map(face_patch_map, triangle_ids) + Face_index_tracker(VertexCornerMapOut vertex_corner_map, FacePatchMapOut face_patch_map) + : Face_index_tracker_base(vertex_corner_map) + , m_f2f_map(face_patch_map, face_ids) {} - std::vector triangle_ids; - void new_triangle_added_to_patch(std::size_t i) + std::vector face_ids; + void new_face_added_to_patch(std::size_t i) { - triangle_ids.push_back(i); + face_ids.push_back(i); } void new_triangles_added_to_patch(std::size_t nb_triangles, std::size_t i) { - triangle_ids.resize(triangle_ids.size()+nb_triangles, i); + face_ids.resize(face_ids.size()+nb_triangles, i); } Face_map @@ -146,17 +149,17 @@ struct Triangle_index_tracker template -struct Triangle_index_tracker - : public Triangle_index_tracker_base +struct Face_index_tracker + : public Face_index_tracker_base { using Fmap = Constant_property_map::face_descriptor>; - Triangle_index_tracker(VertexCornerMapOut vertex_corner_map,internal_np::Param_not_found) - : Triangle_index_tracker_base(vertex_corner_map) + Face_index_tracker(VertexCornerMapOut vertex_corner_map,internal_np::Param_not_found) + : Face_index_tracker_base(vertex_corner_map) {} - void new_triangle_added_to_patch(std::size_t /*in_patch_id*/) {} + void new_face_added_to_patch(std::size_t /*in_patch_id*/) {} void new_triangles_added_to_patch(std::size_t /*nb_triangles*/, std::size_t /*in_patch_id*/) {} Fmap f2f_map() { return Fmap(); } @@ -434,7 +437,7 @@ template bool add_triangle_faces(const std::vector< std::pair >& csts, typename Kernel::Vector_3 normal, const std::vector& corners, - std::vector >& triangles) + std::vector >& out_faces) { typedef Projection_traits_3 P_traits; typedef Triangulation_vertex_base_with_id_2 Vb; @@ -521,13 +524,13 @@ bool add_triangle_faces(const std::vector< std::pair > if (cdt.is_infinite(fit)) return false; if (reverse_face_orientation) - triangles.push_back( make_array(fit->vertex(1)->corner_id(), - fit->vertex(0)->corner_id(), - fit->vertex(2)->corner_id()) ); + out_faces.push_back( {fit->vertex(1)->corner_id(), + fit->vertex(0)->corner_id(), + fit->vertex(2)->corner_id()} ); else - triangles.push_back( make_array(fit->vertex(0)->corner_id(), - fit->vertex(1)->corner_id(), - fit->vertex(2)->corner_id()) ); + out_faces.push_back( {fit->vertex(0)->corner_id(), + fit->vertex(1)->corner_id(), + fit->vertex(2)->corner_id()} ); } return true; @@ -587,8 +590,9 @@ bool decimate_impl(const TriangleMesh& tm, EdgeIsConstrainedMap& edge_is_constrained, FaceCCIdMap& face_cc_ids, const VertexPointMap& vpm, + bool do_not_triangulate_faces, std::vector< typename Kernel::Point_3 >& corners, - std::vector< std::array >& out_triangles, + std::vector< boost::container::small_vector >& out_faces, IndexTracking& t_id_tracker) { typedef typename Kernel::Point_3 Point_3; @@ -601,7 +605,7 @@ bool decimate_impl(const TriangleMesh& tm, std::vector< Vector_3 > face_normals(nb_corners_and_nb_cc.second, NULL_VECTOR); // compute the new mesh - std::vector< std::vector< std::array > > triangles_per_cc(nb_corners_and_nb_cc.second); + std::vector< std::vector< boost::container::small_vector > > faces_per_cc(nb_corners_and_nb_cc.second); boost::dynamic_bitset<> cc_to_handle(nb_corners_and_nb_cc.second); cc_to_handle.set(); @@ -659,8 +663,8 @@ bool decimate_impl(const TriangleMesh& tm, cc_id < cc_to_handle.npos; cc_id = cc_to_handle.find_next(cc_id)) { - std::vector< std::array >& triangles = triangles_per_cc[cc_id]; - triangles.clear(); + std::vector< boost::container::small_vector >& cc_faces = faces_per_cc[cc_id]; + cc_faces.clear(); std::vector< Id_pair >& csts = face_boundaries[cc_id]; @@ -676,20 +680,47 @@ bool decimate_impl(const TriangleMesh& tm, #ifdef CGAL_DEBUG_DECIMATION std::cout << "csts.size() " << csts.size() << "\n"; #endif + if (csts.size()==3) { - triangles.push_back( make_array(csts[0].first, - csts[0].second, - csts[0].first==csts[1].first || - csts[0].second==csts[1].first ? - csts[1].second:csts[1].first) ); + cc_faces.push_back( { csts[0].first, + csts[0].second, + csts[0].first==csts[1].first || + csts[0].second==csts[1].first ? + csts[1].second:csts[1].first} ); cc_to_handle.set(cc_id, 0); - t_id_tracker.new_triangle_added_to_patch(cc_id); + t_id_tracker.new_face_added_to_patch(cc_id); } else { - std::size_t prev_triangles_size=triangles.size(); - if (csts.size() > 3 && add_triangle_faces(csts, face_normals[cc_id], corners, triangles)) + std::size_t prev_cc_faces_size=cc_faces.size(); + + if (csts.size() > 3 && do_not_triangulate_faces) + { + // TODO this is not optimal at all since we already have the set of contraints, + // we could work on the graph on constraint and recover only the orientation + // of the edge. To be done if someone find it too slow. + std::vector hborders; + CGAL::Face_filtered_graph ffg(tm, cc_id, face_cc_ids); + extract_boundary_cycles(ffg, std::back_inserter(hborders)); + + if (hborders.size()==1) + { + cc_faces.resize(1); + for (halfedge_descriptor h : halfedges_around_face(hborders[0], ffg)) + { + std::size_t cid = get(vertex_corner_id, target(h, tm)); + if (is_corner_id(cid)) + cc_faces.back().push_back(cid); + } + std::reverse(cc_faces.back().begin(), cc_faces.back().end()); + cc_to_handle.set(cc_id, 0); + t_id_tracker.new_face_added_to_patch(cc_id); + continue; + } + } + + if (csts.size() > 3 && add_triangle_faces(csts, face_normals[cc_id], corners, cc_faces)) cc_to_handle.set(cc_id, 0); else { @@ -716,10 +747,10 @@ bool decimate_impl(const TriangleMesh& tm, for (face_descriptor f : faces(ffg)) { halfedge_descriptor h = halfedge(f, tm); - triangles.push_back({ get(vertex_corner_id, source(h,tm)), - get(vertex_corner_id, target(h,tm)), + cc_faces.push_back({ get(vertex_corner_id, source(h,tm)), + get(vertex_corner_id, target(h,tm)), get(vertex_corner_id, target(next(h,tm), tm)) }); - t_id_tracker.new_triangle_added_to_patch(cc_id); + t_id_tracker.new_face_added_to_patch(cc_id); } // reset flag for neighbor connected components only if interface has changed for (vertex_descriptor v : new_corners) @@ -736,14 +767,15 @@ bool decimate_impl(const TriangleMesh& tm, } cc_to_handle.set(cc_id, 0); } - t_id_tracker.new_triangles_added_to_patch(triangles.size()-prev_triangles_size, cc_id); + t_id_tracker.new_triangles_added_to_patch(cc_faces.size()-prev_cc_faces_size, cc_id); } } } while(cc_to_handle.any()); - for (const std::vector>& cc_trs : triangles_per_cc) - out_triangles.insert(out_triangles.end(), cc_trs.begin(), cc_trs.end()); + + for (const std::vector>& cc_trs : faces_per_cc) + out_faces.insert(out_faces.end(), cc_trs.begin(), cc_trs.end()); return all_patches_successfully_remeshed; } @@ -767,6 +799,7 @@ bool decimate_impl(const TriangleMeshIn& tm_in, FaceCCIdMap& face_cc_ids, const VertexPointMapIn& vpm_in, const VertexPointMapOut& vpm_out, + bool do_not_triangulate_faces, VertexCornerMapOut vcorner_map_out, FacePatchMapOut fpatch_map_out, Visitor& visitor) @@ -775,7 +808,7 @@ bool decimate_impl(const TriangleMeshIn& tm_in, typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename Kernel::Point_3 Point_3; - Triangle_index_tracker + Face_index_tracker t_id_tracker(vcorner_map_out, fpatch_map_out); //collect corners @@ -789,22 +822,25 @@ bool decimate_impl(const TriangleMeshIn& tm_in, } } - std::vector< std::array > triangles; + std::vector< boost::container::small_vector > faces; bool remeshing_failed = decimate_impl(tm_in, nb_corners_and_nb_cc, vertex_corner_id, edge_is_constrained, face_cc_ids, vpm_in, + do_not_triangulate_faces, corners, - triangles, + faces, t_id_tracker); - if (!is_polygon_soup_a_polygon_mesh(triangles)) + if (!is_polygon_soup_a_polygon_mesh(faces)) + { return false; + } visitor(tm_out); - polygon_soup_to_polygon_mesh(corners, triangles, tm_out, + polygon_soup_to_polygon_mesh(corners, faces, tm_out, parameters::vertex_to_vertex_map(t_id_tracker.v2v_map()). face_to_face_map(t_id_tracker.f2f_map()), parameters::vertex_point_map(vpm_out)); @@ -975,7 +1011,8 @@ template & vpms) + const std::vector& vpms, + bool do_not_triangulate_faces) { typedef typename boost::property_traits::value_type Triangle_mesh; typedef typename std::iterator_traits::value_type Mesh_descriptor; @@ -1109,7 +1146,7 @@ bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes, // now call the decimation // storage of all new triangles and all corners std::vector< std::vector< Point_3 > > all_corners(nb_meshes); - std::vector< std::vector< std::array > > all_triangles(nb_meshes); + std::vector< std::vector< boost::container::small_vector > > all_faces(nb_meshes); bool res = true; std::vector to_be_processed(nb_meshes, true); bool loop_again; @@ -1129,7 +1166,7 @@ bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes, to_be_processed[mesh_id]=false; continue; } - all_triangles[mesh_id].clear(); + all_faces[mesh_id].clear(); Triangle_mesh& tm = *mesh_ptrs[mesh_id]; //collect corners @@ -1148,7 +1185,7 @@ bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes, typedef internal_np::Param_not_found PNF; PNF pnf; - Triangle_index_tracker tracker(pnf, pnf); + Face_index_tracker tracker(pnf, pnf); bool all_patches_successfully_remeshed = decimate_impl(tm, nb_corners_and_nb_cc_all[mesh_id], @@ -1156,10 +1193,11 @@ bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes, edge_is_constrained_maps[mesh_id], face_cc_ids_maps[mesh_id], vpms[mesh_id], + do_not_triangulate_faces, corners, - all_triangles[mesh_id], + all_faces[mesh_id], tracker) && - is_polygon_soup_a_polygon_mesh(all_triangles[mesh_id]); + is_polygon_soup_a_polygon_mesh(all_faces[mesh_id]); #ifdef CGAL_DEBUG_DECIMATION std::cout << "all_patches_successfully_remeshed? " << all_patches_successfully_remeshed << "\n"; #endif @@ -1209,11 +1247,11 @@ bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes, no_remeshing_issue = false; continue; } - CGAL_assertion(is_polygon_soup_a_polygon_mesh(all_triangles[mesh_id])); + CGAL_assertion(is_polygon_soup_a_polygon_mesh(all_faces[mesh_id])); //clear(tm); tm.clear_without_removing_property_maps(); - polygon_soup_to_polygon_mesh(all_corners[mesh_id], all_triangles[mesh_id], + polygon_soup_to_polygon_mesh(all_corners[mesh_id], all_faces[mesh_id], tm, parameters::default_values(), parameters::vertex_point_map(vpms[mesh_id])); } @@ -1282,10 +1320,15 @@ bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes, * \cgalParamNEnd * \cgalParamNBegin{cosinus_threshold} * \cgalParamDescription{the cosinus an angle that is used as the lower bound of both the dihedral angle between two adjacent - triangles to consider then as coplanar, and the angle between adjacent segments to consider then as collinear.} + * triangles to consider then as coplanar, and the angle between adjacent segments to consider then as collinear.} * \cgalParamType{`FT` type from the `geom_traits` parameter} * \cgalParamDefault{-1, which means exact coplanarity and collinearity} * \cgalParamNEnd + * \cgalParamNBegin{do_not_triangulate_faces} + * \cgalParamDescription{if `true`, faces of `out` will not be triangulated, but the one with more than one connected component of the boundary.} + * \cgalParamType{`bool`} + * \cgalParamDefault{false} + * \cgalParamNEnd * \cgalNamedParamsEnd * * \param np_out an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below: @@ -1386,6 +1429,8 @@ void remesh_planar_patches(const TriangleMeshIn& tm_in, Planar_segmentation::Default_visitor>::type visitor = choose_parameter>(get_parameter(np_out, internal_np::visitor)); + bool do_not_triangulate_faces = choose_parameter(get_parameter(np_in, internal_np::do_not_triangulate_faces), false); + std::pair nb_corners_and_nb_cc = Planar_segmentation::tag_corners_and_constrained_edges(tm_in, coplanar_cos_threshold, vertex_corner_id, edge_is_constrained, face_cc_ids, vpm_in); Planar_segmentation::decimate_impl(tm_in, tm_out, @@ -1394,6 +1439,7 @@ void remesh_planar_patches(const TriangleMeshIn& tm_in, edge_is_constrained, face_cc_ids, vpm_in, vpm_out, + do_not_triangulate_faces, get_parameter(np_out, internal_np::vertex_corner_map), get_parameter(np_out, internal_np::face_patch), visitor); @@ -1510,7 +1556,7 @@ bool remesh_almost_planar_patches(const TriangleMeshIn& tm_in, #ifndef DOXYGEN_RUNNING // MeshMap must be a mutable lvalue pmap with Triangle_mesh as value_type template -bool decimate_meshes_with_common_interfaces(TriangleMeshRange& meshes, double coplanar_cos_threshold, MeshMap mesh_map) +bool decimate_meshes_with_common_interfaces(TriangleMeshRange& meshes, double coplanar_cos_threshold, MeshMap mesh_map, bool do_not_triangulate_faces=false) { CGAL_assertion(coplanar_cos_threshold<0); typedef typename boost::property_traits::value_type Triangle_mesh; @@ -1525,7 +1571,7 @@ bool decimate_meshes_with_common_interfaces(TriangleMeshRange& meshes, double co for(Mesh_descriptor& md : meshes) vpms.push_back( get(boost::vertex_point, mesh_map[md]) ); - return Planar_segmentation::decimate_meshes_with_common_interfaces_impl(meshes, mesh_map, coplanar_cos_threshold, vpms); + return Planar_segmentation::decimate_meshes_with_common_interfaces_impl(meshes, mesh_map, coplanar_cos_threshold, vpms, do_not_triangulate_faces); } template diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Remesh_planar_patches_dialog.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Remesh_planar_patches_dialog.ui index 22e6f0d9bfc..3794e1f4cfd 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Remesh_planar_patches_dialog.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Remesh_planar_patches_dialog.ui @@ -52,7 +52,7 @@ - false + true Do not triangulate patches diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Remesh_planar_patches_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Remesh_planar_patches_plugin.cpp index adce4fcf693..b899946b0c3 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Remesh_planar_patches_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Remesh_planar_patches_plugin.cpp @@ -102,7 +102,7 @@ public Q_SLOTS: return; } -// bool retriangulate = ui.notriangulation_checkbox->isChecked(); + bool do_not_triangulate_faces = ui.notriangulation_checkbox->isChecked(); double cos_threshold = ui.cos_dspinbox->value(); std::vector meshes; @@ -128,7 +128,7 @@ public Q_SLOTS: } }; - CGAL::Polygon_mesh_processing::decimate_meshes_with_common_interfaces(meshes, cos_threshold, Mesh_map()); + CGAL::Polygon_mesh_processing::decimate_meshes_with_common_interfaces(meshes, cos_threshold, Mesh_map(), do_not_triangulate_faces); for (Scene_surface_mesh_item* poly_item : meshes) { @@ -160,7 +160,7 @@ public Q_SLOTS: return; } -// bool retriangulate = ui.notriangulation_checkbox->isChecked(); + bool do_not_triangulate_faces = ui.notriangulation_checkbox->isChecked(); bool create_new_item = ui.create_new_item_checkbox->isChecked(); double cos_threshold = ui.cos_dspinbox->value(); @@ -202,7 +202,9 @@ public Q_SLOTS: CGAL::Polygon_mesh_processing::remesh_planar_patches(pmesh, out, - CGAL::parameters::cosinus_threshold(cos_threshold).face_patch_map(in_fpmap), + CGAL::parameters::cosinus_threshold(cos_threshold) + .face_patch_map(in_fpmap) + .do_not_triangulate_faces(do_not_triangulate_faces), CGAL::parameters::face_patch_map(out_fpmap)); @@ -224,7 +226,8 @@ public Q_SLOTS: { CGAL::Polygon_mesh_processing::remesh_planar_patches(pmesh, pmesh, - CGAL::parameters::cosinus_threshold(cos_threshold), + CGAL::parameters::cosinus_threshold(cos_threshold) + .do_not_triangulate_faces(do_not_triangulate_faces), CGAL::parameters::visitor([](Mesh& pmesh){pmesh.clear_without_removing_property_maps ();})); poly_item->invalidateOpenGLBuffers(); diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index 005df4eafa3..8b86278a29c 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -68,6 +68,7 @@ CGAL_add_named_parameter(vertex_incident_patches_t, vertex_incident_patches, ver CGAL_add_named_parameter(density_control_factor_t, density_control_factor, density_control_factor) CGAL_add_named_parameter(use_delaunay_triangulation_t, use_delaunay_triangulation, use_delaunay_triangulation) CGAL_add_named_parameter(do_not_use_cubic_algorithm_t, do_not_use_cubic_algorithm, do_not_use_cubic_algorithm) +CGAL_add_named_parameter(do_not_triangulate_faces_t, do_not_triangulate_faces, do_not_triangulate_faces) CGAL_add_named_parameter(use_2d_constrained_delaunay_triangulation_t, use_2d_constrained_delaunay_triangulation, use_2d_constrained_delaunay_triangulation) CGAL_add_named_parameter(fairing_continuity_t, fairing_continuity, fairing_continuity) CGAL_add_named_parameter(sparse_linear_solver_t, sparse_linear_solver, sparse_linear_solver)