Skip to content

Commit

Permalink
Merge pull request #7919 from hoskillua/icc-todos
Browse files Browse the repository at this point in the history
Interpolated Curvature remaining TODOs
  • Loading branch information
lrineau committed Jan 24, 2024
2 parents c0b02c4 + 806d124 commit 47324c1
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,11 @@ quad meshes, and meshes with n-gon faces (for n-gons, the centroid must be insid
The algorithms used prove to work well in general. Also, on meshes with noise on vertex positions,
they give accurate results, under the condition that the correct vertex normals are provided.

It is worth noting that the Principal Curvatures and Directions can also be estimated using the
\ref PkgJetFitting3 package, which estimates the local differential quantities of a surface at a point
using a local polynomial fitting (fitting a d-jet). Unlike the Interpolated Corrected Curvatures,
the Jet Fitting method discards topological information and thus can be used on point clouds as well.

\subsection ICCBackground Brief Background

Surface curvatures are quantities that describe the local geometry of a surface. They are important in many
Expand All @@ -987,7 +992,7 @@ introduce a new way to compute curvatures on polygonal meshes. The main idea in
based on decoupling the normal information from the position information, which is useful for dealing with
digital surfaces, or meshes with noise on vertex positions. \cgalCite{cgal:lrtc-iccmps-20} introduces some
extensions to this framework, as it uses linear interpolation on the corrected normal vector field
to derive new closed form equations for the corrected curvature measures. These <b>interpolated</b>
to derive new closed-form equations for the corrected curvature measures. These <b>interpolated</b>
curvature measures are the first step for computing the curvatures. For a triangle \f$ \tau_{ijk} \f$,
with vertices \a i, \a j, \a k:

Expand All @@ -1011,8 +1016,13 @@ solver.

The interpolated curvature measures are then computed for each vertex \f$ v \f$ as the sum of
the curvature measures of the faces in a ball around \f$ v \f$ weighted by the inclusion ratio of the
triangle in the ball. If the ball radius is not specified, the sum is instead computed over the incident faces
of \f$ v \f$.
triangle in the ball. This ball radius is an optional (named) parameter of the function. There are 3
cases for the ball radius passed value:
- A positive value is passed: it is naturally used as the radius of the ball.
- 0 is passed, a small epsilon (`average_edge_length * 1e-6`) is used
(to account for the convergence of curvatures at infinitely small balls).
- It is not specified (or negative), the sum is instead computed over the incident faces
of the vertex \f$ v \f$.

To get the final curvature value for a vertex \f$ v \f$, the respective interpolated curvature measure
is divided by the interpolated area measure.
Expand All @@ -1030,7 +1040,7 @@ These computations are performed using (on all vertices of the mesh) `CGAL::Poly
where function named parameters are used to select the curvatures (and possibly directions) to be computed. An overload function with the same name
but taking a given vertex is also available in case the computation should be done only for that vertex.

\subsection ICCResults Results & Performance
\subsection ICCResults Results

First, \cgalFigureRef{icc_measures} illustrates various curvature measures on a triangular mesh.

Expand Down Expand Up @@ -1075,6 +1085,121 @@ When changing the integration ball radius, we obtain a scale space of curvature
\cgalFigureCaptionEnd


\subsection ICCPerformance Performance

The implemented algorithms exhibit a linear complexity in the number of faces of the mesh. It is worth noting that
we pre-computed the vertex normals and passed them as a named parameter to the function to better estimate the
performance of the curvature computation. For the data reported in the following table, we used a machine with an
Intel Core i7-8750H CPU @ 2.20GHz, 16GB of RAM, on Windows 11, 64 bits and compiled with Visual Studio 2019.

\cgalFigureAnchor{icc_performance_table}
<center>
<table>
<tr>
<th>Ball <br>Radius</th>
<th>Computation</th>
<th>Spot<br>(<span>6k </span>faces)</th>
<th>Bunny<br>(<span>144K </span>faces)</th>
<th>Stanford Dragon<br>(<span>871K </span>faces)</th>
<th>Old Age or Winter<br>(<span>6M </span>faces)</th>
</tr>
<tr>
<td rowspan="4">vertex<br>1-ring faces <br>(default)</td>
<td>Mean Curvature</td>
<td> &lt; 0.001 s</td>
<td>0.019 s</td>
<td>0.11 s</td>
<td>2.68 s</td>
</tr>
<tr>
<td>Gaussian Curvature</td>
<td> &lt; 0.001 s</td>
<td>0.017 s</td>
<td>0.10 s</td>
<td>2.77 s</td>
</tr>
<tr>
<td>Principal Curvatures &amp; Directions</td>
<td>0.002 s</td>
<td>0.044 s</td>
<td>0.25 s</td>
<td>3.98 s</td>
</tr>
<tr>
<td>All (optimized for shared computations)</td>
<td>0.003 s</td>
<td>0.049 s</td>
<td>0.28 s</td>
<td>4.52 s</td>
</tr>
<tr>
<td rowspan="4">r = 0.1<br>* avg_edge_length</td>
<td>Mean Curvature</td>
<td>0.017 s</td>
<td>0.401 s</td>
<td>2.66 s</td>
<td>22.29 s</td>
</tr>
<tr>
<td>Gaussian Curvature</td>
<td>0.018 s</td>
<td>0.406 s</td>
<td>2.63 s</td>
<td>21.61 s</td>
</tr>
<tr>
<td>Principal Curvatures &amp; Directions</td>
<td>0.019 s</td>
<td>0.430 s</td>
<td>2.85 s</td>
<td>23.55 s</td>
</tr>
<tr>
<td>All (optimized for shared computations)</td>
<td>0.017 s</td>
<td>0.428 s</td>
<td>2.89 s</td>
<td>24.16 s</td>
</tr>
<tr>
<td rowspan="4">r = 0.5<br>* avg_edge_length</td>
<td>Mean Curvature</td>
<td>0.024 s</td>
<td>0.388 s</td>
<td>3.18 s</td>
<td>22.79 s</td>
</tr>
<tr>
<td>Gaussian Curvature</td>
<td>0.024 s</td>
<td>0.392 s</td>
<td>3.21 s</td>
<td>23.58 s</td>
</tr>
<tr>
<td>Principal Curvatures &amp; Directions</td>
<td>0.027 s</td>
<td>0.428 s</td>
<td>3.41 s</td>
<td>24.44 s</td>
</tr>
<tr>
<td>All (optimized for shared computations)</td>
<td>0.025 s</td>
<td>0.417 s</td>
<td>3.44 s</td>
<td>23.93 s</td>
</tr>
</table>
</center>
\cgalFigureCaptionBegin{icc_performance_table}
Performance of the curvature computation on various meshes (in seconds). The first 4 rows show the performance of the default value for the ball radius,
which is using the 1-ring of neighboring faces around each vertex, instead of actually approximating the inclusion ratio of the faces in a ball of certain radius.
The other rows show a ball radius of 0.1 (and 0.5) scaled by the average edge length of the mesh. It is clear that using the 1-ring of faces
is much faster, but it might not be as effective when used on a noisy input mesh.
\cgalFigureCaptionEnd


\ref BGLPropertyMaps are used to record the computed curvatures as shown in examples. In the following examples, for each property map, we associate
a curvature value to each vertex.

Expand Down Expand Up @@ -1309,7 +1434,7 @@ available on 7th of October 2020. It only uses the high level algorithm of chec
is covered by a set of prisms, where each prism is an offset for an input triangle.
That is, the implementation in \cgal does not use indirect predicates.

The interpolated corrected curvatures were implemented during GSoC 2022. This was implemented by Hossam Saeed and under
The interpolated corrected curvatures were implemented during GSoC 2022. This was implemented by Hossam Saeed and under the
supervision of David Coeurjolly, Jaques-Olivier Lachaud, and Sébastien Loriot. The implementation is based on \cgalCite{cgal:lrtc-iccmps-20}.
<a href="https://dgtal-team.github.io/doc-nightly/moduleCurvatureMeasures.html">DGtal's implementation</a> was also
used as a reference during the project.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,6 @@ struct Principal_curvatures_and_directions {

namespace internal {

template<typename PolygonMesh, typename GT>
typename GT::FT average_edge_length(const PolygonMesh& pmesh) {
const std::size_t n = edges(pmesh).size();
if (n == 0)
return 0;

typename GT::FT avg_edge_length = 0;
for (auto e : edges(pmesh))
avg_edge_length += edge_length(e, pmesh);

avg_edge_length /= static_cast<typename GT::FT>(n);
return avg_edge_length;
}

template<typename GT>
struct Vertex_measures {
typename GT::FT area_measure = 0;
Expand Down Expand Up @@ -650,7 +636,7 @@ void interpolated_corrected_curvatures_one_vertex(
typename GT::FT radius = choose_parameter(get_parameter(np, internal_np::ball_radius), -1);

// calculate avg_edge_length as it is used in case radius is 0, and in the principal curvature computation later
typename GT::FT avg_edge_length = average_edge_length<PolygonMesh, GT>(pmesh);
typename GT::FT avg_edge_length = average_edge_length<PolygonMesh>(pmesh);

// if the radius is 0, we use a small epsilon to expand the ball (scaled with the average edge length)
if (is_zero(radius))
Expand Down Expand Up @@ -799,7 +785,7 @@ class Interpolated_corrected_curvatures_computer

// if no radius is given, we pass -1 which will make the expansion be only on the incident faces instead of a ball
const FT radius = choose_parameter(get_parameter(np, internal_np::ball_radius), -1);
avg_edge_length = average_edge_length<PolygonMesh, GT>(pmesh);
avg_edge_length = average_edge_length<PolygonMesh>(pmesh);
set_ball_radius(radius);

// check which curvature maps are provided by the user (determines which curvatures are computed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,25 @@ squared_edge_length(typename boost::graph_traits<PolygonMesh>::edge_descriptor e
return squared_edge_length(halfedge(e, pmesh), pmesh, np);
}

template<typename PolygonMesh,
typename NamedParameters = parameters::Default_named_parameters>
typename GetGeomTraits<PolygonMesh, NamedParameters>::type::FT
average_edge_length(const PolygonMesh& pmesh,
const NamedParameters& np = parameters::default_values())
{
typedef typename GetGeomTraits<PolygonMesh, NamedParameters>::type GT;

const std::size_t n = edges(pmesh).size();
CGAL_assertion(n > 0);

typename GT::FT avg_edge_length = 0;
for (auto e : edges(pmesh))
avg_edge_length += edge_length(e, pmesh, np);

avg_edge_length /= static_cast<typename GT::FT>(n);
return avg_edge_length;
}

/**
* \ingroup PMP_measure_grp
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class Display_property_plugin
double bI = 0.;

double expand_radius = 0.;
double expand_radius_updated = false;
double maxEdgeLength = -1.;

Color_ramp color_ramp;
Expand Down Expand Up @@ -912,6 +913,8 @@ private Q_SLOTS:

expand_radius = (pow(base, val) - 1) * outMax / (pow(base, sliderMax) - 1);
dock_widget->expandingRadiusLabel->setText(tr("Expanding Radius: %1").arg(expand_radius));
CGAL_assertion(expand_radius >= 0);
expand_radius_updated = true;
}

private:
Expand All @@ -933,7 +936,7 @@ private Q_SLOTS:
bool non_init;
SMesh::Property_map<vertex_descriptor, double> mu_i_map;
std::tie(mu_i_map, non_init) = smesh.add_property_map<vertex_descriptor, double>(tied_string, 0);
if(non_init)
if(non_init || expand_radius_updated)
{
if(vnm_exists)
{
Expand Down Expand Up @@ -967,6 +970,8 @@ private Q_SLOTS:
.ball_radius(expand_radius));
}
}

expand_radius_updated = false;
}

displaySMProperty<vertex_descriptor>(tied_string, smesh);
Expand Down

0 comments on commit 47324c1

Please sign in to comment.