From 4afa5e9cb5db01fa2bfcfdcb77e5a19a16cec972 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Fri, 7 Sep 2018 13:30:44 +0200 Subject: [PATCH] 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. --- .../examples/Surface_mesh/CMakeLists.txt | 2 + .../draw_surface_mesh_small_faces.h | 285 ++++++++++++++++++ .../Surface_mesh/sm_draw_small_faces.cpp | 38 +++ 3 files changed, 325 insertions(+) create mode 100644 Surface_mesh/examples/Surface_mesh/draw_surface_mesh_small_faces.h create mode 100644 Surface_mesh/examples/Surface_mesh/sm_draw_small_faces.cpp diff --git a/Surface_mesh/examples/Surface_mesh/CMakeLists.txt b/Surface_mesh/examples/Surface_mesh/CMakeLists.txt index 6170d1bb2b7..3d0781e990f 100644 --- a/Surface_mesh/examples/Surface_mesh/CMakeLists.txt +++ b/Surface_mesh/examples/Surface_mesh/CMakeLists.txt @@ -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.") diff --git a/Surface_mesh/examples/Surface_mesh/draw_surface_mesh_small_faces.h b/Surface_mesh/examples/Surface_mesh/draw_surface_mesh_small_faces.h new file mode 100644 index 00000000000..9e960be161a --- /dev/null +++ b/Surface_mesh/examples/Surface_mesh/draw_surface_mesh_small_faces.h @@ -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 + +#ifndef CGAL_DRAW_SURFACE_MESH_SMALL_FACES_H +#define CGAL_DRAW_SURFACE_MESH_SMALL_FACES_H + +#include + +#ifdef CGAL_USE_BASIC_VIEWER + +#include +#include + +template +class SimpleSurfaceMeshWithSmallFacesViewerQt : public CGAL::Basic_viewer_qt +{ + typedef CGAL::Basic_viewer_qt Base; + typedef typename SM::Point Point; + typedef typename CGAL::Kernel_traits::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 faces_size; + boost::tie(faces_size, exist)=sm.template property_map("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_sizem_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 faces_size; + boost::tie(faces_size, exist)=sm.template property_map("f:size"); + CGAL_assertion(exist); + + // It it is smaller, color the face in red. + if (get(faces_size, fh)::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 +void draw_surface_mesh_with_small_faces(CGAL::Surface_mesh& 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(argv)); + SimpleSurfaceMeshWithSmallFacesViewerQt> + mainwindow(app.activeWindow(), amesh); + mainwindow.show(); + app.exec(); + } +} + +#endif // CGAL_USE_BASIC_VIEWER + +#endif // CGAL_DRAW_SURFACE_MESH_SMALL_FACES_H diff --git a/Surface_mesh/examples/Surface_mesh/sm_draw_small_faces.cpp b/Surface_mesh/examples/Surface_mesh/sm_draw_small_faces.cpp new file mode 100644 index 00000000000..3ab87459e1d --- /dev/null +++ b/Surface_mesh/examples/Surface_mesh/sm_draw_small_faces.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include +#include +#include "draw_surface_mesh_small_faces.h" + +typedef CGAL::Simple_cartesian K; +typedef CGAL::Surface_mesh 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 faces_size; + bool created; + boost::tie(faces_size, created)=sm.add_property_map("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; +} +