Merge branch 'Point_set_processing_3-Point_set_structuring-GF-old' into Point_set_processing_3-Point_set_structuring-GF

This commit is contained in:
Simon Giraudot 2016-05-17 10:00:03 +02:00
commit a6b11751b1
26 changed files with 102792 additions and 379 deletions

View File

@ -192,7 +192,9 @@ The second example presents a class that enables to traverse the
surface represented in a 2D triangulation data structure where
the faces are connected with the facets of underlying 3D Delaunay triangulation.
The third example shows how to get outliers and the boundaries of
the surface.
the surface. The last example shows how to combine this algorithm with
two \cgal algorithms in order to reconstruct surfaces with sharp
features.
\subsection AFSR_Example_function Examples for Global Function
@ -267,6 +269,42 @@ It returns an iterator range type \link Advancing_front_surface_reconstruction::
\cgalExample{Advancing_front_surface_reconstruction/boundaries.cpp}
\subsection AFSR_Example_sharp_features Example for Sharp Features
The priority queue used by the advancing front surface reconstruction
algorithm can be modified to achieve robustness to sharp edges and
provide piecewise-planar or hybrid reconstruction as described in
\cgalCite{cgal:la-srpss-13}. Two other algorithms available in \cgal
must be applied first as a preprocessing to the point set:
- \ref Chapter_Point_Set_Shape_Detection "Shape detection": detect planar sections of the input.
- \ref Point_set_processing_3Structuring "Point set structuring":
resample the planar sections and edges and corners detected among
them.
\cgalFigureBegin{figAFSRstruct,structured_example.png}
Comparison of advancing front output.
- Top: input point set and raw advancing front reconstruction
- Bottom: structured point set and advancing front reconstruction with
structure-dependent priority functor
\cgalFigureEnd
The quality of the reconstruction can be significantly improved thanks
to point set structuring when dealing with shapes with sharp features,
as shown on the previous figure. The following example shows how to
define a priority functor that favors structurally coherent facets and
makes the advancing front algorithm robust to sharp features.
\cgalExample{Advancing_front_surface_reconstruction/reconstruction_structured.cpp}
*/
} /* namespace CGAL */

View File

@ -10,3 +10,5 @@ Triangulation_3
Number_types
Surface_mesh
Polyhedron
Point_set_shape_detection_3
Point_set_processing_3

View File

@ -3,4 +3,5 @@
\example Advancing_front_surface_reconstruction/reconstruction_class.cpp
\example Advancing_front_surface_reconstruction/reconstruction_surface_mesh.cpp
\example Advancing_front_surface_reconstruction/boundaries.cpp
\example Advancing_front_surface_reconstruction/reconstruction_structured.cpp
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

View File

@ -0,0 +1,185 @@
#include <iostream>
#include <fstream>
#include <algorithm>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_with_normal_3.h>
#include <CGAL/Shape_detection_3.h>
#include <CGAL/structure_point_set.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Triangulation_vertex_base_with_info_3.h>
#include <CGAL/Advancing_front_surface_reconstruction.h>
#include <CGAL/IO/read_xyz_points.h>
#include <boost/lexical_cast.hpp>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef std::pair<Kernel::Point_3, Kernel::Vector_3> Point_with_normal;
typedef std::vector<Point_with_normal> Pwn_vector;
typedef CGAL::First_of_pair_property_map<Point_with_normal> Point_map;
typedef CGAL::Second_of_pair_property_map<Point_with_normal> Normal_map;
// Efficient RANSAC types
typedef CGAL::Shape_detection_3::Efficient_RANSAC_traits
<Kernel, Pwn_vector, Point_map, Normal_map> Traits;
typedef CGAL::Shape_detection_3::Efficient_RANSAC<Traits> Efficient_ransac;
typedef CGAL::Shape_detection_3::Plane<Traits> Plane;
// Point set structuring type
typedef CGAL::Point_set_with_structure<Traits> Structure;
// Advancing front types
typedef CGAL::Advancing_front_surface_reconstruction_vertex_base_3<Kernel> LVb;
typedef CGAL::Advancing_front_surface_reconstruction_cell_base_3<Kernel> LCb;
typedef CGAL::Triangulation_data_structure_3<LVb,LCb> Tds;
typedef CGAL::Delaunay_triangulation_3<Kernel,Tds> Triangulation_3;
typedef Triangulation_3::Vertex_handle Vertex_handle;
typedef CGAL::cpp11::array<std::size_t,3> Facet;
// Functor to init the advancing front algorithm with indexed points
struct On_the_fly_pair{
const Pwn_vector& points;
typedef std::pair<Point, std::size_t> result_type;
On_the_fly_pair(const Pwn_vector& points) : points(points) {}
result_type
operator()(std::size_t i) const
{
return result_type(points[i].first,i);
}
};
// Specialized priority functor that favor structure coherence
template <typename Structure>
struct Priority_with_structure_coherence {
Structure& structure;
double bound;
Priority_with_structure_coherence(Structure& structure,
double bound)
: structure (structure), bound (bound)
{}
template <typename AdvancingFront, typename Cell_handle>
double operator() (AdvancingFront& adv, Cell_handle& c,
const int& index) const
{
// If perimeter > bound, return infinity so that facet is not used
if (bound != 0)
{
double d = 0;
d = sqrt(squared_distance(c->vertex((index+1)%4)->point(),
c->vertex((index+2)%4)->point()));
if(d>bound) return adv.infinity();
d += sqrt(squared_distance(c->vertex((index+2)%4)->point(),
c->vertex((index+3)%4)->point()));
if(d>bound) return adv.infinity();
d += sqrt(squared_distance(c->vertex((index+1)%4)->point(),
c->vertex((index+3)%4)->point()));
if(d>bound) return adv.infinity();
}
Facet f = {{ c->vertex ((index + 1) % 4)->info (),
c->vertex ((index + 2) % 4)->info (),
c->vertex ((index + 3) % 4)->info () }};
// facet_coherence takes values between -1 and 3, 3 being the most
// coherent and -1 being incoherent. Smaller weight means higher
// priority.
double weight = 100. * (5 - structure.facet_coherence (f));
return weight * adv.smallest_radius_delaunay_sphere (c, index);
}
};
// Advancing front type
typedef CGAL::Advancing_front_surface_reconstruction
<Triangulation_3,
Priority_with_structure_coherence<Structure> >
Reconstruction;
int main (int argc, char* argv[])
{
// Points with normals.
Pwn_vector points;
const char* fname = (argc>1) ? argv[1] : "data/cube.pwn";
// Loading point set from a file.
std::ifstream stream(fname);
if (!stream ||
!CGAL::read_xyz_points_and_normals(stream,
std::back_inserter(points),
Point_map(),
Normal_map()))
{
std::cerr << "Error: cannot read file" << std::endl;
return EXIT_FAILURE;
}
std::cerr << "Shape detection... ";
Efficient_ransac ransac;
ransac.set_input(points);
ransac.add_shape_factory<Plane>(); // Only planes are useful for stucturing
// Default RANSAC parameters
Efficient_ransac::Parameters op;
op.probability = 0.05;
op.min_points = 100;
op.epsilon = (argc>2 ? boost::lexical_cast<double>(argv[2]) : 0.002);
op.cluster_epsilon = (argc>3 ? boost::lexical_cast<double>(argv[3]) : 0.02);
op.normal_threshold = 0.7;
ransac.detect(op); // Plane detection
std::cerr << "done\nPoint set structuring... ";
Pwn_vector structured_pts;
Structure pss (points.begin (), points.end (), ransac,
op.cluster_epsilon); // Same parameter as RANSAC
for (std::size_t i = 0; i < pss.size(); ++ i)
structured_pts.push_back (pss[i]);
std::cerr << "done\nAdvancing front... ";
std::vector<std::size_t> point_indices(boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(structured_pts.size()));
Triangulation_3 dt (boost::make_transform_iterator(point_indices.begin(), On_the_fly_pair(structured_pts)),
boost::make_transform_iterator(point_indices.end(), On_the_fly_pair(structured_pts)));
Priority_with_structure_coherence<Structure> priority (pss,
1000. * op.cluster_epsilon); // Avoid too large facets
Reconstruction R(dt, priority);
R.run ();
std::cerr << "done\nWriting result... ";
std::vector<Facet> output;
CGAL::write_triple_indices (std::back_inserter (output), R);
std::ofstream f ("out.off");
f << "OFF\n" << structured_pts.size () << " " << output.size() << " 0\n"; // Header
for (std::size_t i = 0; i < structured_pts.size (); ++ i)
f << structured_pts[i].first << std::endl;
for (std::size_t i = 0; i < output.size (); ++ i)
f << "3 "
<< output[i][0] << " "
<< output[i][1] << " "
<< output[i][2] << std::endl;
std::cerr << "all done\n" << std::endl;
f.close();
return 0;
}

View File

@ -21,6 +21,8 @@
% ----------------------------------------------------------------------------
@article{ cgal:afh-pdecm-02,
author = "P. K. Agarwal and E. Flato and D. Halperin",
title = "Polygon Decomposition for Efficient Construction of {Minkowski} Sums",
@ -1050,6 +1052,15 @@ note = {\url{ttp://hal.inria.fr/inria-00090522}}
annote = {map,generalized map},
}
@INPROCEEDINGS{cgal:la-srpss-13,
author = {Lafarge, Florent and Alliez, Pierre},
title = {Surface reconstruction through point set structuring},
booktitle = {Proc. of Eurographics},
year = {2013},
address = {Girona, Spain}
}
@inproceedings{ cgal:lt-fmeps-98,
author = "Peter Lindstrom and Greg Turk",
title = "Fast and memory efficient polygonal simplification",

View File

@ -159,6 +159,9 @@ and <code>src/</code> directories).
<li>New function <code>CGAL::read_ply_custom_points()</code> that
allows the user to read any additional point attribute from a PLY
input point set.</li>
<li> <code>CGAL::structure_point_set()</code>: new algorithm that
takes advantage of detected planes to produce a structured point
set (with flat regions, sharp edges and vertices).</li>
</ul>
<h3>Point Set Shape Detection</h3>
<ul>

View File

@ -50,6 +50,7 @@
- `CGAL::compute_vcm()`
- `CGAL::vcm_estimate_normals()`
- `CGAL::vcm_is_on_feature_edge()`
- `CGAL::structure_point_set()`
- `CGAL::write_off_points()`
- `CGAL::write_ply_points()`
- `CGAL::write_xyz_points()`

View File

@ -408,6 +408,60 @@ points that are on sharp edges:
\cgalExample{Point_set_processing_3/edges_example.cpp}
\section Point_set_processing_3Structuring Structuring
The function `structure_point_set()` generates a structured version of the
input point set. It requires that a shape detection algorithm is first applied
to the point set (see \ref Chapter_Point_Set_Shape_Detection). It is based on
the article \cgalCite{cgal:la-srpss-13}.
- __Planes__: inliers of each detected plane are replaced by sets of
noise-free points sampled at the vertices of a regular grid: this is
achieved by filling an occupancy grid aligned on the principal
components of the inlier sets with a spacing lower than \f$\sqrt{2}\f$
times the user-defined tolerance.
- __Creases__: adjacencies between 2 planes are detected and regularly
resampled on an occupancy array along the edge with a spacing equal to
twice the user-defined tolerance.
- __Corners__: 3-cycles are detected from the primitive adjacency
graph and sampled using the exact intersection point of the 3 planes
(provided it exists and remains in the given tolerance). These corners
are also locally clustered to former corners of degree higher than 3.
This algorithm is well suited to point sets sampled on surfaces with
planar sections and sharp edges.
\cgalFigureBegin{Point_set_processing_3figstructuring,structuring.png}
Point set structuring. Left: input raw point set. Right: structured point set.
\cgalFigureEnd
Structure information of points can be used to perform feature
preserving reconstruction (see
\ref AFSR_Example_sharp_features "Advancing Front Surface Reconstruction"
for example). More specifically, the class storing a point set with
structure provides the user with a method
`Point_set_with_structure::facet_coherence()` that estimates if a
triplet of points form a coherent facet.
\cgalFigureBegin{Point_set_processing_3figstructuring, structuring_coherence.png}
(a) Input point set (and structured output); (b) output with many
incoherent facets; (c) output with all facets coherent. i, j and k
each corresponds to a primitive index.
\cgalFigureEnd
\subsection Point_set_processing_3Example_9 Example
The following example applies shape detection followed by structuring to a
point set:
\cgalExample{Point_set_processing_3/structuring_example.cpp}
\section Point_set_processing_3ImplementationHistory Implementation History
Pierre Alliez and Laurent Saboret contributed the initial component. Nader Salman contributed the grid simplification.

View File

@ -10,4 +10,5 @@ Bounding_volumes
Principal_component_analysis
Jet_fitting_3
Solver_interface
Point_set_shape_detection_3
Advancing_front_surface_reconstruction

View File

@ -12,4 +12,5 @@
\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
\example Point_set_processing_3/structuring_example.cpp
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@ -55,6 +55,7 @@ if ( CGAL_FOUND )
create_single_source_cgal_program( "remove_outliers_example.cpp" )
create_single_source_cgal_program( "wlop_simplify_and_regularize_point_set_example.cpp" )
create_single_source_cgal_program( "edge_aware_upsample_point_set_example.cpp" )
create_single_source_cgal_program( "structuring_example.cpp" )
# Use Eigen or BLAS and LAPACK (optional)
find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/IO/read_xyz_points.h>
#include <CGAL/IO/write_xyz_points.h>
#include <CGAL/Point_with_normal_3.h>
#include <CGAL/property_map.h>
#include <CGAL/Shape_detection_3.h>
#include <CGAL/structure_point_set.h>
#include <iostream>
#include <fstream>
// Type declarations
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef std::pair<Kernel::Point_3, Kernel::Vector_3> Point_with_normal;
typedef std::vector<Point_with_normal> Pwn_vector;
typedef CGAL::First_of_pair_property_map<Point_with_normal> Point_map;
typedef CGAL::Second_of_pair_property_map<Point_with_normal> Normal_map;
// Efficient RANSAC types
typedef CGAL::Shape_detection_3::Efficient_RANSAC_traits
<Kernel, Pwn_vector, Point_map, Normal_map> Traits;
typedef CGAL::Shape_detection_3::Efficient_RANSAC<Traits> Efficient_ransac;
typedef CGAL::Shape_detection_3::Plane<Traits> Plane;
int main (int argc, char** argv)
{
// Points with normals.
Pwn_vector points;
// Loading point set from a file.
std::ifstream stream(argc>1 ? argv[1] : "data/cube.pwn");
if (!stream ||
!CGAL::read_xyz_points_and_normals(stream,
std::back_inserter(points),
Point_map(),
Normal_map()))
{
std::cerr << "Error: cannot read file cube.pwn" << std::endl;
return EXIT_FAILURE;
}
std::cerr << points.size() << " point(s) read." << std::endl;
// Shape detection
Efficient_ransac ransac;
ransac.set_input(points);
ransac.add_shape_factory<Plane>();
ransac.detect();
Pwn_vector structured_pts;
CGAL::structure_point_set (points.begin (), points.end (), // input points
std::back_inserter (structured_pts),
ransac, // shape detection engine
0.015); // epsilon for structuring points
std::cerr << structured_pts.size ()
<< " structured point(s) generated." << std::endl;
std::ofstream out ("out.pwn");
CGAL::write_xyz_points_and_normals (out, structured_pts.begin(), structured_pts.end(),
Point_map(), Normal_map());
out.close();
return EXIT_SUCCESS;
}

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,7 @@ if ( CGAL_FOUND )
create_single_source_cgal_program( "wlop_simplify_and_regularize_test.cpp" )
create_single_source_cgal_program( "bilateral_smoothing_test.cpp" )
create_single_source_cgal_program( "edge_aware_upsample_test.cpp" )
create_single_source_cgal_program( "structuring_test.cpp" )
# Use Eigen or BLAS and LAPACK (optional)
find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater)

View File

@ -0,0 +1,134 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_with_normal_3.h>
#include <CGAL/property_map.h>
#include <CGAL/Shape_detection_3.h>
#include <CGAL/structure_point_set.h>
#include <CGAL/Random.h>
#include <iostream>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef Kernel::Plane_3 Plane;
typedef std::pair<Point, Vector> Point_with_normal;
typedef std::vector<Point_with_normal> Pwn_vector;
typedef CGAL::First_of_pair_property_map<Point_with_normal> Point_map;
typedef CGAL::Second_of_pair_property_map<Point_with_normal> Normal_map;
typedef CGAL::Shape_detection_3::Efficient_RANSAC_traits
<Kernel, Pwn_vector, Point_map, Normal_map> Traits;
typedef CGAL::Shape_detection_3::Efficient_RANSAC<Traits> Efficient_ransac;
typedef CGAL::Point_set_with_structure<Traits> Points_with_structure;
template <typename OutputIterator>
void generate_random_points (const Point& origin, const Vector& base1, const Vector& base2,
std::size_t nb_pts, OutputIterator output)
{
Vector normal = CGAL::cross_product (base1, base2);
normal = normal / std::sqrt (normal * normal);
for (std::size_t i = 0; i < nb_pts; ++ i)
{
Point point = origin
+ CGAL::get_default_random().get_double() * base1
+ CGAL::get_default_random().get_double() * base2;
*(output ++) = std::make_pair (point, normal);
}
}
int main()
{
Vector vx (1., 0., 0.),
vy (0., 1., 0.),
vz (0., 0., 1.);
Efficient_ransac ransac;
ransac.add_shape_factory<CGAL::Shape_detection_3::Plane<Traits> >();
const std::size_t nb_pts = 1000;
Efficient_ransac::Parameters op;
op.probability = 0.05;
op.min_points = nb_pts / 2;
op.epsilon = 0.02;
op.cluster_epsilon = 0.05;
op.normal_threshold = 0.8;
Pwn_vector points;
generate_random_points (Point (0., 0., 0.), vx, vy,
5000, std::back_inserter (points));
generate_random_points (Point (0., 0., 0.), vx, vz,
5000, std::back_inserter (points));
generate_random_points (Point (0., 0., 0.), vy, vz,
5000, std::back_inserter (points));
generate_random_points (Point (0., 0., 1.), vx, vy,
5000, std::back_inserter (points));
generate_random_points (Point (0., 1., 0.), vx, vz,
5000, std::back_inserter (points));
generate_random_points (Point (1., 0., 0.), vy, vz,
5000, std::back_inserter (points));
ransac.set_input(points);
ransac.detect(op);
Points_with_structure pss (points.begin(), points.end(), ransac, op.cluster_epsilon);
std::vector<Point> vertices;
for (std::size_t i = 0; i < pss.size(); ++ i)
if (pss.adjacency (i).size () == 3)
vertices.push_back (pss.point (i));
if (vertices.size () != 8)
{
std::cerr << "Error: 8 point should have been structural vertices." << std::endl;
return EXIT_FAILURE;
}
std::vector<Point> ground_truth;
ground_truth.push_back (Point (0., 0., 0.));
ground_truth.push_back (Point (0., 0., 1.));
ground_truth.push_back (Point (0., 1., 0.));
ground_truth.push_back (Point (0., 1., 1.));
ground_truth.push_back (Point (1., 0., 0.));
ground_truth.push_back (Point (1., 0., 1.));
ground_truth.push_back (Point (1., 1., 0.));
ground_truth.push_back (Point (1., 1., 1.));
std::vector<bool> found (ground_truth.size(), false);
std::size_t nb_found = 0;
for (std::size_t i = 0; i < vertices.size(); ++ i)
for (std::size_t j = 0; j < ground_truth.size(); ++ j)
{
if (found[j])
continue;
if (CGAL::squared_distance (ground_truth[j], vertices[i]) < 1e-6)
{
found[j] = true;
++ nb_found;
break;
}
}
if (nb_found != ground_truth.size())
{
std::cerr << "Error: the following vert(ex/ices) was/were not found:" << std::endl;
for (std::size_t i = 0; i < ground_truth.size(); ++ i)
if (!(found[i]))
std::cerr << " * " << ground_truth[i] << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -46,6 +46,8 @@ namespace CGAL {
class InputPointMap,
class InputNormalMap>
struct Efficient_RANSAC_traits {
///
typedef Gt Base_kernel;
///
typedef typename Gt::FT FT;
///
@ -55,6 +57,8 @@ namespace CGAL {
///
typedef typename Gt::Sphere_3 Sphere_3;
///
typedef typename Gt::Segment_3 Segment_3;
///
typedef typename Gt::Line_3 Line_3;
///
typedef typename Gt::Circle_2 Circle_2;

View File

@ -138,6 +138,16 @@ namespace CGAL {
m_normal = this->cross_pdct(
this->constr_vec(p2, p1), this->constr_vec(p3, p1));
// Check if normal orientation is consistent
std::size_t nb_correct = 0,
nb_total = (indices.size () > 100) ? 100 : indices.size ();
for (std::size_t i = 0; i < nb_total; ++ i)
if (this->normal (indices[i]) * m_normal > 0)
++ nb_correct;
if (nb_correct < nb_total / 2)
m_normal = -m_normal;
FT length = CGAL::sqrt(this->sqlen(m_normal));
// Are the points almost singular?

View File

@ -2,8 +2,10 @@
#include "Scene_points_with_normal_item.h"
#include "Scene_polygon_soup_item.h"
#include "Scene_polyhedron_item.h"
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <CGAL/Three/Scene_group_item.h>
#include <CGAL/Random.h>
@ -12,6 +14,8 @@
#include <CGAL/Delaunay_triangulation_2.h>
#include <CGAL/Alpha_shape_2.h>
#include <CGAL/structure_point_set.h>
#include <QObject>
#include <QAction>
#include <QMainWindow>
@ -20,9 +24,25 @@
#include <QMessageBox>
#include <boost/foreach.hpp>
#include <boost/function_output_iterator.hpp>
#include "ui_Point_set_shape_detection_plugin.h"
struct build_from_pair
{
Point_set& m_pts;
build_from_pair (Point_set& pts) : m_pts (pts) { }
void operator() (const std::pair<Point_set::Point, Point_set::Vector>& pair)
{
m_pts.push_back (Point_set::Point_with_normal (pair.first, pair.second));
}
};
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic_kernel;
typedef Epic_kernel::Point_3 Point;
//typedef CGAL::Point_with_normal_3<Epic_kernel> Point_with_normal;
@ -101,6 +121,7 @@ public:
bool generate_alpha() const { return m_generate_alpha->isChecked(); }
bool generate_subset() const { return !(m_do_not_generate_subset->isChecked()); }
bool regularize() const { return m_regularize->isChecked(); }
bool generate_structured() const { return m_generate_structured->isChecked(); }
};
void Polyhedron_demo_point_set_shape_detection_plugin::on_actionDetect_triggered() {
@ -128,7 +149,13 @@ void Polyhedron_demo_point_set_shape_detection_plugin::on_actionDetect_triggered
Point_set_demo_point_set_shape_detection_dialog dialog;
if(!dialog.exec())
return;
scene->setSelectedItem(-1);
Scene_group_item *subsets_item = new Scene_group_item(QString("%1 (RANSAC subsets)").arg(item->name()));
subsets_item->setExpanded(false);
Scene_group_item *planes_item = new Scene_group_item(QString("%1 (RANSAC planes)").arg(item->name()));
planes_item->setExpanded(false);
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -241,7 +268,9 @@ void Polyhedron_demo_point_set_shape_detection_plugin::on_actionDetect_triggered
poly_item->setName(QString("%1%2_alpha_shape").arg(QString::fromStdString(ss.str()))
.arg (QString::number (shape->indices_of_assigned_points().size())));
poly_item->setRenderingMode (Flat);
scene->addItem(poly_item);
scene->changeGroup(poly_item, planes_item);
}
}
else if (dynamic_cast<CGAL::Shape_detection_3::Cone<Traits> *>(shape.get()))
@ -259,13 +288,50 @@ void Polyhedron_demo_point_set_shape_detection_plugin::on_actionDetect_triggered
point_item->set_has_normals(true);
point_item->setRenderingMode(item->renderingMode());
if (dialog.generate_subset())
scene->addItem(point_item);
{
scene->addItem(point_item);
scene->changeGroup(point_item, subsets_item);
}
else
delete point_item;
++index;
}
if (dialog.generate_subset())
scene->add_group(subsets_item);
else
delete subsets_item;
if (dialog.generate_alpha())
scene->add_group(planes_item);
else
delete planes_item;
if (dialog.generate_structured ())
{
std::cout << "Structuring point set... ";
Scene_points_with_normal_item *pts_full = new Scene_points_with_normal_item;
CGAL::structure_point_set (points->begin (), points->end (),
boost::make_function_output_iterator (build_from_pair ((*(pts_full->point_set())))),
shape_detection,
op.cluster_epsilon);
if (pts_full->point_set ()->empty ())
delete pts_full;
else
{
pts_full->point_set ()->unselect_all();
pts_full->setName(tr("%1 (structured)").arg(item->name()));
pts_full->set_has_normals(true);
pts_full->setRenderingMode(PointsPlusNormals);
pts_full->setColor(Qt::blue);
scene->addItem (pts_full);
}
std::cerr << "done" << std::endl;
}
// Updates scene
scene->itemChanged(index);

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>444</width>
<height>269</height>
<height>295</height>
</rect>
</property>
<property name="windowTitle">
@ -221,6 +221,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_generate_structured">
<property name="text">
<string>Generate structured point cloud</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">

View File

@ -28,6 +28,8 @@
#include <CGAL/mst_orient_normals.h>
#include <CGAL/Scale_space_surface_reconstruction_3.h>
#include <CGAL/Advancing_front_surface_reconstruction.h>
#include <CGAL/Shape_detection_3.h>
#include <CGAL/structure_point_set.h>
#include "ui_Surface_reconstruction_plugin.h"
@ -38,6 +40,18 @@ typedef CGAL::Parallel_tag Concurrency_tag;
typedef CGAL::Sequential_tag Concurrency_tag;
#endif
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
// types for K nearest neighbors search
typedef CGAL::Search_traits_3<Kernel> Tree_traits;
typedef CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef Neighbor_search::Tree Tree;
typedef Neighbor_search::iterator Search_iterator;
typedef CGAL::Scale_space_surface_reconstruction_3<Kernel> ScaleSpace;
typedef CGAL::cpp11::array<std::size_t,3> Facet;
// Poisson reconstruction method:
// Reconstructs a surface mesh from a point set and returns it as a polyhedron.
@ -84,21 +98,68 @@ struct Radius {
// delaunay sphere
return adv.smallest_radius_delaunay_sphere (c, index);
}
};
template <typename Structuring>
struct Priority_with_structure_coherence {
Structuring& structuring;
double bound;
Priority_with_structure_coherence(Structuring& structuring,
double bound)
: structuring (structuring), bound (bound)
{}
template <typename AdvancingFront, typename Cell_handle>
double operator() (AdvancingFront& adv, Cell_handle& c,
const int& index) const
{
// If perimeter > bound, return infinity so that facet is not used
if (bound != 0)
{
double d = 0;
d = sqrt(squared_distance(c->vertex((index+1)%4)->point(),
c->vertex((index+2)%4)->point()));
if(d>bound) return adv.infinity();
d += sqrt(squared_distance(c->vertex((index+2)%4)->point(),
c->vertex((index+3)%4)->point()));
if(d>bound) return adv.infinity();
d += sqrt(squared_distance(c->vertex((index+1)%4)->point(),
c->vertex((index+3)%4)->point()));
if(d>bound) return adv.infinity();
}
Facet f = {{ c->vertex ((index + 1) % 4)->info (),
c->vertex ((index + 2) % 4)->info (),
c->vertex ((index + 3) % 4)->info () }};
double weight = 100. * (5 - structuring.facet_coherence (f));
return weight * adv.smallest_radius_delaunay_sphere (c, index);
}
};
struct On_the_fly_pair{
const Point_set& points;
typedef std::pair<Point, std::size_t> result_type;
On_the_fly_pair(const Point_set& points) : points(points) {}
result_type
operator()(std::size_t i) const
{
return result_type(points[i].position(),i);
}
};
namespace SurfaceReconstruction
{
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
// types for K nearest neighbors search
typedef CGAL::Search_traits_3<Kernel> Tree_traits;
typedef CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef Neighbor_search::Tree Tree;
typedef Neighbor_search::iterator Search_iterator;
typedef CGAL::Scale_space_surface_reconstruction_3<Kernel> ScaleSpace;
template <typename OutputIterator>
void generate_scales (OutputIterator out,
@ -410,6 +471,19 @@ namespace SurfaceReconstruction
points.end ());
}
struct build_from_pair
{
Point_set& m_pts;
build_from_pair (Point_set& pts) : m_pts (pts) { }
void operator() (const std::pair<Point_set::Point, Point_set::Vector>& pair)
{
m_pts.push_back (Point_set::Point_with_normal (pair.first, pair.second));
}
};
}
@ -434,6 +508,7 @@ public:
if (buttonAdvancing->isChecked ()) return 1;
if (buttonScaleSpace->isChecked ()) return 2;
if (buttonPoisson->isChecked ()) return 3;
if (buttonRANSAC->isChecked ()) return 4;
return -1;
}
bool boundaries () const { return m_boundaries->isChecked (); }
@ -452,7 +527,12 @@ public:
double distance () const { return m_inputDistance->value (); }
bool two_passes () const { return m_inputTwoPasses->isChecked (); }
bool do_not_fill_holes () const { return m_doNotFillHoles->isChecked (); }
double connectivity_tolerance () const { return m_connectivityTolerance->value (); }
double noise_tolerance () const { return m_noiseTolerance->value (); }
unsigned int min_size_subset () const { return m_minSizeSubset->value (); }
bool generate_structured () const { return m_generateStructured->isChecked (); }
QString solver () const { return m_inputSolver->currentText (); }
};
#include <CGAL/Scale_space_surface_reconstruction_3.h>
@ -480,6 +560,7 @@ public:
void advancing_front_reconstruction (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog);
void scale_space_reconstruction (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog);
void poisson_reconstruction (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog);
void ransac_reconstruction (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog);
//! Applicate for Point_sets with normals.
bool applicable(QAction*) const {
@ -524,6 +605,9 @@ void Polyhedron_demo_surface_reconstruction_plugin::on_actionSurfaceReconstructi
case 3:
poisson_reconstruction (dialog);
break;
case 4:
ransac_reconstruction (dialog);
break;
default:
std::cerr << "Error: unkown method." << std::endl;
return;
@ -869,5 +953,138 @@ void Polyhedron_demo_surface_reconstruction_plugin::poisson_reconstruction
}
}
void Polyhedron_demo_surface_reconstruction_plugin::ransac_reconstruction
(const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog)
{
CGAL::Random rand(time(0));
const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_points_with_normal_item* point_set_item =
qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
if(point_set_item)
{
// Gets point set
Point_set* points = point_set_item->point_set();
if(!points) return;
QApplication::setOverrideCursor(Qt::WaitCursor);
CGAL::Timer global_timer;
global_timer.start();
CGAL::Timer local_timer;
if (!(point_set_item->has_normals()))
{
local_timer.start();
std::cerr << "Estimation of normal vectors... ";
CGAL::jet_estimate_normals<Concurrency_tag>(points->begin(), points->end(),
CGAL::make_normal_of_point_with_normal_pmap(Point_set::value_type()),
12);
local_timer.stop();
point_set_item->set_has_normals (true);
point_set_item->setRenderingMode(PointsPlusNormals);
std::cerr << "done in " << local_timer.time() << " second(s)" << std::endl;
local_timer.reset();
}
typedef CGAL::Identity_property_map<Point_set::Point_with_normal> PointPMap;
typedef CGAL::Normal_of_point_with_normal_pmap<Point_set::Geom_traits> NormalPMap;
typedef CGAL::Shape_detection_3::Efficient_RANSAC_traits<Kernel, Point_set, PointPMap, NormalPMap> Traits;
typedef CGAL::Shape_detection_3::Efficient_RANSAC<Traits> Shape_detection;
local_timer.start();
Shape_detection shape_detection;
shape_detection.set_input(*points);
shape_detection.add_shape_factory<CGAL::Shape_detection_3::Plane<Traits> >();
Shape_detection::Parameters op;
op.probability = 0.05;
op.min_points = dialog.min_size_subset();
op.epsilon = dialog.noise_tolerance();
op.cluster_epsilon = dialog.connectivity_tolerance();
op.normal_threshold = 0.7;
shape_detection.detect(op);
local_timer.stop();
std::cout << shape_detection.shapes().size() << " plane(s) found in "
<< local_timer.time() << " second(s)" << std::endl;
local_timer.reset();
std::cout << "Structuring point set... " << std::endl;
typedef CGAL::Point_set_with_structure<Traits> Structuring;
local_timer.start();
Structuring structuring (points->begin (), points->end (),
shape_detection,
op.cluster_epsilon);
Scene_points_with_normal_item *structured = new Scene_points_with_normal_item;
for (std::size_t i = 0; i < structuring.size(); ++ i)
structured->point_set()->push_back (Point_set::Point_with_normal (structuring.point(i),
structuring.normal(i)));
local_timer.stop ();
std::cerr << structured->point_set()->size() << " point(s) generated in "
<< local_timer.time() << std::endl;
local_timer.reset();
typedef CGAL::Advancing_front_surface_reconstruction_vertex_base_3<Kernel> LVb;
typedef CGAL::Advancing_front_surface_reconstruction_cell_base_3<Kernel> LCb;
typedef CGAL::Triangulation_data_structure_3<LVb,LCb> Tds;
typedef CGAL::Delaunay_triangulation_3<Kernel,Tds> Triangulation_3;
typedef CGAL::Advancing_front_surface_reconstruction<Triangulation_3,
Priority_with_structure_coherence<Structuring> > Reconstruction;
std::cerr << "Reconstructing... ";
local_timer.start();
std::vector<std::size_t> point_indices(boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(structured->point_set()->size()));
Triangulation_3 dt (boost::make_transform_iterator(point_indices.begin(), On_the_fly_pair(*(structured->point_set()))),
boost::make_transform_iterator(point_indices.end(), On_the_fly_pair(*(structured->point_set()))));
Priority_with_structure_coherence<Structuring> priority (structuring, 10. * op.cluster_epsilon);
Reconstruction R(dt, priority);
R.run (5., 0.52);
Scene_polyhedron_item* reco_item = new Scene_polyhedron_item(Polyhedron());
Polyhedron& P = * const_cast<Polyhedron*>(reco_item->polyhedron());
CGAL::AFSR::construct_polyhedron(P, R);
local_timer.stop();
std::cerr << "done in " << local_timer.time() << " second(s)" << std::endl;
if (dialog.generate_structured ())
{
structured->setName(tr("%1 (structured)").arg(point_set_item->name()));
structured->set_has_normals(true);
structured->setRenderingMode(PointsPlusNormals);
structured->setColor(Qt::blue);
scene->addItem (structured);
}
else
delete structured;
reco_item->setName(tr("%1 (RANSAC-based reconstruction)").arg(scene->item(index)->name()));
reco_item->setColor(Qt::magenta);
reco_item->setRenderingMode(FlatPlusEdges);
scene->addItem(reco_item);
std::cerr << "All done in " << global_timer.time() << " seconds." << std::endl;
QApplication::restoreOverrideCursor();
}
}
#include "Surface_reconstruction_plugin.moc"

View File

@ -6,378 +6,536 @@
<rect>
<x>0</x>
<y>0</y>
<width>397</width>
<height>663</height>
<width>787</width>
<height>566</height>
</rect>
</property>
<property name="windowTitle">
<string>Surface Reconstruction</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="0">
<widget class="QFrame" name="frameAdvancing">
<property name="enabled">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Longest Edge</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="m_longestEdge">
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Radius Ratio Bound</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Beta Angle</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="m_radiusRatioBound">
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="value">
<double>5.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="m_betaAngle">
<property name="suffix">
<string>°</string>
</property>
<property name="maximum">
<double>150.000000000000000</double>
</property>
<property name="value">
<double>30.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="buttonAuto">
<property name="text">
<string>Select method and parameters automatically</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frameAuto">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="m_boundaries">
<property name="text">
<string>Output surface has boundaries</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_interpolate">
<property name="text">
<string>Output surface must pass exactly through input points</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QRadioButton" name="buttonScaleSpace">
<property name="text">
<string>Scale space reconstruction</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frameScaleSpace">
<property name="enabled">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Average neighborhood size</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="m_neighbors">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Size of sample to estimate neighborhood</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="m_samples">
<property name="maximum">
<number>1000000</number>
</property>
<property name="value">
<number>200</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Iterations</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="m_iterations">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000000</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="m_genShells">
<property name="text">
<string>Generate separate shells</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="m_forceManifold">
<property name="text">
<string>Force manifold output</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="m_genSmooth">
<property name="text">
<string>Smoothed version</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QRadioButton" name="buttonPoisson">
<property name="text">
<string>Poisson reconstruction</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="framePoisson">
<property name="enabled">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Min triangle angle:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="m_inputAngle">
<property name="suffix">
<string> °</string>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>30.000000000000000</double>
</property>
<property name="value">
<double>20.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Max triangle size:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="m_inputRadius">
<property name="suffix">
<string> * average spacing</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Approximation error:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="m_inputDistance">
<property name="suffix">
<string> * average spacing</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.250000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Solver:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="m_inputSolver">
<property name="toolTip">
<string extracomment="Name of the sparse solver"/>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="m_inputTwoPasses">
<property name="text">
<string>Perform two passes</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="m_doNotFillHoles">
<property name="text">
<string>Do not fill holes</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QFrame" name="frameScaleSpace">
<property name="enabled">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Average Neighborhood Size</string>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QRadioButton" name="buttonAdvancing">
<property name="text">
<string>Advancing front reconstruction</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frameAdvancing">
<property name="enabled">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Longest edge</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="m_longestEdge">
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Radius ratio bound</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Beta angle</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="m_radiusRatioBound">
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="value">
<double>5.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="m_betaAngle">
<property name="suffix">
<string>°</string>
</property>
<property name="maximum">
<double>150.000000000000000</double>
</property>
<property name="value">
<double>30.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QRadioButton" name="buttonRANSAC">
<property name="text">
<string>RANSAC-based Feature-preserving reconstruction</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frameRANSAC">
<property name="enabled">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QFormLayout" name="formLayout_4">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="m_neighbors">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Size of Sample to Estimate Neighborhood</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="m_samples">
<property name="maximum">
<number>1000000</number>
</property>
<property name="value">
<number>200</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Iterations</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="m_iterations">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000000</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="m_genShells">
<property name="text">
<string>Generate separate shells</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="m_forceManifold">
<property name="text">
<string>Force manifold output</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="m_genSmooth">
<property name="text">
<string>Smoothed version</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="6" column="0">
<widget class="QRadioButton" name="buttonPoisson">
<property name="text">
<string>Poisson Reconstruction</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QFrame" name="framePoisson">
<property name="enabled">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Min Triangle Angle:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="m_inputAngle">
<property name="suffix">
<string> °</string>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>30.000000000000000</double>
</property>
<property name="value">
<double>20.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Max Triangle Size:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="m_inputRadius">
<property name="suffix">
<string> * average spacing</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Approximation Error:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="m_inputDistance">
<property name="suffix">
<string> * average spacing</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.250000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Solver:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="m_inputSolver">
<property name="toolTip">
<string extracomment="Name of the sparse solver"/>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="m_inputTwoPasses">
<property name="text">
<string>Perform two passes</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="m_doNotFillHoles">
<property name="text">
<string>Do not fill holes</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="buttonAdvancing">
<property name="text">
<string>Advancing Front Reconstruction</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="buttonAuto">
<property name="text">
<string>Select Method and Parameters Automatically</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QRadioButton" name="buttonScaleSpace">
<property name="text">
<string>Scale Space Reconstruction</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QFrame" name="frameAuto">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="m_boundaries">
<property name="text">
<string>Output surface has boundaries</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_interpolate">
<property name="text">
<string>Output surface must pass exactly through input points</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="8" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<item row="3" column="0">
<widget class="QCheckBox" name="m_generateStructured">
<property name="text">
<string>Generate structured point set</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="connectivityToleranceLabel">
<property name="text">
<string>Connectivity tolerance</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="m_connectivityTolerance">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.001000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="noiseToleranceLabel">
<property name="text">
<string>Noise tolerance</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="m_noiseTolerance">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.001000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="minimumSizeOfSubsetLabel">
<property name="text">
<string>Minimum size of subset</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="m_minSizeSubset">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000000000</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
@ -479,5 +637,21 @@
</hint>
</hints>
</connection>
<connection>
<sender>buttonRANSAC</sender>
<signal>toggled(bool)</signal>
<receiver>frameRANSAC</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>587</x>
<y>266</y>
</hint>
<hint type="destinationlabel">
<x>587</x>
<y>350</y>
</hint>
</hints>
</connection>
</connections>
</ui>