From 6ebe6d6845cae015dc0a161fa950ee6f1f7ed66e Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 24 Jul 2020 13:09:53 +0200 Subject: [PATCH] That factorizes the code for the `draw()` function for `Polyhedron_3` and `Surface_mesh`. --- BGL/include/CGAL/draw_face_graph.h | 183 ++++++++++++++++++ Polyhedron/include/CGAL/draw_polyhedron.h | 172 +--------------- Surface_mesh/include/CGAL/draw_surface_mesh.h | 166 +--------------- 3 files changed, 191 insertions(+), 330 deletions(-) create mode 100644 BGL/include/CGAL/draw_face_graph.h diff --git a/BGL/include/CGAL/draw_face_graph.h b/BGL/include/CGAL/draw_face_graph.h new file mode 100644 index 00000000000..2d8032b9ecb --- /dev/null +++ b/BGL/include/CGAL/draw_face_graph.h @@ -0,0 +1,183 @@ +// Copyright (c) 2018-2020 GeometryFactory (France) +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Guillaume Damiand +// Laurent Rineau + +#ifndef CGAL_DRAW_FACE_GRAPH_H +#define CGAL_DRAW_FACE_GRAPH_H + +#ifdef CGAL_USE_BASIC_VIEWER + +#include +#include +#include + +namespace CGAL +{ + +// Default color functor; user can change it to have its own face color +struct DefaultColorFunctorFaceGraph +{ + template + CGAL::Color operator()(const Graph&, + typename boost::graph_traits::face_descriptor fh) const + { + if (fh==boost::graph_traits::null_face()) // use to get the mono color + return CGAL::Color(100, 125, 200); // R G B between 0-255 + + return get_random_color(CGAL::get_default_random()); + } +}; + +class SimpleFaceGraphViewerQt : public Basic_viewer_qt +{ + using Base = Basic_viewer_qt; + +public: + SimpleFaceGraphViewerQt(QWidget* parent) : + Base(parent, "", false, true, true, true, false), + m_compute_elements_impl([]{}) + { + } + + /// Construct the viewer. + /// @param amesh the surface mesh to view + /// @param title the title of the window + /// @param anofaces if true, do not draw faces (faces are not computed; this can be + /// usefull for very big object where this time could be long) + template + SimpleFaceGraphViewerQt(QWidget* parent, + const SM& amesh, + const char* title="Basic Surface_mesh Viewer", + bool anofaces=false) : + SimpleFaceGraphViewerQt(parent, amesh, title, anofaces, DefaultColorFunctorFaceGraph()) + { + } + + template + SimpleFaceGraphViewerQt(QWidget* parent, + const SM& amesh, + const char* title, + bool anofaces, + ColorFunctor fcolor) : + // First draw: no vertex; edges, faces; mono-color; inverse normal + Base(parent, title, false, true, true, true, false), + m_compute_elements_impl(compute_elements_functor(amesh, anofaces, fcolor)) + { + } + + void init() override { + compute_elements(); + Base::init(); + } + + void compute_elements() { + m_compute_elements_impl(); + } + + template + void set_face_graph(const SM& amesh, + bool anofaces, + ColorFunctor fcolor) { + m_compute_elements_impl = compute_elements_functor(amesh, anofaces, fcolor); + } + + template + void set_face_graph(const SM& amesh, + bool anofaces=false) { + set_mesh(amesh, anofaces, DefaultColorFunctorFaceGraph()); + } +protected: + template + std::function + compute_elements_functor(const SM& sm, + bool anofaces, + ColorFunctor fcolor) + { + using Point = + typename boost::property_map_value::type; + using Kernel = typename CGAL::Kernel_traits::Kernel; + using Vector = typename Kernel::Vector_3; + + auto vnormals = get(CGAL::dynamic_vertex_property_t(), sm); + { + // temporary face property map needed by `compute_normals` + auto fpm = get(CGAL::dynamic_face_property_t(), sm); + + CGAL::Polygon_mesh_processing::compute_normals(sm, vnormals, fpm); + } + + // This function return a lambda expression, type-erased in a + // `std::function` object. + return [this, &sm, vnormals, anofaces, fcolor]() + { + this->clear(); + + auto point_pmap = get(CGAL::vertex_point, sm); + if (!anofaces) + { + for (auto fh: faces(sm)) + { + if (fh!=boost::graph_traits::null_face()) + { + CGAL::Color c=fcolor(sm, fh); + face_begin(c); + auto hd=halfedge(fh, sm); + const auto first_hd = hd; + do + { + auto v = source(hd, sm); + add_point_in_face(get(point_pmap, v), get(vnormals, v)); + hd=next(hd, sm); + } + while(hd!=first_hd); + face_end(); + } + } + } + + for (auto e: edges(sm)) + { + add_segment(get(point_pmap, source(halfedge(e, sm), sm)), + get(point_pmap, target(halfedge(e, sm), sm))); + } + + for (auto v: vertices(sm)) + { + this->add_point(get(point_pmap, v)); + } + }; + } + + virtual void keyPressEvent(QKeyEvent *e) + { + // Test key pressed: + // const ::Qt::KeyboardModifiers modifiers = e->modifiers(); + // if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::NoButton)) { ... } + + // 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 + + // Call the base method to process others/classicals key + Base::keyPressEvent(e); + } + +protected: + std::function m_compute_elements_impl; +}; + +} // End namespace CGAL + +#endif // CGAL_USE_BASIC_VIEWER + +#endif // CGAL_DRAW_SURFACE_MESH_H diff --git a/Polyhedron/include/CGAL/draw_polyhedron.h b/Polyhedron/include/CGAL/draw_polyhedron.h index 7e5983c81ac..fd99ad0859b 100644 --- a/Polyhedron/include/CGAL/draw_polyhedron.h +++ b/Polyhedron/include/CGAL/draw_polyhedron.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 ETH Zurich (Switzerland). +// Copyright (c) 2018-2020 ETH Zurich (Switzerland). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -18,175 +18,12 @@ #ifdef CGAL_USE_BASIC_VIEWER #include +#include #include namespace CGAL { -// Default color functor; user can change it to have its own face color -struct DefaultColorFunctorPolyhedron -{ - template - static CGAL::Color run(const Polyhedron&, - typename Polyhedron::Facet_const_handle fh) - { - if (fh==boost::graph_traits::null_face()) // use to get the mono color - return CGAL::Color(100, 125, 200); // R G B between 0-255 - - CGAL::Random random((unsigned int)(std::size_t)(&(*fh))); - return get_random_color(random); - } -}; - -// Viewer class for Polyhedron -template -class SimplePolyhedronViewerQt : public Basic_viewer_qt -{ - typedef Basic_viewer_qt Base; - typedef typename Polyhedron::Traits Kernel; - typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle; - typedef typename Polyhedron::Vertex_const_handle Vertex_const_handle; - typedef typename Polyhedron::Facet_const_handle Facet_const_handle; - -public: - /// Construct the viewer. - /// @param apoly the polyhedron to view - /// @param title the title of the window - /// @param anofaces if true, do not draw faces (faces are not computed; this can be - /// usefull for very big object where this time could be long) - SimplePolyhedronViewerQt(QWidget* parent, - const Polyhedron& apoly, - const char* title="Basic Polyhedron Viewer", - bool anofaces=false, - const ColorFunctor& fcolor=ColorFunctor()) : - // First draw: no vertex; edges, faces; mono-color; inverse normal - Base(parent, title, false, true, true, true, false), - poly(apoly), - m_nofaces(anofaces), - m_fcolor(fcolor) - { - compute_elements(); - } - -protected: - void compute_face(Facet_const_handle fh) - { - CGAL::Color c=m_fcolor.run(poly, fh); - face_begin(c); - Halfedge_const_handle he=fh->facet_begin(); - do - { - add_point_in_face(he->vertex()->point(), - get_vertex_normal(he)); - he=he->next(); - } - while (he!=fh->facet_begin()); - face_end(); - } - - void compute_edge(Halfedge_const_handle he) - { - add_segment(he->vertex()->point(), - he->opposite()->vertex()->point()); - // We can use add_segment(p1, p2, c) with c a CGAL::Color to add a colored segment - } - - void compute_vertex(Vertex_const_handle vh) - { - add_point(vh->point()); - // We can use add_point(p, c) with c a CGAL::Color to add a colored point - } - - void compute_elements() - { - clear(); - - if (!m_nofaces) - { - for(typename Polyhedron::Facet_const_iterator f=poly.facets_begin(); - f!=poly.facets_end(); f++) - { - if (f!=boost::graph_traits::null_face()) - { compute_face(f); } - } - } - - for ( typename Polyhedron::Halfedge_const_iterator e=poly.halfedges_begin(); - e!=poly.halfedges_end(); ++e) - { - if (eopposite()) - { compute_edge(e); } - } - - for ( typename Polyhedron::Vertex_const_iterator v=poly.vertices_begin(); - v!=poly.vertices_end(); ++v) - { compute_vertex(v); } - } - - virtual void keyPressEvent(QKeyEvent *e) - { - // Test key pressed: - // const ::Qt::KeyboardModifiers modifiers = e->modifiers(); - // if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::NoButton)) { ... } - - // 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 - - // Call the base method to process others/classicals key - Base::keyPressEvent(e); - } - -protected: - Local_vector get_face_normal(Halfedge_const_handle he) - { - Local_vector normal=CGAL::NULL_VECTOR; - Halfedge_const_handle end=he; - unsigned int nb=0; - do - { - internal::newell_single_step_3 - (this->get_local_point(he->vertex()->point()), - this->get_local_point(he->next()->vertex()->point()), - normal); - ++nb; - he=he->next(); - } - while (he!=end); - assert(nb>0); - return (typename Local_kernel::Construct_scaled_vector_3()(normal, 1.0/nb)); - } - - Local_vector get_vertex_normal(Halfedge_const_handle he) - { - Local_vector normal=CGAL::NULL_VECTOR; - Halfedge_const_handle end=he; - do - { - if (!he->is_border()) - { - Local_vector n=get_face_normal(he); - normal=typename Local_kernel::Construct_sum_of_vectors_3()(normal, n); - } - he=he->next()->opposite(); - } - while (he!=end); - - if (!typename Local_kernel::Equal_3()(normal, CGAL::NULL_VECTOR)) - { normal=(typename Local_kernel::Construct_scaled_vector_3() - (normal, 1.0/CGAL::sqrt(normal.squared_length()))); } - - return normal; - } - -protected: - const Polyhedron& poly; - bool m_nofaces; - const ColorFunctor& m_fcolor; -}; - // Specialization of draw function. #define CGAL_POLY_TYPE CGAL::Polyhedron_3 \ @@ -211,9 +48,8 @@ void draw(const CGAL_POLY_TYPE& apoly, int argc=1; const char* argv[2]={"polyhedron_viewer","\0"}; QApplication app(argc,const_cast(argv)); - DefaultColorFunctorPolyhedron fcolor; - SimplePolyhedronViewerQt - mainwindow(app.activeWindow(), apoly, title, nofill, fcolor); + SimpleFaceGraphViewerQt + mainwindow(app.activeWindow(), apoly, title, nofill); mainwindow.show(); app.exec(); } diff --git a/Surface_mesh/include/CGAL/draw_surface_mesh.h b/Surface_mesh/include/CGAL/draw_surface_mesh.h index 5b8fc54195a..da0201031af 100644 --- a/Surface_mesh/include/CGAL/draw_surface_mesh.h +++ b/Surface_mesh/include/CGAL/draw_surface_mesh.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 GeometryFactory (France) +// Copyright (c) 2018-2020 GeometryFactory (France) // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -36,168 +36,10 @@ void draw(const SM& asm); #ifdef CGAL_USE_BASIC_VIEWER #include -#include - +#include namespace CGAL { -// Default color functor; user can change it to have its own face color -struct DefaultColorFunctorSM -{ - template - CGAL::Color operator()(const SM&, - typename SM::Face_index fh) const - { - if (fh==boost::graph_traits::null_face()) // use to get the mono color - return CGAL::Color(100, 125, 200); // R G B between 0-255 - - CGAL::Random random((unsigned int)fh); - return get_random_color(random); - } -}; - -class SimpleSurfaceMeshViewerQt : public Basic_viewer_qt -{ - using Base = Basic_viewer_qt; - -public: - /// Construct the viewer. - /// @param amesh the surface mesh to view - /// @param title the title of the window - /// @param anofaces if true, do not draw faces (faces are not computed; this can be - /// usefull for very big object where this time could be long) - template - SimpleSurfaceMeshViewerQt(QWidget* parent, - const SM& amesh, - const char* title="Basic Surface_mesh Viewer", - bool anofaces=false) - : SimpleSurfaceMeshViewerQt(parent, amesh, title, anofaces, DefaultColorFunctorSM()) - { - } - - template - SimpleSurfaceMeshViewerQt(QWidget* parent, - const SM& amesh, - const char* title, - bool anofaces, - ColorFunctor fcolor) : - // First draw: no vertex; edges, faces; mono-color; inverse normal - Base(parent, title, false, true, true, true, false), - m_compute_elements_impl(compute_elements_functor(amesh, anofaces, fcolor)) - { - } - - void init() override { - compute_elements(); - Base::init(); - } - - void compute_elements() { - m_compute_elements_impl(); - } - - template - void set_mesh(const SM& amesh, - bool anofaces=false, - ColorFunctor fcolor=DefaultColorFunctorSM()) { - m_compute_elements_impl = compute_elements_functor(amesh, anofaces, fcolor); - redraw(); - } - -protected: - template - std::function - compute_elements_functor(const SM& sm, - bool anofaces, - ColorFunctor fcolor) - { - using Point = typename SM::Point; - using Kernel = typename CGAL::Kernel_traits::Kernel; - using Vector = typename Kernel::Vector_3; - - auto vnormals = get(CGAL::dynamic_vertex_property_t(), sm); - { - // temporary face property map needed by `compute_normals` - auto fpm = get(CGAL::dynamic_face_property_t(), sm); - - CGAL::Polygon_mesh_processing::compute_normals(sm, vnormals, fpm); - } - - // This function return a lambda expression, type-erased in a - // `std::function` object. - return [this, &sm, vnormals, anofaces, fcolor]() - { - this->clear(); - - if (!anofaces) - { - for (typename SM::Face_range::iterator f=sm.faces().begin(); - f!=sm.faces().end(); ++f) - { - if (*f!=boost::graph_traits::null_face()) - { this->compute_face(sm, vnormals, *f, fcolor); } - } - } - - for (typename SM::Edge_range::iterator e=sm.edges().begin(); - e!=sm.edges().end(); ++e) - { this->compute_edge(sm, *e); } - - for (typename SM::Vertex_range::iterator v=sm.vertices().begin(); - v!=sm.vertices().end(); ++v) - { this->compute_vertex(sm, *v); } - }; - } - - template - void compute_face(const SM& sm, VNormals vnormals, - face_descriptor fh, const ColorFunctor& fcolor) - { - CGAL::Color c=fcolor(sm, fh); - face_begin(c); - auto hd=sm.halfedge(fh); - do - { - auto v = sm.source(hd); - add_point_in_face(sm.point(v), get(vnormals, v)); - hd=sm.next(hd); - } - while(hd!=sm.halfedge(fh)); - face_end(); - } - - template - void compute_edge(const SM& sm, edge_descriptor e) - { - add_segment(sm.point(sm.source(sm.halfedge(e))), - sm.point(sm.target(sm.halfedge(e)))); - } - - template - void compute_vertex(const SM& sm, vertex_descriptor vh) - { add_point(sm.point(vh)); } - - - virtual void keyPressEvent(QKeyEvent *e) - { - // Test key pressed: - // const ::Qt::KeyboardModifiers modifiers = e->modifiers(); - // if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::NoButton)) { ... } - - // 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 - - // Call the base method to process others/classicals key - Base::keyPressEvent(e); - } - -protected: - std::function m_compute_elements_impl; -}; - // Specialization of draw function. template void draw(const Surface_mesh& amesh, @@ -215,8 +57,8 @@ void draw(const Surface_mesh& amesh, int argc=1; const char* argv[2]={"surface_mesh_viewer","\0"}; QApplication app(argc,const_cast(argv)); - SimpleSurfaceMeshViewerQt mainwindow(app.activeWindow(), amesh, title, - nofill); + SimpleFaceGraphViewerQt mainwindow(app.activeWindow(), amesh, title, + nofill); mainwindow.show(); app.exec(); }