Add a plugin to cisualize LCC data structures. (IO plugin for *.off and *.3map)

This commit is contained in:
Maxime Gimeno 2019-03-11 16:25:07 +01:00
parent 94541df835
commit e00a489bc0
5 changed files with 634 additions and 1 deletions

View File

@ -301,7 +301,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND )
add_item(scene_polylines_item Scene_polylines_item.cpp)
target_link_libraries(scene_polylines_item PUBLIC scene_basic_objects scene_points_with_normal_item)
add_item(scene_lcc_item Scene_lcc_item.cpp)
foreach( lib
demo_framework
scene_basic_objects

View File

@ -26,6 +26,8 @@ target_link_libraries(stl_plugin PUBLIC scene_surface_mesh_item scene_polygon_so
polyhedron_demo_plugin(surf_io_plugin Surf_io_plugin KEYWORDS IO)
target_link_libraries(surf_io_plugin PUBLIC scene_surface_mesh_item)
polyhedron_demo_plugin(lcc_io_plugin lcc_io_plugin KEYWORDS IO)
target_link_libraries(lcc_io_plugin PUBLIC scene_lcc_item)
find_package(VTK QUIET COMPONENTS

View File

@ -0,0 +1,74 @@
#include <CGAL/Three/Three.h>
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
#include <CGAL/Combinatorial_map_save_load.h>
#include <CGAL/Polyhedron_3_to_lcc.h>
#include "Scene_lcc_item.h"
#include <iostream>
#include <fstream>
class LCC_io_plugin :
public QObject,
public CGAL::Three::Polyhedron_demo_io_plugin_interface
{
Q_OBJECT
Q_INTERFACES(CGAL::Three::Polyhedron_demo_io_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.0" FILE "lcc_io_plugin.json")
public:
bool isDefaultLoader(const CGAL::Three::Scene_item *item) const
{
if(qobject_cast<const Scene_lcc_item*>(item))
return true;
return false;
}
QString name() const { return "lcc_plugin"; }
QString nameFilters() const { return
"OFF files (*.off);;"
"3-map files (*.3map)"; }
QString saveNameFilters() const {
return
"3-map files (*.3map)";
}
bool canLoad() const { return true; }
CGAL::Three::Scene_item* load(QFileInfo fileinfo){
// Open file
std::ifstream ifs(fileinfo.filePath().toUtf8());
if(!ifs) {
std::cerr << "Error! Cannot open file " << (const char*)fileinfo.filePath().toUtf8() << std::endl;
return nullptr;
}
Scene_lcc_item::LCC lcc;
QString ext = fileinfo.suffix();
bool res = true;
if(ext == "off")
CGAL::import_from_polyhedron_3_flux < Scene_lcc_item::LCC > (lcc, ifs);
else
{
res = CGAL::load_combinatorial_map(ifs, lcc);
}
if(!res)
{
return nullptr;
}
Scene_lcc_item* new_item = new Scene_lcc_item(lcc);
new_item->setName(fileinfo.fileName());
new_item->invalidateOpenGLBuffers();
return new_item;
}
bool canSave(const CGAL::Three::Scene_item*){return true;}
bool save(const CGAL::Three::Scene_item*, QFileInfo fileinfo){
qDebug() << fileinfo.fileName() << "Implement me, you fool !";
return false;
}
};
#include "lcc_io_plugin.moc"

View File

@ -0,0 +1,502 @@
#include <CGAL/Three/Viewer_interface.h>
#include <CGAL/Three/Triangle_container.h>
#include <CGAL/Three/Edge_container.h>
#include <CGAL/Three/Point_container.h>
#include <CGAL/Three/Three.h>
#include <CGAL/Buffer_for_vao.h>
#include "Scene_lcc_item.h"
using namespace CGAL::Three;
typedef Triangle_container Tri;
typedef Edge_container Ec;
typedef Point_container Pc;
typedef Viewer_interface Vi;
typedef Scene_lcc_item::LCC::Dart_handle Dart_handle;
typedef Scene_lcc_item::LCC::Point Point;
struct lcc_priv{
typedef Scene_lcc_item::LCC::Dart_const_handle Dart_const_handle;
Scene_lcc_item::LCC lcc;
std::vector<float> faces;
std::vector<float> lines;
std::vector<float> vertices;
std::size_t nb_lines, nb_vertices, nb_faces;
lcc_priv(const Scene_lcc_item::LCC& lcc)
:lcc(lcc){}
void compute_face(Dart_const_handle dh)
{
// We fill only closed faces.
Dart_const_handle cur=dh;
Dart_const_handle min=dh;
do
{
if (!lcc.is_next_exist(cur)) return; // open face=>not filled
if (cur<min) min=cur;
cur=lcc.next(cur);
}
while(cur!=dh);
cur=dh;
std::vector<Point> pts_in_face;
do
{
pts_in_face.push_back(lcc.point(cur));
cur=lcc.next(cur);
}
while(cur!=dh);
Scene_lcc_item::LCC::Vector normal(0,0,0);
for (std::size_t i = 0; i < pts_in_face.size() ; ++ i){
const Point& pa = pts_in_face[i];
const Point& pb = pts_in_face[(i+1)%pts_in_face.size()];
double x = normal.x() + (pa.y()-pb.y())*(pa.z()+pb.z());
double y = normal.y() + (pa.z()-pb.z())*(pa.x()+pb.x());
double z = normal.z() + (pa.x()-pb.x())*(pa.y()+pb.y());
normal = Scene_lcc_item::LCC::Vector(x,y,z);
}
if (pts_in_face.size()==3)
{
for(auto pt = pts_in_face.begin();
pt != pts_in_face.end();
++pt)
{
faces.push_back(pt->x());
faces.push_back(pt->y());
faces.push_back(pt->z());
}
}
else if (CGAL::Buffer_for_vao<float, std::size_t>::is_facet_convex(pts_in_face,normal))
{
if (pts_in_face.size()==4)
{
Point p = pts_in_face[0];
faces.push_back(p.x());
faces.push_back(p.y());
faces.push_back(p.z());
p = pts_in_face[1];
faces.push_back(p.x());
faces.push_back(p.y());
faces.push_back(p.z());
p = pts_in_face[2];
faces.push_back(p.x());
faces.push_back(p.y());
faces.push_back(p.z());
p = pts_in_face[0];
faces.push_back(p.x());
faces.push_back(p.y());
faces.push_back(p.z());
p = pts_in_face[2];
faces.push_back(p.x());
faces.push_back(p.y());
faces.push_back(p.z());
p = pts_in_face[3];
faces.push_back(p.x());
faces.push_back(p.y());
faces.push_back(p.z());
}
else
{
for(std::size_t i=1; i<pts_in_face.size()-1; ++i)
{
Point& p0 = pts_in_face[0];
Point& p1 = pts_in_face[i];
Point& p2 = pts_in_face[i+1];
// (1) add points
faces.push_back(p0.x());
faces.push_back(p0.y());
faces.push_back(p0.z());
faces.push_back(p1.x());
faces.push_back(p1.y());
faces.push_back(p1.z());
faces.push_back(p2.x());
faces.push_back(p2.y());
faces.push_back(p2.z());
}
} // Convex face with > 4 vertices
}
else
{
struct Vertex_info
{
Scene_lcc_item::LCC::Vector v;
std::size_t index;
};
struct Face_info
{
bool exist_edge[3];
bool is_external;
bool is_process;
};
typedef CGAL::Triangulation_2_projection_traits_3<CGAL::Exact_predicates_inexact_constructions_kernel> P_traits;
typedef CGAL::Triangulation_vertex_base_with_info_2<Vertex_info, P_traits> Vb;
typedef CGAL::Triangulation_face_base_with_info_2<Face_info, P_traits> Fb1;
typedef CGAL::Constrained_triangulation_face_base_2<P_traits, Fb1> Fb;
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
typedef CGAL::Exact_predicates_tag Itag;
typedef CGAL::Constrained_Delaunay_triangulation_2<P_traits, TDS, Itag> CDT;
P_traits cdt_traits(normal);
CDT cdt(cdt_traits);
// (1) We insert all the edges as contraint in the CDT.
typename CDT::Vertex_handle previous=NULL, first=NULL;
for (unsigned int i=0; i<pts_in_face.size(); ++i)
{
typename CDT::Vertex_handle vh = cdt.insert(pts_in_face[i]);
if(first==NULL)
{ first=vh; }
vh->info().v=normal;
if(previous!=NULL && previous!=vh)
{ cdt.insert_constraint(previous, vh); }
previous=vh;
}
if (previous!=NULL && previous!=first)
{ cdt.insert_constraint(previous, first); }
// (2) We mark all external triangles
// (2.1) We initialize is_external and is_process values
for(typename CDT::All_faces_iterator fit = cdt.all_faces_begin(),
fitend = cdt.all_faces_end(); fit!=fitend; ++fit)
{
fit->info().is_external = true;
fit->info().is_process = false;
}
// (2.2) We check if the facet is external or internal
std::queue<typename CDT::Face_handle> face_queue;
typename CDT::Face_handle face_internal = NULL;
if (cdt.infinite_vertex()->face()!=NULL)
{ face_queue.push(cdt.infinite_vertex()->face()); }
while(!face_queue.empty())
{
typename CDT::Face_handle fh = face_queue.front();
face_queue.pop();
if(!fh->info().is_process)
{
fh->info().is_process = true;
for(int i=0; i<3; ++i)
{
if(!cdt.is_constrained(std::make_pair(fh, i)))
{
if (fh->neighbor(i)!=NULL)
{ face_queue.push(fh->neighbor(i)); }
}
else if (face_internal==NULL)
{
face_internal = fh->neighbor(i);
}
}
}
}
if ( face_internal!=NULL )
{ face_queue.push(face_internal); }
while(!face_queue.empty())
{
typename CDT::Face_handle fh = face_queue.front();
face_queue.pop();
if(!fh->info().is_process)
{
fh->info().is_process = true;
fh->info().is_external = false;
for(unsigned int i=0; i<3; ++i)
{
if(!cdt.is_constrained(std::make_pair(fh, i)))
{
if (fh->neighbor(i)!=NULL)
{ face_queue.push(fh->neighbor(i)); }
}
}
}
}
// (3) Now we iterates on the internal faces to add the vertices
// and the normals to the appropriate vectors
for(typename CDT::Finite_faces_iterator ffit=cdt.finite_faces_begin(),
ffitend = cdt.finite_faces_end(); ffit!=ffitend; ++ffit)
{
if(!ffit->info().is_external)
{
for(unsigned int i=0; i<3; ++i)
{
Point p = ffit->vertex(i)->point();
faces.push_back(p.x());
faces.push_back(p.y());
faces.push_back(p.z());
}
}
}
}
}
};
Scene_lcc_item::Scene_lcc_item(const LCC& lcc)
:d(new lcc_priv(lcc))
{
d->nb_faces = 0;
d->nb_lines = 0;
d->nb_vertices = 0;
setTriangleContainer(0,
new Tri(Three::mainViewer()->isOpenGL_4_3() ? Vi::PROGRAM_FLAT
: Vi::PROGRAM_OLD_FLAT, false));
setEdgeContainer(0,
new Ec(Three::mainViewer()->isOpenGL_4_3() ? Vi::PROGRAM_SOLID_WIREFRAME
: Vi::PROGRAM_NO_SELECTION
, false));
setPointContainer(0,
new Pc(Vi::PROGRAM_NO_SELECTION, false));
}
Scene_lcc_item::~Scene_lcc_item()
{
delete d;
}
Scene_lcc_item* Scene_lcc_item::clone() const
{
Scene_lcc_item* item = new Scene_lcc_item(d->lcc);
return item;
}
bool Scene_lcc_item::supportsRenderingMode(RenderingMode m) const
{
return m==FlatPlusEdges;
}
QString Scene_lcc_item::toolTip() const
{
return QString();
}
void Scene_lcc_item::compute_bbox() const
{
Scene_item::Bbox bb;
for (LCC::Dart_range::const_iterator it=d->lcc.darts().begin(),
itend=d->lcc.darts().end(); it!=itend; ++it )
{
bb+=d->lcc.point(it).bbox();
}
this->setBbox(bb);
}
void Scene_lcc_item::draw(CGAL::Three::Viewer_interface* viewer) const
{
if(!isInit())
initGL();
if ( getBuffersFilled() &&
! getBuffersInit(viewer))
{
initializeBuffers(viewer);
setBuffersInit(viewer, true);
}
if(!getBuffersFilled())
{
computeElements();
initializeBuffers(viewer);
}
getTriangleContainer(0)->setColor(this->color());
getTriangleContainer(0)->draw(viewer, true);
}
void Scene_lcc_item::drawEdges(CGAL::Three::Viewer_interface* viewer) const
{
if(!isInit())
initGL();
if ( getBuffersFilled() &&
! getBuffersInit(viewer))
{
initializeBuffers(viewer);
setBuffersInit(viewer, true);
}
if(!getBuffersFilled())
{
computeElements();
initializeBuffers(viewer);
}
GLfloat offset_factor;
GLfloat offset_units;
viewer->glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &offset_factor);
viewer->glGetFloatv(GL_POLYGON_OFFSET_UNITS, &offset_units);
viewer->glEnable(GL_POLYGON_OFFSET_LINE);
viewer->glPolygonOffset(0.3f, 0.3f);
if(viewer->isOpenGL_4_3())
{
QVector2D vp(viewer->width(), viewer->height());
getEdgeContainer(0)->setViewport(vp);
getEdgeContainer(0)->setWidth(2);
}
getEdgeContainer(0)->setColor(QColor(Qt::black));
getEdgeContainer(0)->draw(viewer, true);
drawPoints(viewer);
viewer->glDisable(GL_POLYGON_OFFSET_LINE);
viewer->glPolygonOffset(offset_factor, offset_units);
}
void Scene_lcc_item::drawPoints(CGAL::Three::Viewer_interface* viewer) const
{
if(!visible())
return;
if(!isInit())
initGL();
if ( getBuffersFilled() &&
! getBuffersInit(viewer))
{
initializeBuffers(viewer);
setBuffersInit(viewer, true);
}
GLfloat point_size;
viewer->glGetFloatv(GL_POINT_SIZE, &point_size);
viewer->setGlPointSize(GLfloat(5));
if(!getBuffersFilled())
{
computeElements();
initializeBuffers(viewer);
}
getPointContainer(0)->setColor(QColor(Qt::black));
getPointContainer(0)->draw(viewer, true);
viewer->setGlPointSize(point_size);
}
void Scene_lcc_item::computeElements() const
{
CGAL::Three::Three::CursorScopeGuard guard(QCursor(Qt::WaitCursor));
typename LCC::size_type markvolumes = d->lcc.get_new_mark();
typename LCC::size_type markfaces = d->lcc.get_new_mark();
typename LCC::size_type markedges = d->lcc.get_new_mark();
typename LCC::size_type markvertices = d->lcc.get_new_mark();
for (typename LCC::Dart_range::const_iterator it=d->lcc.darts().begin(),
itend=d->lcc.darts().end(); it!=itend; ++it )
{
if (!d->lcc.is_marked(it, markvolumes))
{
for (typename LCC::template Dart_of_cell_basic_range<3>::
const_iterator itv=d->lcc.template darts_of_cell_basic<3>(it, markvolumes).begin(),
itvend=d->lcc.template darts_of_cell_basic<3>(it, markvolumes).end();
itv!=itvend; ++itv)
{
d->lcc.mark(itv, markvolumes); // To be sure that all darts of the basic iterator will be marked
if (!d->lcc.is_marked(itv, markfaces))
{
d->compute_face(itv);
for (typename LCC::template Dart_of_cell_basic_range<2>::
const_iterator itf=d->lcc.template darts_of_cell_basic<2>(itv, markfaces).begin(),
itfend=d->lcc.template darts_of_cell_basic<2>(itv, markfaces).end();
itf!=itfend; ++itf)
{
d->lcc.mark(itf, markfaces); // To be sure that all darts of the basic iterator will be marked
if ( !d->lcc.is_marked(itf, markedges))
{
Point p1 = d->lcc.point(itf);
LCC::Dart_const_handle d2 = d->lcc.other_extremity(itf);
Point p2 = d->lcc.point(d2);
d->lines.push_back(p1.x());
d->lines.push_back(p1.y());
d->lines.push_back(p1.z());
d->lines.push_back(p2.x());
d->lines.push_back(p2.y());
d->lines.push_back(p2.z());
for (typename LCC::template Dart_of_cell_basic_range<1>::
const_iterator ite=d->lcc.template darts_of_cell_basic<1>(itf, markedges).begin(),
iteend=d->lcc.template darts_of_cell_basic<1>(itf, markedges).end();
ite!=iteend; ++ite)
{
d->lcc.mark(ite, markedges); // To be sure that all darts of the basic iterator will be marked
if ( !d->lcc.is_marked(ite, markvertices))
{
Point p1 = d->lcc.point(ite);
d->vertices.push_back(p1.x());
d->vertices.push_back(p1.y());
d->vertices.push_back(p1.z());
CGAL::mark_cell<LCC, 0>(d->lcc, ite, markvertices);
}
}
}
}
}
}
}
}
for (typename LCC::Dart_range::const_iterator it=d->lcc.darts().begin(),
itend=d->lcc.darts().end(); it!=itend; ++it )
{
d->lcc.unmark(it, markvertices);
d->lcc.unmark(it, markedges);
d->lcc.unmark(it, markfaces);
d->lcc.unmark(it, markvolumes);
}
d->lcc.free_mark(markvolumes);
d->lcc.free_mark(markfaces);
d->lcc.free_mark(markedges);
d->lcc.free_mark(markvertices);
getTriangleContainer(0)->allocate(
Tri::Flat_vertices, d->faces.data(),
static_cast<int>(d->faces.size()*sizeof(float)));
getEdgeContainer(0)->allocate(
Ec::Vertices, d->lines.data(),
static_cast<int>(d->lines.size()*sizeof(float)));
getPointContainer(0)->allocate(
Pc::Vertices, d->vertices.data(),
static_cast<int>(d->vertices.size()*sizeof(float)));
setBuffersFilled(true);
d->nb_faces = d->faces.size();
d->nb_lines = d->lines.size();
d->nb_vertices= d->vertices.size();
}
void Scene_lcc_item::initializeBuffers(CGAL::Three::Viewer_interface *viewer) const
{
getTriangleContainer(0)->initializeBuffers(viewer);
getTriangleContainer(0)->setFlatDataSize(d->nb_faces);
getEdgeContainer(0)->initializeBuffers(viewer);
getEdgeContainer(0)->setFlatDataSize(d->nb_lines);
getPointContainer(0)->initializeBuffers(viewer);
getPointContainer(0)->setFlatDataSize(d->nb_vertices);
d->faces.clear();
d->faces.shrink_to_fit();
d->lines.clear();
d->lines.shrink_to_fit();
d->vertices.clear();
d->vertices.shrink_to_fit();
}
void Scene_lcc_item::invalidateOpenGLBuffers()
{
setBuffersFilled(false);
getTriangleContainer(0)->reset_vbos(ALL);
getEdgeContainer(0)->reset_vbos(ALL);
getPointContainer(0)->reset_vbos(ALL);
compute_bbox();
}
bool Scene_lcc_item::isEmpty() const
{
return false;
}

View File

@ -0,0 +1,53 @@
#ifndef SCENE_LCC_ITEM_H
#define SCENE_LCC_ITEM_H
#include <CGAL/Three/Scene_item_rendering_helper.h>
#include <CGAL/Linear_cell_complex_for_combinatorial_map.h>
#ifdef scene_lcc_item_EXPORTS
# define SCENE_LCC_ITEM_EXPORT Q_DECL_EXPORT
#else
# define SCENE_LCC_ITEM_EXPORT Q_DECL_IMPORT
#endif
struct lcc_priv;
namespace CGAL{
namespace Three{
class Viewer_interface;
}
}
class SCENE_LCC_ITEM_EXPORT Scene_lcc_item : public CGAL::Three::Scene_item_rendering_helper
{
Q_OBJECT
public:
typedef CGAL::Linear_cell_complex_for_combinatorial_map<3> LCC;
Scene_lcc_item(const LCC &lcc);
~Scene_lcc_item();
bool isEmpty()const;
bool isFinite() const { return true; }
Scene_lcc_item* clone() const Q_DECL_OVERRIDE ;
bool supportsRenderingMode(RenderingMode m) const Q_DECL_OVERRIDE ;
QString toolTip() const Q_DECL_OVERRIDE ;
void compute_bbox()const;
void draw(CGAL::Three::Viewer_interface*) const Q_DECL_OVERRIDE ;
void drawEdges(CGAL::Three::Viewer_interface*) const Q_DECL_OVERRIDE ;
void drawPoints(CGAL::Three::Viewer_interface*) const Q_DECL_OVERRIDE ;
void computeElements() const Q_DECL_OVERRIDE;
void initializeBuffers(CGAL::Three::Viewer_interface *) const Q_DECL_OVERRIDE;
public Q_SLOTS:
void invalidateOpenGLBuffers() Q_DECL_OVERRIDE;
private:
friend struct lcc_priv;
lcc_priv* d;
};
#endif // SCENE_LCC_ITEM_H