mirror of https://github.com/CGAL/cgal
Merge branch 'old/gsoc2014-VCM_3-jmeyron' into gsoc2014-VCM_3-jmeyron
Conflicts: Installation/changes.html Point_set_processing_3/doc/Point_set_processing_3/PackageDescription.txt Point_set_processing_3/doc/Point_set_processing_3/Point_set_processing_3.txt Point_set_processing_3/doc/Point_set_processing_3/examples.txt Point_set_processing_3/examples/Point_set_processing_3/CMakeLists.txt Polyhedron/demo/Polyhedron/CMakeLists.txt
This commit is contained in:
commit
c2cd87865e
|
|
@ -0,0 +1,243 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Convex_hull_3/dual/halfspace_intersection_3.h>
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
#include <CGAL/convex_hull_3.h>
|
||||
#include <CGAL/Timer.h>
|
||||
#include <CGAL/point_generators_3.h>
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef K::Point_3 Point;
|
||||
typedef K::Plane_3 Plane;
|
||||
typedef K::Vector_3 Vector;
|
||||
|
||||
typedef CGAL::Convex_hull_traits_3<K> Traits;
|
||||
typedef Traits::Polyhedron_3 Polyhedron;
|
||||
|
||||
typedef CGAL::Delaunay_triangulation_3<K> DT;
|
||||
typedef DT::Vertex_handle Vertex_handle;
|
||||
|
||||
// Function object that computes the volume and the centroid of a polyhedron.
|
||||
template <class K>
|
||||
class Centroid_volume_accumulator {
|
||||
public:
|
||||
typedef typename K::Point_3 Point;
|
||||
typedef typename K::Vector_3 Vector;
|
||||
|
||||
Centroid_volume_accumulator() : vol(0),
|
||||
cx(0), cy(0), cz(0) {}
|
||||
|
||||
void operator () (const Point &a,
|
||||
const Point &b,
|
||||
const Point &c) {
|
||||
Vector ex(1, 0, 0),
|
||||
ey(0, 1, 0),
|
||||
ez(0, 0, 1);
|
||||
|
||||
Vector va = CGAL::ORIGIN - a;
|
||||
Vector vb = CGAL::ORIGIN - b;
|
||||
Vector vc = CGAL::ORIGIN - c;
|
||||
|
||||
// Updating the volume...
|
||||
Vector nhat = CGAL::cross_product(b - a, c - a);
|
||||
vol += nhat * va;
|
||||
|
||||
// ... and the centroid
|
||||
// X
|
||||
cx += (nhat * ex) * (
|
||||
CGAL::square(ex * (va + vb)) +
|
||||
CGAL::square(ex * (vb + vc)) +
|
||||
CGAL::square(ex * (vc + va)) );
|
||||
|
||||
// Y
|
||||
cy += (nhat * ey) * (
|
||||
CGAL::square(ey * (va + vb)) +
|
||||
CGAL::square(ey * (vb + vc)) +
|
||||
CGAL::square(ey * (vc + va)) );
|
||||
|
||||
// Z
|
||||
cz += (nhat * ez) * (
|
||||
CGAL::square(ez * (va + vb)) +
|
||||
CGAL::square(ez * (vb + vc)) +
|
||||
CGAL::square(ez * (vc + va)) );
|
||||
}
|
||||
|
||||
void end () {
|
||||
vol /= 6;
|
||||
cx /= (48 * vol);
|
||||
cy /= (48 * vol);
|
||||
cz /= (48 * vol);
|
||||
}
|
||||
|
||||
Point centroid () const {
|
||||
return Point(cx, cy, cz);
|
||||
}
|
||||
|
||||
float volume () const {
|
||||
return vol;
|
||||
}
|
||||
|
||||
void reset () {
|
||||
vol = 0;
|
||||
cx = 0;
|
||||
cy = 0;
|
||||
cz = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
// Volume
|
||||
float vol;
|
||||
|
||||
// Centroid
|
||||
float cx, cy, cz;
|
||||
};
|
||||
|
||||
// Apply a function object to all the triangles composing the faces of a polyhedron.
|
||||
template <typename Polyhedron, class F>
|
||||
F& apply_function_object_polyhedron (Polyhedron &P,
|
||||
F &f) {
|
||||
typedef typename Polyhedron::Halfedge_around_facet_circulator Hafc;
|
||||
typedef typename Polyhedron::Facet_iterator Facet_iterator;
|
||||
|
||||
f.reset();
|
||||
|
||||
for (Facet_iterator fit = P.facets_begin();
|
||||
fit != P.facets_end();
|
||||
fit++) {
|
||||
Hafc h0 = fit->facet_begin(), hf = h0--, hs = hf;
|
||||
hs ++;
|
||||
|
||||
while (1) {
|
||||
// Apply 'f' on each triangle of the polyhedron's facet
|
||||
f ( h0->vertex()->point(),
|
||||
hf->vertex()->point(),
|
||||
hs->vertex()->point() );
|
||||
|
||||
if (hs == h0)
|
||||
break;
|
||||
|
||||
hs++; hf++;
|
||||
}
|
||||
}
|
||||
|
||||
f.end();
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
// Lloyd algorithm
|
||||
// Generate points uniformly sampled inside a polyhedron.
|
||||
// An initial set of points needs to be given.
|
||||
template <class PolyIterator>
|
||||
void lloyd_algorithm (PolyIterator poly_begin,
|
||||
PolyIterator poly_end,
|
||||
std::vector<Point>& points) {
|
||||
std::list<Plane> planes;
|
||||
std::list<Point> centroids;
|
||||
Centroid_volume_accumulator<K> centroid_acc;
|
||||
|
||||
// Compute Delaunay triangulation
|
||||
DT dt(points.begin(), points.end());
|
||||
|
||||
for (DT::Finite_vertices_iterator vit = dt.finite_vertices_begin();
|
||||
vit != dt.finite_vertices_end();
|
||||
++vit) {
|
||||
planes.clear();
|
||||
// Voronoi cells
|
||||
std::list<Vertex_handle> vertices;
|
||||
dt.incident_vertices(vit, std::back_inserter(vertices));
|
||||
for (std::list<Vertex_handle>::iterator it = vertices.begin();
|
||||
it != vertices.end();
|
||||
it++) {
|
||||
Vector p = ((*it)->point() - vit->point()) / 2;
|
||||
planes.push_back (Plane(CGAL::midpoint((*it)->point(), vit->point()), p));
|
||||
}
|
||||
|
||||
// Add planes of the polyhedron faces
|
||||
for (PolyIterator it = poly_begin;
|
||||
it != poly_end;
|
||||
it++) {
|
||||
planes.push_back(*it);
|
||||
}
|
||||
|
||||
// Intersection
|
||||
Polyhedron P;
|
||||
CGAL::halfspace_intersection_3(planes.begin(),
|
||||
planes.end(),
|
||||
P,
|
||||
vit->point());
|
||||
|
||||
// Centroid
|
||||
apply_function_object_polyhedron(P, centroid_acc);
|
||||
centroids.push_back(centroid_acc.centroid());
|
||||
}
|
||||
|
||||
// Replace the initial points by the computed centroids
|
||||
points.clear();
|
||||
for (std::list<Point>::iterator it = centroids.begin();
|
||||
it != centroids.end();
|
||||
it++) {
|
||||
points.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
// Cube
|
||||
std::list<Plane> planes;
|
||||
planes.push_back(Plane(1, 0, 0, -1));
|
||||
planes.push_back(Plane(-1, 0, 0, -1));
|
||||
planes.push_back(Plane(0, 1, 0, -1));
|
||||
planes.push_back(Plane(0, -1, 0, -1));
|
||||
planes.push_back(Plane(0, 0, 1, -1));
|
||||
planes.push_back(Plane(0, 0, -1, -1));
|
||||
|
||||
std::vector<Point> points;
|
||||
int N, steps;
|
||||
// Number of points
|
||||
if (argc > 1) {
|
||||
N = atoi(argv[1]);
|
||||
} else {
|
||||
N = 50;
|
||||
}
|
||||
|
||||
// Number of steps
|
||||
if (argc > 2) {
|
||||
steps = atoi(argv[2]);
|
||||
} else {
|
||||
steps = 10;
|
||||
}
|
||||
|
||||
CGAL::Random_points_in_sphere_3<Point> g;
|
||||
for (int i = 0; i < N; i++) {
|
||||
Point p = *g++;
|
||||
points.push_back(p);
|
||||
}
|
||||
|
||||
std::ofstream bos("before_lloyd.xyz");
|
||||
std::copy(points.begin(), points.end(),
|
||||
std::ostream_iterator<Point>(bos, "\n"));
|
||||
|
||||
// Apply Lloyd algorithm: will generate points
|
||||
// uniformly sampled inside a cube.
|
||||
for (int i = 0; i < steps; i++) {
|
||||
std::cout << "iteration " << i + 1 << std::endl;
|
||||
|
||||
CGAL::Timer timer;
|
||||
timer.start();
|
||||
lloyd_algorithm(planes.begin(),
|
||||
planes.end(),
|
||||
points);
|
||||
timer.stop();
|
||||
|
||||
std::cout << "Execution time : " << timer.time() << "s\n";
|
||||
}
|
||||
|
||||
std::ofstream aos("after_lloyd.xyz");
|
||||
std::copy(points.begin(), points.end(),
|
||||
std::ostream_iterator<Point>(aos, "\n"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1378,6 +1378,17 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio
|
|||
,update = "99.05 schirra, 00.09 hert"
|
||||
}
|
||||
|
||||
@article{ cgal:mog-vbcfe-11
|
||||
,author = {Merigot, Quentin and Ovsjanikov, Maks and Guibas, Leonidas}
|
||||
,title = {Voronoi-based curvature and feature estimation from point clouds}
|
||||
,journal = {Visualization and Computer Graphics, IEEE Transactions on}
|
||||
,volume = {17}
|
||||
,number = {6}
|
||||
,pages = {743--756}
|
||||
,year = {2011}
|
||||
,publisher = {IEEE}
|
||||
}
|
||||
|
||||
@inproceedings{cgal:mp-fcafg-05
|
||||
, author = "Guillaume Melquiond and Sylvain Pion"
|
||||
, title = "Formal certification of arithmetic filters for geometric predicates"
|
||||
|
|
|
|||
|
|
@ -151,6 +151,18 @@ and <code>src/</code> directories).
|
|||
<!-- Voronoi Diagrams -->
|
||||
<!-- Mesh Generation -->
|
||||
<!-- Geometry Processing -->
|
||||
<h3>Point Set Processing and Surface Reconstruction from Point Sets</h3>
|
||||
<ul>
|
||||
<li>
|
||||
Add the function <code>CGAL::compute_vcm()</code> for computing the
|
||||
Voronoi Covariance Measure (VCM) of a point set. The output of this function
|
||||
can be used with the function <code>CGAL::vcm_is_on_feature_edge()</code>
|
||||
to determine whether a point is on or close to a feature edge. The former
|
||||
function is also internally used by <code>CGAL::vcm_estimate_normals()</code>
|
||||
to estimate the normals of a point set and it is particularly suited to point
|
||||
set with noise.
|
||||
</li>
|
||||
</ul>
|
||||
<!-- Spatial Searching and Sorting -->
|
||||
<h3>Spatial Sorting</h3>
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*!
|
||||
\ingroup PkgPointSetProcessingConcepts
|
||||
\cgalConcept
|
||||
Concept providing functions to extract eigenvectors and eigenvalue from
|
||||
covariance matrices represented by an array `a` as follows:
|
||||
<center>
|
||||
\f$ \begin{bmatrix}
|
||||
a[0] & a[1] & a[2] \\
|
||||
a[1] & a[3] & a[4] \\
|
||||
a[2] & a[4] & a[5] \\
|
||||
\end{bmatrix}\f$
|
||||
</center>
|
||||
\cgalHasModel `CGAL::Eigen_vcm_traits`
|
||||
*/
|
||||
class VCMTraits
|
||||
{
|
||||
public:
|
||||
/// fill `eigenvalues` with the eigenvalues of the covariance matrix represented by `cov`.
|
||||
/// Eigenvalues are sorted by increasing order.
|
||||
/// \return `true` if the operation was successful and `false` otherwise.
|
||||
static bool
|
||||
diagonalize_selfadjoint_covariance_matrix(
|
||||
const cpp11::array<double,6>& cov,
|
||||
cpp11::array<double, 3>& eigenvalues);
|
||||
|
||||
/// Extract the eigenvector associated to the largest eigenvalue
|
||||
/// of the covariance matrix represented by `cov`.
|
||||
/// \return `true` if the operation was successful and `false` otherwise.
|
||||
static bool
|
||||
extract_largest_eigenvector_of_covariance_matrix (
|
||||
const cpp11::array<double,6>& cov,
|
||||
cpp11::array<double,3> &normal);
|
||||
};
|
||||
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
/// \defgroup PkgPointSetProcessing Point Set Processing Reference
|
||||
/// \defgroup PkgPointSetProcessing Point Set Processing Reference
|
||||
/// \defgroup PkgPointSetProcessingConcepts Concepts
|
||||
/// \ingroup PkgPointSetProcessing
|
||||
|
||||
/*!
|
||||
\addtogroup PkgPointSetProcessing
|
||||
|
|
@ -6,7 +8,7 @@
|
|||
\cgalPkgPicture{point_set_processing_detail.png}
|
||||
\cgalPkgSummaryBegin
|
||||
\cgalPkgAuthors{Pierre Alliez, Clément Jamin, Laurent Saboret, Nader Salman, Shihao Wu}
|
||||
\cgalPkgDesc{This \cgal component implements methods to analyze and process point sets. The input is an unorganized point set, possibly with normal attributes (unoriented or oriented). The point set can be analyzed to measure its average spacing, and processed through functions devised for simplification, regularization, upsampling, outlier removal, smoothing, normal estimation and normal orientation.}
|
||||
\cgalPkgDesc{This \cgal component implements methods to analyze and process unorganized point sets. The input is an unorganized point set, possibly with normal attributes (unoriented or oriented). The point set can be analyzed to measure its average spacing, and processed through functions devoted to the simplification, outlier removal, smoothing, normal estimation, normal orientation and feature edges estimation.}
|
||||
\cgalPkgManuals{Chapter_Point_Set_Processing,PkgPointSetProcessing}
|
||||
\cgalPkgSummaryEnd
|
||||
\cgalPkgShortInfoBegin
|
||||
|
|
@ -35,6 +37,9 @@
|
|||
- `CGAL::pca_estimate_normals()`
|
||||
- `CGAL::mst_orient_normals()`
|
||||
- `CGAL::edge_aware_upsample_point_set()`
|
||||
- `CGAL::compute_vcm()`
|
||||
- `CGAL::vcm_estimate_normals()`
|
||||
- `CGAL::vcm_is_on_feature_edge()`
|
||||
- `CGAL::write_off_points()`
|
||||
- `CGAL::write_xyz_points()`
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -255,6 +255,12 @@ at each point from the set by linear least squares fitting of a plane
|
|||
over its `k` nearest neighbors. This algorithm is simpler and
|
||||
faster than `jet_estimate_normals()`.
|
||||
|
||||
Function `vcm_estimate_normals()` estimates the normal direction
|
||||
at each point from the set by using the Voronoi Covariance Measure
|
||||
of the point set. This algorithm is more complex and slower than
|
||||
the previous algorithms. It is based on the
|
||||
article \cgalCite{cgal:mog-vbcfe-11}.
|
||||
|
||||
\section Point_set_processing_3NormalOrientation Normal Orientation
|
||||
|
||||
Function `mst_orient_normals()` orients the normals of a set of
|
||||
|
|
@ -315,10 +321,24 @@ Usually, the neighborhood of sample points should include at least one ring of n
|
|||
Comparison between different sizes of neighbor radius.
|
||||
\cgalFigureEnd
|
||||
|
||||
\section Point_set_processing_3FeaturesEstimation Feature Edges Estimation
|
||||
|
||||
Function `vcm_is_on_feature_edge()` indicates if a points belong to a feature edges of the
|
||||
point set using its Voronoi Covariance Measure.
|
||||
It is based on the article \cgalCite{cgal:mog-vbcfe-11}.
|
||||
|
||||
It first computes the VCM of the points set using `compute_vcm()`. Then, it estimates
|
||||
which points belong to a sharp edge by testing if a ratio of eigenvalues
|
||||
is greater than a given threshold.
|
||||
|
||||
\subsection Point_set_processing_3Example_6 Example
|
||||
|
||||
The following example reads a point set from a file, estimates the
|
||||
points that are on sharp edges:
|
||||
\cgalExample{Point_set_processing_3/edges_example.cpp}
|
||||
|
||||
|
||||
|
||||
\subsection Point_set_processing_3ImplementationHistory Implementation History
|
||||
\section Point_set_processing_3ImplementationHistory Implementation History
|
||||
|
||||
Pierre Alliez and Laurent Saboret contributed the initial component. Nader Salman contributed the grid simplification. Started from GSoC'2013, three new algorithms were implemented by Shihao Wu and Clément Jamin: WLOP, bilateral smoothing and upsampling.
|
||||
|
||||
|
|
|
|||
|
|
@ -9,4 +9,5 @@
|
|||
\example Point_set_processing_3/wlop_simplify_and_regularize_point_set_example.cpp
|
||||
\example Point_set_processing_3/bilateral_smooth_point_set_example.cpp
|
||||
\example Point_set_processing_3/edge_aware_upsample_point_set_example.cpp
|
||||
\example Point_set_processing_3/edges_example.cpp
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ if ( CGAL_FOUND )
|
|||
# Executables that require Eigen or BLAS and LAPACK
|
||||
create_single_source_cgal_program( "jet_smoothing_example.cpp" )
|
||||
create_single_source_cgal_program( "normal_estimation.cpp" )
|
||||
create_single_source_cgal_program( "edges_example.cpp" )
|
||||
else(EIGEN3_FOUND OR LAPACK_FOUND)
|
||||
|
||||
message(STATUS "NOTICE: Some of the executables in this directory need either Eigen 3.1 (or greater) or LAPACK, and will not be compiled.")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,58 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/vcm_estimate_edges.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/IO/read_off_points.h>
|
||||
|
||||
#include <utility> // defines std::pair
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
// Types
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef Kernel::Point_3 Point;
|
||||
typedef Kernel::Vector_3 Vector;
|
||||
|
||||
// Point with normal vector stored in a std::pair.
|
||||
typedef std::pair<Point, Vector> PointVectorPair;
|
||||
typedef std::vector<PointVectorPair> PointList;
|
||||
|
||||
typedef CGAL::cpp11::array<double,6> Covariance;
|
||||
|
||||
int main (int , char**) {
|
||||
// Reads a .xyz point set file in points[].
|
||||
std::list<PointVectorPair> points;
|
||||
std::ifstream stream("data/fandisk.off");
|
||||
if (!stream ||
|
||||
!CGAL::read_off_points(stream,
|
||||
std::back_inserter(points),
|
||||
CGAL::First_of_pair_property_map<PointVectorPair>()))
|
||||
{
|
||||
std::cerr << "Error: cannot read file data/fandisk.off" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Estimates covariance matrices per points.
|
||||
double R = 0.2,
|
||||
r = 0.1;
|
||||
std::vector<Covariance> cov;
|
||||
CGAL::First_of_pair_property_map<PointVectorPair> point_pmap;
|
||||
|
||||
CGAL::compute_vcm(points.begin(), points.end(), point_pmap, cov, R, r, Kernel());
|
||||
|
||||
// Find the points on the edges.
|
||||
// Note that this step is not expensive and can be done several time to get better results
|
||||
double threshold = 0.16;
|
||||
std::ofstream output("points_on_edges.xyz");
|
||||
int i = 0;
|
||||
BOOST_FOREACH(const PointVectorPair& p, points)
|
||||
{
|
||||
if (CGAL::vcm_is_on_feature_edge(cov[i], threshold))
|
||||
output << p.first << "\n";
|
||||
++i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
// This package
|
||||
#include <CGAL/pca_estimate_normals.h>
|
||||
#include <CGAL/jet_estimate_normals.h>
|
||||
#include <CGAL/vcm_estimate_normals.h>
|
||||
#include <CGAL/mst_orient_normals.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/IO/read_off_points.h>
|
||||
|
|
@ -94,6 +95,30 @@ void run_jet_estimate_normals(PointList& points, // input points + output normal
|
|||
<< std::endl;
|
||||
}
|
||||
|
||||
// Compute normals direction using the VCM
|
||||
void run_vcm_estimate_normals(PointList &points, // input points + output normals
|
||||
double R, // radius of the offset
|
||||
double r) { // radius used during the convolution
|
||||
CGAL::Timer task_timer; task_timer.start();
|
||||
std::cerr << "Estimates Normals Direction using VCM (R="
|
||||
<< R << " and r=" << r << ")...\n";
|
||||
|
||||
// Estimates normals direction.
|
||||
// Note: vcm_estimate_normals() requires an iterator over points
|
||||
// + property maps to access each point's position and normal.
|
||||
CGAL::vcm_estimate_normals(points.begin(), points.end(),
|
||||
CGAL::First_of_pair_property_map<PointVectorPair>(),
|
||||
CGAL::Second_of_pair_property_map<PointVectorPair>(),
|
||||
R,
|
||||
r);
|
||||
|
||||
long memory = CGAL::Memory_sizer().virtual_size();
|
||||
std::cerr << "done: " << task_timer.time() << " seconds, "
|
||||
<< (memory>>20) << " Mb allocated"
|
||||
<< std::endl;
|
||||
|
||||
}
|
||||
|
||||
// Hoppe92 normal orientation using a Minimum Spanning Tree.
|
||||
void run_mst_orient_normals(PointList& points, // input points + input/output normals
|
||||
unsigned int nb_neighbors_mst) // number of neighbors
|
||||
|
|
@ -144,15 +169,19 @@ int main(int argc, char * argv[])
|
|||
std::cerr << "Input file formats are .off, .xyz and .pwn.\n";
|
||||
std::cerr << "Output file formats are .xyz and .pwn.\n";
|
||||
std::cerr << "Options:\n";
|
||||
std::cerr << " -estimate plane|quadric Estimates normals direction\n";
|
||||
std::cerr << " using a tangent plane or quadric (default=quadric)\n";
|
||||
std::cerr << " -nb_neighbors_pca <int> Number of neighbors\n";
|
||||
std::cerr << " -estimate plane|quadric|vcm Estimates normals direction\n";
|
||||
std::cerr << " using a tangent plane or quadric or vcm (default=quadric)\n";
|
||||
std::cerr << " -nb_neighbors_pca <int> Number of neighbors\n";
|
||||
std::cerr << " to compute tangent plane (default=18)\n";
|
||||
std::cerr << " -nb_neighbors_jet_fitting <int> Number of neighbors\n";
|
||||
std::cerr << " -nb_neighbors_jet_fitting <int> Number of neighbors\n";
|
||||
std::cerr << " to compute quadric (default=18)\n";
|
||||
std::cerr << " -orient MST Orient normals\n";
|
||||
std::cerr << " -offset_radius_vcm <double> Offset radius\n";
|
||||
std::cerr << " to compute VCM (default=0.1)\n";
|
||||
std::cerr << " -convolve_radius_vcm <double> Convolve radius\n";
|
||||
std::cerr << " to compute VCM (default=0)\n";
|
||||
std::cerr << " -orient MST Orient normals\n";
|
||||
std::cerr << " using a Minimum Spanning Tree (default=MST)\n";
|
||||
std::cerr << " -nb_neighbors_mst <int> Number of neighbors\n";
|
||||
std::cerr << " -nb_neighbors_mst <int> Number of neighbors\n";
|
||||
std::cerr << " to compute the MST (default=18)\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
@ -161,6 +190,8 @@ int main(int argc, char * argv[])
|
|||
unsigned int nb_neighbors_pca_normals = 18; // K-nearest neighbors = 3 rings (estimate normals by PCA)
|
||||
unsigned int nb_neighbors_jet_fitting_normals = 18; // K-nearest neighbors (estimate normals by Jet Fitting)
|
||||
unsigned int nb_neighbors_mst = 18; // K-nearest neighbors (orient normals by MST)
|
||||
double offset_radius_vcm = 0.1; // Offset radius (estimate normals by VCM)
|
||||
double convolve_radius_vcm = 0; // Convolve radius (estimate normals by VCM)
|
||||
std::string estimate = "quadric"; // estimate normals by jet fitting
|
||||
std::string orient = "MST"; // orient normals using a Minimum Spanning Tree
|
||||
|
||||
|
|
@ -171,7 +202,7 @@ int main(int argc, char * argv[])
|
|||
{
|
||||
if (std::string(argv[i])=="-estimate") {
|
||||
estimate = argv[++i];
|
||||
if (estimate != "plane" && estimate != "quadric")
|
||||
if (estimate != "plane" && estimate != "quadric" && estimate != "vcm")
|
||||
std::cerr << "invalid option " << argv[i] << "\n";
|
||||
}
|
||||
else if (std::string(argv[i])=="-nb_neighbors_pca") {
|
||||
|
|
@ -180,6 +211,12 @@ int main(int argc, char * argv[])
|
|||
else if (std::string(argv[i])=="-nb_neighbors_jet_fitting") {
|
||||
nb_neighbors_jet_fitting_normals = atoi(argv[++i]);
|
||||
}
|
||||
else if (std::string(argv[i])=="-offset_radius_vcm") {
|
||||
offset_radius_vcm = atof(argv[++i]);
|
||||
}
|
||||
else if (std::string(argv[i])=="-convolve_radius_vcm") {
|
||||
convolve_radius_vcm = atof(argv[++i]);
|
||||
}
|
||||
else if (std::string(argv[i])=="-orient") {
|
||||
orient = argv[++i];
|
||||
if (orient != "MST")
|
||||
|
|
@ -259,6 +296,8 @@ int main(int argc, char * argv[])
|
|||
run_pca_estimate_normals(points, nb_neighbors_pca_normals);
|
||||
else if (estimate == "quadric")
|
||||
run_jet_estimate_normals(points, nb_neighbors_jet_fitting_normals);
|
||||
else if (estimate == "vcm")
|
||||
run_vcm_estimate_normals(points, offset_radius_vcm, convolve_radius_vcm);
|
||||
|
||||
// Orient normals.
|
||||
if (orient == "MST")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 2014 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Jocelyn Meyron and Quentin Mérigot
|
||||
//
|
||||
|
||||
#ifndef CGAL_EIGEN_VCM_TRAITS_H
|
||||
#define CGAL_EIGEN_VCM_TRAITS_H
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <Eigen/Eigenvalues>
|
||||
|
||||
#include <CGAL/array.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/// A model of the concept `VCMTraits` using \ref thirdpartyEigen.
|
||||
/// \cgalModels `VCMTraits`
|
||||
class Eigen_vcm_traits{
|
||||
// Construct the covariance matrix
|
||||
static Eigen::Matrix3f
|
||||
construct_covariance_matrix (const cpp11::array<double,6>& cov) {
|
||||
Eigen::Matrix3f m;
|
||||
|
||||
m(0,0) = cov[0]; m(0,1) = cov[1]; m(0,2) = cov[2];
|
||||
m(1,1) = cov[3]; m(1,2) = cov[4];
|
||||
m(2,2) = cov[5];
|
||||
|
||||
m(1, 0) = m(0,1); m(2, 0) = m(0, 2); m(2, 1) = m(1, 2);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
// Diagonalize a selfadjoint matrix
|
||||
static bool
|
||||
diagonalize_selfadjoint_matrix (Eigen::Matrix3f &m,
|
||||
Eigen::Matrix3f &eigenvectors,
|
||||
Eigen::Vector3f &eigenvalues) {
|
||||
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigensolver(m);
|
||||
|
||||
if (eigensolver.info() != Eigen::Success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
eigenvalues = eigensolver.eigenvalues();
|
||||
eigenvectors = eigensolver.eigenvectors();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
static bool
|
||||
diagonalize_selfadjoint_covariance_matrix(
|
||||
const cpp11::array<double,6>& cov,
|
||||
cpp11::array<double, 3>& eigenvalues)
|
||||
{
|
||||
Eigen::Matrix3f m = construct_covariance_matrix(cov);
|
||||
|
||||
// Diagonalizing the matrix
|
||||
Eigen::Vector3f eigenvalues_;
|
||||
Eigen::Matrix3f eigenvectors_;
|
||||
bool res = diagonalize_selfadjoint_matrix(m, eigenvectors_, eigenvalues_);
|
||||
|
||||
if (res)
|
||||
{
|
||||
eigenvalues[0]=eigenvalues_[0];
|
||||
eigenvalues[1]=eigenvalues_[1];
|
||||
eigenvalues[2]=eigenvalues_[2];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Extract the eigenvector associated to the largest eigenvalue
|
||||
static bool
|
||||
extract_largest_eigenvector_of_covariance_matrix (
|
||||
const cpp11::array<double,6>& cov,
|
||||
cpp11::array<double,3> &normal)
|
||||
{
|
||||
// Construct covariance matrix
|
||||
Eigen::Matrix3f m = construct_covariance_matrix(cov);
|
||||
|
||||
// Diagonalizing the matrix
|
||||
Eigen::Vector3f eigenvalues;
|
||||
Eigen::Matrix3f eigenvectors;
|
||||
if (! diagonalize_selfadjoint_matrix(m, eigenvectors, eigenvalues)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Eigenvalues are already sorted by increasing order
|
||||
normal[0]=eigenvectors(0,0);
|
||||
normal[1]=eigenvectors(1,0);
|
||||
normal[2]=eigenvectors(2,0);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_EIGEN_VCM_TRAITS_H
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
// Copyright (c) 2014 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Jocelyn Meyron and Quentin Mérigot
|
||||
//
|
||||
|
||||
#ifndef CGAL_INTERNAL_VCM_VORONOI_COVARIANCE_3_HPP
|
||||
#define CGAL_INTERNAL_VCM_VORONOI_COVARIANCE_3_HPP
|
||||
|
||||
#include <list>
|
||||
#include <CGAL/array.h>
|
||||
#include <CGAL/internal/Voronoi_covariance_3/voronoi_covariance_sphere_3.h>
|
||||
#ifdef CGAL_VORONOI_COVARIANCE_USE_CONSTRUCTIONS
|
||||
#include <CGAL/Convex_hull_3/dual/halfspace_intersection_with_constructions_3.h>
|
||||
#else
|
||||
#include <CGAL/Convex_hull_3/dual/halfspace_intersection_3.h>
|
||||
#endif
|
||||
|
||||
namespace CGAL {
|
||||
namespace Voronoi_covariance_3 {
|
||||
namespace internal {
|
||||
template <class FT>
|
||||
inline void
|
||||
covariance_matrix_tetrahedron (FT ax, FT ay, FT az,
|
||||
FT bx, FT by, FT bz,
|
||||
FT cx, FT cy, FT cz,
|
||||
cpp11::array<FT,6> &R)
|
||||
{
|
||||
const FT det = (ax*cz*by - ax*bz*cy - ay*bx*cz +
|
||||
ay*cx*bz + az*bx*cy - az*cx*by) / 60.0;
|
||||
|
||||
R[0] += (ax*ax + ax*bx + ax*cx +
|
||||
bx*bx + bx*cx + cx*cx) * det;
|
||||
R[1] += (ax*ay + ax*by/2.0 + ax*cy/2.0 +
|
||||
bx*ay/2.0 + bx*by + bx*cy/2.0 +
|
||||
cx*ay/2.0 + cx*by/2.0 + cx*cy) * det;
|
||||
R[2] += (ax*az + ax*bz/2.0 + ax*cz/2.0 +
|
||||
bx*az/2.0 + bx*bz + bx*cz/2.0 +
|
||||
cx*az/2.0 + cx*bz/2.0 + cx*cz) * det;
|
||||
|
||||
R[3] += (ay*ay + ay*by + ay*cy +
|
||||
by*by + by*cy + cy*cy) * det;
|
||||
R[4] += (az*ay + az*by/2.0 + az*cy/2.0 +
|
||||
bz*ay/2.0 + bz*by + bz*cy/2.0 +
|
||||
cz*ay/2.0 + cz*by/2.0 + cz*cy) * det;
|
||||
|
||||
R[5] += (az*az + az*bz + az*cz +
|
||||
bz*bz + bz*cz + cz*cz) * det;
|
||||
}
|
||||
|
||||
template <class FT>
|
||||
class Covariance_accumulator_3
|
||||
{
|
||||
public:
|
||||
typedef cpp11::array<FT, 6> Result_type;
|
||||
|
||||
private:
|
||||
Result_type _result;
|
||||
|
||||
public:
|
||||
Covariance_accumulator_3()
|
||||
{
|
||||
std::fill (_result.begin(), _result.end(), FT(0));
|
||||
}
|
||||
|
||||
template <class Point>
|
||||
inline void operator () (const Point &a,
|
||||
const Point &b,
|
||||
const Point &c)
|
||||
{
|
||||
internal::covariance_matrix_tetrahedron (a[0], a[1], a[2],
|
||||
b[0], b[1], b[2],
|
||||
c[0], c[1], c[2],
|
||||
_result);
|
||||
}
|
||||
|
||||
const Result_type &result() const
|
||||
{
|
||||
return _result;
|
||||
}
|
||||
};
|
||||
|
||||
template <class FT>
|
||||
class Volume_accumulator_3
|
||||
{
|
||||
public:
|
||||
typedef FT Result_type;
|
||||
|
||||
private:
|
||||
Result_type _result;
|
||||
|
||||
public:
|
||||
Volume_accumulator_3() : _result(0.0)
|
||||
{}
|
||||
|
||||
template <class Point>
|
||||
inline void operator () (const Point &a,
|
||||
const Point &b,
|
||||
const Point &c)
|
||||
{
|
||||
const double vol = CGAL::volume(a, b, c, Point(CGAL::ORIGIN));
|
||||
//std::cerr << "vol = " << vol << "\n";
|
||||
_result += vol;
|
||||
}
|
||||
|
||||
const Result_type &result() const
|
||||
{
|
||||
return _result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class DT, class Sphere, class F>
|
||||
F& tessellate_and_intersect(const DT &dt,
|
||||
typename DT::Vertex_handle v,
|
||||
const Sphere &sphere,
|
||||
F &f)
|
||||
{
|
||||
typedef typename DT::Vertex_handle Vertex_handle;
|
||||
typedef typename DT::Geom_traits::Kernel K;
|
||||
typedef typename K::Plane_3 Plane;
|
||||
typedef typename K::Point_3 Point;
|
||||
typedef typename K::Vector_3 Vector;
|
||||
typedef typename CGAL::Convex_hull_traits_3<K> Traits;
|
||||
typedef typename Traits::Polyhedron_3 Polyhedron;
|
||||
|
||||
std::list<Vertex_handle> vertices;
|
||||
dt.incident_vertices(v,std::back_inserter(vertices));
|
||||
|
||||
// construct intersection of half-planes using the convex hull function
|
||||
std::list<Plane> planes;
|
||||
for(typename std::list<Vertex_handle>::iterator it = vertices.begin();
|
||||
it != vertices.end(); ++it)
|
||||
{
|
||||
Vector p = ((*it)->point() - v->point())/2;
|
||||
planes.push_back (Plane(CGAL::ORIGIN+p, p));
|
||||
}
|
||||
|
||||
// add half-planes defining the sphere discretization
|
||||
sphere(std::back_inserter(planes));
|
||||
|
||||
Polyhedron P;
|
||||
#ifdef CGAL_VORONOI_COVARIANCE_USE_CONSTRUCTIONS
|
||||
halfspace_intersection_with_constructions_3
|
||||
#else
|
||||
halfspace_intersection_3
|
||||
#endif
|
||||
(planes.begin(), planes.end(), P, Point(CGAL::ORIGIN));
|
||||
|
||||
// apply f to the triangles on the boundary of P
|
||||
for (typename Polyhedron::Facet_iterator it = P.facets_begin();
|
||||
it != P.facets_end(); ++it)
|
||||
{
|
||||
typename Polyhedron::Halfedge_around_facet_circulator
|
||||
h0 = it->facet_begin(), hf = h0--, hs = hf;
|
||||
hs ++;
|
||||
|
||||
while(1)
|
||||
{
|
||||
f (h0->vertex()->point(), hf->vertex()->point(),
|
||||
hs->vertex()->point());
|
||||
if (hs == h0)
|
||||
break;
|
||||
++hs; ++hf;
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
template <class DT, class Sphere, class FT>
|
||||
void
|
||||
voronoi_covariance_3 (const DT &dt,
|
||||
typename DT::Vertex_handle v,
|
||||
const Sphere &sphere,
|
||||
FT covariance[6])
|
||||
{
|
||||
typename internal::Covariance_accumulator_3<FT> ca;
|
||||
internal::tessellate_and_intersect(dt, v, sphere, ca);
|
||||
std::copy (ca.result().begin(), ca.result().end(), covariance);
|
||||
}
|
||||
|
||||
template <class DT, class Sphere>
|
||||
array<typename DT::Geom_traits::FT, 6>
|
||||
voronoi_covariance_3 (const DT &dt,
|
||||
typename DT::Vertex_handle v,
|
||||
const Sphere &sphere)
|
||||
{
|
||||
typedef typename DT::Geom_traits::FT FT;
|
||||
typename internal::Covariance_accumulator_3<FT> ca;
|
||||
|
||||
return internal::tessellate_and_intersect(dt, v, sphere, ca).result();
|
||||
}
|
||||
|
||||
template <class DT, class Sphere>
|
||||
typename DT::Geom_traits::FT
|
||||
voronoi_volume_3 (const DT &dt,
|
||||
typename DT::Vertex_handle v,
|
||||
const Sphere &sphere)
|
||||
{
|
||||
typedef typename DT::Geom_traits::FT FT;
|
||||
typename internal::Volume_accumulator_3<FT> va;
|
||||
|
||||
return internal::tessellate_and_intersect(dt, v, sphere, va).result();
|
||||
}
|
||||
|
||||
}; // namespace Voronoi_covariance_3
|
||||
}; // namespace CGAL
|
||||
|
||||
#endif // CGAL_INTERNAL_VCM_VORONOI_COVARIANCE_3_HPP
|
||||
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) 2014 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Jocelyn Meyron and Quentin Mérigot
|
||||
//
|
||||
|
||||
#ifndef CGAL_INTERNAL_VCM_VORONOI_COVARIANCE_SPHERE_3_HPP
|
||||
#define CGAL_INTERNAL_VCM_VORONOI_COVARIANCE_SPHERE_3_HPP
|
||||
|
||||
#include <CGAL/point_generators_3.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Voronoi_covariance_3 {
|
||||
template <class K>
|
||||
class Sphere_discretization
|
||||
{
|
||||
typedef typename K::FT FT;
|
||||
FT _R;
|
||||
size_t _N;
|
||||
|
||||
public:
|
||||
Sphere_discretization (FT R, size_t N = 20) :
|
||||
_R(R), _N(N)
|
||||
{
|
||||
if (_N != 8 && _N != 20)
|
||||
_N = 20;
|
||||
}
|
||||
|
||||
template <class OutputIterator>
|
||||
void
|
||||
operator ()(OutputIterator out) const
|
||||
{
|
||||
typedef typename K::Plane_3 Plane;
|
||||
|
||||
if (_N == 8)
|
||||
{
|
||||
static const FT phi = (FT(1) + ::sqrt(5))/FT(2);
|
||||
static const FT s = FT(1) / ::sqrt(phi + FT(2));
|
||||
|
||||
*out ++ = Plane(0, +s, +s*phi, -_R);
|
||||
*out ++ = Plane(0, -s, +s*phi, -_R);
|
||||
*out ++ = Plane(0, +s, -s*phi, -_R);
|
||||
*out ++ = Plane(0, -s, -s*phi, -_R);
|
||||
|
||||
*out ++ = Plane(+s, +s*phi, 0, -_R);
|
||||
*out ++ = Plane(+s, -s*phi, 0, -_R);
|
||||
*out ++ = Plane(-s, +s*phi, 0, -_R);
|
||||
*out ++ = Plane(-s, -s*phi, 0, -_R);
|
||||
|
||||
*out ++ = Plane(+s*phi, 0, +s, -_R);
|
||||
*out ++ = Plane(-s*phi, 0, +s, -_R);
|
||||
*out ++ = Plane(+s*phi, 0, -s, -_R);
|
||||
*out ++ = Plane(-s*phi, 0, -s, -_R);
|
||||
}
|
||||
else if (_N == 20)
|
||||
{
|
||||
const FT phi = (FT(1) + ::sqrt(5))/FT(2);
|
||||
const FT one_phi = FT(1)/phi;
|
||||
const FT s = FT(1) / ::sqrt(3.0);
|
||||
|
||||
*out ++ = Plane(+s, +s, +s, -_R);
|
||||
*out ++ = Plane(-s, +s, +s, -_R);
|
||||
*out ++ = Plane(+s, -s, +s, -_R);
|
||||
*out ++ = Plane(-s, -s, +s, -_R);
|
||||
*out ++ = Plane(+s, +s, -s, -_R);
|
||||
*out ++ = Plane(-s, +s, -s, -_R);
|
||||
*out ++ = Plane(+s, -s, -s, -_R);
|
||||
*out ++ = Plane(-s, -s, -s, -_R);
|
||||
|
||||
*out ++ = Plane(0, +s*one_phi, +s*phi, -_R);
|
||||
*out ++ = Plane(0, -s*one_phi, +s*phi, -_R);
|
||||
*out ++ = Plane(0, +s*one_phi, -s*phi, -_R);
|
||||
*out ++ = Plane(0, -s*one_phi, -s*phi, -_R);
|
||||
|
||||
*out ++ = Plane(+s*one_phi, +s*phi, 0, -_R);
|
||||
*out ++ = Plane(-s*one_phi, +s*phi, 0, -_R);
|
||||
*out ++ = Plane(+s*one_phi, -s*phi, 0, -_R);
|
||||
*out ++ = Plane(-s*one_phi, -s*phi, 0, -_R);
|
||||
|
||||
*out ++ = Plane(+s*phi, 0, +s*one_phi, -_R);
|
||||
*out ++ = Plane(-s*phi, 0, +s*one_phi, -_R);
|
||||
*out ++ = Plane(+s*phi, 0, -s*one_phi, -_R);
|
||||
*out ++ = Plane(-s*phi, 0, -s*one_phi, -_R);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace Voronoi_covariance_3
|
||||
}; // namespace CGAL
|
||||
|
||||
#endif // CGAL_INTERNAL_VCM_VORONOI_COVARIANCE_SPHERE_3_HPP
|
||||
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright (c) 2014 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Jocelyn Meyron and Quentin Mérigot
|
||||
//
|
||||
|
||||
#ifndef CGAL_VCM_ESTIMATE_EDGES_H
|
||||
#define CGAL_VCM_ESTIMATE_EDGES_H
|
||||
|
||||
#include <CGAL/vcm_estimate_normals.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/// \ingroup PkgPointSetProcessing
|
||||
/// determines if a point is on a sharp feature edge from a point set
|
||||
/// for which the Voronoi covariance Measures have been computed.
|
||||
///
|
||||
/// The sharpness of the edge, specified by parameter `threshold`,
|
||||
/// is used to filtered points according to the external angle around a sharp feature.
|
||||
///
|
||||
/// A point is considered to be on a sharp feature if the external angle `alpha` at the edge is such that
|
||||
/// `alpha >> 2 / sqrt(3) * sqrt(threshold)`.
|
||||
/// In particular this means that if the input contains sharp features
|
||||
/// with different external angles, the one with the smallest external angle should be considered,
|
||||
/// which however would result in selecting more points on sharper regions.
|
||||
/// More details are provided in \cgalCite{cgal:mog-vbcfe-11}.
|
||||
///
|
||||
/// \tparam VCM_traits is a model of `VCMTraits`. If Eigen 3 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined
|
||||
/// then an overload using `Eigen_vcm_traits` is provided and this template parameter can be omitted.
|
||||
/// \sa CGAL::compute_vcm()`
|
||||
///
|
||||
template <class FT, class VCM_traits>
|
||||
bool
|
||||
vcm_is_on_feature_edge (cpp11::array<FT,6> &cov,
|
||||
double threshold,
|
||||
VCM_traits)
|
||||
{
|
||||
cpp11::array<double,3> eigenvalues;
|
||||
if (!VCM_traits::
|
||||
diagonalize_selfadjoint_covariance_matrix(cov, eigenvalues) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute the ratio
|
||||
double r = eigenvalues[1] / (eigenvalues[0] + eigenvalues[1] + eigenvalues[2]);
|
||||
if (r >= threshold)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef CGAL_EIGEN3_ENABLED
|
||||
template <class FT>
|
||||
bool
|
||||
vcm_is_on_feature_edge (cpp11::array<FT,6> &cov,
|
||||
double threshold)
|
||||
{
|
||||
return vcm_is_on_feature_edge(cov, threshold, Eigen_vcm_traits());
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_VCM_ESTIMATE_EDGES_H
|
||||
|
|
@ -0,0 +1,515 @@
|
|||
// Copyright (c) 2014 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Jocelyn Meyron and Quentin Mérigot
|
||||
//
|
||||
|
||||
#ifndef CGAL_VCM_ESTIMATE_NORMALS_H
|
||||
#define CGAL_VCM_ESTIMATE_NORMALS_H
|
||||
|
||||
#include <CGAL/internal/Voronoi_covariance_3/voronoi_covariance_3.h>
|
||||
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
#include <CGAL/Kd_tree.h>
|
||||
#include <CGAL/Search_traits_3.h>
|
||||
#include <CGAL/Search_traits_adapter.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/Orthogonal_k_neighbor_search.h>
|
||||
#include <CGAL/Fuzzy_sphere.h>
|
||||
|
||||
#ifdef CGAL_EIGEN3_ENABLED
|
||||
#include <CGAL/Eigen_vcm_traits.h>
|
||||
#endif
|
||||
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Private section
|
||||
// ----------------------------------------------------------------------------
|
||||
namespace internal {
|
||||
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
/// Computes the VCM for each point in the property map.
|
||||
/// The matrix is computed by intersecting the Voronoi cell
|
||||
/// of a point and a sphere whose radius is `offset_radius` and discretized
|
||||
/// by `N` planes.
|
||||
///
|
||||
/// @tparam ForwardIterator iterator over input points.
|
||||
/// @tparam PointPMap is a model of `ReadablePropertyMap` with a value_type = `Kernel::Point_3`.
|
||||
/// @tparam K Geometric traits class.
|
||||
/// @tparam Covariance Covariance matrix type. It is similar to an array with a length of 6.
|
||||
template < typename ForwardIterator,
|
||||
typename PointPMap,
|
||||
class K,
|
||||
class Covariance
|
||||
>
|
||||
void
|
||||
vcm_offset (ForwardIterator first, ///< iterator over the first input point.
|
||||
ForwardIterator beyond, ///< past-the-end iterator over the input points.
|
||||
PointPMap point_pmap, ///< property map: value_type of ForwardIterator -> Point_3.
|
||||
std::vector<Covariance> &cov, ///< vector of covariance matrices.
|
||||
double offset_radius, ///< radius of the sphere.
|
||||
std::size_t N, ///< number of planes used to discretize the sphere.
|
||||
const K & /*kernel*/) ///< geometric traits.
|
||||
{
|
||||
// Sphere discretization
|
||||
typename CGAL::Voronoi_covariance_3::Sphere_discretization<K> sphere(offset_radius, N);
|
||||
|
||||
// Compute the Delaunay Triangulation
|
||||
std::vector<typename K::Point_3> points;
|
||||
points.reserve(std::distance(first, beyond));
|
||||
for (ForwardIterator it = first; it != beyond; ++it)
|
||||
points.push_back(get(point_pmap, *it));
|
||||
|
||||
typedef Delaunay_triangulation_3<K> DT;
|
||||
DT dt(points.begin(), points.end());
|
||||
|
||||
cov.clear();
|
||||
cov.reserve(points.size());
|
||||
// Compute the VCM
|
||||
for (typename std::vector<typename K::Point_3>::iterator
|
||||
it = points.begin(); it != points.end(); ++it)
|
||||
{
|
||||
typename DT::Vertex_handle vh = dt.nearest_vertex(*it);
|
||||
cov.push_back(
|
||||
Voronoi_covariance_3::voronoi_covariance_3(dt, vh, sphere)
|
||||
);
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
// Convolve using a radius.
|
||||
template < class ForwardIterator,
|
||||
class PointPMap,
|
||||
class K,
|
||||
class Covariance
|
||||
>
|
||||
void
|
||||
vcm_convolve (ForwardIterator first,
|
||||
ForwardIterator beyond,
|
||||
PointPMap point_pmap,
|
||||
const std::vector<Covariance> &cov,
|
||||
std::vector<Covariance> &ncov,
|
||||
double convolution_radius,
|
||||
const K &)
|
||||
{
|
||||
typedef std::pair<typename K::Point_3, std::size_t> Tree_point;
|
||||
typedef First_of_pair_property_map< Tree_point > Tree_pmap;
|
||||
typedef Search_traits_3<K> Traits_base;
|
||||
typedef Search_traits_adapter<Tree_point, Tree_pmap, Traits_base> Traits;
|
||||
typedef Kd_tree<Traits> Tree;
|
||||
typedef Fuzzy_sphere<Traits> Fuzzy_sphere;
|
||||
|
||||
// Kd tree
|
||||
Tree tree;
|
||||
tree.reserve(cov.size());
|
||||
std::size_t i=0;
|
||||
for (ForwardIterator it = first; it != beyond; ++it, ++i)
|
||||
tree.insert( Tree_point(get(point_pmap, *it), i) );
|
||||
|
||||
// Convolving
|
||||
ncov.clear();
|
||||
ncov.reserve(cov.size());
|
||||
for (ForwardIterator it = first; it != beyond; ++it) {
|
||||
std::vector<Tree_point> nn;
|
||||
tree.search(std::back_inserter(nn),
|
||||
Fuzzy_sphere (get(point_pmap, *it), convolution_radius));
|
||||
|
||||
Covariance m;
|
||||
std::fill(m.begin(), m.end(), typename K::FT(0));
|
||||
for (std::size_t k = 0; k < nn.size(); ++k)
|
||||
{
|
||||
std::size_t index = nn[k].second;
|
||||
for (int i=0; i<6; ++i)
|
||||
m[i] += cov[index][i];
|
||||
}
|
||||
ncov.push_back(m);
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
// Convolve using neighbors.
|
||||
template < class ForwardIterator,
|
||||
class PointPMap,
|
||||
class K,
|
||||
class Covariance
|
||||
>
|
||||
void
|
||||
vcm_convolve (ForwardIterator first,
|
||||
ForwardIterator beyond,
|
||||
PointPMap point_pmap,
|
||||
const std::vector<Covariance> &cov,
|
||||
std::vector<Covariance> &ncov,
|
||||
unsigned int nb_neighbors_convolve,
|
||||
const K &)
|
||||
{
|
||||
typedef std::pair<typename K::Point_3, std::size_t> Tree_point;
|
||||
typedef First_of_pair_property_map< Tree_point > Tree_pmap;
|
||||
typedef Search_traits_3<K> Traits_base;
|
||||
typedef Search_traits_adapter<Tree_point, Tree_pmap, Traits_base> Traits;
|
||||
typedef Orthogonal_k_neighbor_search<Traits> Neighbor_search;
|
||||
typedef typename Neighbor_search::Tree Tree;
|
||||
|
||||
// Search tree
|
||||
Tree tree;
|
||||
tree.reserve(cov.size());
|
||||
std::size_t i=0;
|
||||
for (ForwardIterator it = first; it != beyond; ++it, ++i)
|
||||
tree.insert( Tree_point(get(point_pmap, *it), i) );
|
||||
|
||||
// Convolving
|
||||
ncov.clear();
|
||||
ncov.reserve(cov.size());
|
||||
for (ForwardIterator it = first; it != beyond; ++it) {
|
||||
Neighbor_search search(tree, get(point_pmap, *it), nb_neighbors_convolve);
|
||||
|
||||
Covariance m;
|
||||
for (typename Neighbor_search::iterator nit = search.begin();
|
||||
nit != search.end();
|
||||
++nit)
|
||||
{
|
||||
std::size_t index = nit->first.second;
|
||||
for (int i=0; i<6; ++i)
|
||||
m[i] += cov[index][i];
|
||||
}
|
||||
|
||||
ncov.push_back(m);
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Public section
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// \ingroup PkgPointSetProcessing
|
||||
/// computes the Voronoi Covariance Measure (VCM) of a point cloud,
|
||||
/// a construction that can be used for normal estimation and sharp feature detection.
|
||||
///
|
||||
/// The VCM associates to each point the covariance matrix of its Voronoi
|
||||
/// cell intersected with the ball of radius `offset_radius`.
|
||||
/// In addition, if the second radius `convolution_radius` is positive, the covariance matrices are smoothed
|
||||
/// via a convolution process. More specifically, each covariance matrix is replaced by
|
||||
/// the average of the matrices of the points located at a distance at most `convolution_radius`.
|
||||
/// The choice for parameter `offset_radius` should refer to the geometry of the underlying surface while
|
||||
/// the choice for parameter `convolution_radius` should refer to the noise level in the point cloud.
|
||||
/// For example, if the point cloud is a uniform and noise-free sampling of a smooth surface,
|
||||
/// `offset_radius` should be set to the minimum local feature size of the surface, while `convolution_radius` can be set to zero.
|
||||
///
|
||||
/// The Voronoi covariance matrix of each vertex is stored in an array `a` of length 6 and is as follow:
|
||||
/*!
|
||||
<center>
|
||||
\f$ \begin{bmatrix}
|
||||
a[0] & a[1] & a[2] \\
|
||||
a[1] & a[3] & a[4] \\
|
||||
a[2] & a[4] & a[5] \\
|
||||
\end{bmatrix}\f$
|
||||
</center>
|
||||
*/
|
||||
///
|
||||
/// @tparam ForwardIterator iterator over input points.
|
||||
/// @tparam PointPMap is a model of `ReadablePropertyMap` with a value_type = `Kernel::Point_3`.
|
||||
/// @tparam CovariancePMap is a model of `ReadWritePropertyMap` with a value_type = `cpp11::array<Kernel::FT,6>`.
|
||||
/// @tparam Kernel Geometric traits class.
|
||||
///
|
||||
/// \sa `CGAL::vcm_is_on_feature_edge()`
|
||||
/// \sa `CGAL::vcm_estimate_normals()`
|
||||
///
|
||||
/// \todo replace ccov by a property map.
|
||||
template < class ForwardIterator,
|
||||
class PointPMap,
|
||||
class Kernel
|
||||
>
|
||||
void
|
||||
compute_vcm (ForwardIterator first,
|
||||
ForwardIterator beyond,
|
||||
PointPMap point_pmap,
|
||||
std::vector< cpp11::array<typename Kernel::FT, 6> > &ccov,
|
||||
double offset_radius,
|
||||
double convolution_radius,
|
||||
const Kernel & kernel)
|
||||
{
|
||||
// First, compute the VCM for each point
|
||||
std::vector< cpp11::array<typename Kernel::FT, 6> > cov;
|
||||
std::size_t N = 20;
|
||||
internal::vcm_offset (first, beyond,
|
||||
point_pmap,
|
||||
cov,
|
||||
offset_radius,
|
||||
N,
|
||||
kernel);
|
||||
// Then, convolve it (only when convolution_radius != 0)
|
||||
if (convolution_radius == 0) {
|
||||
ccov.reserve(cov.size());
|
||||
std::copy(cov.begin(), cov.end(), std::back_inserter(ccov));
|
||||
} else {
|
||||
internal::vcm_convolve(first, beyond,
|
||||
point_pmap,
|
||||
cov,
|
||||
ccov,
|
||||
convolution_radius,
|
||||
kernel);
|
||||
}
|
||||
}
|
||||
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
/// Estimates normal directions of the `[first, beyond)` range of points
|
||||
/// using the Voronoi Covariance Measure (see `compute_vcm` for more details on the VCM).
|
||||
/// The output normals are randomly oriented.
|
||||
///
|
||||
/// @tparam ForwardIterator iterator over input points.
|
||||
/// @tparam PointPMap is a model of `ReadablePropertyMap` with a value_type = `Kernel::Point_3`.
|
||||
/// @tparam NormalPMap is a model of `WritablePropertyMap` with a value_type = `Kernel::Vector_3`.
|
||||
/// @tparam Kernel Geometric traits class.
|
||||
/// @tparam Covariance Covariance matrix type. It is similar to an array with a length of 6.
|
||||
/// @pre If `nb_neighbors_convolve` is equal to -1, then the convolution is made using a radius.
|
||||
/// On the contrary, if `nb_neighbors_convolve` is different from -1, the convolution is made using
|
||||
/// this number of neighbors.
|
||||
|
||||
// This variant requires all of the parameters.
|
||||
template < typename VCM_traits,
|
||||
typename ForwardIterator,
|
||||
typename PointPMap,
|
||||
typename NormalPMap,
|
||||
typename Kernel
|
||||
>
|
||||
void
|
||||
vcm_estimate_normals (ForwardIterator first, ///< iterator over the first input point.
|
||||
ForwardIterator beyond, ///< past-the-end iterator over the input points.
|
||||
PointPMap point_pmap, ///< property map: value_type of ForwardIterator -> Point_3.
|
||||
NormalPMap normal_pmap, ///< property map: value_type of ForwardIterator -> Vector_3.
|
||||
double offset_radius, ///< offset radius.
|
||||
double convolution_radius, ///< convolution radius.
|
||||
const Kernel & kernel, ///< geometric traits.
|
||||
int nb_neighbors_convolve = -1 ///< number of neighbors used during the convolution.
|
||||
)
|
||||
{
|
||||
typedef cpp11::array<double, 6> Covariance;
|
||||
// Compute the VCM and convolve it
|
||||
std::vector<Covariance> cov;
|
||||
if (nb_neighbors_convolve == -1) {
|
||||
compute_vcm(first, beyond,
|
||||
point_pmap,
|
||||
cov,
|
||||
offset_radius,
|
||||
convolution_radius,
|
||||
kernel);
|
||||
} else {
|
||||
internal::vcm_offset(first, beyond,
|
||||
point_pmap,
|
||||
cov,
|
||||
offset_radius,
|
||||
20,
|
||||
kernel);
|
||||
|
||||
if (nb_neighbors_convolve > 0)
|
||||
{
|
||||
std::vector<Covariance> ccov;
|
||||
ccov.reserve(cov.size());
|
||||
internal::vcm_convolve(first, beyond,
|
||||
point_pmap,
|
||||
cov,
|
||||
ccov,
|
||||
(unsigned int) nb_neighbors_convolve,
|
||||
kernel);
|
||||
|
||||
cov.clear();
|
||||
std::copy(ccov.begin(), ccov.end(), std::back_inserter(cov));
|
||||
}
|
||||
}
|
||||
|
||||
// And finally, compute the normals
|
||||
int i = 0;
|
||||
for (ForwardIterator it = first; it != beyond; ++it) {
|
||||
cpp11::array<double, 3> enormal = {{ 0,0,0 }};
|
||||
VCM_traits::extract_largest_eigenvector_of_covariance_matrix
|
||||
(cov[i], enormal);
|
||||
|
||||
typename Kernel::Vector_3 normal(enormal[0],
|
||||
enormal[1],
|
||||
enormal[2]);
|
||||
put(normal_pmap, *it, normal);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/// \ingroup PkgPointSetProcessing
|
||||
/// Estimates normal directions of the points in the range `[first, beyond)`
|
||||
/// using the Voronoi Covariance Measure with a radius for the convolution.
|
||||
/// The output normals are randomly oriented.
|
||||
///
|
||||
/// See `compute_vcm()` for a detailed description of the parameters `offset_radius` and `convolution_radius`
|
||||
/// and of the Voronoi Covariance Measure.
|
||||
///
|
||||
/// @tparam ForwardIterator iterator over input points.
|
||||
/// @tparam PointPMap is a model of `ReadablePropertyMap` with a value_type = `Kernel::Point_3`.
|
||||
/// @tparam NormalPMap is a model of `WritablePropertyMap` with a value_type = `Kernel::Vector_3`.
|
||||
/// \tparam VCM_traits is a model of `VCMTraits`. If Eigen 3 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined
|
||||
/// then an overload using `Eigen_vcm_traits` is provided and this template parameter can be omitted.
|
||||
|
||||
// This variant deduces the kernel from the point property map
|
||||
// and uses a radius for the convolution.
|
||||
template < typename ForwardIterator,
|
||||
typename PointPMap,
|
||||
typename NormalPMap,
|
||||
typename VCM_traits
|
||||
>
|
||||
void
|
||||
vcm_estimate_normals (ForwardIterator first, ///< iterator over the first input point.
|
||||
ForwardIterator beyond, ///< past-the-end iterator over the input points.
|
||||
PointPMap point_pmap, ///< property map: value_type of ForwardIterator -> Point_3.
|
||||
NormalPMap normal_pmap, ///< property map: value_type of ForwardIterator -> Vector_3.
|
||||
double offset_radius, ///< offset radius.
|
||||
double convolution_radius, ///< convolution radius.
|
||||
VCM_traits
|
||||
)
|
||||
{
|
||||
typedef typename boost::property_traits<PointPMap>::value_type Point;
|
||||
typedef typename Kernel_traits<Point>::Kernel Kernel;
|
||||
|
||||
vcm_estimate_normals<VCM_traits>(first, beyond,
|
||||
point_pmap, normal_pmap,
|
||||
offset_radius, convolution_radius,
|
||||
Kernel());
|
||||
}
|
||||
|
||||
|
||||
/// \ingroup PkgPointSetProcessing
|
||||
/// Estimates normal directions of the points in the range `[first, beyond)`
|
||||
/// using the Voronoi Covariance Measure with a number of neighbors for the convolution.
|
||||
/// The output normals are randomly oriented.
|
||||
///
|
||||
/// See `compute_vcm()` for a detailed description of the parameter `offset_radius`
|
||||
/// and of the Voronoi Covariance Measure.
|
||||
///
|
||||
/// @tparam ForwardIterator iterator over input points.
|
||||
/// @tparam PointPMap is a model of `ReadablePropertyMap` with a value_type = `Kernel::Point_3`.
|
||||
/// @tparam NormalPMap is a model of `WritablePropertyMap` with a value_type = `Kernel::Vector_3`.
|
||||
/// \tparam VCM_traits is a model of `VCMTraits`. If Eigen 3 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined
|
||||
/// then an overload using `Eigen_vcm_traits` is provided and this template parameter can be omitted.
|
||||
|
||||
// This variant deduces the kernel from the point property map
|
||||
// and uses a number of neighbors for the convolution.
|
||||
template < typename ForwardIterator,
|
||||
typename PointPMap,
|
||||
typename NormalPMap,
|
||||
typename VCM_traits
|
||||
>
|
||||
void
|
||||
vcm_estimate_normals (ForwardIterator first, ///< iterator over the first input point.
|
||||
ForwardIterator beyond, ///< past-the-end iterator over the input points.
|
||||
PointPMap point_pmap, ///< property map: value_type of ForwardIterator -> Point_3.
|
||||
NormalPMap normal_pmap, ///< property map: value_type of ForwardIterator -> Vector_3.
|
||||
double offset_radius, ///< offset radius.
|
||||
unsigned int k, ///< number of neighbor points used for the convolution.
|
||||
VCM_traits
|
||||
)
|
||||
{
|
||||
typedef typename boost::property_traits<PointPMap>::value_type Point;
|
||||
typedef typename Kernel_traits<Point>::Kernel Kernel;
|
||||
|
||||
vcm_estimate_normals<VCM_traits>(first, beyond,
|
||||
point_pmap, normal_pmap,
|
||||
offset_radius, 0,
|
||||
Kernel(),
|
||||
k);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CGAL_EIGEN3_ENABLED
|
||||
template < typename ForwardIterator,
|
||||
typename PointPMap,
|
||||
typename NormalPMap
|
||||
>
|
||||
void
|
||||
vcm_estimate_normals (ForwardIterator first,
|
||||
ForwardIterator beyond,
|
||||
PointPMap point_pmap,
|
||||
NormalPMap normal_pmap,
|
||||
double offset_radius,
|
||||
double convolution_radius)
|
||||
{
|
||||
vcm_estimate_normals(first, beyond, point_pmap, normal_pmap, offset_radius, convolution_radius, Eigen_vcm_traits());
|
||||
}
|
||||
|
||||
template < typename ForwardIterator,
|
||||
typename PointPMap,
|
||||
typename NormalPMap
|
||||
>
|
||||
void
|
||||
vcm_estimate_normals (ForwardIterator first,
|
||||
ForwardIterator beyond,
|
||||
PointPMap point_pmap,
|
||||
NormalPMap normal_pmap,
|
||||
double offset_radius,
|
||||
unsigned int nb_neighbors_convolve)
|
||||
{
|
||||
vcm_estimate_normals(first, beyond, point_pmap, normal_pmap, offset_radius, nb_neighbors_convolve, Eigen_vcm_traits());
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
// This variant creates a default point property map = Identity_property_map
|
||||
// and use a radius for the convolution.
|
||||
template < typename ForwardIterator,
|
||||
typename NormalPMap
|
||||
>
|
||||
void
|
||||
vcm_estimate_normals (ForwardIterator first,
|
||||
ForwardIterator beyond,
|
||||
NormalPMap normal_pmap,
|
||||
double offset_radius,
|
||||
double convolution_radius) {
|
||||
vcm_estimate_normals(first, beyond,
|
||||
make_identity_property_map(typename std::iterator_traits<ForwardIterator>::value_type()),
|
||||
normal_pmap,
|
||||
offset_radius, convolution_radius);
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
// This variant creates a default point property map = Identity_property_map
|
||||
// and use a number of neighbors for the convolution.
|
||||
template < typename ForwardIterator,
|
||||
typename NormalPMap
|
||||
>
|
||||
void
|
||||
vcm_estimate_normals (ForwardIterator first,
|
||||
ForwardIterator beyond,
|
||||
NormalPMap normal_pmap,
|
||||
double offset_radius,
|
||||
unsigned int nb_neighbors_convolve) {
|
||||
vcm_estimate_normals(first, beyond,
|
||||
make_identity_property_map(typename std::iterator_traits<ForwardIterator>::value_type()),
|
||||
normal_pmap,
|
||||
offset_radius, nb_neighbors_convolve);
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_VCM_ESTIMATE_NORMALS_H
|
||||
|
|
@ -76,6 +76,8 @@ if ( CGAL_FOUND )
|
|||
# Executables that require Eigen or BLAS and LAPACK
|
||||
create_single_source_cgal_program( "normal_estimation_test.cpp" )
|
||||
create_single_source_cgal_program( "smoothing_test.cpp" )
|
||||
create_single_source_cgal_program( "vcm_plane_test.cpp" )
|
||||
create_single_source_cgal_program( "vcm_all_test.cpp" )
|
||||
|
||||
else(EIGEN3_FOUND OR LAPACK_FOUND)
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,41 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/vcm_estimate_normals.h>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef CGAL::Point_3<Kernel> Point_3;
|
||||
typedef CGAL::Vector_3<Kernel> Vector_3;
|
||||
typedef std::pair<Point_3, Vector_3> PointWithNormal;
|
||||
|
||||
int main (void) {
|
||||
// Generate points on a plane
|
||||
int k = 100;
|
||||
float r = 10;
|
||||
|
||||
std::vector<PointWithNormal> points;
|
||||
points.push_back(std::make_pair(Point_3(0, 0, 0), Vector_3(0, 0, 0)));
|
||||
for (int i = 0; i < k; ++i) {
|
||||
float theta = 2 * i * M_PI / k;
|
||||
points.push_back(std::make_pair(Point_3(r * cos(theta), r * sin(theta), 0),
|
||||
Vector_3(0, 0, 0)));
|
||||
}
|
||||
|
||||
// Estimate the normals using VCM
|
||||
float R = 20;
|
||||
vcm_estimate_normals(points.begin(), points.end(),
|
||||
CGAL::First_of_pair_property_map<PointWithNormal>(),
|
||||
CGAL::Second_of_pair_property_map<PointWithNormal>(),
|
||||
R, 0.0);
|
||||
|
||||
std::cout << "Normal is " << points[0].second << std::endl;
|
||||
|
||||
// The normal at the origin should be (0, 0, -1)
|
||||
double epsilon=1e-5;
|
||||
assert(points[0].second.x() < epsilon && points[0].second.x() > -epsilon);
|
||||
assert(points[0].second.y() < epsilon && points[0].second.y() > -epsilon);
|
||||
assert(points[0].second.z() < -1+epsilon && points[0].second.z() > -1-epsilon);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -372,6 +372,14 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
|
|||
qt4_wrap_ui( normal_estimationUI_FILES Polyhedron_demo_normal_estimation_plugin.ui)
|
||||
polyhedron_demo_plugin(normal_estimation_plugin Polyhedron_demo_normal_estimation_plugin ${normal_estimationUI_FILES})
|
||||
target_link_libraries(normal_estimation_plugin scene_points_with_normal_item)
|
||||
|
||||
qt4_wrap_ui( vcm_normal_estimationUI_FILES Polyhedron_demo_vcm_normal_estimation_plugin.ui)
|
||||
polyhedron_demo_plugin(vcm_normal_estimation_plugin Polyhedron_demo_vcm_normal_estimation_plugin ${vcm_normal_estimationUI_FILES})
|
||||
target_link_libraries(vcm_normal_estimation_plugin scene_points_with_normal_item)
|
||||
|
||||
qt4_wrap_ui( features_detection_pluginUI_FILES Polyhedron_demo_features_detection_plugin.ui)
|
||||
polyhedron_demo_plugin(features_detection_plugin Polyhedron_demo_features_detection_plugin ${features_detection_pluginUI_FILES})
|
||||
target_link_libraries(features_detection_plugin scene_points_with_normal_item)
|
||||
|
||||
polyhedron_demo_plugin(point_set_smoothing_plugin Polyhedron_demo_point_set_smoothing_plugin)
|
||||
target_link_libraries(point_set_smoothing_plugin scene_points_with_normal_item)
|
||||
|
|
@ -384,11 +392,12 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
|
|||
else(EIGEN3_FOUND)
|
||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Parameterization plugin will not be available.")
|
||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Poisson reconstruction plugin will not be available.")
|
||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Normal estimation plugin will not be available.")
|
||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Normal estimation plugins will not be available.")
|
||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Smoothing plugin will not be available.")
|
||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Average spacing plugin will not be available.")
|
||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Jet fitting plugin will not be available.")
|
||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Scale space reconstruction plugin will not be available.")
|
||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Feature detection plugin will not be available.")
|
||||
endif(EIGEN3_FOUND)
|
||||
|
||||
polyhedron_demo_plugin(self_intersection_plugin Polyhedron_demo_self_intersection_plugin)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QMainWindow>
|
||||
#include "config.h"
|
||||
#include "Scene_points_with_normal_item.h"
|
||||
#include "Polyhedron_demo_plugin_helper.h"
|
||||
#include "Polyhedron_demo_plugin_interface.h"
|
||||
|
||||
#include <CGAL/vcm_estimate_edges.h>
|
||||
|
||||
#include <CGAL/Timer.h>
|
||||
|
||||
#include "ui_Polyhedron_demo_features_detection_plugin.h"
|
||||
|
||||
class Polyhedron_demo_features_detection_plugin :
|
||||
public QObject,
|
||||
public Polyhedron_demo_plugin_helper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(Polyhedron_demo_plugin_interface)
|
||||
QAction* actionDetectFeatures;
|
||||
public:
|
||||
QList<QAction*> actions() const { return QList<QAction*>() << actionDetectFeatures; }
|
||||
void init(QMainWindow* mainWindow, Scene_interface* scene_interface)
|
||||
{
|
||||
actionDetectFeatures= new QAction(tr("VCM features estimation"), mainWindow);
|
||||
actionDetectFeatures->setObjectName("actionDetectFeatures");
|
||||
|
||||
Polyhedron_demo_plugin_helper::init(mainWindow, scene_interface);
|
||||
}
|
||||
|
||||
bool applicable() const {
|
||||
return qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
}
|
||||
|
||||
public slots:
|
||||
void on_actionDetectFeatures_triggered();
|
||||
|
||||
}; // end Polyhedron_demo_features_detection_plugin
|
||||
|
||||
class Polyhedron_demo_features_detection_dialog : public QDialog, private Ui::VCMFeaturesDetectionDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Polyhedron_demo_features_detection_dialog(QWidget* /*parent*/ = 0)
|
||||
{
|
||||
setupUi(this);
|
||||
}
|
||||
|
||||
float offsetRadius() const { return m_inputOffsetRadius->value(); }
|
||||
float convolveRadius() const { return m_inputConvolveRadius->value(); }
|
||||
float threshold() const { return m_inputFeaturesThreshold->value(); }
|
||||
};
|
||||
|
||||
void Polyhedron_demo_features_detection_plugin::on_actionDetectFeatures_triggered()
|
||||
{
|
||||
const Scene_interface::Item_id index = scene->mainSelectionIndex();
|
||||
|
||||
Scene_points_with_normal_item* item =
|
||||
qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
|
||||
|
||||
if(item)
|
||||
{
|
||||
// Gets point set
|
||||
Point_set* points = item->point_set();
|
||||
if(points == NULL)
|
||||
return;
|
||||
|
||||
// Gets options
|
||||
Polyhedron_demo_features_detection_dialog dialog;
|
||||
if(!dialog.exec())
|
||||
return;
|
||||
|
||||
typedef CGAL::cpp11::array<double,6> Covariance;
|
||||
std::vector<Covariance> cov;
|
||||
|
||||
std::cerr << "Compute VCM (offset_radius="
|
||||
<< dialog.offsetRadius() << " and convolution radius=" << dialog.convolveRadius() << ")...\n";
|
||||
|
||||
CGAL::Timer task_timer; task_timer.start();
|
||||
CGAL::compute_vcm(points->begin(), points->end(),
|
||||
CGAL::make_identity_property_map(Point_set::value_type()),
|
||||
cov, dialog.offsetRadius(), dialog.convolveRadius(),
|
||||
Kernel());
|
||||
task_timer.stop();
|
||||
std::cerr << "done: " << task_timer.time() << " seconds\n";
|
||||
|
||||
Scene_points_with_normal_item* new_item = new Scene_points_with_normal_item();
|
||||
task_timer.reset(); task_timer.start();
|
||||
std::size_t i=0;
|
||||
std::cerr << "Select feature points (threshold=" << dialog.threshold() << ")...\n";
|
||||
BOOST_FOREACH(const Point_set::value_type& p, *points)
|
||||
{
|
||||
if (CGAL::vcm_is_on_feature_edge(cov[i], dialog.threshold()))
|
||||
new_item->point_set()->push_back(p);
|
||||
++i;
|
||||
}
|
||||
task_timer.stop();
|
||||
std::cerr << "done: " << task_timer.time() << " seconds\n";
|
||||
|
||||
if ( !new_item->point_set()->empty() )
|
||||
{
|
||||
new_item->setName(tr("Features of %1").arg(item->name()));
|
||||
new_item->setColor(Qt::red);
|
||||
scene->addItem(new_item);
|
||||
item->setVisible(false);
|
||||
}
|
||||
else
|
||||
delete new_item;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN2(Polyhedron_demo_features_detection_plugin, Polyhedron_demo_features_detection_plugin)
|
||||
|
||||
#include "Polyhedron_demo_features_detection_plugin.moc"
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>VCMFeaturesDetectionDialog</class>
|
||||
<widget class="QDialog" name="VCMFeaturesDetectionDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>318</width>
|
||||
<height>208</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Normal estimation</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Offset Radius:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="m_inputOffsetRadius">
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Convolution Radius:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="m_inputConvolveRadius">
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Threshold:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="m_inputFeaturesThreshold">
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.160000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>VCMFeaturesDetectionDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>VCMFeaturesDetectionDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
#include "config.h"
|
||||
#include "Scene_points_with_normal_item.h"
|
||||
#include "Polyhedron_demo_plugin_helper.h"
|
||||
#include "Polyhedron_demo_plugin_interface.h"
|
||||
|
||||
#include <CGAL/vcm_estimate_normals.h>
|
||||
#include <CGAL/mst_orient_normals.h>
|
||||
#include <CGAL/Timer.h>
|
||||
#include <CGAL/Memory_sizer.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QAction>
|
||||
#include <QMainWindow>
|
||||
#include <QApplication>
|
||||
#include <QtPlugin>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "ui_Polyhedron_demo_vcm_normal_estimation_plugin.h"
|
||||
|
||||
class Polyhedron_demo_vcm_normal_estimation_plugin :
|
||||
public QObject,
|
||||
public Polyhedron_demo_plugin_helper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(Polyhedron_demo_plugin_interface)
|
||||
QAction* actionVCMNormalEstimation;
|
||||
QAction* actionNormalInversion;
|
||||
|
||||
public:
|
||||
void init(QMainWindow* mainWindow, Scene_interface* scene_interface) {
|
||||
|
||||
actionVCMNormalEstimation = new QAction(tr("VCM normal estimation"), mainWindow);
|
||||
actionVCMNormalEstimation->setObjectName("actionVCMNormalEstimation");
|
||||
|
||||
Polyhedron_demo_plugin_helper::init(mainWindow, scene_interface);
|
||||
}
|
||||
|
||||
QList<QAction*> actions() const {
|
||||
return QList<QAction*>() << actionVCMNormalEstimation;
|
||||
}
|
||||
|
||||
bool applicable() const {
|
||||
return qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
}
|
||||
|
||||
public slots:
|
||||
void on_actionVCMNormalEstimation_triggered();
|
||||
|
||||
}; // end Polyhedron_demo_vcm_normal_estimation_plugin
|
||||
|
||||
class Point_set_demo_normal_estimation_dialog : public QDialog, private Ui::VCMNormalEstimationDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Point_set_demo_normal_estimation_dialog(QWidget* /*parent*/ = 0)
|
||||
{
|
||||
setupUi(this);
|
||||
}
|
||||
|
||||
float offsetRadius() const { return m_inputOffsetRadius->value(); }
|
||||
float convolveRadius() const { return m_inputConvolveRadius->value(); }
|
||||
unsigned int convolveNeighbors() const { return m_inputConvolveNeighbors->value(); }
|
||||
bool convolveUsingRadius() const { return m_inputUseConvRad->isChecked(); }
|
||||
};
|
||||
|
||||
void Polyhedron_demo_vcm_normal_estimation_plugin::on_actionVCMNormalEstimation_triggered()
|
||||
{
|
||||
const Scene_interface::Item_id index = scene->mainSelectionIndex();
|
||||
|
||||
Scene_points_with_normal_item* item =
|
||||
qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
|
||||
|
||||
if(item)
|
||||
{
|
||||
// Gets point set
|
||||
Point_set* points = item->point_set();
|
||||
if(points == NULL)
|
||||
return;
|
||||
|
||||
// Gets options
|
||||
Point_set_demo_normal_estimation_dialog dialog;
|
||||
if(!dialog.exec())
|
||||
return;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
// First point to delete
|
||||
Point_set::iterator first_unoriented_point = points->end();
|
||||
|
||||
//***************************************
|
||||
// VCM normal estimation
|
||||
//***************************************
|
||||
|
||||
CGAL::Timer task_timer; task_timer.start();
|
||||
|
||||
// Estimates normals direction.
|
||||
if (dialog.convolveUsingRadius())
|
||||
{
|
||||
std::cerr << "Estimates Normals Direction using VCM (R="
|
||||
<< dialog.offsetRadius() << " and r=" << dialog.convolveRadius() << ")...\n";
|
||||
|
||||
CGAL::vcm_estimate_normals(points->begin(), points->end(),
|
||||
CGAL::make_normal_of_point_with_normal_pmap(Point_set::value_type()),
|
||||
dialog.offsetRadius(), dialog.convolveRadius());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Estimates Normals Direction using VCM (R="
|
||||
<< dialog.offsetRadius() << " and k=" << dialog.convolveNeighbors() << ")...\n";
|
||||
|
||||
CGAL::vcm_estimate_normals(points->begin(), points->end(),
|
||||
CGAL::make_normal_of_point_with_normal_pmap(Point_set::value_type()),
|
||||
dialog.offsetRadius(), dialog.convolveNeighbors());
|
||||
}
|
||||
// Mark all normals as unoriented
|
||||
first_unoriented_point = points->begin();
|
||||
|
||||
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
||||
task_timer.stop();
|
||||
std::cerr << "Estimates normal direction: " << task_timer.time() << " seconds, "
|
||||
<< (memory>>20) << " Mb allocated"
|
||||
<< std::endl;
|
||||
|
||||
//***************************************
|
||||
// normal orientation
|
||||
//***************************************
|
||||
|
||||
unsigned int neighbors = 18;
|
||||
task_timer.reset();
|
||||
task_timer.start();
|
||||
std::cerr << "Orient normals with a Minimum Spanning Tree (k=" << neighbors << ")...\n";
|
||||
|
||||
// Tries to orient normals
|
||||
first_unoriented_point = CGAL::mst_orient_normals(points->begin(), points->end(),
|
||||
CGAL::make_normal_of_point_with_normal_pmap(Point_set::value_type()),
|
||||
neighbors);
|
||||
|
||||
std::size_t nb_unoriented_normals = std::distance(first_unoriented_point, points->end());
|
||||
memory = CGAL::Memory_sizer().virtual_size();
|
||||
std::cerr << "Orient normals: " << nb_unoriented_normals << " point(s) with an unoriented normal are selected ("
|
||||
<< task_timer.time() << " seconds, "
|
||||
<< (memory>>20) << " Mb allocated)"
|
||||
<< std::endl;
|
||||
|
||||
// Updates scene
|
||||
scene->itemChanged(index);
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN2(Polyhedron_demo_vcm_normal_estimation_plugin, Polyhedron_demo_vcm_normal_estimation_plugin)
|
||||
|
||||
#include "Polyhedron_demo_vcm_normal_estimation_plugin.moc"
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>VCMNormalEstimationDialog</class>
|
||||
<widget class="QDialog" name="VCMNormalEstimationDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>462</width>
|
||||
<height>401</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Normal estimation</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Offset Radius:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="m_inputOffsetRadius">
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Convolution radius:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="m_inputConvolveRadius">
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Convolution Neighbors:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="m_inputConvolveNeighbors">
|
||||
<property name="suffix">
|
||||
<string> neighbors</string>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>40</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_inputUseConvRad">
|
||||
<property name="text">
|
||||
<string>Use Convolution Radius</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>label</zorder>
|
||||
<zorder>buttonBox</zorder>
|
||||
<zorder>m_inputOffsetRadius</zorder>
|
||||
<zorder>m_inputConvolveRadius</zorder>
|
||||
<zorder>label_2</zorder>
|
||||
<zorder>label_3</zorder>
|
||||
<zorder>m_inputConvolveNeighbors</zorder>
|
||||
<zorder>label_2</zorder>
|
||||
<zorder>m_inputUseConvRad</zorder>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>VCMNormalEstimationDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>VCMNormalEstimationDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
Loading…
Reference in New Issue