added hidden named parameters for isovalue nudging and interior vertex placement

This commit is contained in:
Sven Oesau 2024-12-16 11:32:48 +01:00
parent e832359217
commit b7e1841b1d
4 changed files with 59 additions and 20 deletions

View File

@ -106,7 +106,8 @@ std::size_t get_cell_corners(const Domain& domain,
const typename Domain::cell_descriptor& cell, const typename Domain::cell_descriptor& cell,
const typename Domain::Geom_traits::FT isovalue, const typename Domain::Geom_traits::FT isovalue,
Corners& corners, Corners& corners,
Values& values) Values& values,
bool isovalue_nudging)
{ {
using vertex_descriptor = typename Domain::vertex_descriptor; using vertex_descriptor = typename Domain::vertex_descriptor;
@ -118,10 +119,10 @@ std::size_t get_cell_corners(const Domain& domain,
for(const vertex_descriptor& v : vertices) for(const vertex_descriptor& v : vertices)
{ {
auto val = domain.value(v); auto val = domain.value(v);
// Avoiding singular cases.
if (abs(val - isovalue) < 0.00000001) // Avoiding singular cases.
val = isovalue - 0.00000001; if (isovalue_nudging && abs(val - isovalue) < 0.00000001)
val = isovalue - 0.00000001;
values[v_id] = val; values[v_id] = val;
if(values[v_id] >= isovalue) if(values[v_id] >= isovalue)
@ -130,7 +131,7 @@ std::size_t get_cell_corners(const Domain& domain,
++v_id; ++v_id;
} }
if(index.all() || index.none()) // nothing's happening in this cell if(index.all() || index.none()) // nothing is happening in this cell
return static_cast<std::size_t>(index.to_ullong()); return static_cast<std::size_t>(index.to_ullong());
v_id = 0; v_id = 0;
@ -270,15 +271,18 @@ public:
private: private:
const Domain& m_domain; const Domain& m_domain;
const FT m_isovalue; const FT m_isovalue;
const bool m_isovalue_nudging;
Triangles m_triangles; Triangles m_triangles;
public: public:
// creates a Marching Cubes functor for a domain and isovalue // creates a Marching Cubes functor for a domain and isovalue
Marching_cubes_3(const Domain& domain, Marching_cubes_3(const Domain& domain,
const FT isovalue) const FT isovalue,
const bool isovalue_nudging = true)
: m_domain(domain), : m_domain(domain),
m_isovalue(isovalue) m_isovalue(isovalue),
m_isovalue_nudging(isovalue_nudging)
{ } { }
// returns the created triangle list // returns the created triangle list
@ -300,7 +304,7 @@ public:
std::array<FT, vpc> values; std::array<FT, vpc> values;
std::array<Point_3, vpc> corners; std::array<Point_3, vpc> corners;
const std::size_t i_case = get_cell_corners(m_domain, cell, m_isovalue, corners, values); const std::size_t i_case = get_cell_corners(m_domain, cell, m_isovalue, corners, values, m_isovalue_nudging);
// skip empty / full cells // skip empty / full cells
constexpr std::size_t ones = (1 << vpc) - 1; constexpr std::size_t ones = (1 << vpc) - 1;

View File

@ -115,6 +115,8 @@ private:
private: private:
const Domain& m_domain; const Domain& m_domain;
FT m_isovalue; FT m_isovalue;
bool m_isovalue_nudging;
bool m_constrain_to_cell;
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
std::atomic<Point_index> m_point_counter; std::atomic<Point_index> m_point_counter;
@ -135,16 +137,20 @@ private:
public: public:
TMC_functor(const Domain& domain, TMC_functor(const Domain& domain,
const FT isovalue) const FT isovalue,
const bool isovalue_nudging = true,
const bool constrain_to_cell = true)
: m_domain(domain), : m_domain(domain),
m_isovalue(isovalue), m_isovalue(isovalue),
m_point_counter(0) m_point_counter(0),
m_isovalue_nudging(isovalue_nudging),
m_constrain_to_cell(constrain_to_cell)
{ } { }
void operator()(const cell_descriptor& cell) { void operator()(const cell_descriptor& cell) {
std::array<FT, 8> values; std::array<FT, 8> values;
std::array<Point_3, 8> corners; std::array<Point_3, 8> corners;
const std::size_t i_case = get_cell_corners(m_domain, cell, m_isovalue, corners, values); const std::size_t i_case = get_cell_corners(m_domain, cell, m_isovalue, corners, values, m_isovalue_nudging);
// skip empty / full cells // skip empty / full cells
constexpr std::size_t ones = (1 << 8) - 1; constexpr std::size_t ones = (1 << 8) - 1;
@ -799,7 +805,7 @@ private:
c_ |= (size << 4 * cnt); c_ |= (size << 4 * cnt);
}; };
// set corresponging edge // set corresponding edge
auto set_c = [](const int cnt, const int pos, const int val, unsigned long long& c_) auto set_c = [](const int cnt, const int pos, const int val, unsigned long long& c_)
{ {
const unsigned int mask[4] = {0x0, 0xF, 0xFF, 0xFFF}; const unsigned int mask[4] = {0x0, 0xF, 0xFF, 0xFFF};
@ -871,6 +877,7 @@ private:
if (!std::isfinite(CGAL::to_double(ui[0])) || !std::isfinite(CGAL::to_double(ui[1]))) if (!std::isfinite(CGAL::to_double(ui[0])) || !std::isfinite(CGAL::to_double(ui[1])))
continue; continue;
// In practice, there does not seem to be a difference in choosing the first working over the best one.
break; break;
} }
@ -998,9 +1005,15 @@ private:
Point_index tg_idx[6]; Point_index tg_idx[6];
for(int i=0; i<6; ++i) for(int i=0; i<6; ++i)
{ {
const FT u = hvt[i][0] < 0.05 ? 0.05 : (hvt[i][0] > 0.95 ? 0.95 : hvt[i][0]); FT u = hvt[i][0];
const FT v = hvt[i][1] < 0.05 ? 0.05 : (hvt[i][1] > 0.95 ? 0.95 : hvt[i][1]); FT v = hvt[i][1];
const FT w = hvt[i][2] < 0.05 ? 0.05 : (hvt[i][2] > 0.95 ? 0.95 : hvt[i][2]); FT w = hvt[i][2];
if (m_constrain_to_cell) {
u = u < 0.05 ? 0.05 : (u > 0.95 ? 0.95 : u);
v = v < 0.05 ? 0.05 : (v > 0.95 ? 0.95 : v);
w = w < 0.05 ? 0.05 : (w > 0.95 ? 0.95 : w);
}
const FT px = (FT(1) - w) * ((FT(1) - v) * (x_coord(corners[0]) + u * (x_coord(corners[1]) - x_coord(corners[0]))) + const FT px = (FT(1) - w) * ((FT(1) - v) * (x_coord(corners[0]) + u * (x_coord(corners[1]) - x_coord(corners[0]))) +
v * (x_coord(corners[2]) + u * (x_coord(corners[3]) - x_coord(corners[2])))) + v * (x_coord(corners[2]) + u * (x_coord(corners[3]) - x_coord(corners[2])))) +
@ -1280,9 +1293,11 @@ private:
break; break;
} // switch(c_faces) } // switch(c_faces)
ucoord = ucoord < 0.05 ? 0.05 : (ucoord > 0.95 ? 0.95 : ucoord); if (m_constrain_to_cell) {
vcoord = vcoord < 0.05 ? 0.05 : (vcoord > 0.95 ? 0.95 : vcoord); ucoord = ucoord < 0.05 ? 0.05 : (ucoord > 0.95 ? 0.95 : ucoord);
wcoord = wcoord < 0.05 ? 0.05 : (wcoord > 0.95 ? 0.95 : wcoord); vcoord = vcoord < 0.05 ? 0.05 : (vcoord > 0.95 ? 0.95 : vcoord);
wcoord = wcoord < 0.05 ? 0.05 : (wcoord > 0.95 ? 0.95 : wcoord);
}
// create inner vertex // create inner vertex
const FT px = (FT(1) - wcoord) * ((FT(1) - vcoord) * (x_coord(corners[0]) + ucoord * (x_coord(corners[1]) - x_coord(corners[0]))) + const FT px = (FT(1) - wcoord) * ((FT(1) - vcoord) * (x_coord(corners[0]) + ucoord * (x_coord(corners[1]) - x_coord(corners[0]))) +

View File

@ -51,6 +51,23 @@ namespace Isosurfacing {
* \cgalParamType{Boolean} * \cgalParamType{Boolean}
* \cgalParamDefault{`true`} * \cgalParamDefault{`true`}
* \cgalParamNEnd * \cgalParamNEnd
*
* \cond SKIP_IN_MANUAL
* \cgalParamNBegin{isovalue_nudging}
* \cgalParamDescription{snapping of function value at corner points to an epsilon below the isovalue if the function value is within an epsilon range around the isovalue}
* \cgalParamType{Boolean}
* \cgalParamDefault{`true`}
* \cgalParamExtra{Snapping the function value at corner points prevents singular cases. The geometry is changed only in case of the function value being within a small epsilon range. The potential change is small. }
* \cgalParamNEnd
*
* \cgalParamNBegin{constrain_to_cell}
* \cgalParamDescription{whether to exclude the cell boundary from the interior vertex placement. }
* \cgalParamType{Boolean}
* \cgalParamDefault{`true`}
* \cgalParamExtra{Prevents degenerate or duplicate triangles.}
* \cgalParamNEnd
* \endcond
*
* \cgalNamedParamsEnd * \cgalNamedParamsEnd
* *
* \sa `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()` * \sa `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()`
@ -70,17 +87,19 @@ void marching_cubes(const Domain& domain,
using parameters::get_parameter; using parameters::get_parameter;
const bool use_tmc = choose_parameter(get_parameter(np, internal_np::use_topologically_correct_marching_cubes), true); const bool use_tmc = choose_parameter(get_parameter(np, internal_np::use_topologically_correct_marching_cubes), true);
const bool isovalue_nudging = choose_parameter(get_parameter(np, internal_np::isovalue_nudging), true);
const bool constrain_to_cell = choose_parameter(get_parameter(np, internal_np::constrain_to_cell), true);
if(use_tmc) if(use_tmc)
{ {
internal::TMC_functor<Domain, PointRange, TriangleRange> functor(domain, isovalue); internal::TMC_functor<Domain, PointRange, TriangleRange> functor(domain, isovalue, isovalue_nudging, constrain_to_cell);
domain.template for_each_cell<ConcurrencyTag>(functor); domain.template for_each_cell<ConcurrencyTag>(functor);
functor.to_triangle_soup(points, triangles); functor.to_triangle_soup(points, triangles);
} }
else else
{ {
// run marching cubes // run marching cubes
internal::Marching_cubes_3<Domain> functor(domain, isovalue); internal::Marching_cubes_3<Domain> functor(domain, isovalue, isovalue_nudging);
domain.template for_each_cell<ConcurrencyTag>(functor); domain.template for_each_cell<ConcurrencyTag>(functor);
// copy the result to points and triangles // copy the result to points and triangles

View File

@ -243,6 +243,7 @@ CGAL_add_named_parameter(pca_plane_t, pca_plane, pca_plane)
// List of named parameters used in Isosurfacing_3 // List of named parameters used in Isosurfacing_3
CGAL_add_named_parameter(use_topologically_correct_marching_cubes_t, use_topologically_correct_marching_cubes, use_topologically_correct_marching_cubes) CGAL_add_named_parameter(use_topologically_correct_marching_cubes_t, use_topologically_correct_marching_cubes, use_topologically_correct_marching_cubes)
CGAL_add_named_parameter(constrain_to_cell_t, constrain_to_cell, constrain_to_cell) CGAL_add_named_parameter(constrain_to_cell_t, constrain_to_cell, constrain_to_cell)
CGAL_add_named_parameter(isovalue_nudging_t, isovalue_nudging, isovalue_nudging)
// tetrahedral remeshing parameters // tetrahedral remeshing parameters
CGAL_add_named_parameter(remesh_boundaries_t, remesh_boundaries, remesh_boundaries) CGAL_add_named_parameter(remesh_boundaries_t, remesh_boundaries, remesh_boundaries)