implement API update

This commit is contained in:
Sébastien Loriot 2023-02-10 16:09:44 +01:00
parent 7e38151479
commit 88bb9570c0
3 changed files with 264 additions and 126 deletions

View File

@ -4,6 +4,7 @@
#include <CGAL/Polygon_mesh_processing/remesh.h> #include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/Polygon_mesh_processing/detect_features.h> #include <CGAL/Polygon_mesh_processing/detect_features.h>
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h> #include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@ -17,8 +18,7 @@ namespace PMP = CGAL::Polygon_mesh_processing;
int main() int main()
{ {
Surface_mesh sm; Surface_mesh sm;
std::ifstream in("data/cube_quad.off"); CGAL::IO::read_polygon_mesh(CGAL::data_file_path("meshes/cube_quad.off"), sm);
in >> sm;
// triangulate faces; // triangulate faces;
PMP::triangulate_faces(sm); PMP::triangulate_faces(sm);
@ -36,11 +36,12 @@ int main()
assert(faces(sm).size()>100); assert(faces(sm).size()>100);
// decimate the mesh // decimate the mesh
PMP::remesh_planar_patches(sm); Surface_mesh out;
std::ofstream("cube_decimated.off") << sm; PMP::remesh_planar_patches(sm, out);
std::ofstream("cube_decimated.off") << out;
// we should be back to 12 faces // we should be back to 12 faces
assert(faces(sm).size()==12); assert(faces(out).size()==12);
return 0; return 0;
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018 GeometryFactory (France). // Copyright (c) 2018-2023 GeometryFactory (France).
// All rights reserved. // All rights reserved.
// //
// This file is part of CGAL (www.cgal.org). // This file is part of CGAL (www.cgal.org).
@ -8,7 +8,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
// //
// //
// Author(s) : Sebastien Loriot // Author(s) : Sébastien Loriot
#ifndef CGAL_POLYGON_MESH_PROCESSING_REMESH_PLANAR_PATCHES_H #ifndef CGAL_POLYGON_MESH_PROCESSING_REMESH_PLANAR_PATCHES_H
#define CGAL_POLYGON_MESH_PROCESSING_REMESH_PLANAR_PATCHES_H #define CGAL_POLYGON_MESH_PROCESSING_REMESH_PLANAR_PATCHES_H
@ -27,19 +27,98 @@
#include <CGAL/boost/graph/properties.h> #include <CGAL/boost/graph/properties.h>
#include <unordered_map> #include <unordered_map>
#include <boost/dynamic_bitset.hpp> #include <boost/dynamic_bitset.hpp>
#include <boost/iterator/function_output_iterator.hpp>
#include <algorithm> #include <algorithm>
/// @todo remove Kernel_traits
/// @todo function to move in PMP: retriangulate_planar_patches(in, out, vci, ecm, fccid, np) (pca is a np option)
namespace CGAL{ namespace CGAL{
namespace Polygon_mesh_processing { namespace Polygon_mesh_processing {
namespace Planar_segmentation{ namespace Planar_segmentation{
template <class TriangleMeshOut, class VertexCornerMapOut>
struct Triangle_index_tracker_base
{
typedef boost::graph_traits<TriangleMeshOut> GT;
Triangle_index_tracker_base(VertexCornerMapOut vertex_corner_map)
: vertex_corner_map(vertex_corner_map)
{}
decltype(auto)
v2v_oi()
{
auto l = [this](const std::pair<std::size_t, typename GT::vertex_descriptor>& p)
{
put(vertex_corner_map, p.second, p.first);
};
return boost::make_function_output_iterator(l);
}
VertexCornerMapOut vertex_corner_map;
};
template <class TriangleMeshOut>
struct Triangle_index_tracker_base<TriangleMeshOut, internal_np::Param_not_found>
{
typedef boost::graph_traits<TriangleMeshOut> GT;
Triangle_index_tracker_base(internal_np::Param_not_found) {}
Emptyset_iterator v2v_oi() { return Emptyset_iterator(); }
};
template <class TriangleMeshOut, class VertexCornerMapOut, class FacePatchMapOut>
struct Triangle_index_tracker
: public Triangle_index_tracker_base<TriangleMeshOut, VertexCornerMapOut>
{
typedef boost::graph_traits<TriangleMeshOut> GT;
Triangle_index_tracker(VertexCornerMapOut vertex_corner_map, FacePatchMapOut face_patch_map)
: Triangle_index_tracker_base<TriangleMeshOut, VertexCornerMapOut>(vertex_corner_map)
, face_patch_map(face_patch_map)
{}
std::vector<std::size_t> triangle_ids;
void new_triangle_added_to_patch(std::size_t i)
{
triangle_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);
}
decltype(auto)
f2f_oi()
{
auto l = [this](const std::pair<std::size_t, typename GT::face_descriptor>& p)
{
put(face_patch_map, p.second, triangle_ids[p.first]);
};
return boost::make_function_output_iterator(l);
}
FacePatchMapOut face_patch_map;
};
template <class TriangleMeshOut, class VertexCornerMapOut>
struct Triangle_index_tracker<TriangleMeshOut, VertexCornerMapOut, internal_np::Param_not_found>
: public Triangle_index_tracker_base<TriangleMeshOut, VertexCornerMapOut>
{
Triangle_index_tracker(VertexCornerMapOut vertex_corner_map,internal_np::Param_not_found)
: Triangle_index_tracker_base<TriangleMeshOut, VertexCornerMapOut>(vertex_corner_map)
{}
void new_triangle_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*/) {}
Emptyset_iterator f2f_oi() { return Emptyset_iterator(); }
};
inline std::size_t init_id() inline std::size_t init_id()
{ {
return std::size_t(-1); return std::size_t(-1);
@ -85,7 +164,8 @@ struct FaceInfo2
bool in_domain() const { return m_in_domain==1; } bool in_domain() const { return m_in_domain==1; }
}; };
template <typename TriangleMesh, template <typename Kernel,
typename TriangleMesh,
typename VertexPointMap, typename VertexPointMap,
typename edge_descriptor> typename edge_descriptor>
bool is_edge_between_coplanar_faces(edge_descriptor e, bool is_edge_between_coplanar_faces(edge_descriptor e,
@ -93,8 +173,7 @@ bool is_edge_between_coplanar_faces(edge_descriptor e,
double coplanar_cos_threshold, double coplanar_cos_threshold,
const VertexPointMap& vpm) const VertexPointMap& vpm)
{ {
typedef typename boost::property_traits<VertexPointMap>::value_type Point_3; typedef typename Kernel::Point_3 Point_3;
typedef typename Kernel_traits<Point_3>::type K;
typedef typename boost::property_traits<VertexPointMap>::reference Point_ref_3; typedef typename boost::property_traits<VertexPointMap>::reference Point_ref_3;
if (is_border(e, tm)) return false; if (is_border(e, tm)) return false;
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor typename boost::graph_traits<TriangleMesh>::halfedge_descriptor
@ -108,12 +187,13 @@ bool is_edge_between_coplanar_faces(edge_descriptor e,
return coplanar(p, q, r, s); return coplanar(p, q, r, s);
else else
{ {
typename K::Compare_dihedral_angle_3 pred; typename Kernel::Compare_dihedral_angle_3 pred;
return pred(p, q, r, s, typename K::FT(coplanar_cos_threshold)) == CGAL::LARGER; return pred(p, q, r, s, typename Kernel::FT(coplanar_cos_threshold)) == CGAL::LARGER;
} }
} }
template <typename TriangleMesh, template <typename Kernel,
typename TriangleMesh,
typename VertexPointMap, typename VertexPointMap,
typename halfedge_descriptor, typename halfedge_descriptor,
typename EdgeIsConstrainedMap> typename EdgeIsConstrainedMap>
@ -123,8 +203,7 @@ bool is_target_vertex_a_corner(halfedge_descriptor h,
double coplanar_cos_threshold, double coplanar_cos_threshold,
const VertexPointMap& vpm) const VertexPointMap& vpm)
{ {
typedef typename boost::property_traits<VertexPointMap>::value_type Point_3; typedef typename Kernel::Point_3 Point_3;
typedef typename Kernel_traits<Point_3>::type K;
typedef typename boost::graph_traits<TriangleMesh> graph_traits; typedef typename boost::graph_traits<TriangleMesh> graph_traits;
halfedge_descriptor h2 = graph_traits::null_halfedge(); halfedge_descriptor h2 = graph_traits::null_halfedge();
@ -150,12 +229,13 @@ bool is_target_vertex_a_corner(halfedge_descriptor h,
return !collinear(p, q, r); return !collinear(p, q, r);
else else
{ {
typename K::Compare_angle_3 pred; typename Kernel::Compare_angle_3 pred;
return pred(p, q, r, typename K::FT(coplanar_cos_threshold))==CGAL::SMALLER; return pred(p, q, r, typename Kernel::FT(coplanar_cos_threshold))==CGAL::SMALLER;
} }
} }
template <typename TriangleMesh, template <typename Kernel,
typename TriangleMesh,
typename EdgeIsConstrainedMap, typename EdgeIsConstrainedMap,
typename VertexPointMap> typename VertexPointMap>
void void
@ -168,12 +248,13 @@ mark_constrained_edges(
for(typename boost::graph_traits<TriangleMesh>::edge_descriptor e : edges(tm)) for(typename boost::graph_traits<TriangleMesh>::edge_descriptor e : edges(tm))
{ {
if (!get(edge_is_constrained,e)) if (!get(edge_is_constrained,e))
if (!is_edge_between_coplanar_faces(e, tm, coplanar_cos_threshold, vpm)) if (!is_edge_between_coplanar_faces<Kernel>(e, tm, coplanar_cos_threshold, vpm))
put(edge_is_constrained, e, true); put(edge_is_constrained, e, true);
} }
} }
template <typename TriangleMesh, template <typename Kernel,
typename TriangleMesh,
typename VertexPointMap, typename VertexPointMap,
typename EdgeIsConstrainedMap, typename EdgeIsConstrainedMap,
typename VertexCornerIdMap> typename VertexCornerIdMap>
@ -194,14 +275,14 @@ mark_corner_vertices(
if (is_init_id(get(vertex_corner_id, target(h, tm)))) if (is_init_id(get(vertex_corner_id, target(h, tm))))
{ {
if (is_target_vertex_a_corner(h, edge_is_constrained, tm, coplanar_cos_threshold, vpm)) if (is_target_vertex_a_corner<Kernel>(h, edge_is_constrained, tm, coplanar_cos_threshold, vpm))
put(vertex_corner_id, target(h, tm), corner_id++); put(vertex_corner_id, target(h, tm), corner_id++);
else else
put(vertex_corner_id, target(h, tm), default_id()); put(vertex_corner_id, target(h, tm), default_id());
} }
if (is_init_id(get(vertex_corner_id, source(h, tm)))) if (is_init_id(get(vertex_corner_id, source(h, tm))))
{ {
if (is_target_vertex_a_corner(opposite(h, tm), edge_is_constrained, tm, coplanar_cos_threshold, vpm)) if (is_target_vertex_a_corner<Kernel>(opposite(h, tm), edge_is_constrained, tm, coplanar_cos_threshold, vpm))
put(vertex_corner_id, source(h, tm), corner_id++); put(vertex_corner_id, source(h, tm), corner_id++);
else else
put(vertex_corner_id, source(h, tm), default_id()); put(vertex_corner_id, source(h, tm), default_id());
@ -301,7 +382,7 @@ template <typename Kernel>
bool add_triangle_faces(const std::vector< std::pair<std::size_t, std::size_t> >& csts, bool add_triangle_faces(const std::vector< std::pair<std::size_t, std::size_t> >& csts,
typename Kernel::Vector_3 normal, typename Kernel::Vector_3 normal,
const std::vector<typename Kernel::Point_3>& corners, const std::vector<typename Kernel::Point_3>& corners,
std::vector<cpp11::array<std::size_t, 3> >& triangles) std::vector<std::array<std::size_t, 3> >& triangles)
{ {
typedef Projection_traits_3<Kernel> P_traits; typedef Projection_traits_3<Kernel> P_traits;
typedef Triangulation_vertex_base_with_id_2<P_traits> Vb; typedef Triangulation_vertex_base_with_id_2<P_traits> Vb;
@ -400,7 +481,8 @@ bool add_triangle_faces(const std::vector< std::pair<std::size_t, std::size_t> >
return true; return true;
} }
template <typename TriangleMesh, template <typename Kernel,
typename TriangleMesh,
typename VertexCornerIdMap, typename VertexCornerIdMap,
typename EdgeIsConstrainedMap, typename EdgeIsConstrainedMap,
typename FaceCCIdMap, typename FaceCCIdMap,
@ -415,7 +497,7 @@ tag_corners_and_constrained_edges(TriangleMesh& tm,
{ {
typedef typename boost::graph_traits<TriangleMesh> graph_traits; typedef typename boost::graph_traits<TriangleMesh> graph_traits;
// mark constrained edges // mark constrained edges
mark_constrained_edges(tm, edge_is_constrained, coplanar_cos_threshold, vpm); mark_constrained_edges<Kernel>(tm, edge_is_constrained, coplanar_cos_threshold, vpm);
// mark connected components (cc) delimited by constrained edges // mark connected components (cc) delimited by constrained edges
std::size_t nb_cc = Polygon_mesh_processing::connected_components( std::size_t nb_cc = Polygon_mesh_processing::connected_components(
@ -435,40 +517,39 @@ tag_corners_and_constrained_edges(TriangleMesh& tm,
} }
std::size_t nb_corners = std::size_t nb_corners =
mark_corner_vertices(tm, edge_is_constrained, vertex_corner_id, coplanar_cos_threshold, vpm); mark_corner_vertices<Kernel>(tm, edge_is_constrained, vertex_corner_id, coplanar_cos_threshold, vpm);
return std::make_pair(nb_corners, nb_cc); return std::make_pair(nb_corners, nb_cc);
} }
template <typename TriangleMesh, template <typename Kernel,
typename TriangleMesh,
typename VertexCornerIdMap, typename VertexCornerIdMap,
typename EdgeIsConstrainedMap, typename EdgeIsConstrainedMap,
typename FaceCCIdMap, typename FaceCCIdMap,
typename VertexPointMap, typename VertexPointMap,
typename Point_3> typename IndexTracking>
bool decimate_impl(const TriangleMesh& tm, bool decimate_impl(const TriangleMesh& tm,
std::pair<std::size_t, std::size_t>& nb_corners_and_nb_cc, std::pair<std::size_t, std::size_t>& nb_corners_and_nb_cc,
VertexCornerIdMap& vertex_corner_id, VertexCornerIdMap& vertex_corner_id,
EdgeIsConstrainedMap& edge_is_constrained, EdgeIsConstrainedMap& edge_is_constrained,
FaceCCIdMap& face_cc_ids, FaceCCIdMap& face_cc_ids,
const VertexPointMap& vpm, const VertexPointMap& vpm,
std::vector< Point_3 >& corners, std::vector< typename Kernel::Point_3 >& corners,
std::vector< cpp11::array<std::size_t, 3> >& out_triangles) std::vector< std::array<std::size_t, 3> >& out_triangles,
IndexTracking& t_id_tracker)
{ {
typedef typename Kernel_traits<Point_3>::type K; typedef typename Kernel::Point_3 Point_3;
typedef typename Kernel::Vector_3 Vector_3;
typedef typename boost::graph_traits<TriangleMesh> graph_traits; typedef typename boost::graph_traits<TriangleMesh> graph_traits;
typedef typename graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename graph_traits::halfedge_descriptor halfedge_descriptor;
typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::vertex_descriptor vertex_descriptor;
typedef typename graph_traits::face_descriptor face_descriptor; typedef typename graph_traits::face_descriptor face_descriptor;
typedef std::pair<std::size_t, std::size_t> Id_pair; typedef std::pair<std::size_t, std::size_t> Id_pair;
std::vector< typename K::Vector_3 > face_normals(nb_corners_and_nb_cc.second, NULL_VECTOR); std::vector< Vector_3 > face_normals(nb_corners_and_nb_cc.second, NULL_VECTOR);
/// @TODO this is rather drastic in particular if the mesh has almost none simplified faces
/// TODO use add_faces?
// compute the new mesh // compute the new mesh
std::vector< std::vector< cpp11::array<std::size_t, 3> > > triangles_per_cc(nb_corners_and_nb_cc.second); std::vector< std::vector< std::array<std::size_t, 3> > > triangles_per_cc(nb_corners_and_nb_cc.second);
boost::dynamic_bitset<> cc_to_handle(nb_corners_and_nb_cc.second); boost::dynamic_bitset<> cc_to_handle(nb_corners_and_nb_cc.second);
cc_to_handle.set(); cc_to_handle.set();
@ -526,7 +607,7 @@ bool decimate_impl(const TriangleMesh& tm,
cc_id < cc_to_handle.npos; cc_id < cc_to_handle.npos;
cc_id = cc_to_handle.find_next(cc_id)) cc_id = cc_to_handle.find_next(cc_id))
{ {
std::vector< cpp11::array<std::size_t, 3> >& triangles = triangles_per_cc[cc_id]; std::vector< std::array<std::size_t, 3> >& triangles = triangles_per_cc[cc_id];
triangles.clear(); triangles.clear();
std::vector< Id_pair >& csts = face_boundaries[cc_id]; std::vector< Id_pair >& csts = face_boundaries[cc_id];
@ -551,10 +632,12 @@ bool decimate_impl(const TriangleMesh& tm,
csts[0].second==csts[1].first ? csts[0].second==csts[1].first ?
csts[1].second:csts[1].first) ); csts[1].second:csts[1].first) );
cc_to_handle.set(cc_id, 0); cc_to_handle.set(cc_id, 0);
t_id_tracker.new_triangle_added_to_patch(cc_id);
} }
else else
{ {
if (csts.size() > 3 && add_triangle_faces<K>(csts, face_normals[cc_id], corners, triangles)) std::size_t prev_triangles_size=triangles.size();
if (csts.size() > 3 && add_triangle_faces<Kernel>(csts, face_normals[cc_id], corners, triangles))
cc_to_handle.set(cc_id, 0); cc_to_handle.set(cc_id, 0);
else else
{ {
@ -571,7 +654,8 @@ bool decimate_impl(const TriangleMesh& tm,
std::size_t i = get(vertex_corner_id, v); std::size_t i = get(vertex_corner_id, v);
if ( !is_corner_id(i) ) if ( !is_corner_id(i) )
{ {
put(vertex_corner_id, v, nb_corners_and_nb_cc.first++); i = nb_corners_and_nb_cc.first++;
put(vertex_corner_id, v, i);
corners.push_back(get(vpm, v)); corners.push_back(get(vpm, v));
new_corners.push_back(v); new_corners.push_back(v);
} }
@ -583,6 +667,7 @@ bool decimate_impl(const TriangleMesh& tm,
triangles.push_back({ get(vertex_corner_id, source(h,tm)), triangles.push_back({ get(vertex_corner_id, source(h,tm)),
get(vertex_corner_id, target(h,tm)), get(vertex_corner_id, target(h,tm)),
get(vertex_corner_id, target(next(h,tm), tm)) }); get(vertex_corner_id, target(next(h,tm), tm)) });
t_id_tracker.new_triangle_added_to_patch(cc_id);
} }
// reset flag for neighbor connected components only if interface has changed // reset flag for neighbor connected components only if interface has changed
for (vertex_descriptor v : new_corners) for (vertex_descriptor v : new_corners)
@ -599,58 +684,75 @@ bool decimate_impl(const TriangleMesh& tm,
} }
cc_to_handle.set(cc_id, 0); cc_to_handle.set(cc_id, 0);
} }
t_id_tracker.new_triangles_added_to_patch(triangles.size()-prev_triangles_size, cc_id);
} }
} }
} }
while(cc_to_handle.any()); while(cc_to_handle.any());
for (const std::vector<cpp11::array<std::size_t, 3>>& cc_trs : triangles_per_cc) for (const std::vector<std::array<std::size_t, 3>>& cc_trs : triangles_per_cc)
out_triangles.insert(out_triangles.end(), cc_trs.begin(), cc_trs.end()); out_triangles.insert(out_triangles.end(), cc_trs.begin(), cc_trs.end());
return all_patches_successfully_remeshed; return all_patches_successfully_remeshed;
} }
template <typename TriangleMesh, template <typename Kernel,
typename TriangleMeshIn,
typename TriangleMeshOut,
typename VertexCornerIdMap, typename VertexCornerIdMap,
typename EdgeIsConstrainedMap, typename EdgeIsConstrainedMap,
typename FaceCCIdMap, typename FaceCCIdMap,
typename VertexPointMap> typename VertexPointMapIn,
bool decimate_impl(TriangleMesh& tm, typename VertexPointMapOut,
typename VertexCornerMapOut,
typename FacePatchMapOut>
bool decimate_impl(const TriangleMeshIn& tm_in,
TriangleMeshOut& tm_out,
std::pair<std::size_t, std::size_t> nb_corners_and_nb_cc, std::pair<std::size_t, std::size_t> nb_corners_and_nb_cc,
VertexCornerIdMap& vertex_corner_id, VertexCornerIdMap& vertex_corner_id,
EdgeIsConstrainedMap& edge_is_constrained, EdgeIsConstrainedMap& edge_is_constrained,
FaceCCIdMap& face_cc_ids, FaceCCIdMap& face_cc_ids,
const VertexPointMap& vpm) const VertexPointMapIn& vpm_in,
const VertexPointMapOut& vpm_out,
VertexCornerMapOut vcorner_map_out,
FacePatchMapOut fpatch_map_out)
{ {
typedef typename boost::graph_traits<TriangleMesh> graph_traits; typedef typename boost::graph_traits<TriangleMeshIn> graph_traits;
typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::vertex_descriptor vertex_descriptor;
typedef typename boost::property_traits<VertexPointMap>::value_type Point_3; typedef typename Kernel::Point_3 Point_3;
Triangle_index_tracker<TriangleMeshOut, VertexCornerMapOut, FacePatchMapOut>
t_id_tracker(vcorner_map_out, fpatch_map_out);
//collect corners //collect corners
std::vector< Point_3 > corners(nb_corners_and_nb_cc.first); std::vector< Point_3 > corners(nb_corners_and_nb_cc.first);
for(vertex_descriptor v : vertices(tm)) for(vertex_descriptor v : vertices(tm_in))
{ {
std::size_t i = get(vertex_corner_id, v); std::size_t i = get(vertex_corner_id, v);
if ( is_corner_id(i) ) if ( is_corner_id(i) )
corners[i]=get(vpm, v); {
corners[i]=get(vpm_in, v);
}
} }
std::vector< cpp11::array<std::size_t, 3> > triangles; std::vector< std::array<std::size_t, 3> > triangles;
bool remeshing_failed = decimate_impl(tm, bool remeshing_failed = decimate_impl<Kernel>(tm_in,
nb_corners_and_nb_cc, nb_corners_and_nb_cc,
vertex_corner_id, vertex_corner_id,
edge_is_constrained, edge_is_constrained,
face_cc_ids, face_cc_ids,
vpm, vpm_in,
corners, corners,
triangles); triangles,
t_id_tracker);
if (!is_polygon_soup_a_polygon_mesh(triangles)) if (!is_polygon_soup_a_polygon_mesh(triangles))
return false; return false;
//clear(tm); polygon_soup_to_polygon_mesh(corners, triangles, tm_out,
tm.clear_without_removing_property_maps(); parameters::vertex_to_vertex_output_iterator(t_id_tracker.v2v_oi()).
polygon_soup_to_polygon_mesh(corners, triangles, tm, parameters::all_default(), parameters::vertex_point_map(vpm)); face_to_face_output_iterator(t_id_tracker.f2f_oi()),
parameters::vertex_point_map(vpm_out));
return remeshing_failed; return remeshing_failed;
} }
@ -811,7 +913,8 @@ void propagate_corner_status(
} }
} }
template <typename TriangleMeshRange, template <typename Kernel,
typename TriangleMeshRange,
typename MeshMap, typename MeshMap,
typename VertexPointMap> typename VertexPointMap>
bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes, bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes,
@ -922,7 +1025,7 @@ bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes,
if (!mesh_has_non_manifold_vertices[mesh_id]) if (!mesh_has_non_manifold_vertices[mesh_id])
nb_corners_and_nb_cc_all[mesh_id] = nb_corners_and_nb_cc_all[mesh_id] =
tag_corners_and_constrained_edges(tm, tag_corners_and_constrained_edges<Kernel>(tm,
coplanar_cos_threshold, coplanar_cos_threshold,
vertex_corner_id_maps[mesh_id], vertex_corner_id_maps[mesh_id],
edge_is_constrained_maps[mesh_id], edge_is_constrained_maps[mesh_id],
@ -951,7 +1054,7 @@ bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes,
// now call the decimation // now call the decimation
// storage of all new triangles and all corners // storage of all new triangles and all corners
std::vector< std::vector< Point_3 > > all_corners(nb_meshes); std::vector< std::vector< Point_3 > > all_corners(nb_meshes);
std::vector< std::vector< cpp11::array<std::size_t, 3> > > all_triangles(nb_meshes); std::vector< std::vector< std::array<std::size_t, 3> > > all_triangles(nb_meshes);
bool res = true; bool res = true;
std::vector<bool> to_be_processed(nb_meshes, true); std::vector<bool> to_be_processed(nb_meshes, true);
bool loop_again; bool loop_again;
@ -1162,45 +1265,68 @@ void remesh_planar_patches(const TriangleMeshIn& tm_in,
const NamedParametersIn& np_in = parameters::default_values(), const NamedParametersIn& np_in = parameters::default_values(),
const NamedParametersOut& np_out = parameters::default_values()) const NamedParametersOut& np_out = parameters::default_values())
{ {
/* //TODO: demo plugin
// typedef typename GetGeomTraits<TriangleMesh, NamedParameters>::type Traits;
typedef typename GetVertexPointMap <TriangleMesh, NamedParameters>::type VPM; typedef typename GetGeomTraits<TriangleMeshIn, NamedParametersIn>::type Traits;
typedef typename GetVertexPointMap <TriangleMeshIn, NamedParametersIn>::const_type VPM_in;
typedef typename GetVertexPointMap <TriangleMeshIn, NamedParametersOut>::type VPM_out;
using parameters::choose_parameter; using parameters::choose_parameter;
using parameters::get_parameter; using parameters::get_parameter;
typedef typename boost::graph_traits<TriangleMesh> graph_traits; typedef typename boost::graph_traits<TriangleMeshIn> graph_traits;
typedef typename graph_traits::edge_descriptor edge_descriptor; typedef typename graph_traits::edge_descriptor edge_descriptor;
typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::vertex_descriptor vertex_descriptor;
typedef typename graph_traits::face_descriptor face_descriptor; typedef typename graph_traits::face_descriptor face_descriptor;
double coplanar_cos_threshold = choose_parameter(get_parameter(np, internal_np::cosinus_threshold), -1); double coplanar_cos_threshold = choose_parameter(get_parameter(np_in, internal_np::cosinus_threshold), -1);
CGAL_precondition(coplanar_cos_threshold<0); CGAL_precondition(coplanar_cos_threshold<0);
// initialize property maps // initialize property maps (fill user provided or user internal ones)
typename boost::property_map<TriangleMesh, CGAL::dynamic_edge_property_t<bool> >::type edge_is_constrained = get(CGAL::dynamic_edge_property_t<bool>(), tm); typedef typename boost::property_map<TriangleMeshIn,
for(edge_descriptor e : edges(tm)) dynamic_edge_property_t<bool> >::const_type Default_ECM;
put(edge_is_constrained, e, false); typedef typename boost::property_map<TriangleMeshIn,
dynamic_vertex_property_t<std::size_t> >::const_type Default_VCM;
typedef typename boost::property_map<TriangleMeshIn,
dynamic_face_property_t<std::size_t> >::const_type Default_FCM;
typename boost::property_map<TriangleMesh, CGAL::dynamic_vertex_property_t<std::size_t> >::type vertex_corner_id = get(CGAL::dynamic_vertex_property_t<std::size_t>(), tm); typename internal_np::Lookup_named_param_def< internal_np::edge_is_constrained_t,
for(vertex_descriptor v : vertices(tm)) NamedParametersIn,
put(vertex_corner_id, v, Planar_segmentation::init_id()); Default_ECM>::type
edge_is_constrained = choose_parameter<Default_ECM>(get_parameter(np_in, internal_np::edge_is_constrained),
dynamic_edge_property_t<bool>(), tm_in);
typename boost::property_map<TriangleMesh, CGAL::dynamic_face_property_t<std::size_t> >::type face_cc_ids = get(CGAL::dynamic_face_property_t<std::size_t>(), tm); typename internal_np::Lookup_named_param_def< internal_np::vertex_corner_map_t,
for(face_descriptor f : faces(tm)) NamedParametersIn,
put(face_cc_ids, f, -1); Default_VCM>::type
vertex_corner_id = choose_parameter<Default_VCM>(get_parameter(np_in, internal_np::vertex_corner_map),
dynamic_vertex_property_t<std::size_t>(), tm_in);
VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), typename internal_np::Lookup_named_param_def< internal_np::face_patch_t,
get_property_map(vertex_point, tm)); NamedParametersIn,
Default_FCM>::type
face_cc_ids = choose_parameter<Default_FCM>(get_parameter(np_in, internal_np::face_patch),
dynamic_face_property_t<std::size_t>(), tm_in);
for(edge_descriptor e : edges(tm_in)) put(edge_is_constrained, e, false);
for(vertex_descriptor v : vertices(tm_in)) put(vertex_corner_id, v, Planar_segmentation::init_id());
for(face_descriptor f : faces(tm_in)) put(face_cc_ids, f, -1);
VPM_in vpm_in = choose_parameter(get_parameter(np_in, internal_np::vertex_point),
get_const_property_map(vertex_point, tm_in));
VPM_out vpm_out = choose_parameter(get_parameter(np_out, internal_np::vertex_point),
get_property_map(vertex_point, tm_out));
std::pair<std::size_t, std::size_t> nb_corners_and_nb_cc = std::pair<std::size_t, std::size_t> nb_corners_and_nb_cc =
Planar_segmentation::tag_corners_and_constrained_edges(tm, coplanar_cos_threshold, vertex_corner_id, edge_is_constrained, face_cc_ids, vpm); Planar_segmentation::tag_corners_and_constrained_edges<Traits>(tm_in, coplanar_cos_threshold, vertex_corner_id, edge_is_constrained, face_cc_ids, vpm_in);
Planar_segmentation::decimate_impl(tm, Planar_segmentation::decimate_impl<Traits>(tm_in, tm_out,
nb_corners_and_nb_cc, nb_corners_and_nb_cc,
vertex_corner_id, vertex_corner_id,
edge_is_constrained, edge_is_constrained,
face_cc_ids, face_cc_ids,
vpm); vpm_in, vpm_out,
*/ get_parameter(np_out, internal_np::vertex_corner_map),
get_parameter(np_out, internal_np::face_patch));
} }
/*! /*!
@ -1280,7 +1406,8 @@ template <typename TriangleMeshIn,
typename FacePatchMap, typename FacePatchMap,
typename EdgeIsConstrainedMap, typename EdgeIsConstrainedMap,
typename VertexCornerMap, typename VertexCornerMap,
typename NamedParameters = parameters::Default_named_parameters> typename NamedParametersIn = parameters::Default_named_parameters,
typename NamedParametersOut = parameters::Default_named_parameters>
bool remesh_almost_planar_patches(const TriangleMeshIn& tm_in, bool remesh_almost_planar_patches(const TriangleMeshIn& tm_in,
TriangleMeshOut& tm_out, TriangleMeshOut& tm_out,
std::size_t nb_patches, std::size_t nb_patches,
@ -1291,21 +1418,25 @@ bool remesh_almost_planar_patches(const TriangleMeshIn& tm_in,
const NamedParametersIn& np_in = parameters::default_values(), const NamedParametersIn& np_in = parameters::default_values(),
const NamedParametersOut& np_out = parameters::default_values()) const NamedParametersOut& np_out = parameters::default_values())
{ {
/* typedef typename GetGeomTraits<TriangleMeshIn, NamedParametersIn>::type Traits;
typedef typename GetVertexPointMap <TriangleMesh, NamedParameters>::type VPM; typedef typename GetVertexPointMap <TriangleMeshIn, NamedParametersIn>::const_type VPM_in;
typedef typename GetVertexPointMap <TriangleMeshIn, NamedParametersOut>::type VPM_out;
using parameters::choose_parameter; using parameters::choose_parameter;
using parameters::get_parameter; using parameters::get_parameter;
VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), VPM_in vpm_in = choose_parameter(get_parameter(np_in, internal_np::vertex_point),
get_property_map(vertex_point, tm)); get_const_property_map(vertex_point, tm_in));
return Planar_segmentation::decimate_impl(tm, VPM_out vpm_out = choose_parameter(get_parameter(np_out, internal_np::vertex_point),
get_property_map(vertex_point, tm_out));
return Planar_segmentation::decimate_impl<Traits>(tm_in, tm_out,
std::make_pair(nb_corners, nb_patches), std::make_pair(nb_corners, nb_patches),
vertex_corner_map, ecm, face_patch_map, vpm); vertex_corner_map, ecm, face_patch_map, vpm_in, vpm_out,
*/ get_parameter(np_out, internal_np::vertex_corner_map),
get_parameter(np_out, internal_np::face_patch));
} }
#ifndef DOXYGEN_RUNNING #ifndef DOXYGEN_RUNNING
// MeshMap must be a mutable lvalue pmap with Triangle_mesh as value_type // MeshMap must be a mutable lvalue pmap with Triangle_mesh as value_type
template <typename TriangleMeshRange, typename MeshMap> template <typename TriangleMeshRange, typename MeshMap>

View File

@ -38,7 +38,8 @@ int main()
in >> sm; in >> sm;
// call the decimation function // call the decimation function
if (!PMP::remesh_planar_patches(sm)) Surface_mesh out;
if (!PMP::remesh_planar_patches(sm, out))
{ {
std::cerr << "ERROR: decimate failed to remesh some patches\n"; std::cerr << "ERROR: decimate failed to remesh some patches\n";
OK=false; OK=false;
@ -46,9 +47,9 @@ int main()
ss=std::stringstream(); ss=std::stringstream();
ss << "out" << i << ".off"; ss << "out" << i << ".off";
std::ofstream out(ss.str().c_str()); std::ofstream out(ss.str().c_str());
out << sm; out << out;
std::cout << " output written to out" << i << ".off\n"; std::cout << " output written to out" << i << ".off\n";
assert(is_valid_polygon_mesh(sm)); assert(is_valid_polygon_mesh(out));
} }
// testing border non-manifold vertex: not working for now, test kept // testing border non-manifold vertex: not working for now, test kept
/* /*
@ -81,11 +82,12 @@ int main()
CGAL::Euler::remove_face(halfedge(f2, sm), sm); CGAL::Euler::remove_face(halfedge(f2, sm), sm);
PMP::duplicate_non_manifold_vertices(sm); PMP::duplicate_non_manifold_vertices(sm);
std::size_t nbv_before = vertices(sm).size(); std::size_t nbv_before = vertices(sm).size();
if (!PMP::remesh_planar_patches(sm)) Surface_mesh out;
if (!PMP::remesh_planar_patches(sm, out))
std::cerr << "decimate failed to remesh some patches (expected)\n"; std::cerr << "decimate failed to remesh some patches (expected)\n";
assert(vertices(sm).size()<nbv_before); assert(vertices(out).size()<nbv_before);
std::ofstream("nmd_m1.off") << std::setprecision(17) << sm; std::ofstream("nmd_m1.off") << std::setprecision(17) << out;
assert(is_valid_polygon_mesh(sm)); assert(is_valid_polygon_mesh(out));
} }
// test duplicated vertex at patch interface // test duplicated vertex at patch interface
{ {
@ -98,11 +100,12 @@ int main()
CGAL::Euler::remove_face(halfedge(f2, sm), sm); CGAL::Euler::remove_face(halfedge(f2, sm), sm);
PMP::duplicate_non_manifold_vertices(sm); PMP::duplicate_non_manifold_vertices(sm);
std::size_t nbv_before = vertices(sm).size(); std::size_t nbv_before = vertices(sm).size();
if (!PMP::remesh_planar_patches(sm)) Surface_mesh out;
if (!PMP::remesh_planar_patches(sm, out))
std::cerr << "decimate failed to remesh some patches (expected)\n"; std::cerr << "decimate failed to remesh some patches (expected)\n";
assert(vertices(sm).size()<nbv_before); assert(vertices(out).size()<nbv_before);
std::ofstream("nmdi_m1.off") << std::setprecision(17) << sm; std::ofstream("nmdi_m1.off") << std::setprecision(17) << out;
assert(is_valid_polygon_mesh(sm)); assert(is_valid_polygon_mesh(out));
} }
assert(OK); assert(OK);
@ -117,7 +120,8 @@ int main()
in >> sm; in >> sm;
// call the decimation function // call the decimation function
if (!PMP::remesh_planar_patches(sm, CGAL::parameters::cosinus_threshold(-0.99))) Surface_mesh out;
if (!PMP::remesh_planar_patches(sm, out, CGAL::parameters::cosinus_threshold(-0.99)))
{ {
OK=false; OK=false;
std::cerr << "ERROR: decimate failed to remesh some patches\n"; std::cerr << "ERROR: decimate failed to remesh some patches\n";
@ -125,9 +129,9 @@ int main()
ss=std::stringstream(); ss=std::stringstream();
ss << "out_a" << i << ".off"; ss << "out_a" << i << ".off";
std::ofstream out(ss.str().c_str()); std::ofstream out(ss.str().c_str());
out << sm; out << out;
std::cout << " output written to out_a" << i << ".off\n"; std::cout << " output written to out_a" << i << ".off\n";
assert(is_valid_polygon_mesh(sm)); assert(is_valid_polygon_mesh(out));
} }
//testing decimation of meshes, preserving common interface //testing decimation of meshes, preserving common interface
@ -310,7 +314,8 @@ int main()
std::cout << "decimate of data/decimation/sphere.off using approximate predicates\n"; std::cout << "decimate of data/decimation/sphere.off using approximate predicates\n";
std::ifstream in("data/decimation/sphere.off"); std::ifstream in("data/decimation/sphere.off");
in >> sm; in >> sm;
if (!PMP::remesh_planar_patches(sm, CGAL::parameters::cosinus_threshold(-0.99))) Surface_mesh out;
if (!PMP::remesh_planar_patches(sm, out, CGAL::parameters::cosinus_threshold(-0.99)))
std::cerr << "decimate failed to remesh some patches\n"; std::cerr << "decimate failed to remesh some patches\n";
} }
{ {
@ -318,12 +323,13 @@ int main()
std::cout << "decimate of data/decimation/sphere_selection.off using approximate predicates\n"; std::cout << "decimate of data/decimation/sphere_selection.off using approximate predicates\n";
std::ifstream in("data/decimation/sphere_selection.off"); std::ifstream in("data/decimation/sphere_selection.off");
in >> sm; in >> sm;
if (!PMP::remesh_planar_patches(sm, CGAL::parameters::cosinus_threshold(-0.99))) Surface_mesh out;
if (!PMP::remesh_planar_patches(sm, out, CGAL::parameters::cosinus_threshold(-0.99)))
std::cout << "decimate failed to remesh some patches (this is the expected behavior)\n"; std::cout << "decimate failed to remesh some patches (this is the expected behavior)\n";
std::ofstream out("sphere_selection_app.off"); std::ofstream out("sphere_selection_app.off");
out << sm; out << out;
std::cout << "output written to sphere_selection_app.off\n"; std::cout << "output written to sphere_selection_app.off\n";
assert(is_valid_polygon_mesh(sm)); assert(is_valid_polygon_mesh(out));
} }
assert(OK); assert(OK);