mirror of https://github.com/CGAL/cgal
WIP: simplify/reorganize reconstruction plugin
This commit is contained in:
parent
0dd30b1a68
commit
d7b0fcc4f6
|
|
@ -1,7 +1,7 @@
|
||||||
include( polyhedron_demo_macros )
|
include( polyhedron_demo_macros )
|
||||||
if(EIGEN3_FOUND)
|
if(EIGEN3_FOUND)
|
||||||
qt5_wrap_ui( surface_reconstructionUI_FILES Surface_reconstruction_plugin.ui)
|
qt5_wrap_ui( surface_reconstructionUI_FILES Surface_reconstruction_plugin.ui)
|
||||||
polyhedron_demo_plugin(surface_reconstruction_plugin Surface_reconstruction_plugin Surface_reconstruction_plugin_impl ${surface_reconstructionUI_FILES} KEYWORDS PointSetProcessing)
|
polyhedron_demo_plugin(surface_reconstruction_plugin Surface_reconstruction_plugin Surface_reconstruction_poisson_impl Surface_reconstruction_advancing_front_impl Surface_reconstruction_scale_space_impl ${surface_reconstructionUI_FILES} KEYWORDS PointSetProcessing)
|
||||||
target_link_libraries(surface_reconstruction_plugin PUBLIC scene_polygon_soup_item scene_surface_mesh_item scene_points_with_normal_item)
|
target_link_libraries(surface_reconstruction_plugin PUBLIC scene_polygon_soup_item scene_surface_mesh_item scene_points_with_normal_item)
|
||||||
|
|
||||||
qt5_wrap_ui( point_set_normal_estimationUI_FILES Point_set_normal_estimation_plugin.ui)
|
qt5_wrap_ui( point_set_normal_estimationUI_FILES Point_set_normal_estimation_plugin.ui)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,235 @@
|
||||||
|
#include <CGAL/Advancing_front_surface_reconstruction.h>
|
||||||
|
#include <CGAL/structure_point_set.h>
|
||||||
|
#include <CGAL/linear_least_squares_fitting_3.h>
|
||||||
|
|
||||||
|
#include "Kernel_type.h"
|
||||||
|
#include "SMesh_type.h"
|
||||||
|
#include "Scene_points_with_normal_item.h"
|
||||||
|
|
||||||
|
typedef std::array<std::size_t,3> Facet;
|
||||||
|
typedef CGAL::Point_set_with_structure<Kernel> Structuring;
|
||||||
|
typedef Kernel::Plane_3 Plane_3;
|
||||||
|
|
||||||
|
struct Construct{
|
||||||
|
typedef std::array<std::size_t,3> Facet;
|
||||||
|
typedef typename boost::property_map<SMesh, boost::vertex_point_t>::type VPmap;
|
||||||
|
SMesh& mesh;
|
||||||
|
VPmap vpmap;
|
||||||
|
std::vector<typename boost::graph_traits<SMesh>::vertex_descriptor> vertices;
|
||||||
|
|
||||||
|
template <typename PointRange>
|
||||||
|
Construct(SMesh& mesh, const PointRange& points)
|
||||||
|
: mesh(mesh)
|
||||||
|
{
|
||||||
|
vpmap = get(boost::vertex_point, mesh);
|
||||||
|
for (const auto& p : points)
|
||||||
|
{
|
||||||
|
typename boost::graph_traits<SMesh>::vertex_descriptor v;
|
||||||
|
v = add_vertex(mesh);
|
||||||
|
vertices.push_back(v);
|
||||||
|
put(vpmap, v, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Construct& operator=(const Facet f)
|
||||||
|
{
|
||||||
|
typedef typename boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
|
||||||
|
std::vector<vertex_descriptor> facet;
|
||||||
|
facet.resize(3);
|
||||||
|
facet[0]=vertices[f[0]];
|
||||||
|
facet[1]=vertices[f[1]];
|
||||||
|
facet[2]=vertices[f[2]];
|
||||||
|
CGAL::Euler::add_face(facet, mesh);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Construct&
|
||||||
|
operator*() { return *this; }
|
||||||
|
Construct&
|
||||||
|
operator++() { return *this; }
|
||||||
|
Construct
|
||||||
|
operator++(int) { return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Radius {
|
||||||
|
|
||||||
|
double bound;
|
||||||
|
|
||||||
|
Radius(double bound)
|
||||||
|
: bound(bound)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <typename AdvancingFront, typename Cell_handle>
|
||||||
|
double operator() (const AdvancingFront& adv, Cell_handle& c,
|
||||||
|
const int& index) const
|
||||||
|
{
|
||||||
|
// bound == 0 is better than bound < infinity
|
||||||
|
// as it avoids the distance computations
|
||||||
|
if(bound == 0){
|
||||||
|
return adv.smallest_radius_delaunay_sphere (c, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If radius > bound, return infinity so that facet is not used
|
||||||
|
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();
|
||||||
|
|
||||||
|
// Otherwise, return usual priority value: smallest radius of
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void get_planes_from_shape_map (const Point_set& points,
|
||||||
|
Point_set::Property_map<int> shape_map,
|
||||||
|
std::vector<Plane_3>& planes)
|
||||||
|
{
|
||||||
|
std::vector<Point_set::Index> sorted_indices;
|
||||||
|
sorted_indices.reserve (points.size());
|
||||||
|
std::copy (points.begin(), points.end(), std::back_inserter (sorted_indices));
|
||||||
|
|
||||||
|
std::sort (sorted_indices.begin(), sorted_indices.end(),
|
||||||
|
[&](const Point_set::Index& a, const Point_set::Index& b) -> bool
|
||||||
|
{
|
||||||
|
return shape_map[a] < shape_map[b];
|
||||||
|
});
|
||||||
|
|
||||||
|
std::size_t nb_planes = shape_map[sorted_indices.back()] + 1;
|
||||||
|
planes.reserve (nb_planes);
|
||||||
|
|
||||||
|
std::vector<Point_set::Index>::iterator begin = sorted_indices.end();
|
||||||
|
int plane_idx = shape_map[sorted_indices.front()];
|
||||||
|
if (plane_idx != -1)
|
||||||
|
begin = sorted_indices.begin();
|
||||||
|
|
||||||
|
for (std::vector<Point_set::Index>::iterator it = sorted_indices.begin();
|
||||||
|
it != sorted_indices.end(); ++ it)
|
||||||
|
{
|
||||||
|
if (shape_map[*it] != plane_idx)
|
||||||
|
{
|
||||||
|
if (begin != sorted_indices.end())
|
||||||
|
{
|
||||||
|
Plane_3 plane;
|
||||||
|
CGAL::linear_least_squares_fitting_3
|
||||||
|
(boost::make_transform_iterator
|
||||||
|
(begin, CGAL::Property_map_to_unary_function<Point_set::Point_map>(points.point_map())),
|
||||||
|
boost::make_transform_iterator
|
||||||
|
(it, CGAL::Property_map_to_unary_function<Point_set::Point_map>(points.point_map())),
|
||||||
|
plane, CGAL::Dimension_tag<0>());
|
||||||
|
planes.push_back (plane);
|
||||||
|
}
|
||||||
|
begin = it;
|
||||||
|
plane_idx = shape_map[*it];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Plane_3 plane;
|
||||||
|
CGAL::linear_least_squares_fitting_3
|
||||||
|
(boost::make_transform_iterator
|
||||||
|
(begin, CGAL::Property_map_to_unary_function<Point_set::Point_map>(points.point_map())),
|
||||||
|
boost::make_transform_iterator
|
||||||
|
(sorted_indices.end(), CGAL::Property_map_to_unary_function<Point_set::Point_map>(points.point_map())),
|
||||||
|
plane, CGAL::Dimension_tag<0>());
|
||||||
|
planes.push_back (plane);
|
||||||
|
}
|
||||||
|
|
||||||
|
SMesh* advancing_front (const Point_set& points,
|
||||||
|
double longest_edge,
|
||||||
|
double radius_ratio_bound,
|
||||||
|
double beta,
|
||||||
|
bool structuring)
|
||||||
|
{
|
||||||
|
SMesh* mesh = new SMesh;
|
||||||
|
|
||||||
|
if (structuring) // todo
|
||||||
|
{
|
||||||
|
Point_set::Property_map<int> shape_map
|
||||||
|
= points.property_map<int>("shape").first;
|
||||||
|
|
||||||
|
typedef CGAL::Point_set_with_structure<Kernel> Structuring;
|
||||||
|
std::vector<Plane_3> planes;
|
||||||
|
|
||||||
|
get_planes_from_shape_map (points, shape_map, planes);
|
||||||
|
Structuring structuring
|
||||||
|
(points, planes,
|
||||||
|
longest_edge,
|
||||||
|
points.parameters().
|
||||||
|
plane_map(CGAL::Identity_property_map<Plane_3>()).
|
||||||
|
plane_index_map(shape_map));
|
||||||
|
|
||||||
|
std::vector<Point_3> structured;
|
||||||
|
structured.reserve (structuring.size());
|
||||||
|
for (std::size_t i = 0; i < structuring.size(); ++ i)
|
||||||
|
structured.push_back (structuring.point(i));
|
||||||
|
|
||||||
|
Priority_with_structure_coherence<Structuring> priority
|
||||||
|
(structuring, longest_edge);
|
||||||
|
Construct construct(*mesh, structured);
|
||||||
|
CGAL::advancing_front_surface_reconstruction(points.points().begin(),
|
||||||
|
points.points().end(),
|
||||||
|
construct,
|
||||||
|
priority,
|
||||||
|
radius_ratio_bound,
|
||||||
|
beta);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Radius filter(longest_edge);
|
||||||
|
Construct construct (*mesh, points.points());
|
||||||
|
CGAL::advancing_front_surface_reconstruction(points.points().begin(),
|
||||||
|
points.points().end(),
|
||||||
|
construct,
|
||||||
|
filter,
|
||||||
|
radius_ratio_bound,
|
||||||
|
beta);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,8 +6,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>725</width>
|
<width>702</width>
|
||||||
<height>429</height>
|
<height>463</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
|
@ -23,10 +23,20 @@
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Advancing Front</string>
|
<string>Advancing Front</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QFormLayout" name="formLayout_5">
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
<property name="fieldGrowthPolicy">
|
<item row="0" column="1">
|
||||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
<spacer name="verticalSpacer_8">
|
||||||
</property>
|
<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 row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
@ -41,14 +51,14 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_9">
|
<widget class="QLabel" name="label_9">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Radius ratio bound</string>
|
<string>Radius ratio bound</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QDoubleSpinBox" name="m_radiusRatioBound">
|
<widget class="QDoubleSpinBox" name="m_radiusRatioBound">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>0.010000000000000</double>
|
<double>0.010000000000000</double>
|
||||||
|
|
@ -61,14 +71,14 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="label_10">
|
<widget class="QLabel" name="label_10">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Beta angle</string>
|
<string>Beta angle</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QDoubleSpinBox" name="m_betaAngle">
|
<widget class="QDoubleSpinBox" name="m_betaAngle">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
<string>°</string>
|
<string>°</string>
|
||||||
|
|
@ -81,18 +91,15 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="4" column="0" colspan="2">
|
||||||
<spacer name="verticalSpacer_8">
|
<widget class="QCheckBox" name="m_use_structuring">
|
||||||
<property name="orientation">
|
<property name="enabled">
|
||||||
<enum>Qt::Vertical</enum>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="text">
|
||||||
<size>
|
<string>Use Point Set Structuring (run Shape Detection first)</string>
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="1">
|
<item row="5" column="1">
|
||||||
<spacer name="verticalSpacer_9">
|
<spacer name="verticalSpacer_9">
|
||||||
|
|
@ -113,117 +120,8 @@
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Poisson</string>
|
<string>Poisson</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QFormLayout" name="formLayout_6">
|
<layout class="QVBoxLayout" name="verticalLayout_15">
|
||||||
<item row="1" column="0">
|
<item>
|
||||||
<widget class="QLabel" name="label_5">
|
|
||||||
<property name="text">
|
|
||||||
<string>Min triangle angle:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" 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="2" column="0">
|
|
||||||
<widget class="QLabel" name="label_7">
|
|
||||||
<property name="text">
|
|
||||||
<string>Max triangle size:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" 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="3" column="0">
|
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="text">
|
|
||||||
<string>Approximation error:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" 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="4" column="0">
|
|
||||||
<widget class="QLabel" name="label_8">
|
|
||||||
<property name="text">
|
|
||||||
<string>Solver:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="1">
|
|
||||||
<widget class="QComboBox" name="m_inputSolver">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string extracomment="Name of the sparse solver"/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="0">
|
|
||||||
<widget class="QCheckBox" name="m_inputTwoPasses">
|
|
||||||
<property name="text">
|
|
||||||
<string>Perform two passes</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="0">
|
|
||||||
<widget class="QCheckBox" name="m_doNotFillHoles">
|
|
||||||
<property name="text">
|
|
||||||
<string>Do not fill holes</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<spacer name="verticalSpacer_10">
|
<spacer name="verticalSpacer_10">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
|
|
@ -236,7 +134,198 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="1">
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_29">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mesher:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="m_marching_tet">
|
||||||
|
<property name="text">
|
||||||
|
<string>Marching Tetrahedra</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="m_surface_mesher">
|
||||||
|
<property name="text">
|
||||||
|
<string>Surface Mesher</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="m_conjugate_gradient">
|
||||||
|
<property name="text">
|
||||||
|
<string>Conjugate Gradient</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="m_simplicial_ldlt">
|
||||||
|
<property name="text">
|
||||||
|
<string>Simplicial LDLT</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Solver:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="m_surface_mesh_parameters">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="accessibleName">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Surface Mesher Parameters</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<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="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="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="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Max triangle size:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="m_inputTwoPasses">
|
||||||
|
<property name="text">
|
||||||
|
<string>Perform two passes</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="m_doNotFillHoles">
|
||||||
|
<property name="text">
|
||||||
|
<string>Do not fill holes</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<spacer name="verticalSpacer_11">
|
<spacer name="verticalSpacer_11">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
|
|
@ -662,208 +751,6 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="tab_4">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Feature Preserving</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QFormLayout" name="formLayout_7">
|
|
||||||
<property name="fieldGrowthPolicy">
|
|
||||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
|
||||||
</property>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<spacer name="verticalSpacer_12">
|
|
||||||
<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 row="1" column="0">
|
|
||||||
<widget class="QRadioButton" name="m_regionGrowing">
|
|
||||||
<property name="text">
|
|
||||||
<string>Region growing</string>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QRadioButton" name="m_RANSAC">
|
|
||||||
<property name="text">
|
|
||||||
<string>RANSAC</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QLabel" name="connectivityToleranceLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Connectivity tolerance</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" 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="4" column="0">
|
|
||||||
<widget class="QLabel" name="noiseToleranceLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Noise tolerance</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" 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="6" column="0">
|
|
||||||
<widget class="QLabel" name="normalToleranceLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Normal tolerance</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="1">
|
|
||||||
<widget class="QDoubleSpinBox" name="m_normalTolerance">
|
|
||||||
<property name="minimum">
|
|
||||||
<double>0.010000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>1.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<double>0.010000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<double>0.900000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="0">
|
|
||||||
<widget class="QLabel" name="minimumSizeOfSubsetLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Minimum size of subset</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" 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>
|
|
||||||
<item row="8" column="0">
|
|
||||||
<widget class="QCheckBox" name="m_generateStructured">
|
|
||||||
<property name="text">
|
|
||||||
<string>Generate structured point set</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="8" column="1">
|
|
||||||
<spacer name="verticalSpacer_13">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="tab_5">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Automatic</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer_14">
|
|
||||||
<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="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>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer_7">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|
@ -910,34 +797,18 @@
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
<connection>
|
<connection>
|
||||||
<sender>m_scalespace_jet</sender>
|
<sender>m_scalespace_as</sender>
|
||||||
<signal>toggled(bool)</signal>
|
<signal>toggled(bool)</signal>
|
||||||
<receiver>frame_jet</receiver>
|
<receiver>frame_as</receiver>
|
||||||
<slot>setEnabled(bool)</slot>
|
<slot>setEnabled(bool)</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>215</x>
|
<x>565</x>
|
||||||
<y>87</y>
|
<y>246</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>215</x>
|
<x>565</x>
|
||||||
<y>158</y>
|
<y>308</y>
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>m_scalespace_pca</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>frame_pca</receiver>
|
|
||||||
<slot>setEnabled(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>215</x>
|
|
||||||
<y>236</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>215</x>
|
|
||||||
<y>307</y>
|
|
||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
|
|
@ -958,18 +829,50 @@
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
<connection>
|
<connection>
|
||||||
<sender>m_scalespace_as</sender>
|
<sender>m_scalespace_pca</sender>
|
||||||
<signal>toggled(bool)</signal>
|
<signal>toggled(bool)</signal>
|
||||||
<receiver>frame_as</receiver>
|
<receiver>frame_pca</receiver>
|
||||||
<slot>setEnabled(bool)</slot>
|
<slot>setEnabled(bool)</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>565</x>
|
<x>215</x>
|
||||||
<y>246</y>
|
<y>236</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>565</x>
|
<x>215</x>
|
||||||
<y>308</y>
|
<y>307</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>m_scalespace_jet</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>frame_jet</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>215</x>
|
||||||
|
<y>87</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>215</x>
|
||||||
|
<y>158</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>m_surface_mesher</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>m_surface_mesh_parameters</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>149</x>
|
||||||
|
<y>251</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>532</x>
|
||||||
|
<y>200</y>
|
||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
|
|
|
||||||
|
|
@ -1,262 +0,0 @@
|
||||||
//----------------------------------------------------------
|
|
||||||
// Poisson reconstruction method:
|
|
||||||
// Reconstructs a surface mesh from a point set and returns it as a polyhedron.
|
|
||||||
//----------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
// CGAL
|
|
||||||
#include <CGAL/AABB_tree.h> // must be included before kernel
|
|
||||||
#include <CGAL/AABB_traits.h>
|
|
||||||
#include <CGAL/AABB_face_graph_triangle_primitive.h>
|
|
||||||
#include <CGAL/Timer.h>
|
|
||||||
#include <CGAL/Surface_mesh_default_triangulation_3.h>
|
|
||||||
#include <CGAL/make_surface_mesh.h>
|
|
||||||
#include <CGAL/Implicit_surface_3.h>
|
|
||||||
#include <CGAL/IO/facets_in_complex_2_to_triangle_mesh.h>
|
|
||||||
#include <CGAL/Poisson_reconstruction_function.h>
|
|
||||||
#include <CGAL/compute_average_spacing.h>
|
|
||||||
|
|
||||||
#ifdef CGAL_EIGEN3_ENABLED
|
|
||||||
#include <CGAL/Eigen_solver_traits.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "Kernel_type.h"
|
|
||||||
#include "SMesh_type.h"
|
|
||||||
#include "Scene_points_with_normal_item.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Concurrency
|
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
|
||||||
typedef CGAL::Parallel_tag Concurrency_tag;
|
|
||||||
#else
|
|
||||||
typedef CGAL::Sequential_tag Concurrency_tag;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Poisson reconstruction method:
|
|
||||||
// Reconstructs a surface mesh from a point set and returns it as a polyhedron.
|
|
||||||
template<class FaceGraph, typename Traits>
|
|
||||||
bool poisson_reconstruct(FaceGraph* graph,
|
|
||||||
Point_set& points,
|
|
||||||
typename Traits::FT sm_angle, // Min triangle angle (degrees).
|
|
||||||
typename Traits::FT sm_radius, // Max triangle size w.r.t. point set average spacing.
|
|
||||||
typename Traits::FT sm_distance, // Approximation error w.r.t. point set average spacing.
|
|
||||||
const QString& solver_name, // solver name
|
|
||||||
bool use_two_passes,
|
|
||||||
bool do_not_fill_holes)
|
|
||||||
{
|
|
||||||
// Poisson implicit function
|
|
||||||
typedef CGAL::Poisson_reconstruction_function<Traits> Poisson_reconstruction_function;
|
|
||||||
|
|
||||||
// Surface mesher
|
|
||||||
typedef CGAL::Surface_mesh_default_triangulation_3 STr;
|
|
||||||
typedef CGAL::Surface_mesh_complex_2_in_triangulation_3<STr> C2t3;
|
|
||||||
typedef CGAL::Implicit_surface_3<Traits, Poisson_reconstruction_function> Surface_3;
|
|
||||||
|
|
||||||
// AABB tree
|
|
||||||
typedef CGAL::AABB_face_graph_triangle_primitive<FaceGraph> Primitive;
|
|
||||||
typedef CGAL::AABB_traits<Traits, Primitive> AABB_traits;
|
|
||||||
typedef CGAL::AABB_tree<AABB_traits> AABB_tree;
|
|
||||||
CGAL::Timer task_timer; task_timer.start();
|
|
||||||
|
|
||||||
//***************************************
|
|
||||||
// Checks requirements
|
|
||||||
//***************************************
|
|
||||||
|
|
||||||
if (points.size() == 0)
|
|
||||||
{
|
|
||||||
std::cerr << "Error: empty point set" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool points_have_normals = points.has_normal_map();
|
|
||||||
if ( ! points_have_normals )
|
|
||||||
{
|
|
||||||
std::cerr << "Input point set not supported: this reconstruction method requires oriented normals" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CGAL::Timer reconstruction_timer; reconstruction_timer.start();
|
|
||||||
|
|
||||||
//***************************************
|
|
||||||
// Computes implicit function
|
|
||||||
//***************************************
|
|
||||||
|
|
||||||
|
|
||||||
std::cerr << "Computes Poisson implicit function "
|
|
||||||
<< "using " << solver_name.toLatin1().data() << " solver...\n";
|
|
||||||
|
|
||||||
|
|
||||||
// Creates implicit function from the point set.
|
|
||||||
// Note: this method requires an iterator over points
|
|
||||||
// + property maps to access each point's position and normal.
|
|
||||||
Poisson_reconstruction_function function(points.begin_or_selection_begin(), points.end(),
|
|
||||||
points.point_map(), points.normal_map());
|
|
||||||
|
|
||||||
bool ok = false;
|
|
||||||
#ifdef CGAL_EIGEN3_ENABLED
|
|
||||||
if(solver_name=="Eigen - built-in simplicial LDLt")
|
|
||||||
{
|
|
||||||
CGAL::Eigen_solver_traits<Eigen::SimplicialCholesky<CGAL::Eigen_sparse_matrix<double>::EigenType> > solver;
|
|
||||||
ok = function.compute_implicit_function(solver, use_two_passes);
|
|
||||||
}
|
|
||||||
if(solver_name=="Eigen - built-in CG")
|
|
||||||
{
|
|
||||||
CGAL::Eigen_solver_traits<Eigen::ConjugateGradient<CGAL::Eigen_sparse_matrix<double>::EigenType> > solver;
|
|
||||||
solver.solver().setTolerance(1e-6);
|
|
||||||
solver.solver().setMaxIterations(1000);
|
|
||||||
ok = function.compute_implicit_function(solver, use_two_passes);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Computes the Poisson indicator function f()
|
|
||||||
// at each vertex of the triangulation.
|
|
||||||
if ( ! ok )
|
|
||||||
{
|
|
||||||
std::cerr << "Error: cannot compute implicit function" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prints status
|
|
||||||
std::cerr << "Total implicit function (triangulation+refinement+solver): " << task_timer.time() << " seconds\n";
|
|
||||||
task_timer.reset();
|
|
||||||
|
|
||||||
//***************************************
|
|
||||||
// Surface mesh generation
|
|
||||||
//***************************************
|
|
||||||
|
|
||||||
std::cerr << "Surface meshing...\n";
|
|
||||||
|
|
||||||
// Computes average spacing
|
|
||||||
Kernel::FT average_spacing = CGAL::compute_average_spacing<Concurrency_tag>(points.all_or_selection_if_not_empty(),
|
|
||||||
6 /* knn = 1 ring */,
|
|
||||||
points.parameters());
|
|
||||||
|
|
||||||
// Gets one point inside the implicit surface
|
|
||||||
Kernel::Point_3 inner_point = function.get_inner_point();
|
|
||||||
Kernel::FT inner_point_value = function(inner_point);
|
|
||||||
if(inner_point_value >= 0.0)
|
|
||||||
{
|
|
||||||
std::cerr << "Error: unable to seed (" << inner_point_value << " at inner_point)" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets implicit function's radius
|
|
||||||
Kernel::Sphere_3 bsphere = function.bounding_sphere();
|
|
||||||
Kernel::FT radius = std::sqrt(bsphere.squared_radius());
|
|
||||||
|
|
||||||
// Defines the implicit surface: requires defining a
|
|
||||||
// conservative bounding sphere centered at inner point.
|
|
||||||
Kernel::FT sm_sphere_radius = 5.0 * radius;
|
|
||||||
Kernel::FT sm_dichotomy_error = sm_distance*average_spacing/1000.0; // Dichotomy error must be << sm_distance
|
|
||||||
Surface_3 surface(function,
|
|
||||||
Kernel::Sphere_3(inner_point,sm_sphere_radius*sm_sphere_radius),
|
|
||||||
sm_dichotomy_error/sm_sphere_radius);
|
|
||||||
|
|
||||||
// Defines surface mesh generation criteria
|
|
||||||
CGAL::Surface_mesh_default_criteria_3<STr> criteria(sm_angle, // Min triangle angle (degrees)
|
|
||||||
sm_radius*average_spacing, // Max triangle size
|
|
||||||
sm_distance*average_spacing); // Approximation error
|
|
||||||
|
|
||||||
CGAL_TRACE_STREAM << " make_surface_mesh(sphere center=("<<inner_point << "),\n"
|
|
||||||
<< " sphere radius="<<sm_sphere_radius<<",\n"
|
|
||||||
<< " angle="<<sm_angle << " degrees,\n"
|
|
||||||
<< " triangle size="<<sm_radius<<" * average spacing="<<sm_radius*average_spacing<<",\n"
|
|
||||||
<< " distance="<<sm_distance<<" * average spacing="<<sm_distance*average_spacing<<",\n"
|
|
||||||
<< " dichotomy error=distance/"<<sm_distance*average_spacing/sm_dichotomy_error<<",\n"
|
|
||||||
<< " Manifold_with_boundary_tag)\n";
|
|
||||||
|
|
||||||
// Generates surface mesh with manifold option
|
|
||||||
STr tr; // 3D Delaunay triangulation for surface mesh generation
|
|
||||||
C2t3 c2t3(tr); // 2D complex in 3D Delaunay triangulation
|
|
||||||
CGAL::make_surface_mesh(c2t3, // reconstructed mesh
|
|
||||||
surface, // implicit surface
|
|
||||||
criteria, // meshing criteria
|
|
||||||
CGAL::Manifold_with_boundary_tag()); // require manifold mesh
|
|
||||||
|
|
||||||
// Prints status
|
|
||||||
std::cerr << "Surface meshing: " << task_timer.time() << " seconds, "
|
|
||||||
<< tr.number_of_vertices() << " output vertices"
|
|
||||||
<< std::endl;
|
|
||||||
task_timer.reset();
|
|
||||||
|
|
||||||
if(tr.number_of_vertices() == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Converts to polyhedron
|
|
||||||
CGAL::facets_in_complex_2_to_triangle_mesh(c2t3, *graph);
|
|
||||||
|
|
||||||
// Prints total reconstruction duration
|
|
||||||
std::cerr << "Total reconstruction (implicit function + meshing): " << reconstruction_timer.time() << " seconds\n";
|
|
||||||
|
|
||||||
//***************************************
|
|
||||||
// Computes reconstruction error
|
|
||||||
//***************************************
|
|
||||||
|
|
||||||
// Constructs AABB tree and computes internal KD-tree
|
|
||||||
// data structure to accelerate distance queries
|
|
||||||
AABB_tree tree(faces(*graph).first, faces(*graph).second, *graph);
|
|
||||||
tree.accelerate_distance_queries();
|
|
||||||
|
|
||||||
// Computes distance from each input point to reconstructed mesh
|
|
||||||
double max_distance = DBL_MIN;
|
|
||||||
double avg_distance = 0;
|
|
||||||
|
|
||||||
std::set<typename boost::graph_traits<FaceGraph>::face_descriptor> faces_to_keep;
|
|
||||||
|
|
||||||
for (Point_set::const_iterator p=points.begin_or_selection_begin(); p!=points.end(); p++)
|
|
||||||
{
|
|
||||||
typename AABB_traits::Point_and_primitive_id pap = tree.closest_point_and_primitive (points.point (*p));
|
|
||||||
double distance = std::sqrt(CGAL::squared_distance (pap.first, points.point(*p)));
|
|
||||||
|
|
||||||
max_distance = (std::max)(max_distance, distance);
|
|
||||||
avg_distance += distance;
|
|
||||||
|
|
||||||
typename boost::graph_traits<FaceGraph>::face_descriptor f = pap.second;
|
|
||||||
faces_to_keep.insert (f);
|
|
||||||
}
|
|
||||||
avg_distance /= double(points.size());
|
|
||||||
|
|
||||||
std::cerr << "Reconstruction error:\n"
|
|
||||||
<< " max = " << max_distance << " = " << max_distance/average_spacing << " * average spacing\n"
|
|
||||||
<< " avg = " << avg_distance << " = " << avg_distance/average_spacing << " * average spacing\n";
|
|
||||||
|
|
||||||
if (do_not_fill_holes)
|
|
||||||
{
|
|
||||||
typename boost::graph_traits<FaceGraph>::face_iterator it = faces(*graph).begin ();
|
|
||||||
while (it != faces(*graph).end ())
|
|
||||||
{
|
|
||||||
typename boost::graph_traits<FaceGraph>::face_iterator current = it ++;
|
|
||||||
|
|
||||||
if (faces_to_keep.find (*current) == faces_to_keep.end ())
|
|
||||||
{
|
|
||||||
CGAL::Euler::remove_face(halfedge (*current, *graph), *graph);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SMesh* poisson_reconstruct_sm(Point_set& points,
|
|
||||||
Kernel::FT sm_angle, // Min triangle angle (degrees).
|
|
||||||
Kernel::FT sm_radius, // Max triangle size w.r.t. point set average spacing.
|
|
||||||
Kernel::FT sm_distance, // Approximation error w.r.t. point set average spacing.
|
|
||||||
const QString& solver_name, // solver name
|
|
||||||
bool use_two_passes,
|
|
||||||
bool do_not_fill_holes)
|
|
||||||
{
|
|
||||||
SMesh* res = new SMesh;
|
|
||||||
if(poisson_reconstruct<SMesh, Kernel>(res, points, sm_angle, sm_radius, sm_distance,
|
|
||||||
solver_name, use_two_passes, do_not_fill_holes))
|
|
||||||
return res;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delete res;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,238 @@
|
||||||
|
//----------------------------------------------------------
|
||||||
|
// Poisson reconstruction method:
|
||||||
|
// Reconstructs a surface mesh from a point set and returns it as a polyhedron.
|
||||||
|
//----------------------------------------------------------
|
||||||
|
|
||||||
|
// CGAL
|
||||||
|
#include <CGAL/AABB_tree.h> // must be included before kernel
|
||||||
|
#include <CGAL/AABB_traits.h>
|
||||||
|
#include <CGAL/AABB_face_graph_triangle_primitive.h>
|
||||||
|
#include <CGAL/Timer.h>
|
||||||
|
#include <CGAL/Surface_mesh_default_triangulation_3.h>
|
||||||
|
#include <CGAL/make_surface_mesh.h>
|
||||||
|
#include <CGAL/Implicit_surface_3.h>
|
||||||
|
#include <CGAL/IO/facets_in_complex_2_to_triangle_mesh.h>
|
||||||
|
#include <CGAL/Poisson_reconstruction_function.h>
|
||||||
|
#include <CGAL/compute_average_spacing.h>
|
||||||
|
|
||||||
|
#include <CGAL/Eigen_solver_traits.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "Kernel_type.h"
|
||||||
|
#include "SMesh_type.h"
|
||||||
|
#include "Scene_points_with_normal_item.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Concurrency
|
||||||
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
|
#else
|
||||||
|
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Poisson reconstruction method:
|
||||||
|
// Reconstructs a surface mesh from a point set and returns it as a polyhedron.
|
||||||
|
SMesh* poisson_reconstruct_sm(Point_set& points,
|
||||||
|
Kernel::FT sm_angle, // Min triangle angle (degrees).
|
||||||
|
Kernel::FT sm_radius, // Max triangle size w.r.t. point set average spacing.
|
||||||
|
Kernel::FT sm_distance, // Approximation error w.r.t. point set average spacing.
|
||||||
|
bool conjugate_gradient,
|
||||||
|
bool use_two_passes,
|
||||||
|
bool do_not_fill_holes)
|
||||||
|
{
|
||||||
|
// Poisson implicit function
|
||||||
|
typedef CGAL::Poisson_reconstruction_function<Kernel> Poisson_reconstruction_function;
|
||||||
|
|
||||||
|
// Surface mesher
|
||||||
|
typedef CGAL::Surface_mesh_default_triangulation_3 STr;
|
||||||
|
typedef CGAL::Surface_mesh_complex_2_in_triangulation_3<STr> C2t3;
|
||||||
|
typedef CGAL::Implicit_surface_3<Kernel, Poisson_reconstruction_function> Surface_3;
|
||||||
|
|
||||||
|
// AABB tree
|
||||||
|
typedef CGAL::AABB_face_graph_triangle_primitive<SMesh> Primitive;
|
||||||
|
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_traits;
|
||||||
|
typedef CGAL::AABB_tree<AABB_traits> AABB_tree;
|
||||||
|
CGAL::Timer task_timer; task_timer.start();
|
||||||
|
|
||||||
|
//***************************************
|
||||||
|
// Checks requirements
|
||||||
|
//***************************************
|
||||||
|
|
||||||
|
if (points.size() == 0)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: empty point set" << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool points_have_normals = points.has_normal_map();
|
||||||
|
if ( ! points_have_normals )
|
||||||
|
{
|
||||||
|
std::cerr << "Input point set not supported: this reconstruction method requires oriented normals" << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGAL::Timer reconstruction_timer; reconstruction_timer.start();
|
||||||
|
|
||||||
|
//***************************************
|
||||||
|
// Computes implicit function
|
||||||
|
//***************************************
|
||||||
|
|
||||||
|
|
||||||
|
std::cerr << "Computes Poisson implicit function "
|
||||||
|
<< "using " << (conjugate_gradient ? "Conjugate Gradient" : "Simplicial LDLT") << "..." << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
// Creates implicit function from the point set.
|
||||||
|
// Note: this method requires an iterator over points
|
||||||
|
// + property maps to access each point's position and normal.
|
||||||
|
Poisson_reconstruction_function function(points.begin_or_selection_begin(), points.end(),
|
||||||
|
points.point_map(), points.normal_map());
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
if(conjugate_gradient)
|
||||||
|
{
|
||||||
|
CGAL::Eigen_solver_traits<Eigen::SimplicialCholesky<CGAL::Eigen_sparse_matrix<double>::EigenType> > solver;
|
||||||
|
ok = function.compute_implicit_function(solver, use_two_passes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CGAL::Eigen_solver_traits<Eigen::ConjugateGradient<CGAL::Eigen_sparse_matrix<double>::EigenType> > solver;
|
||||||
|
solver.solver().setTolerance(1e-6);
|
||||||
|
solver.solver().setMaxIterations(1000);
|
||||||
|
ok = function.compute_implicit_function(solver, use_two_passes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes the Poisson indicator function f()
|
||||||
|
// at each vertex of the triangulation.
|
||||||
|
if ( ! ok )
|
||||||
|
{
|
||||||
|
std::cerr << "Error: cannot compute implicit function" << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints status
|
||||||
|
std::cerr << "Total implicit function (triangulation+refinement+solver): " << task_timer.time() << " seconds\n";
|
||||||
|
task_timer.reset();
|
||||||
|
|
||||||
|
//***************************************
|
||||||
|
// Surface mesh generation
|
||||||
|
//***************************************
|
||||||
|
|
||||||
|
std::cerr << "Surface meshing...\n";
|
||||||
|
|
||||||
|
// Computes average spacing
|
||||||
|
Kernel::FT average_spacing = CGAL::compute_average_spacing<Concurrency_tag>(points.all_or_selection_if_not_empty(),
|
||||||
|
6 /* knn = 1 ring */,
|
||||||
|
points.parameters());
|
||||||
|
|
||||||
|
// Gets one point inside the implicit surface
|
||||||
|
Kernel::Point_3 inner_point = function.get_inner_point();
|
||||||
|
Kernel::FT inner_point_value = function(inner_point);
|
||||||
|
if(inner_point_value >= 0.0)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: unable to seed (" << inner_point_value << " at inner_point)" << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets implicit function's radius
|
||||||
|
Kernel::Sphere_3 bsphere = function.bounding_sphere();
|
||||||
|
Kernel::FT radius = std::sqrt(bsphere.squared_radius());
|
||||||
|
|
||||||
|
// Defines the implicit surface: requires defining a
|
||||||
|
// conservative bounding sphere centered at inner point.
|
||||||
|
Kernel::FT sm_sphere_radius = 5.0 * radius;
|
||||||
|
Kernel::FT sm_dichotomy_error = sm_distance*average_spacing/1000.0; // Dichotomy error must be << sm_distance
|
||||||
|
Surface_3 surface(function,
|
||||||
|
Kernel::Sphere_3(inner_point,sm_sphere_radius*sm_sphere_radius),
|
||||||
|
sm_dichotomy_error/sm_sphere_radius);
|
||||||
|
|
||||||
|
// Defines surface mesh generation criteria
|
||||||
|
CGAL::Surface_mesh_default_criteria_3<STr> criteria(sm_angle, // Min triangle angle (degrees)
|
||||||
|
sm_radius*average_spacing, // Max triangle size
|
||||||
|
sm_distance*average_spacing); // Approximation error
|
||||||
|
|
||||||
|
CGAL_TRACE_STREAM << " make_surface_mesh(sphere center=("<<inner_point << "),\n"
|
||||||
|
<< " sphere radius="<<sm_sphere_radius<<",\n"
|
||||||
|
<< " angle="<<sm_angle << " degrees,\n"
|
||||||
|
<< " triangle size="<<sm_radius<<" * average spacing="<<sm_radius*average_spacing<<",\n"
|
||||||
|
<< " distance="<<sm_distance<<" * average spacing="<<sm_distance*average_spacing<<",\n"
|
||||||
|
<< " dichotomy error=distance/"<<sm_distance*average_spacing/sm_dichotomy_error<<",\n"
|
||||||
|
<< " Manifold_with_boundary_tag)\n";
|
||||||
|
|
||||||
|
// Generates surface mesh with manifold option
|
||||||
|
STr tr; // 3D Delaunay triangulation for surface mesh generation
|
||||||
|
C2t3 c2t3(tr); // 2D complex in 3D Delaunay triangulation
|
||||||
|
CGAL::make_surface_mesh(c2t3, // reconstructed mesh
|
||||||
|
surface, // implicit surface
|
||||||
|
criteria, // meshing criteria
|
||||||
|
CGAL::Manifold_with_boundary_tag()); // require manifold mesh
|
||||||
|
|
||||||
|
// Prints status
|
||||||
|
std::cerr << "Surface meshing: " << task_timer.time() << " seconds, "
|
||||||
|
<< tr.number_of_vertices() << " output vertices"
|
||||||
|
<< std::endl;
|
||||||
|
task_timer.reset();
|
||||||
|
|
||||||
|
if(tr.number_of_vertices() == 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Converts to polyhedron
|
||||||
|
SMesh* mesh = new SMesh;
|
||||||
|
CGAL::facets_in_complex_2_to_triangle_mesh(c2t3, *mesh);
|
||||||
|
|
||||||
|
// Prints total reconstruction duration
|
||||||
|
std::cerr << "Total reconstruction (implicit function + meshing): " << reconstruction_timer.time() << " seconds\n";
|
||||||
|
|
||||||
|
//***************************************
|
||||||
|
// Computes reconstruction error
|
||||||
|
//***************************************
|
||||||
|
|
||||||
|
// Constructs AABB tree and computes internal KD-tree
|
||||||
|
// data structure to accelerate distance queries
|
||||||
|
AABB_tree tree(faces(*mesh).first, faces(*mesh).second, *mesh);
|
||||||
|
tree.accelerate_distance_queries();
|
||||||
|
|
||||||
|
// Computes distance from each input point to reconstructed mesh
|
||||||
|
double max_distance = DBL_MIN;
|
||||||
|
double avg_distance = 0;
|
||||||
|
|
||||||
|
std::set<typename boost::graph_traits<SMesh>::face_descriptor> faces_to_keep;
|
||||||
|
|
||||||
|
for (Point_set::const_iterator p=points.begin_or_selection_begin(); p!=points.end(); p++)
|
||||||
|
{
|
||||||
|
typename AABB_traits::Point_and_primitive_id pap = tree.closest_point_and_primitive (points.point (*p));
|
||||||
|
double distance = std::sqrt(CGAL::squared_distance (pap.first, points.point(*p)));
|
||||||
|
|
||||||
|
max_distance = (std::max)(max_distance, distance);
|
||||||
|
avg_distance += distance;
|
||||||
|
|
||||||
|
typename boost::graph_traits<SMesh>::face_descriptor f = pap.second;
|
||||||
|
faces_to_keep.insert (f);
|
||||||
|
}
|
||||||
|
avg_distance /= double(points.size());
|
||||||
|
|
||||||
|
std::cerr << "Reconstruction error:\n"
|
||||||
|
<< " max = " << max_distance << " = " << max_distance/average_spacing << " * average spacing\n"
|
||||||
|
<< " avg = " << avg_distance << " = " << avg_distance/average_spacing << " * average spacing\n";
|
||||||
|
|
||||||
|
if (do_not_fill_holes)
|
||||||
|
{
|
||||||
|
typename boost::graph_traits<SMesh>::face_iterator it = faces(*mesh).begin ();
|
||||||
|
while (it != faces(*mesh).end ())
|
||||||
|
{
|
||||||
|
typename boost::graph_traits<SMesh>::face_iterator current = it ++;
|
||||||
|
|
||||||
|
if (faces_to_keep.find (*current) == faces_to_keep.end ())
|
||||||
|
{
|
||||||
|
CGAL::Euler::remove_face(halfedge (*current, *mesh), *mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
#include "Kernel_type.h"
|
||||||
|
#include "SMesh_type.h"
|
||||||
|
#include "Scene_points_with_normal_item.h"
|
||||||
|
#include "Scene_polygon_soup_item.h"
|
||||||
|
#include "Point_set_3.h"
|
||||||
|
|
||||||
|
#include <CGAL/compute_average_spacing.h>
|
||||||
|
#include <CGAL/Scale_space_surface_reconstruction_3.h>
|
||||||
|
#include <CGAL/Scale_space_reconstruction_3/Advancing_front_mesher.h>
|
||||||
|
#include <CGAL/Scale_space_reconstruction_3/Jet_smoother.h>
|
||||||
|
#include <CGAL/Scale_space_reconstruction_3/Alpha_shape_mesher.h>
|
||||||
|
#include <CGAL/Scale_space_reconstruction_3/Weighted_PCA_smoother.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Concurrency
|
||||||
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
|
#else
|
||||||
|
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef CGAL::Scale_space_surface_reconstruction_3<Kernel> ScaleSpace;
|
||||||
|
typedef CGAL::Scale_space_reconstruction_3::Advancing_front_mesher<Kernel> ScaleSpaceAFM;
|
||||||
|
typedef CGAL::Scale_space_reconstruction_3::Alpha_shape_mesher<Kernel> ScaleSpaceASM;
|
||||||
|
typedef CGAL::Scale_space_reconstruction_3::Jet_smoother<Kernel> ScaleSpaceJS;
|
||||||
|
typedef CGAL::Scale_space_reconstruction_3::Weighted_PCA_smoother<Kernel> ScaleSpaceWPS;
|
||||||
|
|
||||||
|
void scale_space (const Point_set& points,
|
||||||
|
std::vector<Scene_polygon_soup_item*>& items,
|
||||||
|
bool jet_smoother,
|
||||||
|
unsigned int iterations,
|
||||||
|
unsigned int neighbors, unsigned int fitting, unsigned int monge,
|
||||||
|
unsigned int neighborhood_size, unsigned int samples,
|
||||||
|
bool advancing_front_mesher,
|
||||||
|
bool generate_smooth,
|
||||||
|
double longest_edge, double radius_ratio_bound, double beta_angle,
|
||||||
|
bool separate_shells, bool force_manifold)
|
||||||
|
{
|
||||||
|
ScaleSpace reconstruct (points.points().begin(), points.points().end());
|
||||||
|
|
||||||
|
double squared_radius = 0.;
|
||||||
|
if (jet_smoother)
|
||||||
|
{
|
||||||
|
ScaleSpaceJS smoother(neighbors, fitting, monge);
|
||||||
|
reconstruct.increase_scale(iterations, smoother);
|
||||||
|
if (!advancing_front_mesher)
|
||||||
|
squared_radius = CGAL::compute_average_spacing<Concurrency_tag> (points, neighbors);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScaleSpaceWPS smoother(neighborhood_size, samples);
|
||||||
|
reconstruct.increase_scale(iterations, smoother);
|
||||||
|
squared_radius = smoother.squared_radius();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (advancing_front_mesher)
|
||||||
|
{
|
||||||
|
ScaleSpaceAFM mesher (longest_edge, radius_ratio_bound, beta_angle);
|
||||||
|
reconstruct.reconstruct_surface (mesher);
|
||||||
|
|
||||||
|
Scene_polygon_soup_item* new_item
|
||||||
|
= new Scene_polygon_soup_item ();
|
||||||
|
new_item->setColor(Qt::lightGray);
|
||||||
|
new_item->setRenderingMode(FlatPlusEdges);
|
||||||
|
new_item->init_polygon_soup(points.size(), reconstruct.number_of_facets ());
|
||||||
|
|
||||||
|
Scene_polygon_soup_item* smooth_item = NULL;
|
||||||
|
if (generate_smooth)
|
||||||
|
{
|
||||||
|
smooth_item = new Scene_polygon_soup_item ();
|
||||||
|
smooth_item->setColor(Qt::lightGray);
|
||||||
|
smooth_item->setRenderingMode(FlatPlusEdges);
|
||||||
|
smooth_item->init_polygon_soup(points.size(), reconstruct.number_of_facets ());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::size_t, std::size_t> map_i2i;
|
||||||
|
std::size_t current_index = 0;
|
||||||
|
|
||||||
|
for (ScaleSpace::Facet_iterator it = reconstruct.facets_begin();
|
||||||
|
it != reconstruct.facets_end(); ++ it)
|
||||||
|
{
|
||||||
|
for (unsigned int ind = 0; ind < 3; ++ ind)
|
||||||
|
{
|
||||||
|
if (map_i2i.find ((*it)[ind]) == map_i2i.end ())
|
||||||
|
{
|
||||||
|
map_i2i.insert (std::make_pair ((*it)[ind], current_index ++));
|
||||||
|
Point_3 p = points.point(*(points.begin_or_selection_begin() + (*it)[ind]));
|
||||||
|
new_item->new_vertex (p.x (), p.y (), p.z ());
|
||||||
|
|
||||||
|
if (generate_smooth)
|
||||||
|
{
|
||||||
|
p = *(reconstruct.points_begin() + (*it)[ind]);
|
||||||
|
smooth_item->new_vertex (p.x (), p.y (), p.z ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_item->new_triangle( map_i2i[(*it)[0]],
|
||||||
|
map_i2i[(*it)[1]],
|
||||||
|
map_i2i[(*it)[2]] );
|
||||||
|
if (generate_smooth)
|
||||||
|
smooth_item->new_triangle( map_i2i[(*it)[0]],
|
||||||
|
map_i2i[(*it)[1]],
|
||||||
|
map_i2i[(*it)[2]] );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push_back(new_item);
|
||||||
|
if (generate_smooth)
|
||||||
|
items.push_back (smooth_item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScaleSpaceASM mesher (squared_radius, separate_shells, force_manifold);
|
||||||
|
reconstruct.reconstruct_surface (mesher);
|
||||||
|
|
||||||
|
for( unsigned int sh = 0; sh < mesher.number_of_shells(); ++sh )
|
||||||
|
{
|
||||||
|
Scene_polygon_soup_item* new_item
|
||||||
|
= new Scene_polygon_soup_item ();
|
||||||
|
new_item->setColor(Qt::lightGray);
|
||||||
|
new_item->setRenderingMode(FlatPlusEdges);
|
||||||
|
new_item->init_polygon_soup(points.size(), mesher.number_of_triangles ());
|
||||||
|
|
||||||
|
Scene_polygon_soup_item* smooth_item = NULL;
|
||||||
|
if (generate_smooth)
|
||||||
|
{
|
||||||
|
smooth_item = new Scene_polygon_soup_item ();
|
||||||
|
smooth_item->setColor(Qt::lightGray);
|
||||||
|
smooth_item->setRenderingMode(FlatPlusEdges);
|
||||||
|
smooth_item->init_polygon_soup(points.size(), mesher.number_of_triangles ());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<unsigned int, unsigned int> map_i2i;
|
||||||
|
unsigned int current_index = 0;
|
||||||
|
|
||||||
|
for (ScaleSpaceASM::Facet_iterator it = mesher.shell_begin (sh);
|
||||||
|
it != mesher.shell_end (sh); ++ it)
|
||||||
|
{
|
||||||
|
for (unsigned int ind = 0; ind < 3; ++ ind)
|
||||||
|
{
|
||||||
|
if (map_i2i.find ((*it)[ind]) == map_i2i.end ())
|
||||||
|
{
|
||||||
|
map_i2i.insert (std::make_pair ((*it)[ind], current_index ++));
|
||||||
|
Point_3 p = points.point(*(points.begin_or_selection_begin() + (*it)[ind]));
|
||||||
|
new_item->new_vertex (p.x (), p.y (), p.z ());
|
||||||
|
|
||||||
|
if (generate_smooth)
|
||||||
|
{
|
||||||
|
p = *(reconstruct.points_begin() + (*it)[ind]);
|
||||||
|
smooth_item->new_vertex (p.x (), p.y (), p.z ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_item->new_triangle( map_i2i[(*it)[0]],
|
||||||
|
map_i2i[(*it)[1]],
|
||||||
|
map_i2i[(*it)[2]] );
|
||||||
|
if (generate_smooth)
|
||||||
|
smooth_item->new_triangle( map_i2i[(*it)[0]],
|
||||||
|
map_i2i[(*it)[1]],
|
||||||
|
map_i2i[(*it)[2]] );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push_back (new_item);
|
||||||
|
if (generate_smooth)
|
||||||
|
items.push_back (smooth_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force_manifold)
|
||||||
|
{
|
||||||
|
std::ptrdiff_t num = std::distance( mesher.garbage_begin( ),
|
||||||
|
mesher.garbage_end( ) );
|
||||||
|
|
||||||
|
Scene_polygon_soup_item* new_item
|
||||||
|
= new Scene_polygon_soup_item ();
|
||||||
|
new_item->setColor(Qt::blue);
|
||||||
|
new_item->setRenderingMode(FlatPlusEdges);
|
||||||
|
new_item->init_polygon_soup(points.size(), num);
|
||||||
|
|
||||||
|
Scene_polygon_soup_item* smooth_item = NULL;
|
||||||
|
if (generate_smooth)
|
||||||
|
{
|
||||||
|
smooth_item = new Scene_polygon_soup_item ();
|
||||||
|
smooth_item->setColor(Qt::blue);
|
||||||
|
smooth_item->setRenderingMode(FlatPlusEdges);
|
||||||
|
smooth_item->init_polygon_soup(points.size(), num);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::size_t, std::size_t> map_i2i;
|
||||||
|
|
||||||
|
std::size_t current_index = 0;
|
||||||
|
for (ScaleSpaceASM::Facet_iterator it=mesher.garbage_begin(),
|
||||||
|
end=mesher.garbage_end();it!=end;++it)
|
||||||
|
{
|
||||||
|
for (unsigned int ind = 0; ind < 3; ++ ind)
|
||||||
|
{
|
||||||
|
if (map_i2i.find ((*it)[ind]) == map_i2i.end ())
|
||||||
|
{
|
||||||
|
map_i2i.insert (std::make_pair ((*it)[ind], current_index ++));
|
||||||
|
Point_3 p = points.point(*(points.begin_or_selection_begin() + (*it)[ind]));
|
||||||
|
new_item->new_vertex (p.x (), p.y (), p.z ());
|
||||||
|
|
||||||
|
if (generate_smooth)
|
||||||
|
{
|
||||||
|
p = *(reconstruct.points_begin() + (*it)[ind]);
|
||||||
|
smooth_item->new_vertex (p.x (), p.y (), p.z ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
new_item->new_triangle( map_i2i[(*it)[0]],
|
||||||
|
map_i2i[(*it)[1]],
|
||||||
|
map_i2i[(*it)[2]] );
|
||||||
|
if (generate_smooth)
|
||||||
|
smooth_item->new_triangle( map_i2i[(*it)[0]],
|
||||||
|
map_i2i[(*it)[1]],
|
||||||
|
map_i2i[(*it)[2]] );
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push_back (new_item);
|
||||||
|
if (generate_smooth)
|
||||||
|
items.push_back (smooth_item);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue