mirror of https://github.com/CGAL/cgal
Merge PR #6760 into gsoc2023-adaptive_remesh-ipadjen
This commit is contained in:
commit
eb2a023c31
|
|
@ -152043,6 +152043,7 @@ pages = {179--189}
|
|||
Pages = {215--224},
|
||||
Year = {2012},
|
||||
Url = {https://monge.univ-mlv.fr/~colinde/pub/09edgewidth.pdf}
|
||||
}
|
||||
|
||||
@inproceedings{tang2009interactive,
|
||||
title={Interactive Hausdorff distance computation for general polygonal models},
|
||||
|
|
@ -152054,3 +152055,25 @@ pages = {179--189}
|
|||
year={2009},
|
||||
organization={ACM}
|
||||
}
|
||||
|
||||
@article{lachaud2020,
|
||||
author = {Jacques-Olivier Lachaud and Pascal Romon and Boris Thibert and David Coeurjolly},
|
||||
journal = {Computer Graphics Forum (Proceedings of Symposium on Geometry Processing)},
|
||||
number = {5},
|
||||
title = {Interpolated corrected curvature measures for polygonal surfaces},
|
||||
volume = {39},
|
||||
month = jul,
|
||||
year = {2020}
|
||||
}
|
||||
|
||||
@article{lachaud2022
|
||||
author = {Jacques-Olivier Lachaud and Pascal Romon and Boris Thibert},
|
||||
journal = {Discrete & Computational Geometry},
|
||||
title = {Corrected Curvature Measures},
|
||||
volume = {68},
|
||||
pages = {477-524},
|
||||
month = jul,
|
||||
year = {2022},
|
||||
url = {https://doi.org/10.1007/s00454-022-00399-4}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2016 GeometryFactory SARL (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org)
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
// Author(s) : Andreas Fabri
|
||||
//
|
||||
// Warning: this file is generated, see include/CGAL/licence/README.md
|
||||
|
||||
#ifndef CGAL_POLYGON_MESH_PROCESSING_INTERPOLATED_CORRECTED_CURVATURES_H
|
||||
#define CGAL_POLYGON_MESH_PROCESSING_INTERPOLATED_CORRECTED_CURVATURES_H
|
||||
|
||||
#include <CGAL/config.h>
|
||||
#include <CGAL/license.h>
|
||||
|
||||
#ifdef CGAL_POLYGON_MESH_PROCESSING_INTERPOLATED_CORRECTED_CURVATURES_COMMERCIAL_LICENSE
|
||||
|
||||
# if CGAL_POLYGON_MESH_PROCESSING_INTERPOLATED_CORRECTED_CURVATURES_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE
|
||||
|
||||
# if defined(CGAL_LICENSE_WARNING)
|
||||
|
||||
CGAL_pragma_warning("Your commercial license for CGAL does not cover "
|
||||
"this release of the Polygon Mesh Processing - Interpolated Corrected Curvatures package.")
|
||||
# endif
|
||||
|
||||
# ifdef CGAL_LICENSE_ERROR
|
||||
# error "Your commercial license for CGAL does not cover this release \
|
||||
of the Polygon Mesh Processing - Interpolated Corrected Curvatures package. \
|
||||
You get this error, as you defined CGAL_LICENSE_ERROR."
|
||||
# endif // CGAL_LICENSE_ERROR
|
||||
|
||||
# endif // CGAL_POLYGON_MESH_PROCESSING_INTERPOLATED_CORRECTED_CURVATURES_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE
|
||||
|
||||
#else // no CGAL_POLYGON_MESH_PROCESSING_INTERPOLATED_CORRECTED_CURVATURES_COMMERCIAL_LICENSE
|
||||
|
||||
# if defined(CGAL_LICENSE_WARNING)
|
||||
CGAL_pragma_warning("\nThe macro CGAL_POLYGON_MESH_PROCESSING_INTERPOLATED_CORRECTED_CURVATURES_COMMERCIAL_LICENSE is not defined."
|
||||
"\nYou use the CGAL Polygon Mesh Processing - Interpolated Corrected Curvatures package under "
|
||||
"the terms of the GPLv3+.")
|
||||
# endif // CGAL_LICENSE_WARNING
|
||||
|
||||
# ifdef CGAL_LICENSE_ERROR
|
||||
# error "The macro CGAL_POLYGON_MESH_PROCESSING_INTERPOLATED_CORRECTED_CURVATURES_COMMERCIAL_LICENSE is not defined.\
|
||||
You use the CGAL Polygon Mesh Processing - Interpolated Corrected Curvatures package under the terms of \
|
||||
the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR."
|
||||
# endif // CGAL_LICENSE_ERROR
|
||||
|
||||
#endif // no CGAL_POLYGON_MESH_PROCESSING_INTERPOLATED_CORRECTED_CURVATURES_COMMERCIAL_LICENSE
|
||||
|
||||
#endif // CGAL_POLYGON_MESH_PROCESSING_INTERPOLATED_CORRECTED_CURVATURES_H
|
||||
|
|
@ -51,6 +51,7 @@ Polygon_mesh_processing/connected_components Polygon Mesh Processing - Connected
|
|||
Polygon_mesh_processing/corefinement Polygon Mesh Processing - Corefinement
|
||||
Polygon_mesh_processing/core Polygon Mesh Processing - Core
|
||||
Polygon_mesh_processing/distance Polygon Mesh Processing - Distance
|
||||
Polygon_mesh_processing/interpolated_corrected_curvatures Polygon Mesh Processing - Interpolated Corrected Curvatures
|
||||
Polygon_mesh_processing/measure Polygon Mesh Processing - Geometric Measure
|
||||
Polygon_mesh_processing/meshing_hole_filling Polygon Mesh Processing - Meshing and Hole Filling
|
||||
Polygon_mesh_processing/orientation Polygon Mesh Processing - Orientation
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ EXCLUDE_SYMBOLS += experimental
|
|||
HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/selfintersections.jpg \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/mesh_smoothing.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/shape_smoothing.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/icc_diff_radius.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/decimate_cheese.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/decimate_colors.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/decimate_rg_joint.png
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@
|
|||
/// Functions to triangulate faces, and to refine and fair regions of a polygon mesh.
|
||||
/// \ingroup PkgPolygonMeshProcessingRef
|
||||
|
||||
/// \defgroup PMP_corrected_curvatures_grp Corrected Curvature Computation
|
||||
/// Functions to compute the corrected curvatures of a polygon mesh.
|
||||
/// \ingroup PkgPolygonMeshProcessingRef
|
||||
|
||||
/// \defgroup PMP_normal_grp Normal Computation
|
||||
/// Functions to compute unit normals for individual/all vertices or faces.
|
||||
/// \ingroup PkgPolygonMeshProcessingRef
|
||||
|
|
@ -75,7 +79,7 @@
|
|||
\cgalPkgPicture{hole_filling_ico.png}
|
||||
|
||||
\cgalPkgSummaryBegin
|
||||
\cgalPkgAuthors{Sébastien Loriot, Mael Rouxel-Labbé, Jane Tournois, and Ilker %O. Yaz}
|
||||
\cgalPkgAuthors{David Coeurjolly, Jaques-Olivier Lachaud, Konstantinos Katriopla, Sébastien Loriot, Mael Rouxel-Labbé, Hossam Saeed, Jane Tournois, and Ilker %O. Yaz}
|
||||
\cgalPkgDesc{This package provides a collection of methods and classes for polygon mesh processing,
|
||||
ranging from basic operations on simplices, to complex geometry processing algorithms such as
|
||||
Boolean operations, remeshing, repairing, collision and intersection detection, and more.}
|
||||
|
|
@ -208,6 +212,17 @@ The page \ref bgl_namedparameters "Named Parameters" describes their usage.
|
|||
- \link PMP_locate_grp Nearest Face Location Queries \endlink
|
||||
- \link PMP_locate_grp Random Location Generation \endlink
|
||||
|
||||
\cgalCRPSection{Corrected Curvatures}
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_mean_curvature()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_Gaussian_curvature()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_principal_curvatures_and_directions()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_curvatures()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_mean_curvature_one_vertex()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_Gaussian_curvature_one_vertex()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_principal_curvatures_and_directions_one_vertex()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_curvatures_one_vertex()`
|
||||
- `CGAL::Polygon_mesh_processing::Principal_curvatures_and_directions`
|
||||
|
||||
\cgalCRPSection{Normal Computation Functions}
|
||||
- `CGAL::Polygon_mesh_processing::compute_face_normal()`
|
||||
- `CGAL::Polygon_mesh_processing::compute_face_normals()`
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace CGAL {
|
|||
\anchor Chapter_PolygonMeshProcessing
|
||||
|
||||
\cgalAutoToc
|
||||
\authors Sébastien Loriot, Mael Rouxel-Labbé, Jane Tournois, Ilker %O. Yaz
|
||||
\authors David Coeurjolly, Jaques-Olivier Lachaud, Konstantinos Katriopla, Sébastien Loriot, Mael Rouxel-Labbé, Hossam Saeed, Jane Tournois, and Ilker %O. Yaz
|
||||
|
||||
\image html neptun_head.jpg
|
||||
\image latex neptun_head.jpg
|
||||
|
|
@ -49,6 +49,7 @@ mesh, which includes point location and self intersection tests.
|
|||
- \ref PMPCombinatorialRepair : repair of polygon meshes and polygon soups.
|
||||
- \ref PMPGeometricRepair : repair of the geometry of polygon meshes.
|
||||
- \ref PMPNormalComp : normal computation at vertices and on faces of a polygon mesh.
|
||||
- \ref PMPICC : computing curvatures (mean, gaussian, principal) on a polygon mesh.
|
||||
- \ref PMPSlicer : functor able to compute the intersections of a polygon mesh with arbitrary planes (slicer).
|
||||
- \ref PMPConnectedComponents : methods to deal with connected
|
||||
components of a polygon mesh (extraction, marks, removal, ...).
|
||||
|
|
@ -935,6 +936,128 @@ not provide storage for the normals.
|
|||
|
||||
\cgalExample{Polygon_mesh_processing/compute_normals_example_Polyhedron.cpp}
|
||||
|
||||
****************************************
|
||||
\section PMPICC Computing Curvatures
|
||||
|
||||
This package provides methods to compute curvatures on polygonal meshes based on Interpolated
|
||||
Corrected Curvatures on Polyhedral Surfaces \cgalCite{lachaud2020}. This includes mean curvature,
|
||||
Gaussian curvature, principal curvatures and directions. These can be computed on triangle meshes,
|
||||
quad meshes, and meshes with n-gon faces (for n-gons, the centroid must be inside the n-gon face).
|
||||
The algorithms used prove to work well in general. Also, on meshes with noise on vertex positions,
|
||||
they give accurate results, on the condition that the correct vertex normals are provided.
|
||||
|
||||
\subsection ICCBackground Brief Background
|
||||
|
||||
Surface curvatures are quantities that describe the local geometry of a surface. They are important in many
|
||||
geometry processing applications. As surfaces are 2-dimensional objects (embedded in 3D), they can bend
|
||||
in 2 independent directions. These directions are called principal directions, and the amount of bending
|
||||
in each direction is called the principal curvature: \f$ k_1 \f$ and \f$ k_2 \f$ (denoting max and min
|
||||
curvatures). Curvature is usually expressed as scalar quantities like the mean curvature \f$ H \f$ and
|
||||
the Gaussian curvature \f$ K \f$ which are defined in terms of the principal curvatures.
|
||||
|
||||
The algorithms are based on the two papers \cgalCite{lachaud2022} and \cgalCite{lachaud2020}. They
|
||||
introduce a new way to compute curvatures on polygonal meshes. The main idea in \cgalCite{lachaud2022} is
|
||||
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{lachaud2020} 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>
|
||||
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:
|
||||
|
||||
\f[
|
||||
\begin{align*}
|
||||
\mu^{(0)}(\tau_{ijk}) = &\frac{1}{2} \langle \bar{\mathbf{u}} \mid (\mathbf{x}_j - \mathbf{x}_i) \times (\mathbf{x}_k - \mathbf{x}_i) \rangle, \\
|
||||
\mu^{(1)}(\tau_{ijk}) = &\frac{1}{2} \langle \bar{\mathbf{u}} \mid (\mathbf{u}_k - \mathbf{u}_j) \times \mathbf{x}_i + (\mathbf{u}_i - \mathbf{u}_k) \times \mathbf{x}_j + (\mathbf{u}_j - \mathbf{u}_i) \times \mathbf{x}_k \rangle, \\
|
||||
\mu^{(2)}(\tau_{ijk}) = &\frac{1}{2} \langle \mathbf{u}_i \mid \mathbf{u}_j \times \mathbf{u}_k \rangle, \\
|
||||
\mu^{\mathbf{X},\mathbf{Y}}(\tau_{ijk}) = & \frac{1}{2} \big\langle \bar{\mathbf{u}} \big| \langle \mathbf{Y} | \mathbf{u}_k -\mathbf{u}_i \rangle \mathbf{X} \times (\mathbf{x}_j - \mathbf{x}_i) \big\rangle
|
||||
-\frac{1}{2} \big\langle \bar{\mathbf{u}} \big| \langle \mathbf{Y} | \mathbf{u}_j -\mathbf{u}_i \rangle \mathbf{X} \times (\mathbf{x}_k - \mathbf{x}_i) \big\rangle,
|
||||
\end{align*}
|
||||
\f]
|
||||
where \f$ \langle \cdot \mid \cdot \rangle \f$ denotes the usual scalar product,
|
||||
\f$ \bar{\mathbf{u}}=\frac{1}{3}( \mathbf{u}_i + \mathbf{u}_j + \mathbf{u}_k )\f$.
|
||||
|
||||
The first measure \f$ \mu^{(0)} \f$ is the area measure of the triangle, and the measures \f$ \mu^{(1)} \f$ and
|
||||
\f$ \mu^{(2)} \f$ are the mean and Gaussian corrected curvature measures of the triangle. The last measure
|
||||
\f$ \mu^{\mathbf{X},\mathbf{Y}} \f$ is the anisotropic corrected curvature measure of the triangle. The
|
||||
anisotropic measure is later used to compute the principal curvatures and directions through an eigenvalue
|
||||
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 over the incident faces
|
||||
of \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.
|
||||
|
||||
\f[
|
||||
\mu^{(k)}( B ) = \sum_{\tau : \text{triangle} } \mu^{(k)}( \tau ) \frac{\mathrm{Area}( \tau \cap B )}{\mathrm{Area}(\tau)}.
|
||||
\f]
|
||||
|
||||
\subsection ICCAPI API
|
||||
|
||||
The implementation is generic in terms of mesh data structure. It can be used on `Surface_mesh`,
|
||||
`Polyhedron_3` and other polygonal mesh structures based on the concept `FaceGraph`.
|
||||
|
||||
These computations are performed using (on all vertices of the mesh):
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_mean_curvature()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_Gaussian_curvature()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_principal_curvatures_and_directions()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_curvatures()`
|
||||
|
||||
Where it is recommended to use the last function for computing multiple curvatures (for example: mean and
|
||||
Gaussian) as the implementation performs the shared computations only once, making it more efficient.
|
||||
|
||||
Similarly, we can use the following functions to compute curvatures on a specific vertex:
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_mean_curvature_one_vertex()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_Gaussian_curvature_one_vertex()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_principal_curvatures_and_directions_one_vertex()`
|
||||
- `CGAL::Polygon_mesh_processing::interpolated_corrected_curvatures_one_vertex()`
|
||||
|
||||
\subsection ICCResults Results & Performance
|
||||
|
||||
**To be updated**
|
||||
|
||||
\cgalFigureRef{icc_diff_radius} shows how the mean curvature changes depending on
|
||||
the named parameter `ball_radius`, which can be set to a value > 0 to get a smoother
|
||||
distribution of values and "diffuses" the extreme values of curvatures across the mesh.
|
||||
|
||||
\cgalFigureAnchor{icc_diff_radius}
|
||||
<center>
|
||||
<img src="icc_diff_radius.png" style="max-width:85%;"/>
|
||||
</center>
|
||||
\cgalFigureCaptionBegin{icc_diff_radius}
|
||||
The mean curvature on a mesh with different values for the ball radius
|
||||
parameter: (a) R = 0, (b) R = 0.025, (c) R = 0.05, (d) R = 0.16. Note that the max
|
||||
edge length is 0.031 and the size of the bounding box of the mesh is 1 x .7 x .8.
|
||||
\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.
|
||||
|
||||
\subsection ICCExampleSM Interpolated Corrected Curvatures on a Surface Mesh Example
|
||||
|
||||
The following example illustrates how to
|
||||
compute the curvatures on vertices
|
||||
and store them in the property maps provided by the class `Surface_mesh`.
|
||||
|
||||
\cgalExample{Polygon_mesh_processing/interpolated_corrected_curvatures_SM.cpp}
|
||||
|
||||
\subsection ICCExamplePH Interpolated Corrected Curvatures on a Polyhedron Example
|
||||
|
||||
The following example illustrates how to
|
||||
compute the curvatures on vertices
|
||||
and store them in dynamic property maps as the class `Polyhedron_3` does
|
||||
not provide storage for the curvatures.
|
||||
|
||||
\cgalExample{Polygon_mesh_processing/interpolated_corrected_curvatures_PH.cpp}
|
||||
|
||||
\subsection ICCExampleSV Interpolated Corrected Curvatures on a Vertex Example
|
||||
|
||||
The following example illustrates how to
|
||||
compute the curvatures on a specific vertex
|
||||
|
||||
\cgalExample{Polygon_mesh_processing/interpolated_corrected_curvatures_vertex.cpp}
|
||||
|
||||
****************************************
|
||||
\section PMPSlicer Slicer
|
||||
|
|
@ -1143,6 +1266,10 @@ 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
|
||||
supervision of David Coeurjolly, Jaques-Olivier Lachaud, and Sébastien Loriot. The implementation is based on \cgalCite{lachaud2020}.
|
||||
<a href="https://dgtal-team.github.io/doc-nightly/moduleCurvatureMeasures.html">DGtal's implementation</a> was also
|
||||
used as a reference during the project.
|
||||
|
||||
*/
|
||||
} /* namespace CGAL */
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
\example Polygon_mesh_processing/refine_fair_example.cpp
|
||||
\example Polygon_mesh_processing/mesh_slicer_example.cpp
|
||||
\example Polygon_mesh_processing/isotropic_remeshing_example.cpp
|
||||
\example Polygon_mesh_processing/interpolated_corrected_curvatures_SM.cpp
|
||||
\example Polygon_mesh_processing/interpolated_corrected_curvatures_PH.cpp
|
||||
\example Polygon_mesh_processing/interpolated_corrected_curvatures_vertex.cpp
|
||||
\example Polygon_mesh_processing/delaunay_remeshing_example.cpp
|
||||
\example Polygon_mesh_processing/compute_normals_example_Polyhedron.cpp
|
||||
\example Polygon_mesh_processing/hausdorff_distance_remeshing_example.cpp
|
||||
|
|
|
|||
|
|
@ -74,6 +74,12 @@ if(TARGET CGAL::Eigen3_support)
|
|||
target_link_libraries(delaunay_remeshing_example PUBLIC CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("remesh_almost_planar_patches.cpp")
|
||||
target_link_libraries(remesh_almost_planar_patches PUBLIC CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("interpolated_corrected_curvatures_SM.cpp")
|
||||
target_link_libraries(interpolated_corrected_curvatures_SM PUBLIC CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("interpolated_corrected_curvatures_PH.cpp")
|
||||
target_link_libraries(interpolated_corrected_curvatures_PH PUBLIC CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("interpolated_corrected_curvatures_vertex.cpp")
|
||||
target_link_libraries(interpolated_corrected_curvatures_vertex PUBLIC CGAL::Eigen3_support)
|
||||
else()
|
||||
message(STATUS "NOTICE: Examples that use Eigen will not be compiled.")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_mesh_processing/interpolated_corrected_curvatures.h>
|
||||
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/property_map.h>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic_kernel;
|
||||
typedef CGAL::Polyhedron_3<Epic_kernel> Polyhedron;
|
||||
typedef boost::graph_traits<Polyhedron>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Polyhedron polyhedron;
|
||||
const std::string filename = (argc > 1) ?
|
||||
argv[1] :
|
||||
CGAL::data_file_path("meshes/sphere.off");
|
||||
|
||||
if (!CGAL::IO::read_polygon_mesh(filename, polyhedron))
|
||||
{
|
||||
std::cerr << "Invalid input file." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
boost::property_map<Polyhedron, CGAL::dynamic_vertex_property_t<Epic_kernel::FT>>::type
|
||||
mean_curvature_map = get(CGAL::dynamic_vertex_property_t<Epic_kernel::FT>(), polyhedron),
|
||||
Gaussian_curvature_map = get(CGAL::dynamic_vertex_property_t<Epic_kernel::FT>(), polyhedron);
|
||||
|
||||
boost::property_map<Polyhedron, CGAL::dynamic_vertex_property_t<PMP::Principal_curvatures_and_directions<Epic_kernel>>>::type
|
||||
principal_curvatures_and_directions_map =
|
||||
get(CGAL::dynamic_vertex_property_t<PMP::Principal_curvatures_and_directions<Epic_kernel>>(), polyhedron);
|
||||
|
||||
PMP::interpolated_corrected_mean_curvature(polyhedron, mean_curvature_map);
|
||||
|
||||
PMP::interpolated_corrected_Gaussian_curvature(polyhedron, Gaussian_curvature_map);
|
||||
|
||||
PMP::interpolated_corrected_principal_curvatures_and_directions(polyhedron, principal_curvatures_and_directions_map);
|
||||
|
||||
// uncomment this to compute a curvature while specifying named parameters
|
||||
// Example: an expansion ball radius of 0.5 and a vertex normals map (does not have to depend on positions)
|
||||
|
||||
/*std::unordered_map<vertex_descriptor, Epic_Kernel::Vector_3> vnm;
|
||||
|
||||
PMP::interpolated_corrected_mean_curvature(
|
||||
polyhedron,
|
||||
mean_curvature_map,
|
||||
CGAL::parameters::ball_radius(0.5).vertex_normal_map(boost::make_assoc_property_map(vnm))
|
||||
);*/
|
||||
|
||||
// This function can be used to compute multiple curvature types by specifiying them as named parameters
|
||||
// This is more efficient than computing each one separately (shared computations).
|
||||
PMP::interpolated_corrected_curvatures(
|
||||
polyhedron,
|
||||
CGAL::parameters::vertex_mean_curvature_map(mean_curvature_map)
|
||||
.vertex_principal_curvatures_and_directions_map(principal_curvatures_and_directions_map));
|
||||
|
||||
int i = 0;
|
||||
for (vertex_descriptor v : vertices(polyhedron))
|
||||
{
|
||||
auto PC = get(principal_curvatures_and_directions_map, v);
|
||||
std::cout << i << ": HC = " << get(mean_curvature_map, v)
|
||||
<< ", GC = " << get(Gaussian_curvature_map, v) << "\n"
|
||||
<< ", PC = [ " << PC.min_curvature << " , " << PC.max_curvature << " ]\n";
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_mesh_processing/interpolated_corrected_curvatures.h>
|
||||
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/property_map.h>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic_kernel;
|
||||
typedef CGAL::Surface_mesh<Epic_kernel::Point_3> Surface_Mesh;
|
||||
typedef boost::graph_traits<Surface_Mesh>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Surface_Mesh smesh;
|
||||
const std::string filename = (argc > 1) ?
|
||||
argv[1] :
|
||||
CGAL::data_file_path("meshes/sphere.off");
|
||||
|
||||
if (!CGAL::IO::read_polygon_mesh(filename, smesh))
|
||||
{
|
||||
std::cerr << "Invalid input file." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// creating and tying surface mesh property maps for curvatures (with defaults = 0)
|
||||
bool created = false;
|
||||
Surface_Mesh::Property_map<vertex_descriptor, Epic_kernel::FT>
|
||||
mean_curvature_map, Gaussian_curvature_map;
|
||||
|
||||
boost::tie(mean_curvature_map, created) =
|
||||
smesh.add_property_map<vertex_descriptor, Epic_kernel::FT>("v:mean_curvature_map", 0);
|
||||
assert(created);
|
||||
|
||||
boost::tie(Gaussian_curvature_map, created) =
|
||||
smesh.add_property_map<vertex_descriptor, Epic_kernel::FT>("v:Gaussian_curvature_map", 0);
|
||||
assert(created);
|
||||
|
||||
// we use a tuple of 2 scalar values and 2 vectors for principal curvatures and directions
|
||||
Surface_Mesh::Property_map<vertex_descriptor, PMP::Principal_curvatures_and_directions<Epic_kernel>>
|
||||
principal_curvatures_and_directions_map;
|
||||
|
||||
boost::tie(principal_curvatures_and_directions_map, created) =
|
||||
smesh.add_property_map<vertex_descriptor, PMP::Principal_curvatures_and_directions<Epic_kernel>>
|
||||
("v:principal_curvatures_and_directions_map", { 0, 0,
|
||||
Epic_kernel::Vector_3(0,0,0),
|
||||
Epic_kernel::Vector_3(0,0,0) });
|
||||
assert(created);
|
||||
|
||||
// user can call these fucntions to compute a specfic curvature type on each vertex.
|
||||
// (Note: if no ball radius is specified, the measure expansion of each vertex happens by
|
||||
// summing measures on faces adjacent to each vertex.)
|
||||
PMP::interpolated_corrected_mean_curvature(smesh, mean_curvature_map);
|
||||
|
||||
PMP::interpolated_corrected_Gaussian_curvature(smesh, Gaussian_curvature_map);
|
||||
|
||||
PMP::interpolated_corrected_principal_curvatures_and_directions(smesh, principal_curvatures_and_directions_map);
|
||||
|
||||
// uncomment this to compute a curvature while specifying named parameters
|
||||
// Example: an expansion ball radius of 0.5 and a vertex normals map (does not have to depend on positions)
|
||||
|
||||
/*Surface_Mesh::Property_map<vertex_descriptor, Epic_kernel::Vector_3> vnm;
|
||||
boost::tie(vnm, created) = smesh.add_property_map<vertex_descriptor, Epic_kernel::Vector_3>(
|
||||
"v:vnm", Epic_kernel::Vector_3(0, 0, 0)
|
||||
);
|
||||
|
||||
assert(created);
|
||||
|
||||
PMP::interpolated_corrected_mean_curvature(
|
||||
smesh,
|
||||
mean_curvature_map,
|
||||
CGAL::parameters::ball_radius(0.5).vertex_normal_map(vnm)
|
||||
);*/
|
||||
|
||||
// This function can be used to compute multiple curvature types by specifiying them as named parameters
|
||||
// This is more efficient than computing each one separately (shared computations).
|
||||
PMP::interpolated_corrected_curvatures(
|
||||
smesh,
|
||||
CGAL::parameters::vertex_mean_curvature_map(mean_curvature_map)
|
||||
.vertex_principal_curvatures_and_directions_map(principal_curvatures_and_directions_map)
|
||||
);
|
||||
|
||||
for (vertex_descriptor v : vertices(smesh))
|
||||
{
|
||||
auto PC = principal_curvatures_and_directions_map[v];
|
||||
std::cout << v.idx() << ": HC = " << mean_curvature_map[v]
|
||||
<< ", GC = " << Gaussian_curvature_map[v] << "\n"
|
||||
<< ", PC = [ " << PC.min_curvature << " , " << PC.max_curvature << " ]\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_mesh_processing/interpolated_corrected_curvatures.h>
|
||||
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic_kernel;
|
||||
typedef CGAL::Surface_mesh<Epic_kernel::Point_3> Surface_Mesh;
|
||||
typedef boost::graph_traits<Surface_Mesh>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// instantiating and reading mesh
|
||||
Surface_Mesh smesh;
|
||||
const std::string filename = (argc > 1) ?
|
||||
argv[1] :
|
||||
CGAL::data_file_path("meshes/sphere.off");
|
||||
|
||||
if (!CGAL::IO::read_polygon_mesh(filename, smesh))
|
||||
{
|
||||
std::cerr << "Invalid input file." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// loop over vertices and use vertex_descriptor to compute a curvature on one vertex
|
||||
for (vertex_descriptor v : vertices(smesh))
|
||||
{
|
||||
double h = PMP::interpolated_corrected_mean_curvature_one_vertex(smesh, v);
|
||||
double g = PMP::interpolated_corrected_Gaussian_curvature_one_vertex(smesh, v);
|
||||
PMP::Principal_curvatures_and_directions<Epic_kernel> p =
|
||||
PMP::interpolated_corrected_principal_curvatures_and_directions_one_vertex(smesh, v);
|
||||
|
||||
// we can also specify a ball radius for expansion and a user defined vertex normals map using
|
||||
// named parameters. Refer to interpolated_corrected_curvatures_SM.cpp to see example usage.
|
||||
|
||||
// Can also use interpolated_corrected_curvatures_one_vertex() to compute multiple curvatures
|
||||
// on the vertex at the same time. This is more efficient than computing each one separately.
|
||||
// The following commented lines show this (all mentioned named parameters work on it as well)
|
||||
// we specify which curvatures we want to compute by passing pointers as named parameters
|
||||
// as shown. These pointers are used for storing the result as well. in this example we
|
||||
// selected mean and Gaussian curvatures
|
||||
// PMP::interpolated_corrected_curvatures_one_vertex(
|
||||
// smesh,
|
||||
// v,
|
||||
// CGAL::parameters::vertex_mean_curvature(&h)
|
||||
// .vertex_Gaussian_curvature(&g)
|
||||
// );
|
||||
|
||||
std::cout << v.idx() << ": HC = " << h
|
||||
<< ", GC = " << g << "\n"
|
||||
<< ", PC = [ " << p.min_curvature << " , " << p.max_curvature << " ]\n";
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -80,6 +80,8 @@ if(TARGET CGAL::Eigen3_support)
|
|||
target_link_libraries(test_shape_smoothing PUBLIC CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("delaunay_remeshing_test.cpp")
|
||||
target_link_libraries(delaunay_remeshing_test PUBLIC CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("test_interpolated_corrected_curvatures.cpp")
|
||||
target_link_libraries(test_interpolated_corrected_curvatures PUBLIC CGAL::Eigen3_support)
|
||||
create_single_source_cgal_program("test_decimation_of_planar_patches.cpp")
|
||||
target_link_libraries(test_decimation_of_planar_patches PUBLIC CGAL::Eigen3_support)
|
||||
else()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,255 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_mesh_processing/interpolated_corrected_curvatures.h>
|
||||
#include <CGAL/Polygon_mesh_processing/random_perturbation.h>
|
||||
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/property_map.h>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
|
||||
#define ABS_ERROR 1e-6
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic_kernel;
|
||||
typedef CGAL::Surface_mesh<Epic_kernel::Point_3> SMesh;
|
||||
typedef CGAL::Polyhedron_3<Epic_kernel> Polyhedron;
|
||||
|
||||
struct Average_test_info {
|
||||
Epic_kernel::FT expansion_radius = -1;
|
||||
Epic_kernel::FT mean_curvature_avg;
|
||||
Epic_kernel::FT gaussian_curvature_avg;
|
||||
Epic_kernel::FT principal_curvature_avg;
|
||||
Epic_kernel::FT tolerance = 0.9;
|
||||
|
||||
Average_test_info(
|
||||
Epic_kernel::FT mean_curvature_avg,
|
||||
Epic_kernel::FT gaussian_curvature_avg,
|
||||
Epic_kernel::FT principal_curvature_avg,
|
||||
Epic_kernel::FT expansion_radius = -1,
|
||||
Epic_kernel::FT tolerance = 0.9
|
||||
) :
|
||||
expansion_radius(expansion_radius),
|
||||
mean_curvature_avg(mean_curvature_avg),
|
||||
gaussian_curvature_avg(gaussian_curvature_avg),
|
||||
principal_curvature_avg(principal_curvature_avg),
|
||||
tolerance(tolerance)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
bool passes_comparison(Epic_kernel::FT result, Epic_kernel::FT expected, Epic_kernel::FT tolerance) {
|
||||
if (abs(expected) < ABS_ERROR && abs(result) < ABS_ERROR)
|
||||
return true; // expected 0, got 0
|
||||
else if (abs(expected) < ABS_ERROR)
|
||||
return false; // expected 0, got non-0
|
||||
|
||||
return (std::min)(result, expected) / (std::max)(result, expected) > tolerance;
|
||||
}
|
||||
|
||||
template <typename PolygonMesh>
|
||||
void test_average_curvatures(std::string mesh_path,
|
||||
Average_test_info test_info,
|
||||
bool compare_single_vertex = false,
|
||||
int scale_factor_exponent = 0
|
||||
) {
|
||||
typedef typename boost::graph_traits<PolygonMesh>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
PolygonMesh pmesh;
|
||||
const std::string filename = CGAL::data_file_path(mesh_path);
|
||||
|
||||
if (!CGAL::IO::read_polygon_mesh(filename, pmesh) || faces(pmesh).size() == 0)
|
||||
{
|
||||
std::cerr << "Invalid input file." << std::endl;
|
||||
}
|
||||
|
||||
// The following part is used to scale the given mesh and expected curvatures by a constant factor
|
||||
// this is used to test the stability of the implementation across different scales
|
||||
if (scale_factor_exponent) {
|
||||
Epic_kernel::FT factor = pow(10, scale_factor_exponent);
|
||||
|
||||
test_info.expansion_radius *= factor;
|
||||
test_info.mean_curvature_avg /= factor;
|
||||
test_info.gaussian_curvature_avg /= factor * factor;
|
||||
test_info.principal_curvature_avg /= factor;
|
||||
|
||||
auto vpm = get(CGAL::vertex_point, pmesh);
|
||||
|
||||
for (vertex_descriptor vi : vertices(pmesh)) {
|
||||
Epic_kernel::Point_3 pi = get(vpm, vi);
|
||||
Epic_kernel::Point_3 pi_new(pi.x() * factor, pi.y() * factor, pi.z() * factor);
|
||||
put(vpm, vi, pi_new);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typename boost::property_map<PolygonMesh, CGAL::dynamic_vertex_property_t<Epic_kernel::FT>>::type
|
||||
mean_curvature_map = get(CGAL::dynamic_vertex_property_t<Epic_kernel::FT>(), pmesh),
|
||||
gaussian_curvature_map = get(CGAL::dynamic_vertex_property_t<Epic_kernel::FT>(), pmesh);
|
||||
typename boost::property_map
|
||||
<PolygonMesh, CGAL::dynamic_vertex_property_t<PMP::Principal_curvatures_and_directions<Epic_kernel>>>::type
|
||||
principal_curvatures_and_directions_map =
|
||||
get(CGAL::dynamic_vertex_property_t<PMP::Principal_curvatures_and_directions<Epic_kernel>>(), pmesh);
|
||||
// test_info.expansion_radius -> test if no radius is provided by user.
|
||||
if (test_info.expansion_radius < 0) {
|
||||
PMP::interpolated_corrected_mean_curvature(pmesh, mean_curvature_map);
|
||||
PMP::interpolated_corrected_Gaussian_curvature(pmesh, gaussian_curvature_map);
|
||||
PMP::interpolated_corrected_principal_curvatures_and_directions(pmesh, principal_curvatures_and_directions_map);
|
||||
}
|
||||
else {
|
||||
PMP::interpolated_corrected_mean_curvature(
|
||||
pmesh,
|
||||
mean_curvature_map,
|
||||
CGAL::parameters::ball_radius(test_info.expansion_radius)
|
||||
);
|
||||
|
||||
PMP::interpolated_corrected_Gaussian_curvature(
|
||||
pmesh,
|
||||
gaussian_curvature_map,
|
||||
CGAL::parameters::ball_radius(test_info.expansion_radius)
|
||||
);
|
||||
|
||||
PMP::interpolated_corrected_principal_curvatures_and_directions(
|
||||
pmesh,
|
||||
principal_curvatures_and_directions_map,
|
||||
CGAL::parameters::ball_radius(test_info.expansion_radius)
|
||||
);
|
||||
}
|
||||
|
||||
Epic_kernel::FT mean_curvature_avg = 0, gaussian_curvature_avg = 0, principal_curvature_avg = 0;
|
||||
|
||||
for (vertex_descriptor v : vertices(pmesh)) {
|
||||
mean_curvature_avg += get(mean_curvature_map, v);
|
||||
gaussian_curvature_avg += get(gaussian_curvature_map, v);
|
||||
principal_curvature_avg += get(principal_curvatures_and_directions_map, v).min_curvature
|
||||
+ get(principal_curvatures_and_directions_map, v).max_curvature;
|
||||
}
|
||||
|
||||
mean_curvature_avg /= vertices(pmesh).size();
|
||||
gaussian_curvature_avg /= vertices(pmesh).size();
|
||||
principal_curvature_avg /= vertices(pmesh).size() * 2;
|
||||
|
||||
// are average curvatures equal to expected?
|
||||
assert(passes_comparison(mean_curvature_avg, test_info.mean_curvature_avg, test_info.tolerance));
|
||||
assert(passes_comparison(gaussian_curvature_avg, test_info.gaussian_curvature_avg, test_info.tolerance));
|
||||
assert(passes_comparison(principal_curvature_avg, test_info.principal_curvature_avg, test_info.tolerance));
|
||||
|
||||
// computing curvatures together from interpolated_corrected_curvatures()
|
||||
PMP::interpolated_corrected_curvatures(
|
||||
pmesh,
|
||||
CGAL::parameters::ball_radius(test_info.expansion_radius)
|
||||
.vertex_mean_curvature_map(mean_curvature_map)
|
||||
.vertex_Gaussian_curvature_map(gaussian_curvature_map)
|
||||
.vertex_principal_curvatures_and_directions_map(principal_curvatures_and_directions_map)
|
||||
);
|
||||
|
||||
Epic_kernel::FT new_mean_curvature_avg = 0, new_Gaussian_curvature_avg = 0, new_principal_curvature_avg = 0;
|
||||
|
||||
for (vertex_descriptor v : vertices(pmesh)) {
|
||||
new_mean_curvature_avg += get(mean_curvature_map, v);
|
||||
new_Gaussian_curvature_avg += get(gaussian_curvature_map, v);
|
||||
new_principal_curvature_avg += get(principal_curvatures_and_directions_map, v).min_curvature
|
||||
+ get(principal_curvatures_and_directions_map, v).max_curvature;
|
||||
}
|
||||
|
||||
new_mean_curvature_avg /= vertices(pmesh).size();
|
||||
new_Gaussian_curvature_avg /= vertices(pmesh).size();
|
||||
new_principal_curvature_avg /= vertices(pmesh).size() * 2;
|
||||
|
||||
// are average curvatures computed from interpolated_corrected_curvatures()
|
||||
// equal to average curvatures each computed on its own?
|
||||
assert(passes_comparison(mean_curvature_avg, new_mean_curvature_avg, 0.99));
|
||||
assert(passes_comparison(gaussian_curvature_avg, new_Gaussian_curvature_avg, 0.99));
|
||||
assert(passes_comparison(principal_curvature_avg, new_principal_curvature_avg, 0.99));
|
||||
|
||||
if (compare_single_vertex) {
|
||||
// computing curvatures together from interpolated_corrected_curvatures()
|
||||
|
||||
Epic_kernel::FT single_vertex_mean_curvature_avg = 0,
|
||||
single_vertex_Gaussian_curvature_avg = 0,
|
||||
single_vertex_principal_curvature_avg = 0;
|
||||
|
||||
Epic_kernel::FT h, g;
|
||||
PMP::Principal_curvatures_and_directions<Epic_kernel> p;
|
||||
|
||||
for (vertex_descriptor v : vertices(pmesh)) {
|
||||
PMP::interpolated_corrected_curvatures_one_vertex(
|
||||
pmesh,
|
||||
v,
|
||||
CGAL::parameters::vertex_Gaussian_curvature(std::ref(g))
|
||||
.vertex_mean_curvature(std::ref(h))
|
||||
.vertex_principal_curvatures_and_directions(std::ref(p))
|
||||
.ball_radius(test_info.expansion_radius)
|
||||
);
|
||||
|
||||
single_vertex_mean_curvature_avg += h;
|
||||
single_vertex_Gaussian_curvature_avg += g;
|
||||
single_vertex_principal_curvature_avg += p.min_curvature + p.max_curvature;
|
||||
}
|
||||
|
||||
single_vertex_mean_curvature_avg /= vertices(pmesh).size();
|
||||
single_vertex_Gaussian_curvature_avg /= vertices(pmesh).size();
|
||||
single_vertex_principal_curvature_avg /= vertices(pmesh).size() * 2;
|
||||
|
||||
assert(passes_comparison(mean_curvature_avg, single_vertex_mean_curvature_avg, 0.99));
|
||||
assert(passes_comparison(gaussian_curvature_avg, single_vertex_Gaussian_curvature_avg, 0.99));
|
||||
assert(passes_comparison(principal_curvature_avg, single_vertex_principal_curvature_avg, 0.99));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// testing on a simple sphere(r = 0.5), on both Polyhedron & SurfaceMesh:
|
||||
// For this mesh, ina addition to the whole mesh functions, we also compare against the single vertex
|
||||
// curvature functions to make sure the produce the same results
|
||||
// Expected: Mean Curvature = 2, Gaussian Curvature = 4, Principal Curvatures = 2 & 2 so 2 on avg.
|
||||
test_average_curvatures<Polyhedron>("meshes/sphere.off", Average_test_info(2, 4, 2), true);
|
||||
test_average_curvatures<SMesh>("meshes/sphere.off", Average_test_info(2, 4, 2), true);
|
||||
|
||||
// Same mesh but with specified expansion radii of 0 and 0.25 (half radius of sphere)
|
||||
test_average_curvatures<SMesh>("meshes/sphere.off", Average_test_info(2, 4, 2, 0), true);
|
||||
test_average_curvatures<SMesh>("meshes/sphere.off", Average_test_info(2, 4, 2, 0.25), true);
|
||||
|
||||
// testing on a simple sphere(r = 10), on both Polyhedron & SurfaceMesh:
|
||||
// Expected: Mean Curvature = 0.1, Gaussian Curvature = 0.01, Principal Curvatures = 0.1 & 0.1 so 0.1 on avg.
|
||||
test_average_curvatures<Polyhedron>("meshes/sphere966.off", Average_test_info(0.1, 0.01, 0.1));
|
||||
test_average_curvatures<SMesh>("meshes/sphere966.off", Average_test_info(0.1, 0.01, 0.1));
|
||||
|
||||
// Same mesh but with specified expansion radii of 0 and 5 (half radius of sphere)
|
||||
test_average_curvatures<SMesh>("meshes/sphere966.off", Average_test_info(0.1, 0.01, 0.1, 0));
|
||||
test_average_curvatures<SMesh>("meshes/sphere966.off", Average_test_info(0.1, 0.01, 0.1, 5));
|
||||
|
||||
// testing on a simple half cylinder(r = 1), on both Polyhedron & SurfaceMesh:
|
||||
// Expected: Mean Curvature = 0.5, Gaussian Curvature = 0, Principal Curvatures = 0 & 1 so 0.5 on avg.
|
||||
test_average_curvatures<Polyhedron>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5));
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5));
|
||||
|
||||
// Same mesh but with specified expansion radii of 0 and 0.5 (half radius of cylinder)
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0));
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0.5));
|
||||
|
||||
// Same tests as last one, but with a scaling on the mesh with different values to check for scale stability
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0), false, -6);
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0.5), false, -6);
|
||||
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0), false, -3);
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0.5), false, -3);
|
||||
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0), false, -1);
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0.5), false, -1);
|
||||
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0), false, 1);
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0.5), false, 1);
|
||||
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0), false, 3);
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0.5), false, 3);
|
||||
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0), false, 6);
|
||||
test_average_curvatures<SMesh>("meshes/cylinder.off", Average_test_info(0.5, 0, 0.5, 0.5), false, 6);
|
||||
}
|
||||
|
|
@ -84,18 +84,18 @@
|
|||
<property name="title">
|
||||
<string>Ramp Colors</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QPushButton" name="minColorButton">
|
||||
<property name="text">
|
||||
<string>Color Min...</string>
|
||||
<string>Min</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="maxColorButton">
|
||||
<property name="text">
|
||||
<string>Color Max...</string>
|
||||
<string>Max</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -135,7 +135,7 @@
|
|||
<property name="title">
|
||||
<string>Zoom </string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QPushButton" name="zoomToMinButton">
|
||||
<property name="text">
|
||||
|
|
@ -158,7 +158,7 @@
|
|||
<property name="title">
|
||||
<string>Ramp Extrema</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="DoubleEdit" name="minBox">
|
||||
<property name="text">
|
||||
|
|
@ -186,6 +186,32 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QSlider" name="expandingRadiusSlider">
|
||||
<property name="minimum">
|
||||
<float>0</float>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<float>100</float>
|
||||
</property>
|
||||
<property name="tracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QLabel" name="expandingRadiusLabel">
|
||||
<property name="text">
|
||||
<string>Expanding Radius: 0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <QColorDialog>
|
||||
#include <QPalette>
|
||||
#include <QColor>
|
||||
#include <QSlider>
|
||||
#include <QStyleFactory>
|
||||
#include <QMessageBox>
|
||||
#include <QAbstractItemView>
|
||||
|
|
@ -15,6 +16,7 @@
|
|||
#include <CGAL/boost/graph/helpers.h>
|
||||
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
|
||||
#include <CGAL/Heat_method_3/Surface_mesh_geodesic_distances_3.h>
|
||||
#include <CGAL/Polygon_mesh_processing/interpolated_corrected_curvatures.h>
|
||||
|
||||
#include "Scene_points_with_normal_item.h"
|
||||
|
||||
|
|
@ -31,6 +33,7 @@
|
|||
#include <CGAL/Dynamic_property_map.h>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#define ARBITRARY_DBL_MIN 1.0E-30
|
||||
#define ARBITRARY_DBL_MAX 1.0E+30
|
||||
|
|
@ -41,6 +44,8 @@
|
|||
typedef CGAL::Three::Triangle_container Tri;
|
||||
typedef CGAL::Three::Viewer_interface VI;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
class Scene_heat_item
|
||||
: public CGAL::Three::Scene_item_rendering_helper
|
||||
{
|
||||
|
|
@ -333,7 +338,10 @@ class DisplayPropertyPlugin :
|
|||
typedef CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<SMesh, CGAL::Heat_method_3::Intrinsic_Delaunay> Heat_method_idt;
|
||||
typedef CGAL::dynamic_vertex_property_t<bool> Vertex_source_tag;
|
||||
typedef boost::property_map<SMesh, Vertex_source_tag>::type Vertex_source_map;
|
||||
|
||||
enum CurvatureType {
|
||||
MEAN_CURVATURE,
|
||||
GAUSSIAN_CURVATURE,
|
||||
};
|
||||
public:
|
||||
|
||||
bool applicable(QAction* action) const Q_DECL_OVERRIDE
|
||||
|
|
@ -482,8 +490,10 @@ public:
|
|||
connect(scene_obj, SIGNAL(itemIndexSelected(int)),
|
||||
this,SLOT(detectScalarProperties(int)));
|
||||
|
||||
on_propertyBox_currentIndexChanged(0);
|
||||
connect(dock_widget->expandingRadiusSlider, SIGNAL(valueChanged(int)),
|
||||
this, SLOT(setExpandingRadius(int)));
|
||||
|
||||
on_propertyBox_currentIndexChanged(0);
|
||||
|
||||
}
|
||||
private:
|
||||
|
|
@ -529,6 +539,8 @@ private Q_SLOTS:
|
|||
dock_widget->propertyBox->addItem("Scaled Jacobian");
|
||||
dock_widget->propertyBox->addItem("Heat Intensity");
|
||||
dock_widget->propertyBox->addItem("Heat Intensity (Intrinsic Delaunay)");
|
||||
dock_widget->propertyBox->addItem("Interpolated Corrected Mean Curvature");
|
||||
dock_widget->propertyBox->addItem("Interpolated Corrected Gaussian Curvature");
|
||||
detectSMScalarProperties(sm_item->face_graph());
|
||||
|
||||
}
|
||||
|
|
@ -603,6 +615,14 @@ private Q_SLOTS:
|
|||
return;
|
||||
sm_item->setRenderingMode(Gouraud);
|
||||
break;
|
||||
case 4: // Interpolated Corrected Mean Curvature
|
||||
displayInterpolatedCurvatureMeasure(sm_item, MEAN_CURVATURE);
|
||||
sm_item->setRenderingMode(Gouraud);
|
||||
break;
|
||||
case 5: // Interpolated Corrected Gaussian Curvature
|
||||
displayInterpolatedCurvatureMeasure(sm_item, GAUSSIAN_CURVATURE);
|
||||
sm_item->setRenderingMode(Gouraud);
|
||||
break;
|
||||
default:
|
||||
if(dock_widget->propertyBox->currentText().contains("v:"))
|
||||
{
|
||||
|
|
@ -637,6 +657,14 @@ private Q_SLOTS:
|
|||
sm_item->face_graph()->property_map<face_descriptor,double>("f:angle");
|
||||
if(does_exist)
|
||||
sm_item->face_graph()->remove_property_map(pmap);
|
||||
std::tie(pmap, does_exist) =
|
||||
sm_item->face_graph()->property_map<face_descriptor, double>("v:interpolated_corrected_mean_curvature");
|
||||
if (does_exist)
|
||||
sm_item->face_graph()->remove_property_map(pmap);
|
||||
std::tie(pmap, does_exist) =
|
||||
sm_item->face_graph()->property_map<face_descriptor, double>("v:interpolated_corrected_Gaussian_curvature");
|
||||
if (does_exist)
|
||||
sm_item->face_graph()->remove_property_map(pmap);
|
||||
});
|
||||
QApplication::restoreOverrideCursor();
|
||||
sm_item->invalidateOpenGLBuffers();
|
||||
|
|
@ -668,13 +696,21 @@ private Q_SLOTS:
|
|||
switch(dock_widget->propertyBox->currentIndex())
|
||||
{
|
||||
case 0:
|
||||
dock_widget->zoomToMinButton->setEnabled(angles_max.count(sm_item)>0 );
|
||||
dock_widget->zoomToMinButton->setEnabled(angles_min.count(sm_item)>0 );
|
||||
dock_widget->zoomToMaxButton->setEnabled(angles_max.count(sm_item)>0 );
|
||||
break;
|
||||
case 1:
|
||||
dock_widget->zoomToMinButton->setEnabled(jacobian_max.count(sm_item)>0);
|
||||
dock_widget->zoomToMinButton->setEnabled(jacobian_min.count(sm_item)>0);
|
||||
dock_widget->zoomToMaxButton->setEnabled(jacobian_max.count(sm_item)>0);
|
||||
break;
|
||||
case 4:
|
||||
dock_widget->zoomToMinButton->setEnabled(mean_curvature_min.count(sm_item) > 0);
|
||||
dock_widget->zoomToMaxButton->setEnabled(mean_curvature_max.count(sm_item) > 0);
|
||||
break;
|
||||
case 5:
|
||||
dock_widget->zoomToMinButton->setEnabled(gaussian_curvature_min.count(sm_item) > 0);
|
||||
dock_widget->zoomToMaxButton->setEnabled(gaussian_curvature_max.count(sm_item) > 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -685,6 +721,10 @@ private Q_SLOTS:
|
|||
{
|
||||
Scene_surface_mesh_item* item =
|
||||
qobject_cast<Scene_surface_mesh_item*>(sender());
|
||||
|
||||
maxEdgeLength = -1;
|
||||
setExpandingRadius(dock_widget->expandingRadiusSlider->value());
|
||||
|
||||
if(!item)
|
||||
return;
|
||||
SMesh& smesh = *item->face_graph();
|
||||
|
|
@ -701,11 +741,22 @@ private Q_SLOTS:
|
|||
{
|
||||
smesh.remove_property_map(angles);
|
||||
}
|
||||
SMesh::Property_map<vertex_descriptor, double> mean_curvature;
|
||||
std::tie(mean_curvature, found) = smesh.property_map<vertex_descriptor, double>("v:interpolated_corrected_mean_curvature");
|
||||
if (found)
|
||||
{
|
||||
smesh.remove_property_map(mean_curvature);
|
||||
}
|
||||
SMesh::Property_map<vertex_descriptor, double> gaussian_curvature;
|
||||
std::tie(gaussian_curvature, found) = smesh.property_map<vertex_descriptor, double>("v:interpolated_corrected_Gaussian_curvature");
|
||||
if (found)
|
||||
{
|
||||
smesh.remove_property_map(gaussian_curvature);
|
||||
}
|
||||
}
|
||||
|
||||
void displayScaledJacobian(Scene_surface_mesh_item* item)
|
||||
{
|
||||
|
||||
SMesh& smesh = *item->face_graph();
|
||||
//compute and store the jacobian per face
|
||||
bool non_init;
|
||||
|
|
@ -742,16 +793,118 @@ private Q_SLOTS:
|
|||
treat_sm_property<face_descriptor>("f:jacobian", item->face_graph());
|
||||
}
|
||||
|
||||
bool resetScaledJacobian(Scene_surface_mesh_item* item)
|
||||
void setExpandingRadius(int val_int)
|
||||
{
|
||||
SMesh& smesh = *item->face_graph();
|
||||
if(!smesh.property_map<face_descriptor, double>("f:jacobian").second)
|
||||
double sliderMin = dock_widget->expandingRadiusSlider->minimum();
|
||||
double sliderMax = dock_widget->expandingRadiusSlider->maximum() - sliderMin;
|
||||
double val = val_int - sliderMin;
|
||||
sliderMin = 0;
|
||||
|
||||
SMesh& smesh = *(qobject_cast<Scene_surface_mesh_item*>(scene->item(scene->mainSelectionIndex())))->face_graph();
|
||||
|
||||
auto vpm = get(CGAL::vertex_point, smesh);
|
||||
|
||||
if (maxEdgeLength < 0)
|
||||
{
|
||||
return false;
|
||||
auto edge_range = CGAL::edges(smesh);
|
||||
|
||||
if (edge_range.begin() == edge_range.end())
|
||||
{
|
||||
expand_radius = 0;
|
||||
dock_widget->expandingRadiusLabel->setText(tr("Expanding Radius : %1").arg(expand_radius));
|
||||
return;
|
||||
}
|
||||
|
||||
auto edge_reference = std::max_element(edge_range.begin(), edge_range.end(), [&, vpm, smesh](auto l, auto r) {
|
||||
auto res = EPICK().compare_squared_distance_3_object()(
|
||||
get(vpm, source((l), smesh)),
|
||||
get(vpm, target((l), smesh)),
|
||||
get(vpm, source((r), smesh)),
|
||||
get(vpm, target((r), smesh)));
|
||||
return res == CGAL::SMALLER;
|
||||
});
|
||||
|
||||
// if edge_reference is not derefrenceble
|
||||
if (edge_reference == edge_range.end())
|
||||
{
|
||||
expand_radius = 0;
|
||||
dock_widget->expandingRadiusLabel->setText(tr("Expanding Radius : %1").arg(expand_radius));
|
||||
return;
|
||||
}
|
||||
|
||||
maxEdgeLength = sqrt(
|
||||
(get(vpm, source((*edge_reference), smesh)) - get(vpm, target((*edge_reference), smesh)))
|
||||
.squared_length()
|
||||
);
|
||||
|
||||
}
|
||||
dock_widget->minBox->setValue(jacobian_min[item].first-0.01);
|
||||
dock_widget->maxBox->setValue(jacobian_max[item].first);
|
||||
return true;
|
||||
|
||||
double outMax = 5 * maxEdgeLength, base = 1.2;
|
||||
|
||||
expand_radius = (pow(base, val) - 1) * outMax / (pow(base, sliderMax) - 1);
|
||||
dock_widget->expandingRadiusLabel->setText(tr("Expanding Radius : %1").arg(expand_radius));
|
||||
|
||||
}
|
||||
|
||||
void displayInterpolatedCurvatureMeasure(Scene_surface_mesh_item* item, CurvatureType mu_index)
|
||||
{
|
||||
if (mu_index != MEAN_CURVATURE && mu_index != GAUSSIAN_CURVATURE) return;
|
||||
|
||||
std::string tied_string = (mu_index == MEAN_CURVATURE)?
|
||||
"v:interpolated_corrected_mean_curvature": "v:interpolated_corrected_Gaussian_curvature";
|
||||
SMesh& smesh = *item->face_graph();
|
||||
|
||||
const auto vnm = smesh.property_map<vertex_descriptor, EPICK::Vector_3>("v:normal_before_perturbation").first;
|
||||
const bool vnm_exists = smesh.property_map<vertex_descriptor, EPICK::Vector_3>("v:normal_before_perturbation").second;
|
||||
|
||||
//compute once and store the value per vertex
|
||||
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 (vnm_exists) {
|
||||
if (mu_index == MEAN_CURVATURE)
|
||||
PMP::interpolated_corrected_mean_curvature(smesh, mu_i_map, CGAL::parameters::ball_radius(expand_radius).vertex_normal_map(vnm));
|
||||
else
|
||||
PMP::interpolated_corrected_Gaussian_curvature(smesh, mu_i_map, CGAL::parameters::ball_radius(expand_radius).vertex_normal_map(vnm));
|
||||
}
|
||||
else {
|
||||
if (mu_index == MEAN_CURVATURE)
|
||||
PMP::interpolated_corrected_mean_curvature(smesh, mu_i_map, CGAL::parameters::ball_radius(expand_radius));
|
||||
else
|
||||
PMP::interpolated_corrected_Gaussian_curvature(smesh, mu_i_map, CGAL::parameters::ball_radius(expand_radius));
|
||||
}
|
||||
double res_min = ARBITRARY_DBL_MAX,
|
||||
res_max = -ARBITRARY_DBL_MAX;
|
||||
SMesh::Vertex_index min_index, max_index;
|
||||
for (SMesh::Vertex_index v : vertices(smesh))
|
||||
{
|
||||
if (mu_i_map[v] > res_max)
|
||||
{
|
||||
res_max = mu_i_map[v];
|
||||
max_index = v;
|
||||
}
|
||||
if (mu_i_map[v] < res_min)
|
||||
{
|
||||
res_min = mu_i_map[v];
|
||||
min_index = v;
|
||||
}
|
||||
}
|
||||
if (mu_index == MEAN_CURVATURE){
|
||||
mean_curvature_max[item] = std::make_pair(res_max, max_index);
|
||||
mean_curvature_min[item] = std::make_pair(res_min, min_index);
|
||||
}
|
||||
else {
|
||||
gaussian_curvature_max[item] = std::make_pair(res_max, max_index);
|
||||
gaussian_curvature_min[item] = std::make_pair(res_min, min_index);
|
||||
}
|
||||
|
||||
connect(item, &Scene_surface_mesh_item::itemChanged,
|
||||
this, &DisplayPropertyPlugin::resetProperty);
|
||||
}
|
||||
treat_sm_property<vertex_descriptor>(tied_string, item->face_graph());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1054,6 +1207,8 @@ private Q_SLOTS:
|
|||
break;
|
||||
}
|
||||
case 1:
|
||||
case 4:
|
||||
case 5:
|
||||
dock_widget->groupBox-> setEnabled(true);
|
||||
dock_widget->groupBox_3->setEnabled(true);
|
||||
|
||||
|
|
@ -1113,6 +1268,26 @@ private Q_SLOTS:
|
|||
dummy_fd,
|
||||
dummy_p);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
::zoomToId(*item->face_graph(),
|
||||
QString("v%1").arg(mean_curvature_min[item].second),
|
||||
getActiveViewer(),
|
||||
dummy_fd,
|
||||
dummy_p);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
::zoomToId(*item->face_graph(),
|
||||
QString("v%1").arg(gaussian_curvature_min[item].second),
|
||||
getActiveViewer(),
|
||||
dummy_fd,
|
||||
dummy_p);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -1146,7 +1321,25 @@ private Q_SLOTS:
|
|||
dummy_fd,
|
||||
dummy_p);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
::zoomToId(*item->face_graph(),
|
||||
QString("v%1").arg(mean_curvature_max[item].second),
|
||||
getActiveViewer(),
|
||||
dummy_fd,
|
||||
dummy_p);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
::zoomToId(*item->face_graph(),
|
||||
QString("v%1").arg(gaussian_curvature_max[item].second),
|
||||
getActiveViewer(),
|
||||
dummy_fd,
|
||||
dummy_p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1315,10 +1508,10 @@ private:
|
|||
void displayMapLegend(const std::vector<Value_type>& values)
|
||||
{
|
||||
// Create a legend_ and display it
|
||||
const std::size_t size = (std::min)(color_map.size(), (std::size_t)256);
|
||||
const std::size_t size = (std::min)(color_map.size(), (std::size_t)2048);
|
||||
const int text_height = 20;
|
||||
const int height = text_height*static_cast<int>(size) + text_height;
|
||||
const int width = 140;
|
||||
const int width = 170;
|
||||
const int cell_width = width/3;
|
||||
const int top_margin = 15;
|
||||
const int left_margin = 5;
|
||||
|
|
@ -1344,8 +1537,8 @@ private:
|
|||
tick_height,
|
||||
color);
|
||||
QRect text_rect(left_margin + cell_width+10, drawing_height - top_margin - j,
|
||||
50, text_height);
|
||||
painter.drawText(text_rect, Qt::AlignCenter, tr("%1").arg(values[i], 0, 'f', 3, QLatin1Char(' ')));
|
||||
100, text_height);
|
||||
painter.drawText(text_rect, Qt::AlignCenter, tr("%1").arg(values[i], 0, 'f', 7, QLatin1Char(' ')));
|
||||
}
|
||||
if(color_map.size() > size){
|
||||
QRect text_rect(left_margin + cell_width+10, 0,
|
||||
|
|
@ -1364,7 +1557,7 @@ private:
|
|||
{
|
||||
// Create a legend_ and display it
|
||||
const int height = 256;
|
||||
const int width = 140;
|
||||
const int width = 170;
|
||||
const int cell_width = width/3;
|
||||
const int top_margin = 5;
|
||||
const int left_margin = 5;
|
||||
|
|
@ -1408,11 +1601,11 @@ private:
|
|||
painter.setPen(Qt::blue);
|
||||
QRect min_text_rect(left_margin + cell_width+10,drawing_height - top_margin,
|
||||
100, text_height);
|
||||
painter.drawText(min_text_rect, Qt::AlignCenter, tr("%1").arg(min_value, 0, 'f', 1));
|
||||
painter.drawText(min_text_rect, Qt::AlignCenter, tr("%1").arg(min_value, 0, 'f', 7));
|
||||
|
||||
QRect max_text_rect(left_margin + cell_width+10, drawing_height - top_margin - 200,
|
||||
100, text_height);
|
||||
painter.drawText(max_text_rect, Qt::AlignCenter, tr("%1").arg(max_value, 0, 'f', 1));
|
||||
painter.drawText(max_text_rect, Qt::AlignCenter, tr("%1").arg(max_value, 0, 'f', 7));
|
||||
|
||||
dock_widget->legendLabel->setPixmap(legend_);
|
||||
}
|
||||
|
|
@ -1436,9 +1629,17 @@ private:
|
|||
|
||||
std::unordered_map<Scene_surface_mesh_item*, std::pair<double, SMesh::Face_index> > angles_min;
|
||||
std::unordered_map<Scene_surface_mesh_item*, std::pair<double, SMesh::Face_index> > angles_max;
|
||||
|
||||
std::unordered_map<Scene_surface_mesh_item*, std::pair<double, SMesh::Vertex_index> > mean_curvature_min;
|
||||
std::unordered_map<Scene_surface_mesh_item*, std::pair<double, SMesh::Vertex_index> > mean_curvature_max;
|
||||
|
||||
std::unordered_map<Scene_surface_mesh_item*, std::pair<double, SMesh::Vertex_index> > gaussian_curvature_min;
|
||||
std::unordered_map<Scene_surface_mesh_item*, std::pair<double, SMesh::Vertex_index> > gaussian_curvature_max;
|
||||
|
||||
std::unordered_map<Scene_surface_mesh_item*, Vertex_source_map> is_source;
|
||||
|
||||
|
||||
double expand_radius = 0;
|
||||
double maxEdgeLength = -1;
|
||||
double minBox;
|
||||
double maxBox;
|
||||
QPixmap legend_;
|
||||
|
|
@ -1718,7 +1919,7 @@ private:
|
|||
}
|
||||
|
||||
|
||||
EPICK::Vector_3 unit_center_normal = CGAL::Polygon_mesh_processing::compute_face_normal(f, mesh);
|
||||
EPICK::Vector_3 unit_center_normal = PMP::compute_face_normal(f, mesh);
|
||||
unit_center_normal *= 1.0/CGAL::approximate_sqrt(unit_center_normal.squared_length());
|
||||
|
||||
for(std::size_t i = 0; i < corner_areas.size(); ++i)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,20 @@ else()
|
|||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Jet fitting plugin will not be available.")
|
||||
endif()
|
||||
|
||||
if(TARGET CGAL::Eigen3_support)
|
||||
|
||||
polyhedron_demo_plugin(interpolated_corrected_principal_curvatures_plugin Interpolated_corrected_principal_curvatures_plugin)
|
||||
target_link_libraries(
|
||||
interpolated_corrected_principal_curvatures_plugin PUBLIC scene_surface_mesh_item scene_polylines_item
|
||||
CGAL::Eigen3_support)
|
||||
|
||||
else()
|
||||
message(
|
||||
STATUS
|
||||
"NOTICE: Eigen 3.1 (or greater) was not found. Interpolated corrected principal curvatures plugin will not be available."
|
||||
)
|
||||
endif()
|
||||
|
||||
polyhedron_demo_plugin(extrude_plugin Extrude_plugin KEYWORDS PMP)
|
||||
target_link_libraries(extrude_plugin PUBLIC scene_surface_mesh_item
|
||||
scene_selection_item)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include "Scene_surface_mesh_item.h"
|
||||
#include "Scene_polylines_item.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "Scene.h"
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/measure.h>
|
||||
#include <CGAL/Polygon_mesh_processing/interpolated_corrected_curvatures.h>
|
||||
|
||||
using namespace CGAL::Three;
|
||||
class Polyhedron_demo_interpolated_corrected_principal_curvatures_and_directions_plugin :
|
||||
public QObject,
|
||||
public Polyhedron_demo_plugin_interface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
|
||||
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
|
||||
|
||||
public:
|
||||
|
||||
QList<QAction*> actions() const {
|
||||
return _actions;
|
||||
}
|
||||
void init(QMainWindow* mw,
|
||||
Scene_interface* scene_interface,
|
||||
Messages_interface*)
|
||||
{
|
||||
scene = scene_interface;
|
||||
QAction *actionEstimateCurvature = new QAction(tr("Interpolated Corrected Principal Curvatures"), mw);
|
||||
connect(actionEstimateCurvature, SIGNAL(triggered()), this, SLOT(on_actionEstimateCurvature_triggered()));
|
||||
_actions <<actionEstimateCurvature;
|
||||
|
||||
}
|
||||
|
||||
bool applicable(QAction*) const {
|
||||
return qobject_cast<Scene_surface_mesh_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
void on_actionEstimateCurvature_triggered();
|
||||
private :
|
||||
Scene_interface *scene;
|
||||
QList<QAction*> _actions;
|
||||
}; // end Polyhedron_demo_interpolated_corrected_principal_curvatures_and_directions_plugin
|
||||
|
||||
|
||||
void compute(SMesh* sMesh,
|
||||
Scene_polylines_item* max_curv,
|
||||
Scene_polylines_item* min_curv,
|
||||
Scene_polylines_item* max_negative_curv,
|
||||
Scene_polylines_item* min_negative_curv)
|
||||
{
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic_kernel;
|
||||
typedef Epic_kernel::Point_3 Point;
|
||||
typedef Epic_kernel::Point_3 Point;
|
||||
typedef Epic_kernel::Vector_3 Vector;
|
||||
typedef boost::graph_traits<SMesh>::vertex_descriptor Vertex_descriptor;
|
||||
|
||||
typename boost::property_map<SMesh, CGAL::vertex_point_t>::type vpmap = get(CGAL::vertex_point, *sMesh);
|
||||
|
||||
bool created = false;
|
||||
SMesh::Property_map<Vertex_descriptor, PMP::Principal_curvatures_and_directions<Epic_kernel>> principal_curvatures_and_directions_map;
|
||||
|
||||
boost::tie(principal_curvatures_and_directions_map, created) = sMesh->add_property_map<Vertex_descriptor, PMP::Principal_curvatures_and_directions<Epic_kernel>>
|
||||
("v:principal_curvatures_and_directions_map", { 0, 0,
|
||||
Vector(0,0,0),
|
||||
Vector(0,0,0) });
|
||||
assert(created);
|
||||
|
||||
|
||||
PMP::interpolated_corrected_principal_curvatures_and_directions(
|
||||
*sMesh,
|
||||
principal_curvatures_and_directions_map,
|
||||
CGAL::parameters::ball_radius(0)
|
||||
);
|
||||
|
||||
double max_curvature_magnitude_on_mesh = 0;
|
||||
for (Vertex_descriptor v : vertices(*sMesh))
|
||||
{
|
||||
const PMP::Principal_curvatures_and_directions<Epic_kernel> pc = principal_curvatures_and_directions_map[v];
|
||||
max_curvature_magnitude_on_mesh = std::max(max_curvature_magnitude_on_mesh, std::max(abs(pc.min_curvature), abs(pc.max_curvature)));
|
||||
}
|
||||
|
||||
for(Vertex_descriptor v : vertices(*sMesh))
|
||||
{
|
||||
std::vector<Point> points;
|
||||
|
||||
// pick central point
|
||||
const Point& central_point = get(vpmap,v);
|
||||
points.push_back(central_point);
|
||||
|
||||
// compute min edge len around central vertex
|
||||
// to scale the ribbons used to display the directions
|
||||
|
||||
const std::size_t n = CGAL::edges(*sMesh).size();
|
||||
|
||||
double avg_edge_length = 0;
|
||||
if (n > 0) {
|
||||
for (auto e : CGAL::edges(*sMesh))
|
||||
avg_edge_length += PMP::edge_length(e, *sMesh);
|
||||
avg_edge_length /= n;
|
||||
}
|
||||
|
||||
const PMP::Principal_curvatures_and_directions<Epic_kernel> pc = principal_curvatures_and_directions_map[v];
|
||||
|
||||
Vector umin = (pc.min_curvature / max_curvature_magnitude_on_mesh) * pc.min_direction * avg_edge_length;
|
||||
Vector umax = (pc.max_curvature / max_curvature_magnitude_on_mesh) * pc.max_direction * avg_edge_length;
|
||||
|
||||
Scene_polylines_item::Polyline max_segment(2), min_segment(2);
|
||||
|
||||
const double du = 0.4;
|
||||
|
||||
min_segment[0] = central_point + du * umin;
|
||||
min_segment[1] = central_point - du * umin;
|
||||
max_segment[0] = central_point + du * umax;
|
||||
max_segment[1] = central_point - du * umax;
|
||||
|
||||
(pc.min_curvature > 0 ? min_curv : min_negative_curv)->polylines.push_back(min_segment);
|
||||
(pc.max_curvature > 0 ? max_curv : max_negative_curv)->polylines.push_back(max_segment);
|
||||
}
|
||||
}
|
||||
|
||||
void Polyhedron_demo_interpolated_corrected_principal_curvatures_and_directions_plugin::on_actionEstimateCurvature_triggered()
|
||||
{
|
||||
// get active polyhedron
|
||||
const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
|
||||
QString name = scene->item(index)->name();
|
||||
Scene_surface_mesh_item* sm_item =
|
||||
qobject_cast<Scene_surface_mesh_item*>(scene->item(index));
|
||||
if(! sm_item){
|
||||
return;
|
||||
}
|
||||
// wait cursor
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
// types
|
||||
Scene_polylines_item* max_curv = new Scene_polylines_item;
|
||||
max_curv->setColor(Qt::red);
|
||||
max_curv->setWidth(3);
|
||||
max_curv->setName(tr("%1 (max curvatures)").arg(name));
|
||||
|
||||
Scene_polylines_item* min_curv = new Scene_polylines_item;
|
||||
min_curv->setColor(QColor(255,210,0));
|
||||
min_curv->setWidth(4);
|
||||
min_curv->setName(tr("%1 (min curvatures)").arg(name));
|
||||
|
||||
Scene_polylines_item* max_negative_curv = new Scene_polylines_item;
|
||||
max_negative_curv->setColor(Qt::cyan);
|
||||
max_negative_curv->setWidth(4);
|
||||
max_negative_curv->setName(tr("%1 (max negative curvatures)").arg(name));
|
||||
|
||||
Scene_polylines_item* min_negative_curv = new Scene_polylines_item;
|
||||
min_negative_curv->setColor(Qt::blue);
|
||||
min_negative_curv->setWidth(3);
|
||||
min_negative_curv->setName(tr("%1 (min negative curvatures)").arg(name));
|
||||
|
||||
SMesh* pMesh = sm_item->polyhedron();
|
||||
compute(pMesh, max_curv, min_curv, max_negative_curv, min_negative_curv);
|
||||
|
||||
scene->addItem(max_curv);
|
||||
scene->addItem(min_curv);
|
||||
max_curv->invalidateOpenGLBuffers();
|
||||
min_curv->invalidateOpenGLBuffers();
|
||||
scene->addItem(max_negative_curv);
|
||||
scene->addItem(min_negative_curv);
|
||||
max_negative_curv->invalidateOpenGLBuffers();
|
||||
min_negative_curv->invalidateOpenGLBuffers();
|
||||
|
||||
// default cursor
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
#include "Interpolated_corrected_principal_curvatures_plugin.moc"
|
||||
|
|
@ -135,6 +135,26 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="keep_normal_label">
|
||||
<property name="text">
|
||||
<string>keep vertex normals unperturbed</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>seed_spinbox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="keep_normal_checkbox">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="seed_label">
|
||||
<property name="text">
|
||||
<string>Random seed</string>
|
||||
|
|
@ -147,7 +167,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="seed_spinbox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
|
|
@ -163,6 +183,8 @@
|
|||
</layout>
|
||||
<zorder>seed_spinbox</zorder>
|
||||
<zorder>seed_label</zorder>
|
||||
<zorder>keep_normal_label</zorder>
|
||||
<zorder>keep_normal_checkbox</zorder>
|
||||
<zorder>deterministic_label</zorder>
|
||||
<zorder>deterministic_checkbox</zorder>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <CGAL/utility.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/random_perturbation.h>
|
||||
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <CGAL/property_map.h>
|
||||
|
|
@ -102,6 +103,12 @@ public Q_SLOTS:
|
|||
if (poly_item)
|
||||
{
|
||||
SMesh& pmesh = *poly_item->face_graph();
|
||||
if(ui.keep_normal_checkbox->isChecked())
|
||||
{
|
||||
SMesh::Property_map<vertex_descriptor, EPICK::Vector_3 > vnormals =
|
||||
pmesh.add_property_map<vertex_descriptor, EPICK::Vector_3 >("v:normal_before_perturbation").first;
|
||||
CGAL::Polygon_mesh_processing::compute_vertex_normals(pmesh,vnormals);
|
||||
}
|
||||
if(ui.deterministic_checkbox->isChecked())
|
||||
{
|
||||
unsigned int seed = static_cast<unsigned int>(ui.seed_spinbox->value());
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ hole_filling_plugin \
|
|||
hole_filling_sm_plugin \
|
||||
hole_filling_polyline_plugin \
|
||||
inside_out_plugin \
|
||||
interpolated_corrected_principal_curvatures_plugin\
|
||||
surface_intersection_plugin \
|
||||
surface_intersection_sm_plugin \
|
||||
io_image_plugin \
|
||||
|
|
|
|||
|
|
@ -93,6 +93,13 @@ CGAL_add_named_parameter(number_of_points_per_edge_t, number_of_points_per_edge,
|
|||
CGAL_add_named_parameter(number_of_points_on_edges_t, number_of_points_on_edges, number_of_points_on_edges)
|
||||
CGAL_add_named_parameter(nb_points_per_area_unit_t, nb_points_per_area_unit, number_of_points_per_area_unit)
|
||||
CGAL_add_named_parameter(nb_points_per_distance_unit_t, nb_points_per_distance_unit, number_of_points_per_distance_unit)
|
||||
CGAL_add_named_parameter(vertex_mean_curvature_map_t, vertex_mean_curvature_map, vertex_mean_curvature_map)
|
||||
CGAL_add_named_parameter(vertex_Gaussian_curvature_map_t, vertex_Gaussian_curvature_map, vertex_Gaussian_curvature_map)
|
||||
CGAL_add_named_parameter(vertex_principal_curvatures_and_directions_map_t, vertex_principal_curvatures_and_directions_map, vertex_principal_curvatures_and_directions_map)
|
||||
CGAL_add_named_parameter(vertex_mean_curvature_t, vertex_mean_curvature, vertex_mean_curvature)
|
||||
CGAL_add_named_parameter(vertex_Gaussian_curvature_t, vertex_Gaussian_curvature, vertex_Gaussian_curvature)
|
||||
CGAL_add_named_parameter(vertex_principal_curvatures_and_directions_t, vertex_principal_curvatures_and_directions, vertex_principal_curvatures_and_directions)
|
||||
CGAL_add_named_parameter(ball_radius_t, ball_radius, ball_radius)
|
||||
CGAL_add_named_parameter(outward_orientation_t, outward_orientation, outward_orientation)
|
||||
CGAL_add_named_parameter(overlap_test_t, overlap_test, do_overlap_test_of_bounded_sides)
|
||||
CGAL_add_named_parameter(preserve_genus_t, preserve_genus, preserve_genus)
|
||||
|
|
|
|||
Loading…
Reference in New Issue