mirror of https://github.com/CGAL/cgal
Add an example for surface mesh that allows to visualize small faces; this example will be used in a tutorial explaining how to define and modify one viewer.
This commit is contained in:
parent
ddd7f8fa3b
commit
4afa5e9cb5
|
|
@ -41,6 +41,8 @@ if ( CGAL_FOUND )
|
|||
target_link_libraries(draw_surface_mesh PUBLIC CGAL::CGAL_Qt5)
|
||||
endif()
|
||||
|
||||
create_single_source_cgal_program("sm_draw_small_faces.cpp")
|
||||
|
||||
else()
|
||||
|
||||
message(STATUS "This program requires the CGAL library, and will not be compiled.")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,285 @@
|
|||
// Copyright (c) 2018 GeometryFactory (France)
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
// Author(s) : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
|
||||
|
||||
#ifndef CGAL_DRAW_SURFACE_MESH_SMALL_FACES_H
|
||||
#define CGAL_DRAW_SURFACE_MESH_SMALL_FACES_H
|
||||
|
||||
#include <CGAL/Qt/Basic_viewer_qt.h>
|
||||
|
||||
#ifdef CGAL_USE_BASIC_VIEWER
|
||||
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Random.h>
|
||||
|
||||
template<class SM>
|
||||
class SimpleSurfaceMeshWithSmallFacesViewerQt : public CGAL::Basic_viewer_qt
|
||||
{
|
||||
typedef CGAL::Basic_viewer_qt Base;
|
||||
typedef typename SM::Point Point;
|
||||
typedef typename CGAL::Kernel_traits<Point>::Kernel Kernel;
|
||||
typedef typename SM::Vertex_index vertex_descriptor;
|
||||
typedef typename SM::Face_index face_descriptor;
|
||||
typedef typename SM::Edge_index edge_descriptor;
|
||||
typedef typename SM::Halfedge_index halfedge_descriptor;
|
||||
typedef typename Kernel::FT FT;
|
||||
|
||||
public:
|
||||
/// Construct the viewer.
|
||||
/// @param amesh the surface mesh to view
|
||||
SimpleSurfaceMeshWithSmallFacesViewerQt(QWidget* parent,
|
||||
SM& amesh) :
|
||||
// First draw: no vertex; no edge, faces; multi-color; inverse normal
|
||||
Base(parent, "Surface mesh viewer with small faces", false, false, true, false, false),
|
||||
sm(amesh),
|
||||
m_threshold(85),
|
||||
m_draw_small_faces(true),
|
||||
m_draw_big_faces(true)
|
||||
{
|
||||
// Add custom key description (see keyPressEvent).
|
||||
setKeyDescription(Qt::Key_I, "Increment threshold for small faces");
|
||||
setKeyDescription(Qt::Key_D, "Decrement threshold for small faces");
|
||||
setKeyDescription(Qt::Key_S, "Draw small faces only , big faces only, both");
|
||||
|
||||
if (sm.faces().begin()!=sm.faces().end())
|
||||
{
|
||||
bool exist;
|
||||
typename SM::template Property_map<face_descriptor, FT> faces_size;
|
||||
boost::tie(faces_size, exist)=sm.template property_map<face_descriptor, FT>("f:size");
|
||||
CGAL_assertion(exist);
|
||||
|
||||
m_min_size=faces_size[*(sm.faces().begin())];
|
||||
m_max_size=m_min_size;
|
||||
FT cur_size;
|
||||
|
||||
for (typename SM::Face_range::iterator f=sm.faces().begin(); f!=sm.faces().end(); ++f)
|
||||
{
|
||||
cur_size=faces_size[*f];
|
||||
if (cur_size<m_min_size) m_min_size=cur_size;
|
||||
if (cur_size>m_max_size) m_max_size=cur_size;
|
||||
}
|
||||
}
|
||||
|
||||
compute_elements();
|
||||
}
|
||||
|
||||
protected:
|
||||
void compute_face(face_descriptor fh)
|
||||
{
|
||||
/// [Face creation]
|
||||
bool small=false;
|
||||
|
||||
// Default color of faces
|
||||
CGAL::Color c(75,160,255);
|
||||
|
||||
// Compare the size of the face with the % m_threshold
|
||||
bool exist;
|
||||
typename SM::template Property_map<face_descriptor, FT> faces_size;
|
||||
boost::tie(faces_size, exist)=sm.template property_map<face_descriptor, FT>("f:size");
|
||||
CGAL_assertion(exist);
|
||||
|
||||
// It it is smaller, color the face in red.
|
||||
if (get(faces_size, fh)<m_min_size+((m_max_size-m_min_size)/(100-m_threshold)))
|
||||
{
|
||||
c=CGAL::Color(255,20,20);
|
||||
small=true;
|
||||
}
|
||||
|
||||
if ((small && !m_draw_small_faces) || (!small && !m_draw_big_faces))
|
||||
{ return; }
|
||||
|
||||
// Add the color of the face, then all its points.
|
||||
face_begin(c);
|
||||
halfedge_descriptor hd=sm.halfedge(fh);
|
||||
do
|
||||
{
|
||||
add_point_in_face(sm.point(sm.source(hd)), get_vertex_normal(hd));
|
||||
hd=sm.next(hd);
|
||||
}
|
||||
while(hd!=sm.halfedge(fh));
|
||||
face_end();
|
||||
/// [Face creation]
|
||||
}
|
||||
|
||||
// Copy from draw_surface_mesh.h
|
||||
void compute_edge(edge_descriptor e)
|
||||
{
|
||||
/// [Edge creation]
|
||||
add_segment(sm.point(sm.source(sm.halfedge(e))),
|
||||
sm.point(sm.target(sm.halfedge(e))));
|
||||
/// [Edge creation]
|
||||
}
|
||||
|
||||
void compute_vertex(vertex_descriptor vh)
|
||||
{
|
||||
/// [Vertex creation]
|
||||
add_point(sm.point(vh));
|
||||
/// [Vertex creation]
|
||||
}
|
||||
|
||||
void compute_elements()
|
||||
{
|
||||
clear();
|
||||
|
||||
for (typename SM::Face_range::iterator f=sm.faces().begin();
|
||||
f!=sm.faces().end(); ++f)
|
||||
{
|
||||
if (*f!=boost::graph_traits<SM>::null_face())
|
||||
{ compute_face(*f); }
|
||||
}
|
||||
|
||||
for (typename SM::Edge_range::iterator e=sm.edges().begin();
|
||||
e!=sm.edges().end(); ++e)
|
||||
{ compute_edge(*e); }
|
||||
|
||||
for (typename SM::Vertex_range::iterator v=sm.vertices().begin();
|
||||
v!=sm.vertices().end(); ++v)
|
||||
{ compute_vertex(*v); }
|
||||
}
|
||||
|
||||
// Call: * compute_elements() if the model changed, followed by
|
||||
// * redraw() if some viewing parameters changed that implies some
|
||||
// modifications of the buffers
|
||||
// (eg. type of normal, color/mono)
|
||||
// * update() just to update the drawing
|
||||
virtual void keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
/// [Keypress]
|
||||
const ::Qt::KeyboardModifiers modifiers = e->modifiers();
|
||||
if ((e->key()==Qt::Key_I) && (modifiers==Qt::NoButton))
|
||||
{
|
||||
if (m_threshold<100) ++m_threshold;
|
||||
displayMessage(QString("Threshold percent=%1 \%.").arg(m_threshold));
|
||||
compute_elements();
|
||||
redraw();
|
||||
}
|
||||
else if ((e->key()==Qt::Key_D) && (modifiers==Qt::NoButton))
|
||||
{
|
||||
if (m_threshold>0) --m_threshold;
|
||||
displayMessage(QString("Threshold percent=%1 \%.").arg(m_threshold));
|
||||
compute_elements();
|
||||
redraw();
|
||||
}
|
||||
else if ((e->key()==Qt::Key_S) && (modifiers==Qt::NoButton))
|
||||
{
|
||||
QString msg;
|
||||
if (m_draw_small_faces)
|
||||
{
|
||||
if (m_draw_big_faces)
|
||||
{
|
||||
m_draw_big_faces=false;
|
||||
msg=QString("Draw small faces only.");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_draw_big_faces=true; m_draw_small_faces=false;
|
||||
msg=QString("Draw big faces only.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(m_draw_big_faces);
|
||||
m_draw_small_faces=true;
|
||||
msg=QString("Draw small and big faces.");
|
||||
}
|
||||
|
||||
displayMessage(msg);
|
||||
compute_elements();
|
||||
redraw();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Call the base method to process others/classicals key
|
||||
Base::keyPressEvent(e);
|
||||
}
|
||||
/// [Keypress]
|
||||
}
|
||||
|
||||
protected:
|
||||
typename Kernel::Vector_3 get_face_normal(halfedge_descriptor he)
|
||||
{
|
||||
typename Kernel::Vector_3 normal=CGAL::NULL_VECTOR;
|
||||
halfedge_descriptor end=he;
|
||||
unsigned int nb=0;
|
||||
do
|
||||
{
|
||||
CGAL::internal::newell_single_step_3(sm.point(sm.source(he)),
|
||||
sm.point(sm.target(he)), normal);
|
||||
++nb;
|
||||
he=sm.next(he);
|
||||
}
|
||||
while (he!=end);
|
||||
assert(nb>0);
|
||||
return (typename Kernel::Construct_scaled_vector_3()(normal, 1.0/nb));
|
||||
}
|
||||
|
||||
typename Kernel::Vector_3 get_vertex_normal(halfedge_descriptor he)
|
||||
{
|
||||
typename Kernel::Vector_3 normal=CGAL::NULL_VECTOR;
|
||||
halfedge_descriptor end=he;
|
||||
do
|
||||
{
|
||||
if (!sm.is_border(he))
|
||||
{
|
||||
typename Kernel::Vector_3 n=get_face_normal(he);
|
||||
normal=typename Kernel::Construct_sum_of_vectors_3()(normal, n);
|
||||
}
|
||||
he=sm.next(sm.opposite(he));
|
||||
}
|
||||
while (he!=end);
|
||||
|
||||
if (!typename Kernel::Equal_3()(normal, CGAL::NULL_VECTOR))
|
||||
{ normal=(typename Kernel::Construct_scaled_vector_3()
|
||||
(normal, 1.0/CGAL::sqrt(normal.squared_length()))); }
|
||||
|
||||
return normal;
|
||||
}
|
||||
|
||||
protected:
|
||||
SM& sm;
|
||||
unsigned int m_threshold;
|
||||
FT m_min_size, m_max_size;
|
||||
bool m_draw_small_faces;
|
||||
bool m_draw_big_faces;
|
||||
};
|
||||
|
||||
template<class K>
|
||||
void draw_surface_mesh_with_small_faces(CGAL::Surface_mesh<K>& amesh)
|
||||
{
|
||||
#if defined(CGAL_TEST_SUITE)
|
||||
bool cgal_test_suite=true;
|
||||
#else
|
||||
bool cgal_test_suite=qEnvironmentVariableIsSet("CGAL_TEST_SUITE");
|
||||
#endif
|
||||
|
||||
if (!cgal_test_suite)
|
||||
{
|
||||
int argc=1;
|
||||
const char* argv[2]={"surface_mesh_viewer","\0"};
|
||||
QApplication app(argc,const_cast<char**>(argv));
|
||||
SimpleSurfaceMeshWithSmallFacesViewerQt<CGAL::Surface_mesh<K>>
|
||||
mainwindow(app.activeWindow(), amesh);
|
||||
mainwindow.show();
|
||||
app.exec();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CGAL_USE_BASIC_VIEWER
|
||||
|
||||
#endif // CGAL_DRAW_SURFACE_MESH_SMALL_FACES_H
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/measure.h>
|
||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <boost/foreach.hpp>
|
||||
#include "draw_surface_mesh_small_faces.h"
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||
typedef Mesh::Vertex_index vertex_descriptor;
|
||||
typedef Mesh::Face_index face_descriptor;
|
||||
typedef K::FT FT;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Mesh sm;
|
||||
std::ifstream input((argc>1)?argv[1]:"data/elephant.off");
|
||||
input>>sm;
|
||||
|
||||
CGAL::Polygon_mesh_processing::triangulate_faces(sm);
|
||||
|
||||
Mesh::Property_map<face_descriptor, FT> faces_size;
|
||||
bool created;
|
||||
boost::tie(faces_size, created)=sm.add_property_map<face_descriptor, FT>("f:size",0.);
|
||||
CGAL_assertion(created);
|
||||
|
||||
BOOST_FOREACH(face_descriptor fd, sm.faces())
|
||||
{ faces_size[fd]=CGAL::Polygon_mesh_processing::face_area(fd, sm); }
|
||||
|
||||
draw_surface_mesh_with_small_faces(sm);
|
||||
|
||||
sm.remove_property_map(faces_size);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue