Protect border edges (sharp edges will come).

For the moment, the display does not work!
This commit is contained in:
Laurent Rineau 2009-11-23 01:00:12 +00:00
parent 679933b028
commit 118b6af6c3
11 changed files with 476 additions and 18 deletions

1
.gitattributes vendored
View File

@ -2578,6 +2578,7 @@ Polyhedron/demo/Polyhedron/data/bull.off -text svneol=unset#application/octet-st
Polyhedron/demo/Polyhedron/data/couplingdown.off -text svneol=unset#application/octet-stream
Polyhedron/demo/Polyhedron/data/cow.off -text svneol=unset#application/octet-stream
Polyhedron/demo/Polyhedron/data/cross.off -text svneol=unset#application/octet-stream
Polyhedron/demo/Polyhedron/data/cube-ouvert.off -text svneol=unset#application/octet-stream
Polyhedron/demo/Polyhedron/data/cube.off -text svneol=unset#application/octet-stream
Polyhedron/demo/Polyhedron/data/dragknob.off -text svneol=unset#application/octet-stream
Polyhedron/demo/Polyhedron/data/elephant.off -text svneol=unset#application/octet-stream

View File

@ -0,0 +1,27 @@
#ifndef C2T3_TYPE_H
#define C2T3_TYPE_H
#include <CGAL/Surface_mesh_default_triangulation_3.h>
#include <CGAL/Complex_2_in_triangulation_3.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Regular_triangulation_3.h>
#include <CGAL/Regular_triangulation_euclidean_traits_3.h>
// traits class
typedef CGAL::Exact_predicates_inexact_constructions_kernel K2;
typedef CGAL::Robust_circumcenter_traits_3<K2> K;
typedef CGAL::Regular_triangulation_euclidean_traits_3<K> Traits;
// vertex and cell types
typedef CGAL::Surface_mesh_vertex_base_3<Traits> Vb;
typedef CGAL::Surface_mesh_cell_base_3<Traits> Cb;
typedef CGAL::Triangulation_cell_base_with_circumcenter_3<Traits, Cb> Cb_with_circumcenter;
// triangulation
typedef CGAL::Triangulation_data_structure_3<Vb, Cb_with_circumcenter> Tds;
typedef CGAL::Regular_triangulation_3<Traits, Tds> Tr;
typedef CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
#endif

View File

@ -85,6 +85,9 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
qt4_generate_moc( "${CMAKE_CURRENT_SOURCE_DIR}/Scene.h" Scene_moc.cpp )
add_file_dependencies( Scene_moc.cpp "${CMAKE_CURRENT_SOURCE_DIR}/Scene.h" )
qt4_generate_moc( "${CMAKE_CURRENT_SOURCE_DIR}/Polyhedron_demo_remeshing_plugin_cgal_code.cpp" Polyhedron_demo_remeshing_plugin_cgal_code.moc )
qt4_add_resources ( RESOURCE_FILES Polyhedron_3.qrc )
qt4_automoc(Scene_item.cpp
@ -187,7 +190,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
target_link_libraries( ${plugin_name} ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} )
endmacro(polyhedron_demo_plugin)
polyhedron_demo_plugin(remeshing_plugin Polyhedron_demo_remeshing_plugin Polyhedron_demo_remeshing_plugin_cgal_code.cpp)
polyhedron_demo_plugin(remeshing_plugin Polyhedron_demo_remeshing_plugin Polyhedron_demo_remeshing_plugin_cgal_code.cpp Polyhedron_demo_remeshing_plugin_protection_cgal_code.cpp Polyhedron_demo_remeshing_plugin_cgal_code.moc)
target_link_libraries(remeshing_plugin scene_polyhedron_item polygon_soup)
qt4_generate_moc("${CMAKE_CURRENT_SOURCE_DIR}/Polyhedron_demo_mesh_3_plugin_cgal_code.cpp" Scene_c3t3_item.moc )

View File

@ -15,6 +15,7 @@
// declare the CGAL function
Scene_item* cgal_code_mesh_3(const Polyhedron*,
QString filename,
const double angle,
const double sizing,
const double approx,
@ -109,7 +110,7 @@ void Polyhedron_demo_mesh_3_plugin::mesh_3()
QApplication::setOverrideCursor(Qt::WaitCursor);
Scene_item* result_item = cgal_code_mesh_3(pMesh, angle, sizing, approx, tets_sizing);
Scene_item* result_item = cgal_code_mesh_3(pMesh, item->name(), angle, sizing, approx, tets_sizing);
if(result_item) {
result_item->setName(tr("%1 3d mesh (%2 %3 %4 %5)")
.arg(item->name())

View File

@ -279,6 +279,7 @@ private:
};
Scene_item* cgal_code_mesh_3(const Polyhedron* pMesh,
const QString filename,
const double angle,
const double sizing,
const double approx,
@ -297,6 +298,11 @@ Scene_item* cgal_code_mesh_3(const Polyhedron* pMesh,
CGAL::Timer timer;
timer.start();
std::cerr << "Meshing file \"" << qPrintable(filename) << "\"\n";
std::cerr << " angle: " << angle << std::endl
<< " facets size bound: " << sizing << std::endl
<< " approximation bound: " << approx << std::endl
<< " tetrahedra size bound: " << tets_sizing << std::endl;
std::cerr << "Build AABB tree...";
// Create domain
Mesh_domain domain(*pMesh);

View File

@ -13,7 +13,7 @@
#include <QStringList>
// declare the CGAL function
Scene_item* cgal_code_remesh(const Polyhedron*,
Scene_item* cgal_code_remesh(Polyhedron*,
const double angle,
const double sizing,
const double approx,

View File

@ -3,12 +3,14 @@
#include "Polyhedron_type.h"
#include "Scene_item.h"
#include <qgl.h>
#include "Scene_polyhedron_item.h"
#include "Scene_polygon_soup.h"
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh_default_triangulation_3.h>
#include <CGAL/Complex_2_in_triangulation_3.h>
#include "C2t3_type.h"
#include <CGAL/make_surface_mesh.h>
#include <CGAL/Surface_mesh_default_criteria_3.h>
@ -18,11 +20,139 @@
#include <CGAL/Timer.h>
#include <CGAL/assertions_behaviour.h>
#include <CGAL/exceptions.h>
#include <algorithm>
#include <sstream>
Scene_item* cgal_code_remesh(const Polyhedron* pMesh,
#include "Scene_item.h"
#include <Qt/qglobal.h>
#include <CGAL/gl.h>
#include <QGLViewer/manipulatedFrame.h>
#include <QGLViewer/qglviewer.h>
namespace {
void CGALglcolor(QColor c)
{
::glColor4f(c.red()/255.0, c.green()/255.0, c.blue()/255.0, c.alpha()/255.0);
}
}
class Q_DECL_EXPORT Scene_c2t3_item : public Scene_item
{
Q_OBJECT
public:
Scene_c2t3_item(const C2t3& c2t3)
: sphere_display_list(0), quadric(0), c2t3_(c2t3)
{
}
~Scene_c2t3_item()
{
if(quadric != 0)
gluDeleteQuadric(quadric);
if(sphere_display_list != 0)
glDeleteLists(sphere_display_list, 1);
}
const C2t3& c2t3() const {
return c2t3_;
}
bool isFinite() const { return true; }
bool isEmpty() const {
return c2t3().triangulation().number_of_vertices() == 0;
}
Bbox bbox() const {
if(isEmpty())
return Bbox();
else {
CGAL::Bbox_3 result = c2t3().triangulation().vertices_begin()->point().bbox();
for(Tr::Finite_vertices_iterator
vit = ++c2t3().triangulation().finite_vertices_begin(),
end = c2t3().triangulation().finite_vertices_end();
vit != end; ++vit)
{
result = result + vit->point().bbox();
}
return Bbox(result.xmin(), result.ymin(), result.zmin(),
result.xmax(), result.ymax(), result.zmax());
}
}
Scene_c2t3_item* clone() const {
return 0;
}
QString toolTip() const {
return tr("<p><b>2D complex in a 3D triangulation</b></p>"
"<p>Number of vertices: %1<br />"
"Number of surface facets: %2<br />")
.arg(c2t3().triangulation().number_of_vertices())
.arg(c2t3().number_of_facets());
}
// Indicate if rendering mode is supported
bool supportsRenderingMode(RenderingMode m) const {
return (m != Gouraud); // CHECK THIS!
}
void draw() const {
if(sphere_display_list == 0) {
sphere_display_list = glGenLists(1);
glNewList(sphere_display_list, GL_COMPILE);
}
for(Tr::Finite_vertices_iterator
vit = c2t3().triangulation().finite_vertices_begin(),
end = c2t3().triangulation().finite_vertices_end();
vit != end; ++vit)
{
draw_sphere(vit->point());
}
}
void draw_sphere(const Tr::Point p) const
{
if(p.weight() > 0) {
std::cerr << "draw_sphere(" << p << ")\n";
if(sphere_display_list == 0) {
sphere_display_list = glGenLists(1);
if(sphere_display_list == 0)
std::cerr << "ERROR: Cannot create display list!\n";
if(quadric == 0)
quadric = gluNewQuadric();
if(quadric == 0)
std::cerr << "ERROR: Cannot create GLU quadric!\n";
glNewList(sphere_display_list, GL_COMPILE);
gluSphere(quadric, 1., 10, 10);
glEndList();
if(glGetError() != GL_NO_ERROR)
std::cerr << gluErrorString(glGetError());
}
glPushMatrix();
glTranslated(CGAL::to_double(p.point().x()),
CGAL::to_double(p.point().y()),
CGAL::to_double(p.point().z()));
const GLdouble r = CGAL::to_double(CGAL_NTS sqrt(p.weight()));
glScaled(r, r, r);
glCallList(sphere_display_list);
glPopMatrix();
}
}
private:
mutable GLuint sphere_display_list;
mutable GLUquadric* quadric;
C2t3 c2t3_;
};
typedef Tr::Geom_traits GT;
bool insert_spheres(C2t3& c2t3, Polyhedron* pMesh, const GT::FT size);
Scene_item* cgal_code_remesh(Polyhedron* pMesh,
const double angle,
const double sizing,
const double approx,
@ -32,12 +162,10 @@ Scene_item* cgal_code_remesh(const Polyhedron* pMesh,
// remesh
typedef CGAL::Surface_mesh_default_triangulation_3 Tr;
typedef CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
typedef Tr::Geom_traits GT;
Tr triangulation; // 3D-Delaunay triangulation
C2t3 c2t3(triangulation); // 2D-complex in 3D-Delaunay triangulation
Tr& triangulation = * new Tr;; // 3D-Delaunay triangulation
C2t3& c2t3 = *(new C2t3(triangulation));
// C2t3 c2t3(triangulation); // 2D-complex in 3D-Delaunay triangulation
// meshing parameters
CGAL::Surface_mesh_default_criteria_3<Tr> facets_criteria(angle,sizing,approx);
@ -48,7 +176,7 @@ Scene_item* cgal_code_remesh(const Polyhedron* pMesh,
std::cerr << "Build AABB tree...";
typedef CGAL::Simple_cartesian<double> Simple_cartesian_kernel;
// input surface
typedef CGAL::AABB_polyhedral_oracle<Polyhedron,GT,Simple_cartesian_kernel> Input_surface;
typedef CGAL::AABB_polyhedral_oracle<Polyhedron,Kernel,Simple_cartesian_kernel> Input_surface;
Input_surface input(*pMesh);
std::cerr << "done (" << timer.time() << " ms)" << std::endl;
@ -75,7 +203,7 @@ Scene_item* cgal_code_remesh(const Polyhedron* pMesh,
n = triangulation.number_of_vertices())
{
const int pos = CGAL::default_random.get_int(0, polyhedron_points.size());
triangulation.insert(convert(polyhedron_points[pos]));
triangulation.insert(polyhedron_points[pos]);
}
}
if(triangulation.dimension() < 3)
@ -83,6 +211,9 @@ Scene_item* cgal_code_remesh(const Polyhedron* pMesh,
std::cerr << "done (" << timer.time() << " ms)" << std::endl;
insert_spheres(c2t3, pMesh, sizing / 3);
std::cerr << c2t3.number_of_facets() << std::endl;
return new Scene_c2t3_item(c2t3);
// remesh
timer.reset();
std::cerr << "Remesh...";
@ -104,7 +235,14 @@ Scene_item* cgal_code_remesh(const Polyhedron* pMesh,
// add remesh as new polyhedron
Polyhedron *pRemesh = new Polyhedron;
CGAL::Complex_2_in_triangulation_3_polyhedron_builder<C2t3, Polyhedron> builder(c2t3);
pRemesh->delegate(builder);
try {
CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
pRemesh->delegate(builder);
} catch(CGAL::Failure_exception)
{
}
CGAL::set_error_behaviour(CGAL::ABORT);
if(c2t3.number_of_facets() != pRemesh->size_of_facets())
{
delete pRemesh;
@ -129,3 +267,5 @@ Scene_item* cgal_code_remesh(const Polyhedron* pMesh,
else
return 0;
}
#include "Polyhedron_demo_remeshing_plugin_cgal_code.moc"

View File

@ -0,0 +1,259 @@
#include <CGAL/config.h>
#include "Polyhedron_type.h"
#include "C2t3_type.h"
#include <set>
#include <map>
typedef Tr::Geom_traits::FT FT;
struct Less {
template <typename Handle>
bool operator()(const Handle& va, const Handle& vb) const {
return &*va < &*vb;
}
};
struct Insert_spheres {
typedef Polyhedron::Halfedge_const_handle Halfedge_const_handle;
typedef Polyhedron::Vertex_const_handle Vertex_const_handle;
typedef Polyhedron::size_type size_type;
typedef Tr::Geom_traits::Point_3 Point_3;
typedef std::set<Vertex_const_handle, Less> Vertices_set;
typedef std::map<Vertex_const_handle, size_type, Less> Vertices_counter;
typedef std::set<Halfedge_const_handle, Less> Border_edges_set;
Border_edges_set edges_to_consider;
Vertices_counter border_vertices;
Vertices_set corner_vertices;
typedef std::vector<Tr::Geom_traits::Point_3> Polyline;
typedef std::vector<Polyline> Polylines;
Polylines polylines;
C2t3& c2t3;
Polyhedron* pMesh;
const FT size;
Halfedge_const_handle canonical(Halfedge_const_handle he)
{
const Halfedge_const_handle& op = he->opposite();
if(Less()(he, op))
return he;
else
return op;
}
/** Follow a polyline or a polygon, from the halfedge he. */
void follow_half_edge(const Halfedge_const_handle he)
{
Border_edges_set::iterator it = edges_to_consider.find(canonical(he));
if(it == edges_to_consider.end()) {
return;
}
Polyline polyline;
polyline.push_back(he->opposite()->vertex()->point());
// std::cerr << "Start: " << he->opposite()->vertex()->point() << std::endl;
Halfedge_const_handle current_he = he;
do {
CGAL_assertion(current_he->is_border() ||
current_he->opposite()->is_border());
const size_type n = edges_to_consider.erase(canonical(current_he));
CGAL_assertion(n > 0);
Vertex_const_handle v = current_he->vertex();
polyline.push_back(v->point());
// std::cerr << v->point() << std::endl;
if(corner_vertices.count(v) > 0) break;
Polyhedron::Halfedge_around_vertex_const_circulator
loop_he = v->vertex_begin(), end(loop_he);
++loop_he;
// CGAL_assertion((&*loop_he) != (&*current_he) );
while((&*loop_he) == (&*current_he) ||
(!loop_he->is_border() && !loop_he->opposite()->is_border()) ) {
++loop_he;
// CGAL_assertion((&*loop_he) != (&*current_he) );
}
current_he = loop_he->opposite();
} while(current_he != he );
if(current_he == he)
std::cerr << "New polyline, of size " << polyline.size() << std::endl;
else
std::cerr << "New polygon (cycle), of size " << polyline.size() << std::endl;
polylines.push_back(polyline);
}
/** Loop around a corner vertex, and try to follow a polyline of border
edges, from each incident edge. */
void loop_around_corner(const Vertex_const_handle v)
{
Polyhedron::Halfedge_around_vertex_const_circulator
he = v->vertex_begin(), end(he);
do {
CGAL_assertion(he->vertex() == v);
follow_half_edge(he->opposite());
++he;
} while(he != end);
}
/** For a non-corner vertex v (that is incident to two border edges),
mesure the angle between the two edges, and mark the vertex as corner
edge, if the angle is < 120°. **/
void mesure_angle(const Vertex_const_handle v)
{
Halfedge_const_handle e1;
Halfedge_const_handle e2;
Polyhedron::Halfedge_around_vertex_const_circulator he = v->vertex_begin(), end(he);
// std::cerr << "mesure_handle(" << (void*)(&*v)
// << " = " << v->point() << ")";
bool first = true;
do {
CGAL_assertion(he->vertex() == v);
// std::cerr << he->opposite()->vertex()->point() << std::endl;
if(he->is_border() || he->opposite()->is_border()) {
if(first) {
e1 = he;
first = false;
}
else {
CGAL_assertion(e2 == Halfedge_const_handle());
e2 = he;
}
std::cerr << "x";
}
else
std::cerr << ".";
++he;
} while(he != end);
std::cerr << "\n";
const Point_3 pv = v->point();
const Point_3 pa = e1->opposite()->vertex()->point();
const Point_3 pb = e2->opposite()->vertex()->point();
const Tr::Geom_traits::Vector_3 av = pv - pa;
const Tr::Geom_traits::Vector_3 bv = pv - pb;
const FT sc_prod = av * bv;
if( sc_prod >= 0 ||
(sc_prod < 0 &&
CGAL::square(sc_prod) < (av * av) * (bv * bv) / 4 ) )
{
std::cerr << "Corner (" << pa << ", " << pv
<< ", " << pb << ")\n";
corner_vertices.insert(v);
}
}
void protect(Polyline::const_iterator begin,
Polyline::const_iterator end) {
CGAL_assertion(begin+1 != end);
// for(Polyline::const_iterator it
Polyline::const_iterator end2 = end;
--end2;
FT distance = 0;
for(Polyline::const_iterator it = begin;
it != end2;) {
const Point& a = *it;
const Point& b = *++it;
distance += CGAL_NTS sqrt( CGAL::squared_distance(a, b) );
}
std::cerr << "Distance: " << distance << std::endl;
std::cerr << "Size: " << size << std::endl;
const size_type n = static_cast<size_type>(std::ceil(distance / size) + 0.5);
const FT local_size = distance / n;
std::cerr << n << std::endl;
std::cerr << "Local size: " << local_size << std::endl;
CGAL_assertion(local_size < size);
Point_3 a(begin->point(), local_size/1.5);
Point_3 b(end2->point(), local_size/1.5);
c2t3.triangulation().insert(a);
Polyline::const_iterator it = begin;
++it;
FT small_distance_to_go = local_size;
while(it != end) {
const Point& a = *it;
const Point& b = *++it;
const FT d = CGAL_NTS squared_distance(a, b);
unsigned i = 0;
for(; small_distance_to_go + i * local_size >= d;
++i)
{
const Point p = a +
(small_distance_to_go + i * local_size) * ( b - a ) / d;
c2t3.triangulation().insert(Point_3(p, local_size / 1.5));
}
small_distance_to_go -= d;
small_distance_to_go += i * local_size;
}
c2t3.triangulation().insert(b);
std::cerr << "One polyline is protected!\n";
}
Insert_spheres(C2t3& c2t3, Polyhedron* pMesh, const FT size)
: c2t3(c2t3), pMesh(pMesh), size(size)
{
// That call orders the set of edges of the polyhedron, so that the
// border edges are at the end of the sequence of edges.
pMesh->normalize_border();
// Iterate over border edges, and find out which vertices are corner
// vertices (more than two incident border edges).
for(Polyhedron::Edge_const_iterator
eit = pMesh->border_edges_begin (),
end = pMesh->edges_end();
eit != end; ++eit)
{
edges_to_consider.insert(canonical(eit));
Polyhedron::Vertex_const_handle v = eit->vertex();
for(unsigned i = 0; i < 2; ++i) {
if(++border_vertices[v] == 3)
corner_vertices.insert(v);
v = eit->opposite()->vertex();
}
}
std::cerr << "Corner vertices: " << corner_vertices.size() << std::endl;
std::cerr << "Border vertices: " << border_vertices.size() << std::endl;
// Iterate over non-corner border vertices, and mesure the angle.
for(Vertices_counter::iterator it = border_vertices.begin(),
end = border_vertices.end(); it != end; ++it)
{
const Vertex_const_handle v = it->first;
if(corner_vertices.count(v) == 0) {
CGAL_assertion(it->second == 2);
mesure_angle(v);
}
}
std::cerr << "New corner vertices: " << corner_vertices.size() << std::endl;
// Follow the polylines...
for(Vertices_set::iterator it = corner_vertices.begin(),
end = corner_vertices.end(); it != end; ++it)
{
loop_around_corner(*it);
}
// ... and the cycles.
while(! edges_to_consider.empty() ) {
follow_half_edge(*edges_to_consider.begin());
}
for(Polylines::const_iterator it = polylines.begin(),
end = polylines.end(); it != end; ++it)
{
protect(it->begin(), it->end());
}
}
};
void insert_spheres(C2t3& c2t3, Polyhedron* pMesh, const FT size) {
Insert_spheres go(c2t3, pMesh, size);
}

View File

@ -5,10 +5,9 @@
#ifdef USE_FORWARD_DECL
namespace CGAL {
#include <CGAL/Filtered_kernel_fwd.h>
template <class CK>
struct Filtered_kernel;
namespace CGAL {
template < typename FT_ >
struct Simple_cartesian;

View File

@ -61,7 +61,7 @@ Scene_polyhedron_item::toolTip() const
if(!poly)
return QString();
return QObject::tr("<p><b>%1</b> (mode: %5, color: %6)</p>"
return QObject::tr("<p>Polyhedron <b>%1</b> (mode: %5, color: %6)</p>"
"<p>Number of vertices: %2<br />"
"Number of edges: %3<br />"
"Number of facets: %4</p>")

View File

@ -0,0 +1,22 @@
OFF
9 10 0
-1 -1 -1
-1 1 -1
1 1 -1
1 -1 -1
-1 -1 1
-1 1 1
1 1 1
1 -1 1
1 2 1
3 0 1 3
3 3 1 2
3 0 4 1
3 1 4 5
3 3 2 7
3 7 2 6
3 4 0 3
3 7 4 3
3 6 4 7
3 6 5 4