mirror of https://github.com/CGAL/cgal
397 lines
11 KiB
C++
397 lines
11 KiB
C++
#include <CGAL/AABB_polyhedral_oracle.h>
|
|
#include <CGAL/AABB_tree.h>
|
|
|
|
#include "Polyhedron_type.h"
|
|
#include "Scene_item.h"
|
|
#include <qgl.h>
|
|
#include "Scene_polyhedron_item.h"
|
|
#include "Scene_polygon_soup_item.h"
|
|
|
|
#include <CGAL/Simple_cartesian.h>
|
|
|
|
#include "C2t3_type.h"
|
|
#include "Scene_c2t3_item.h"
|
|
|
|
#include <CGAL/make_surface_mesh.h>
|
|
#include <CGAL/Surface_mesh_default_criteria_3.h>
|
|
#include <CGAL/Mesh_3/Robust_intersection_traits_3.h>
|
|
|
|
#include <CGAL/IO/Complex_2_in_triangulation_3_file_writer.h>
|
|
#include <CGAL/IO/Complex_2_in_triangulation_3_polyhedron_builder.h>
|
|
|
|
#include <CGAL/Timer.h>
|
|
|
|
#include <CGAL/assertions_behaviour.h>
|
|
#include <CGAL/exceptions.h>
|
|
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
|
|
#include <CGAL/array.h>
|
|
|
|
#include "Scene_item.h"
|
|
|
|
#include <QtCore/qglobal.h>
|
|
#include <CGAL/gl.h>
|
|
#include <QGLViewer/manipulatedFrame.h>
|
|
#include <QGLViewer/qglviewer.h>
|
|
#include <QApplication>
|
|
#include <QThread>
|
|
#include <QMessageBox>
|
|
|
|
template <class Tr>
|
|
class Surface_mesh_modified_criteria_3
|
|
{
|
|
public:
|
|
typedef Tr Triangulation;
|
|
typedef typename Tr::Geom_traits::FT FT;
|
|
|
|
typedef typename CGAL::array<FT, 3> Quality;
|
|
typedef typename Tr::Facet Facet;
|
|
const FT sq_distance_bound;
|
|
|
|
Surface_mesh_modified_criteria_3(const FT angle_bound,
|
|
const FT radius_bound,
|
|
const FT distance_bound)
|
|
: sq_distance_bound(distance_bound*distance_bound/100),
|
|
curvature_size_criterion(distance_bound),
|
|
uniform_size_criterion(radius_bound),
|
|
aspect_ratio_criterion(angle_bound)
|
|
|
|
{
|
|
}
|
|
|
|
bool is_bad (const Facet& f, Quality& q) const
|
|
{
|
|
const typename Tr::Point& pa = f.first->vertex((f.second+1)%4)->point();
|
|
const typename Tr::Point& pb = f.first->vertex((f.second+2)%4)->point();
|
|
const typename Tr::Point& pc = f.first->vertex((f.second+3)%4)->point();
|
|
if( squared_distance(pa, pb) < sq_distance_bound )
|
|
return false;
|
|
if( squared_distance(pc, pb) < sq_distance_bound )
|
|
return false;
|
|
if( squared_distance(pa, pc) < sq_distance_bound )
|
|
return false;
|
|
if(aspect_ratio_criterion.is_bad(f, q[0]))
|
|
return true;
|
|
else {
|
|
q[0] = 1;
|
|
if(uniform_size_criterion.is_bad(f, q[1]))
|
|
return true;
|
|
else {
|
|
q[1] = 1;
|
|
if(curvature_size_criterion.is_bad(f, q[2]))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
private:
|
|
CGAL::Surface_mesher::Curvature_size_criterion<Tr> curvature_size_criterion;
|
|
// bound on Hausdorff distance does not play any role if bigger than
|
|
// the square of the Uniform_size_criterion
|
|
|
|
CGAL::Surface_mesher::Uniform_size_criterion<Tr> uniform_size_criterion;
|
|
// bound on radii of surface Delaunay balls
|
|
|
|
CGAL::Surface_mesher::Aspect_ratio_criterion<Tr> aspect_ratio_criterion;
|
|
// lower bound on minimum angle in degrees
|
|
|
|
}; // end class Surface_mesh_default_criteria_3
|
|
|
|
|
|
namespace {
|
|
void CGALglcolor(QColor c)
|
|
{
|
|
::glColor4d(c.red()/255.0, c.green()/255.0, c.blue()/255.0, c.alpha()/255.0);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Types for meshing
|
|
//
|
|
typedef CGAL::Simple_cartesian<double> Simple_cartesian_kernel;
|
|
// input surface
|
|
// typedef CGAL::Mesh_3::Robust_intersection_traits_3<Kernel> IGT;
|
|
typedef CGAL::AABB_polyhedral_oracle<Polyhedron,Kernel,Simple_cartesian_kernel> Input_surface;
|
|
|
|
|
|
// A base non-templated class, to allow
|
|
class Mesher_base : public QObject {
|
|
Q_OBJECT
|
|
protected:
|
|
bool is_stopped;
|
|
public:
|
|
Mesher_base(QObject* parent) : QObject(parent) {
|
|
is_stopped = true;
|
|
};
|
|
virtual ~Mesher_base() {}
|
|
public slots:
|
|
virtual void mesh() = 0;
|
|
virtual void one_step() = 0;
|
|
|
|
void stop() {
|
|
std::cerr << "STOP!\n";
|
|
is_stopped = true;
|
|
}
|
|
};
|
|
|
|
// Class template, refines Mesher_base
|
|
// That allows to create meshers with different criteria or manifold tag,
|
|
// and thread them with the API of Mesher_base (mesh/one_step/stop).
|
|
template <typename Criteria, typename Manifold_tag>
|
|
class Mesher : public Mesher_base
|
|
{
|
|
typedef typename CGAL::Surface_mesher_generator<
|
|
C2t3,
|
|
Input_surface,
|
|
Criteria,
|
|
Manifold_tag,
|
|
CGAL_SURFACE_MESHER_VERBOSITY >::type MyMesher;
|
|
|
|
MyMesher mesher;
|
|
const C2t3& c2t3;
|
|
const Input_surface& surface;
|
|
CGAL::Null_mesh_visitor visitor;
|
|
public:
|
|
Mesher(QObject* parent,
|
|
C2t3& c2t3,
|
|
const Input_surface& surface,
|
|
const Criteria& criteria)
|
|
: Mesher_base(parent),
|
|
mesher(c2t3, surface, surface, criteria),
|
|
c2t3(c2t3),
|
|
surface(surface)
|
|
{
|
|
typename Input_surface::Construct_initial_points get_initial_points =
|
|
surface.construct_initial_points_object();
|
|
|
|
get_initial_points(surface,
|
|
CGAL::inserter(c2t3.triangulation()),
|
|
20);
|
|
mesher.init();
|
|
}
|
|
|
|
void mesh()
|
|
{
|
|
int global_nbsteps = 0;
|
|
int nbsteps = 0;
|
|
CGAL::Timer timer;
|
|
timer.start();
|
|
is_stopped = false;
|
|
|
|
std::cerr << "Legende of the following line: "
|
|
<< "(#vertices,#steps," << mesher.debug_info_header()
|
|
<< ")\n";
|
|
|
|
while(!is_stopped && !mesher.is_algorithm_done())
|
|
{
|
|
one_step();
|
|
++nbsteps;
|
|
++global_nbsteps;
|
|
if(timer.time() > 1)
|
|
{
|
|
std::cerr
|
|
<< boost::format("\r \r"
|
|
"(%1%,%2%,%3%) (%|4$.1f| vertices/s)")
|
|
% c2t3.triangulation().number_of_vertices()
|
|
% global_nbsteps % mesher.debug_info()
|
|
% (nbsteps / timer.time());
|
|
qApp->processEvents();
|
|
nbsteps = 0;
|
|
timer.reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
void one_step()
|
|
{
|
|
mesher.one_step(visitor);
|
|
}
|
|
};
|
|
|
|
// That thread takes a Mesher_base* as parent. It just launches the meshing
|
|
// process.
|
|
struct Meshing_thread : QThread
|
|
{
|
|
Mesher_base* mesher;
|
|
|
|
Meshing_thread(Mesher_base* parent)
|
|
: QThread(parent), mesher(parent)
|
|
{
|
|
}
|
|
|
|
void run() {
|
|
mesher->mesh();
|
|
mesher->moveToThread(QApplication::instance()->thread());
|
|
}
|
|
};
|
|
|
|
typedef Tr::Geom_traits GT;
|
|
typedef Tr::Geom_traits::FT FT;
|
|
|
|
Scene_item* cgal_code_remesh(QWidget* parent,
|
|
Polyhedron* pMesh,
|
|
const double angle,
|
|
const double sizing,
|
|
const double approx,
|
|
int tag) {
|
|
// };
|
|
|
|
// class Mesh_process : public QObject {
|
|
// Q_OBJECT
|
|
|
|
// QWidget* parent;
|
|
// Polyhedron* pMesh;
|
|
// const double angle;
|
|
// const double sizing;
|
|
// const double approx;
|
|
// int tag;
|
|
|
|
// public:
|
|
// Mesh_process(QWidget* parent,
|
|
// Polyhedron* pMesh,
|
|
// const double angle,
|
|
// const double sizing,
|
|
// const double approx,
|
|
// int tag)
|
|
// : parent(parent),
|
|
// pMesh(pMesh),
|
|
// angle(angle),
|
|
// sizing(sizing),
|
|
// approx(approx)
|
|
// tag(tag)
|
|
// {
|
|
// }
|
|
|
|
// Scene_item* launch()
|
|
|
|
if(!pMesh) return 0;
|
|
|
|
CGAL::set_error_behaviour(CGAL::ABORT);
|
|
// remesh
|
|
|
|
|
|
Tr& triangulation = * new Tr;; // 3D-Delaunay triangulation
|
|
C2t3& c2t3 = *(new C2t3(triangulation));
|
|
// C2t3 c2t3(triangulation); // 2D-complex in 3D-Delaunay triangulation
|
|
|
|
// meshing parameters
|
|
typedef Surface_mesh_modified_criteria_3<Tr> Criteria;
|
|
const Criteria facets_criteria(angle,sizing,approx);
|
|
|
|
// const Criteria new_facets_criteria(facets_criteria);
|
|
|
|
// AABB tree
|
|
CGAL::Timer timer;
|
|
timer.start();
|
|
std::cerr << "Build AABB tree...";
|
|
Input_surface input(*pMesh);
|
|
std::cerr << "done (" << timer.time() << " ms)" << std::endl;
|
|
|
|
// initial point set
|
|
timer.reset();
|
|
std::cerr << "Insert initial point set... ";
|
|
|
|
{ // new scope for the initialization, so that the vector
|
|
// polyhedron_points is destroyed as soon as the initialization is
|
|
// finished
|
|
typedef Kernel::Point_3 Point;
|
|
|
|
std::vector<Point> polyhedron_points;
|
|
polyhedron_points.reserve(pMesh->size_of_vertices());
|
|
std::copy(pMesh->points_begin(), pMesh->points_end(),
|
|
std::back_inserter(polyhedron_points));
|
|
|
|
typedef std::vector<Point>::size_type size_type;
|
|
size_type nb_initial_points = 10;
|
|
nb_initial_points = (std::min)(nb_initial_points, polyhedron_points.size());
|
|
for(size_type n = 0;
|
|
n < nb_initial_points || (n < 10 * nb_initial_points &&
|
|
triangulation.dimension() < 3 );
|
|
n = triangulation.number_of_vertices())
|
|
{
|
|
const int pos = CGAL::default_random.get_int(0, (int)polyhedron_points.size());
|
|
triangulation.insert(polyhedron_points[pos]);
|
|
}
|
|
}
|
|
if(triangulation.dimension() < 3)
|
|
return 0;
|
|
|
|
std::cerr << "done (" << timer.time() << " ms)" << std::endl;
|
|
|
|
// return new Scene_c2t3_item(c2t3);
|
|
// remesh
|
|
timer.reset();
|
|
Mesher_base* mesher;
|
|
std::cerr << "Remesh...";
|
|
QMessageBox* message_box = new QMessageBox(QMessageBox::NoIcon,
|
|
"Remeshing...",
|
|
"Meshing process is running...",
|
|
QMessageBox::Cancel,
|
|
parent);
|
|
switch(tag) {
|
|
case 0:
|
|
mesher = new Mesher<Criteria,
|
|
CGAL::Non_manifold_tag>(0, c2t3, input, facets_criteria);
|
|
;
|
|
break;
|
|
case 1:
|
|
mesher = new Mesher<Criteria,
|
|
CGAL::Manifold_tag>(0, c2t3, input, facets_criteria);
|
|
break;
|
|
default:
|
|
mesher = new Mesher<Criteria,
|
|
CGAL::Manifold_with_boundary_tag>(0, c2t3, input, facets_criteria);
|
|
}
|
|
QObject::connect(message_box, SIGNAL(buttonClicked( QAbstractButton *)),
|
|
mesher, SLOT(stop()));
|
|
message_box->show();
|
|
qApp->processEvents();
|
|
|
|
|
|
Meshing_thread* thread = new Meshing_thread(mesher);
|
|
mesher->moveToThread(thread);
|
|
thread->start();
|
|
while(!thread->isFinished())
|
|
{
|
|
qApp->processEvents();
|
|
thread->wait(200);
|
|
}
|
|
delete message_box;
|
|
delete mesher;
|
|
std::cerr << "done (" << timer.time() << " ms, " << triangulation.number_of_vertices() << " vertices)" << std::endl;
|
|
|
|
if(triangulation.number_of_vertices() > 0)
|
|
{
|
|
// add remesh as new polyhedron
|
|
Polyhedron *pRemesh = new Polyhedron;
|
|
CGAL::Complex_2_in_triangulation_3_polyhedron_builder<C2t3, Polyhedron> builder(c2t3);
|
|
pRemesh->delegate(builder);
|
|
if(c2t3.number_of_facets() != pRemesh->size_of_facets())
|
|
{
|
|
delete pRemesh;
|
|
std::stringstream temp_file;
|
|
if(!CGAL::output_surface_facets_to_off(temp_file, c2t3))
|
|
{
|
|
std::cerr << "Cannot write the mesh to an off file!\n";
|
|
return 0;
|
|
}
|
|
Scene_polygon_soup_item* soup = new Scene_polygon_soup_item();
|
|
if(!soup->load(temp_file))
|
|
{
|
|
std::cerr << "Cannot reload the mesh from an off file!\n";
|
|
return 0;
|
|
}
|
|
else
|
|
return soup;
|
|
} else {
|
|
return new Scene_polyhedron_item(pRemesh);
|
|
}
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
#include "Polyhedron_demo_remeshing_plugin_cgal_code.moc"
|