diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map.h b/Combinatorial_map/include/CGAL/Combinatorial_map.h index d6da5650c85..4c2bb810685 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map.h @@ -1250,7 +1250,7 @@ namespace CGAL { /** Test if the map is valid. * @return true iff the map is valid. */ - bool is_valid() const + bool is_valid(bool show_errors=true) const { bool valid = true; unsigned int i = 0, j = 0; @@ -1276,9 +1276,11 @@ namespace CGAL { if ((!is_free(it, 0) && beta(it, 0, 1)!=it) || (!is_free(it, 1) && beta(it, 1, 0)!=it )) { - std::cerr << "Map not valid: beta(0) " - "is not the inverse of beta(1) for dart " - < + for ( typename CMap::template Dart_of_cell_basic_range::iterator it(amap, adart, amark); it.cont(); ++it, ++nb ) { if ( a!=amap.template attribute(it) ) diff --git a/GraphicsView/include/CGAL/Buffer_for_vao.h b/GraphicsView/include/CGAL/Buffer_for_vao.h new file mode 100644 index 00000000000..b8ca1f752bb --- /dev/null +++ b/GraphicsView/include/CGAL/Buffer_for_vao.h @@ -0,0 +1,800 @@ +// Copyright (c) 2018 GeometryFactory Sarl (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_VBO_BUFFER_FILLER_H +#define CGAL_VBO_BUFFER_FILLER_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace CGAL +{ + typedef CGAL::Exact_predicates_inexact_constructions_kernel Local_kernel; + typedef Local_kernel::Point_3 Local_point; + typedef Local_kernel::Vector_3 Local_vector; + +//------------------------------------------------------------------------------ +namespace internal +{ + template + void newell_single_step_3(const Point& p, const Point& q, Vector& n) + { + // Compute normal of the face by using Newell's method: for each edge PQ + // Nx += (Py - Qy) * (Pz + Qz); + // Ny += (Pz - Qz) * (Px + Qx); + // Nz += (Px - Qx) * (Py + Qy); + n = Vector(n.x()+((p.y()-q.y())*(p.z()+q.z())), + n.y()+((p.z()-q.z())*(p.x()+q.x())), + n.z()+((p.x()-q.x())*(p.y()+q.y()))); + } + + inline + Local_vector compute_normal_of_face(const std::vector& points) + { + Local_vector normal(CGAL::NULL_VECTOR); + unsigned int nb = 0; + for (std::size_t i=0; i0); + return (Local_kernel::Construct_scaled_vector_3()(normal, 1.0/nb)); + } + + //////////////////////////////////////////////////////////////// + // Structs to transform any CGAL point/vector into a Local_point/Local_vector + template + struct Geom_utils + { + static Local_point get_local_point(const typename K::Point_2& p) + { + CGAL::Cartesian_converter converter; + return Local_point(converter(p.x()), 0, converter(p.y())); + } + static Local_point get_local_point(const typename K::Weighted_point_2& p) + { + typename K::Point_2 lp(p); + return Geom_utils::get_local_point(lp); + } + static Local_point get_local_point(const typename K::Point_3& p) + { + CGAL::Cartesian_converter converter; + return converter(p); + } + static Local_point get_local_point(const typename K::Weighted_point_3& p) + { + typename K::Point_3 lp(p); + return Geom_utils::get_local_point(lp); + } + static Local_vector get_local_vector(const typename K::Vector_2& v) + { + CGAL::Cartesian_converter converter; + return Local_vector(converter(v.x()), 0, converter(v.y())); + } + static Local_vector get_local_vector(const typename K::Vector_3& v) + { + CGAL::Cartesian_converter converter; + return converter(v); + } + }; + + // Specialization for Local_kernel, because there is no need of convertion here. + template<> + struct Geom_utils + { + static Local_point get_local_point(const Local_kernel::Point_2& p) + { return Local_point(p.x(), 0, p.y()); } + static Local_point get_local_point(const Local_kernel::Weighted_point_2& p) + { return Local_point(p.point().x(), 0, p.point().y());} + static const Local_point & get_local_point(const Local_kernel::Point_3& p) + { return p; } + static Local_point get_local_point(const Local_kernel::Weighted_point_3& p) + { return Local_point(p);} + static Local_vector get_local_vector(const Local_kernel::Vector_2& v) + { return Local_vector(v.x(), 0, v.y()); } + static const Local_vector& get_local_vector(const Local_kernel::Vector_3& v) + { return v; } + }; + + //////////////////////////////////////////////////////////////// + // Global function to simplify function calls. + template + Local_point get_local_point(const KPoint& p) + { + return Geom_utils::Kernel>:: + get_local_point(p); + } + template + Local_vector get_local_vector(const KVector& v) + { + return Geom_utils::Kernel>:: + get_local_vector(v); + } +} // End namespace internal + +//------------------------------------------------------------------------------ +template +class Buffer_for_vao +{ +public: + Buffer_for_vao(std::vector* pos=NULL, + std::vector* indices=NULL, + CGAL::Bbox_3* bbox=NULL, + std::vector* color=NULL, + std::vector* flat_normal=NULL, + std::vector* gouraud_normal=NULL) : + m_pos_buffer(pos), + m_index_buffer(indices), + m_color_buffer(color), + m_flat_normal_buffer(flat_normal), + m_gouraud_normal_buffer(gouraud_normal), + m_bb(bbox), + m_face_started(false) + {} + + void clear() + { + if (m_pos_buffer!=NULL) { m_pos_buffer->clear(); } + if (m_color_buffer!=NULL) { m_color_buffer->clear(); } + if (m_index_buffer!=NULL) { m_index_buffer->clear(); } + if (m_flat_normal_buffer!=NULL) { m_flat_normal_buffer->clear(); } + if (m_gouraud_normal_buffer!=NULL) { m_gouraud_normal_buffer->clear(); } + } + + bool is_empty() const + { + return + (m_pos_buffer!=NULL && m_pos_buffer->empty()) && + (m_color_buffer!=NULL || m_color_buffer->empty()) && + (m_flat_normal_buffer!=NULL || m_flat_normal_buffer->empty()) && + (m_gouraud_normal_buffer!=NULL || m_gouraud_normal_buffer->empty()) && + (m_index_buffer!=NULL || m_index_buffer->empty()); + } + + bool has_position() const + { return m_pos_buffer!=NULL; } + + bool has_indices() const + { return m_index_buffer!=NULL; } + + bool has_color() const + { return m_color_buffer!=NULL; } + + bool has_flat_normal() const + { return m_flat_normal_buffer!=NULL; } + + bool has_gouraud_normal() const + { return m_gouraud_normal_buffer!=NULL; } + + // 1.1) Add a point, without color. Return the index of the added point. + template + std::size_t add_point(const KPoint& kp) + { + if (!has_position()) return (std::size_t)-1; + + Local_point p=internal::get_local_point(kp); + add_point_in_buffer(p, *m_pos_buffer); + + if (m_bb!=NULL) + { (*m_bb)=(*m_bb)+p.bbox(); } + + return m_pos_buffer->size()-3; + } + + // 1.2) Add a point, with color. + template + void add_point(const KPoint& kp, const CGAL::Color& c) + { + add_point(kp); + add_color(c); + } + + // 1.3) Add an indexed point, without color. + template + void add_indexed_point(T index) + { + if (!has_indices()) return; + m_index_buffer->push_back((IndexType)index); + } + + // 2.1) Add a segment, without color. + template + void add_segment(const KPoint& kp1, const KPoint& kp2) + { + add_point(kp1); + add_point(kp2); + } + + // 2.2) Add a segment, with color. + template + void add_segment(const KPoint& kp1, const KPoint& kp2, const CGAL::Color& c) + { + add_segment(kp1, kp2); + add_color(c); + add_color(c); + } + + // 2.3) Add an indexed segment, without color. + template + void add_indexed_segment(T index1, T index2) + { + add_indexed_point(index1); + add_indexed_point(index2); + } + + /// @return true iff a face has begun. + bool is_a_face_started() const + { return m_face_started; } + + // 3.1) Add a face, without color, without normal. + void face_begin() + { face_begin_internal(false, false); } + + // 3.2) Add a face, with a color, without normal. + void face_begin(const CGAL::Color& c) + { + m_color_of_face=c; + face_begin_internal(true, false); + } + + // 3.3) Add a face, without a color, with a normal. + template + void face_begin(const KNormal& kv) + { + m_normal_of_face=internal::get_local_vector(kv); + face_begin_internal(false, true); + } + + // 3.3) Add a face, with a color and with a normal. + template + void face_begin(const CGAL::Color& c, const KNormal& kv) + { + m_color_of_face=c; + m_normal_of_face=internal::get_local_vector(kv); + face_begin_internal(true, true); + } + + /// Add a point at the end of the current face, without giving the vertex normal. + /// When this method is used, it is not possible to use the Gouraud shading. + /// @param p the point to add + template + bool add_point_in_face(const KPoint& kp) + { + if (!is_a_face_started()) return false; + + Local_point p=internal::get_local_point(kp); + if (m_points_of_face.empty() || m_points_of_face.back()!=p) // TODO test if the distance between prev point and kp is smaller than an epsilon (?? not sure ??) + { + m_points_of_face.push_back(p); + return true; + } + return false; + } + + /// Add a point at the end of the current face + /// @param p the point to add + /// @p_normal the vertex normal at this point (for Gouraud shading) + template + bool add_point_in_face(const KPoint& kp, const KVector& p_normal) + { + if (add_point_in_face(kp)) + { + m_vertex_normals_for_face.push_back(internal::get_local_vector(p_normal)); + return true; + } + return false; + } + + /// Add an indexed point at the end of the current face, without giving the vertex normal. + /// When Indexation is used, it is not possible to use flat shading or multiple colors + /// for face sor edges. + /// Note that we still need the point itself, in order to triangulate the face when necessary. + template + bool add_indexed_point_in_face(T index, const KPoint& kp) + { + if (add_point_in_face(kp)) + { + m_indices_of_points_of_face.push_back(index); + return true; + } + return false; + } + + /// End the face: compute the triangulation. + void face_end() + { + if (!is_a_face_started()) return; + + if (m_points_of_face.size()<3) + { + std::cerr<<"PB: you try to triangulate a face with "<0 && + m_indices_of_points_of_face.size()!=m_points_of_face.size()) + { + std::cerr<<"PB: you mixed some add_point_in_face(...) and some add_indexed_point_in_face(...)" + <<" for a same face. Indices for this face are ignored."<0 && + m_vertex_normals_for_face.size()!=m_points_of_face.size()) + { + std::cerr<<"PB: you only gave some vertex normals (and not all) for a same face. " + <<"All vertex normal are ignored and thus it is not possible to use Gouraud " + <<"shading for this face." + < 4 vertices + } + else + { // Non convex and more than 3 points: we triangulate + nonconvex_face_end_internal(normal); + } + + m_face_started=false; + } + + /// adds `kp` coordinates to `buffer` + template + static void add_point_in_buffer(const KPoint& kp, std::vector& buffer) + { + Local_point p=internal::get_local_point(kp); + buffer.push_back(p.x()); + buffer.push_back(p.y()); + buffer.push_back(p.z()); + } + + /// adds `kv` coordinates to `buffer` + template + static void add_normal_in_buffer(const KVector& kv, std::vector& buffer) + { + Local_vector n=internal::get_local_vector(kv); + buffer.push_back(n.x()); + buffer.push_back(n.y()); + buffer.push_back(n.z()); + } + + ///adds `acolor` RGB components to `buffer` + static void add_color_in_buffer(const CGAL::Color& acolor, std::vector& buffer) + { + buffer.push_back((float)acolor.red()/(float)255); + buffer.push_back((float)acolor.green()/(float)255); + buffer.push_back((float)acolor.blue()/(float)255); + } + + /// @return true iff the points of 'facet' form a convex face + static bool is_facet_convex(const std::vector& facet, + const Local_vector& normal) + { + Local_kernel::Orientation orientation, local_orientation; + std::size_t id=0; + do + { + const Local_point& S=facet[id]; + const Local_point& T=facet[(id+1==facet.size())?0:id+1]; + Local_vector V1=Local_vector((T-S).x(), (T-S).y(), (T-S).z()); + + const Local_point& U=facet[(id+2==facet.size())?0:id+2]; + Local_vector V2=Local_vector((U-T).x(), (U-T).y(), (U-T).z()); + + orientation = Local_kernel::Orientation_3()(V1, V2, normal); + // Is it possible that orientation==COPLANAR ? Maybe if V1 or V2 is very small ? + } + while(++id!=facet.size() && + (orientation==CGAL::COPLANAR || orientation==CGAL::ZERO)); + + //Here, all orientations were COPLANAR. Not sure this case is possible, + // but we stop here. + if (orientation==CGAL::COPLANAR || orientation==CGAL::ZERO) + { return false; } + + // Now we compute convexness + for(id=0; id0) + { + add_indexed_point(m_indices_of_points_of_face[i]); + } + else + { + add_point(m_points_of_face[i]); // Add the position of the point + if (m_started_face_is_colored) + { add_color(m_color_of_face); } // Add the color + add_flat_normal(normal); // Add the flat normal + // Its smooth normal (if given by the user) + if (m_vertex_normals_for_face.size()>0) + { // Here we have 3 vertex normals; we can use Gouraud + add_gouraud_normal(m_vertex_normals_for_face[i]); + } + else + { // Here user does not provide all vertex normals: we use face normal istead + // and thus we will not be able to use Gouraud + add_gouraud_normal(normal); + } + } + } + } + + void convex_quadrangular_face_end_internal(const Local_vector& normal) + { + // Add indices when they exist + if (m_indices_of_points_of_face.size()>0) + { + add_indexed_point(m_indices_of_points_of_face[0]); + add_indexed_point(m_indices_of_points_of_face[1]); + add_indexed_point(m_indices_of_points_of_face[2]); + + add_indexed_point(m_indices_of_points_of_face[0]); + add_indexed_point(m_indices_of_points_of_face[2]); + add_indexed_point(m_indices_of_points_of_face[3]); + } + else + { + // (1) add points + add_point(m_points_of_face[0]); + add_point(m_points_of_face[1]); + add_point(m_points_of_face[2]); + + add_point(m_points_of_face[0]); + add_point(m_points_of_face[2]); + add_point(m_points_of_face[3]); + + // (2) Add flat and smooth normals and color + for(unsigned int i=0; i<6; ++i) + { + if (m_started_face_is_colored) + { add_color(m_color_of_face); } + + add_flat_normal(normal); + + if (m_vertex_normals_for_face.size()==0) + { add_gouraud_normal(normal); } + } + + if (m_vertex_normals_for_face.size()>0) + { + add_gouraud_normal(m_vertex_normals_for_face[0]); + add_gouraud_normal(m_vertex_normals_for_face[1]); + add_gouraud_normal(m_vertex_normals_for_face[2]); + + add_gouraud_normal(m_vertex_normals_for_face[0]); + add_gouraud_normal(m_vertex_normals_for_face[2]); + add_gouraud_normal(m_vertex_normals_for_face[3]); + } + } + } + + void convex_face_end_internal(const Local_vector& normal) + { + for(std::size_t i=1; i0) + { + add_indexed_point(m_indices_of_points_of_face[0]); + add_indexed_point(m_indices_of_points_of_face[i]); + add_indexed_point(m_indices_of_points_of_face[i+1]); + } + else + { + Local_point& p0 = m_points_of_face[0]; + Local_point& p1 = m_points_of_face[i]; + Local_point& p2 = m_points_of_face[i+1]; + + // (1) add points + add_point(p0); + add_point(p1); + add_point(p2); + + // (2) Add flat normal and color + for(unsigned int j=0; j<3; ++j) + { + if (m_started_face_is_colored) + { add_color(m_color_of_face); } + + add_flat_normal(normal); + + if (m_vertex_normals_for_face.size()==0) + { add_gouraud_normal(normal); } // No smooth normal, we use the flat one instead + } + + // (3) Add smooth normals if they exist + if (m_vertex_normals_for_face.size()>0) + { + add_gouraud_normal(m_vertex_normals_for_face[0]); + add_gouraud_normal(m_vertex_normals_for_face[i]); + add_gouraud_normal(m_vertex_normals_for_face[i+1]); + } + } + } + } + + void nonconvex_face_end_internal(const Local_vector& normal) + { + try + { + P_traits cdt_traits(normal); + CDT cdt(cdt_traits); + + bool with_vertex_normal=(m_vertex_normals_for_face.size()==m_points_of_face.size()); + + // (1) We insert all the edges as contraint in the CDT. + typename CDT::Vertex_handle previous=NULL, first=NULL; + for (unsigned int i=0; iinfo().v=m_vertex_normals_for_face[i]; } + else + { vh->info().v=normal; } + + if (m_indices_of_points_of_face.size()>0) + { vh->info().index=m_indices_of_points_of_face[i]; } + + 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 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) + { + // Add indices when they exist + if (m_indices_of_points_of_face.size()>0) + { add_indexed_point(ffit->vertex(i)->info().index); } + else + { + // (1) add point + add_point(ffit->vertex(i)->point()); + // (2) Add face color + if (m_started_face_is_colored) + { add_color(m_color_of_face); } + + // (3) Add flat normal + add_flat_normal(normal); + + // (4) Add smooth normals (or flat if smooth normals do not exist) + add_gouraud_normal(ffit->vertex(i)->info().v); + } + } + } + } + } + catch(...) + { // Triangulation crash: the face is not filled + std::cerr<<"Catch: face not filled."< + void add_flat_normal(const KVector& kv) + { + if(m_flat_normal_buffer != NULL) + { add_normal_in_buffer(kv, *m_flat_normal_buffer); } + } + + template + void add_gouraud_normal(const KVector& kv) + { + if(m_gouraud_normal_buffer != NULL) + { add_normal_in_buffer(kv, *m_gouraud_normal_buffer); } + } + +protected: + // Types usefull for triangulation + struct Vertex_info + { + Local_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 P_traits; + typedef CGAL::Triangulation_vertex_base_with_info_2 Vb; + typedef CGAL::Triangulation_face_base_with_info_2 Fb1; + typedef CGAL::Constrained_triangulation_face_base_2 Fb; + typedef CGAL::Triangulation_data_structure_2 TDS; + typedef CGAL::Exact_predicates_tag Itag; + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; + +protected: + std::vector* m_pos_buffer; + std::vector* m_index_buffer; + std::vector* m_color_buffer; + std::vector* m_flat_normal_buffer; + std::vector* m_gouraud_normal_buffer; + + CGAL::Bbox_3* m_bb; + + // Local variables, used when we started a new face. + bool m_face_started; + bool m_started_face_is_colored; + bool m_started_face_has_normal; + std::vector m_points_of_face; + std::vector m_vertex_normals_for_face; + std::vector m_indices_of_points_of_face; + CGAL::Color m_color_of_face; + Local_vector m_normal_of_face; +}; + +} // End namespace CGAL + +#endif // CGAL_VBO_BUFFER_FILLER_H diff --git a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h new file mode 100644 index 00000000000..dcf9168521d --- /dev/null +++ b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h @@ -0,0 +1,1081 @@ +// Copyright (c) 2018 GeometryFactory Sarl (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_BASIC_VIEWER_QT_H +#define CGAL_BASIC_VIEWER_QT_H + +#include +#include + +#ifdef CGAL_USE_BASIC_VIEWER + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace CGAL +{ + +//------------------------------------------------------------------------------ +const char vertex_source_color[] = + { + "#version 120 \n" + "attribute highp vec4 vertex;\n" + "attribute highp vec3 normal;\n" + "attribute highp vec3 color;\n" + + "uniform highp mat4 mvp_matrix;\n" + "uniform highp mat4 mv_matrix; \n" + + "varying highp vec4 fP; \n" + "varying highp vec3 fN; \n" + "varying highp vec4 fColor; \n" + "void main(void)\n" + "{\n" + " fP = mv_matrix * vertex; \n" + " fN = mat3(mv_matrix)* normal; \n" + " fColor = vec4(color, 1.0); \n" + " gl_Position = mvp_matrix * vertex;\n" + "}" + }; + +const char fragment_source_color[] = + { + "#version 120 \n" + "varying highp vec4 fP; \n" + "varying highp vec3 fN; \n" + "varying highp vec4 fColor; \n" + "uniform vec4 light_pos; \n" + "uniform vec4 light_diff; \n" + "uniform vec4 light_spec; \n" + "uniform vec4 light_amb; \n" + "uniform float spec_power ; \n" + + "void main(void) { \n" + + " vec3 L = light_pos.xyz - fP.xyz; \n" + " vec3 V = -fP.xyz; \n" + + " vec3 N = normalize(fN); \n" + " L = normalize(L); \n" + " V = normalize(V); \n" + + " vec3 R = reflect(-L, N); \n" + " vec4 diffuse = max(dot(N,L), 0.0) * light_diff * fColor; \n" + " vec4 specular = pow(max(dot(R,V), 0.0), spec_power) * light_spec; \n" + + "gl_FragColor = light_amb*fColor + diffuse ; \n" + "} \n" + "\n" + }; + +const char vertex_source_p_l[] = + { + "#version 120 \n" + "attribute highp vec4 vertex;\n" + "attribute highp vec3 color;\n" + "uniform highp mat4 mvp_matrix;\n" + "varying highp vec4 fColor; \n" + "void main(void)\n" + "{\n" + " fColor = vec4(color, 1.0); \n" + " gl_Position = mvp_matrix * vertex;\n" + "}" + }; + +const char fragment_source_p_l[] = + { + "#version 120 \n" + "varying highp vec4 fColor; \n" + "void main(void) { \n" + "gl_FragColor = fColor; \n" + "} \n" + "\n" + }; +//------------------------------------------------------------------------------ +inline CGAL::Color get_random_color(CGAL::Random& random) +{ + CGAL::Color res; + do + { + res=CGAL::Color(random.get_int(0,256), + random.get_int(0,256), + random.get_int(0,256)); + } + while(res.red()==255 && res.green()==255 && res.blue()==255); + return res; +} +//------------------------------------------------------------------------------ +class Basic_viewer_qt : public CGAL::QGLViewer +{ + typedef CGAL::Exact_predicates_inexact_constructions_kernel Local_kernel; + typedef Local_kernel::Point_3 Local_point; + typedef Local_kernel::Vector_3 Local_vector; + +public: + // Constructor/Destructor + Basic_viewer_qt(QWidget* parent, + const char* title="", + bool draw_vertices=false, + bool draw_edges=true, + bool draw_faces=true, + bool use_mono_color=false, + bool inverse_normal=false) : + CGAL::QGLViewer(parent), + m_draw_vertices(draw_vertices), + m_draw_edges(draw_edges), + m_draw_faces(draw_faces), + m_flatShading(true), + m_use_mono_color(use_mono_color), + m_inverse_normal(inverse_normal), + m_size_points(7.), + m_size_edges(3.1), + m_vertices_mono_color(200, 60, 60), + m_edges_mono_color(0, 0, 0), + m_faces_mono_color(60, 60, 200), + m_ambient_color(0.6f, 0.5f, 0.5f, 0.5f), + m_are_buffers_initialized(false), + m_buffer_for_mono_points(&arrays[POS_MONO_POINTS], + NULL, + &m_bounding_box, + NULL, NULL, NULL), + m_buffer_for_colored_points(&arrays[POS_COLORED_POINTS], + NULL, + &m_bounding_box, + &arrays[COLOR_POINTS], + NULL, NULL), + m_buffer_for_mono_segments(&arrays[POS_MONO_SEGMENTS], + NULL, + &m_bounding_box, + NULL, NULL, NULL), + m_buffer_for_colored_segments(&arrays[POS_COLORED_SEGMENTS], + NULL, + &m_bounding_box, + &arrays[COLOR_SEGMENTS], + NULL, NULL), + m_buffer_for_mono_faces(&arrays[POS_MONO_FACES], + NULL, + &m_bounding_box, + NULL, + &arrays[FLAT_NORMAL_MONO_FACES], + &arrays[SMOOTH_NORMAL_MONO_FACES]), + m_buffer_for_colored_faces(&arrays[POS_COLORED_FACES], + NULL, + &m_bounding_box, + &arrays[COLOR_FACES], + &arrays[FLAT_NORMAL_COLORED_FACES], + &arrays[SMOOTH_NORMAL_COLORED_FACES]) + { + if (title[0]==0) + setWindowTitle("CGAL Basic Viewer"); + else + setWindowTitle(title); + + resize(500, 450); + } + + ~Basic_viewer_qt() + { + for (unsigned int i=0; i + void add_point(const KPoint& p) + { m_buffer_for_mono_points.add_point(p); } + + template + void add_point(const KPoint& p, const CGAL::Color& acolor) + { m_buffer_for_colored_points.add_point(p, acolor); } + + template + void add_segment(const KPoint& p1, const KPoint& p2) + { m_buffer_for_mono_segments.add_segment(p1, p2); } + + template + void add_segment(const KPoint& p1, const KPoint& p2, + const CGAL::Color& acolor) + { m_buffer_for_colored_segments.add_segment(p1, p2, acolor); } + + bool is_a_face_started() const + { + return m_buffer_for_mono_faces.is_a_face_started() || + m_buffer_for_colored_faces.is_a_face_started(); + } + + void face_begin() + { + if (is_a_face_started()) + { + std::cerr<<"You cannot start a new face before to finish the previous one."< + bool add_point_in_face(const KPoint& kp) + { + if (m_buffer_for_mono_faces.is_a_face_started()) + { return m_buffer_for_mono_faces.add_point_in_face(kp); } + else if (m_buffer_for_colored_faces.is_a_face_started()) + { return m_buffer_for_colored_faces.add_point_in_face(kp); } + return false; + } + + template + bool add_point_in_face(const KPoint& kp, const KVector& p_normal) + { + if (m_buffer_for_mono_faces.is_a_face_started()) + { return m_buffer_for_mono_faces.add_point_in_face(kp, p_normal); } + else if (m_buffer_for_colored_faces.is_a_face_started()) + { return m_buffer_for_colored_faces.add_point_in_face(kp, p_normal); } + return false; + } + + void face_end() + { + if (m_buffer_for_mono_faces.is_a_face_started()) + { m_buffer_for_mono_faces.face_end(); } + else if (m_buffer_for_colored_faces.is_a_face_started()) + { return m_buffer_for_colored_faces.face_end(); } + } + +protected: + void compile_shaders() + { + rendering_program_face.removeAllShaders(); + rendering_program_p_l.removeAllShaders(); + + // Create the buffers + for (unsigned int i=0; icompileSourceCode(vertex_source_p_l)) + { std::cerr<<"Compiling vertex source FAILED"<compileSourceCode(fragment_source_p_l)) + { std::cerr<<"Compiling fragmentsource FAILED"<compileSourceCode(vertex_source_color)) + { std::cerr<<"Compiling vertex source FAILED"<compileSourceCode(fragment_source_color)) + { std::cerr<<"Compiling fragmentsource FAILED"<(arrays[POS_MONO_POINTS].size()*sizeof(float))); + rendering_program_p_l.enableAttributeArray("vertex"); + rendering_program_p_l.setAttributeBuffer("vertex",GL_FLOAT,0,3); + + buffers[bufn].release(); + + rendering_program_p_l.disableAttributeArray("color"); + + vao[VAO_MONO_POINTS].release(); + + // 1.2) Color points + vao[VAO_COLORED_POINTS].bind(); + + ++bufn; + assert(bufn(arrays[POS_COLORED_POINTS].size()*sizeof(float))); + rendering_program_p_l.enableAttributeArray("vertex"); + rendering_program_p_l.setAttributeBuffer("vertex",GL_FLOAT,0,3); + buffers[bufn].release(); + + ++bufn; + assert(bufn(arrays[COLOR_POINTS].size()*sizeof(float))); + rendering_program_p_l.enableAttributeArray("color"); + rendering_program_p_l.setAttributeBuffer("color",GL_FLOAT,0,3); + buffers[bufn].release(); + + vao[VAO_COLORED_POINTS].release(); + + // 2) SEGMENT SHADER + + // 2.1) Mono segments + vao[VAO_MONO_SEGMENTS].bind(); + + ++bufn; + assert(bufn(arrays[POS_MONO_SEGMENTS].size()*sizeof(float))); + rendering_program_p_l.enableAttributeArray("vertex"); + rendering_program_p_l.setAttributeBuffer("vertex",GL_FLOAT,0,3); + + buffers[bufn].release(); + + rendering_program_p_l.disableAttributeArray("color"); + + vao[VAO_MONO_SEGMENTS].release(); + + // 1.2) Color segments + vao[VAO_COLORED_SEGMENTS].bind(); + + ++bufn; + assert(bufn(arrays[POS_COLORED_SEGMENTS].size()*sizeof(float))); + rendering_program_p_l.enableAttributeArray("vertex"); + rendering_program_p_l.setAttributeBuffer("vertex",GL_FLOAT,0,3); + + buffers[bufn].release(); + + ++bufn; + assert(bufn(arrays[COLOR_SEGMENTS].size()*sizeof(float))); + rendering_program_p_l.enableAttributeArray("color"); + rendering_program_p_l.setAttributeBuffer("color",GL_FLOAT,0,3); + buffers[bufn].release(); + + vao[VAO_COLORED_SEGMENTS].release(); + + rendering_program_p_l.release(); + + // 3) FACE SHADER + rendering_program_face.bind(); + + // 3.1) Mono faces + vao[VAO_MONO_FACES].bind(); + + // 3.1.1) points of the mono faces + ++bufn; + assert(bufn(arrays[POS_MONO_FACES].size()*sizeof(float))); + rendering_program_face.enableAttributeArray("vertex"); + rendering_program_face.setAttributeBuffer("vertex",GL_FLOAT,0,3); + + buffers[bufn].release(); + + // 3.1.2) normals of the mono faces + ++bufn; + assert(bufn(arrays[FLAT_NORMAL_MONO_FACES].size()* + sizeof(float))); + } + else + { + buffers[bufn].allocate(arrays[SMOOTH_NORMAL_MONO_FACES].data(), + static_cast(arrays[SMOOTH_NORMAL_MONO_FACES].size()* + sizeof(float))); + } + rendering_program_face.enableAttributeArray("normal"); + rendering_program_face.setAttributeBuffer("normal",GL_FLOAT,0,3); + + buffers[bufn].release(); + + // 3.1.3) color of the mono faces + rendering_program_face.disableAttributeArray("color"); + vao[VAO_MONO_FACES].release(); + + // 3.2) Color faces + vao[VAO_COLORED_FACES].bind(); + + // 3.2.1) points of the color faces + ++bufn; + assert(bufn(arrays[POS_COLORED_FACES].size()*sizeof(float))); + rendering_program_face.enableAttributeArray("vertex"); + rendering_program_face.setAttributeBuffer("vertex",GL_FLOAT,0,3); + + buffers[bufn].release(); + + // 3.2.2) normals of the color faces + ++bufn; + assert(bufn(arrays[FLAT_NORMAL_COLORED_FACES].size()* + sizeof(float))); + } + else + { + buffers[bufn].allocate(arrays[SMOOTH_NORMAL_COLORED_FACES].data(), + static_cast(arrays[SMOOTH_NORMAL_COLORED_FACES].size()* + sizeof(float))); + } + rendering_program_face.enableAttributeArray("normal"); + rendering_program_face.setAttributeBuffer("normal",GL_FLOAT,0,3); + + buffers[bufn].release(); + + // 3.2.3) colors of the faces + ++bufn; + assert(bufn(arrays[COLOR_FACES].size()*sizeof(float))); + rendering_program_face.enableAttributeArray("color"); + rendering_program_face.setAttributeBuffer("color",GL_FLOAT,0,3); + + buffers[bufn].release(); + + vao[VAO_COLORED_FACES].release(); + + rendering_program_face.release(); + + m_are_buffers_initialized = true; + } + + void attrib_buffers(CGAL::QGLViewer* viewer) + { + QMatrix4x4 mvpMatrix; + QMatrix4x4 mvMatrix; + double mat[16]; + viewer->camera()->getModelViewProjectionMatrix(mat); + for(int i=0; i < 16; i++) + { + mvpMatrix.data()[i] = (float)mat[i]; + } + viewer->camera()->getModelViewMatrix(mat); + for(int i=0; i < 16; i++) + { + mvMatrix.data()[i] = (float)mat[i]; + } + // define material + QVector4D diffuse( 0.9f, + 0.9f, + 0.9f, + 0.9f ); + + QVector4D specular( 0.0f, + 0.0f, + 0.0f, + 1.0f ); + + CGAL::Bbox_3 bb; + if (bb==bounding_box()) // Case of "empty" bounding box + { + bb=Local_point(CGAL::ORIGIN).bbox(); + bb=bb + Local_point(1,1,1).bbox(); // To avoid a warning from Qglviewer + } + else + { bb=bounding_box(); } + + QVector4D position((bb.xmax()-bb.xmin())/2, + (bb.ymax()-bb.ymin())/2, + bb.zmax(), 0.0); + GLfloat shininess = 1.0f; + + rendering_program_face.bind(); + int mvpLocation = rendering_program_face.uniformLocation("mvp_matrix"); + int mvLocation = rendering_program_face.uniformLocation("mv_matrix"); + int lightLocation[5]; + lightLocation[0] = rendering_program_face.uniformLocation("light_pos"); + lightLocation[1] = rendering_program_face.uniformLocation("light_diff"); + lightLocation[2] = rendering_program_face.uniformLocation("light_spec"); + lightLocation[3] = rendering_program_face.uniformLocation("light_amb"); + lightLocation[4] = rendering_program_face.uniformLocation("spec_power"); + + rendering_program_face.setUniformValue(lightLocation[0], position); + rendering_program_face.setUniformValue(lightLocation[1], diffuse); + rendering_program_face.setUniformValue(lightLocation[2], specular); + rendering_program_face.setUniformValue(lightLocation[3], m_ambient_color); + rendering_program_face.setUniformValue(lightLocation[4], shininess); + rendering_program_face.setUniformValue(mvpLocation, mvpMatrix); + rendering_program_face.setUniformValue(mvLocation, mvMatrix); + rendering_program_face.release(); + + rendering_program_p_l.bind(); + int mvpLocation2 = rendering_program_p_l.uniformLocation("mvp_matrix"); + rendering_program_p_l.setUniformValue(mvpLocation2, mvpMatrix); + rendering_program_p_l.release(); + } + + virtual void draw() + { + glEnable(GL_DEPTH_TEST); + if(!m_are_buffers_initialized) + { initialize_buffers(); } + + QColor color; + attrib_buffers(this); + + if(m_draw_vertices) + { + rendering_program_p_l.bind(); + + vao[VAO_MONO_POINTS].bind(); + color.setRgbF((double)m_vertices_mono_color.red()/(double)255, + (double)m_vertices_mono_color.green()/(double)255, + (double)m_vertices_mono_color.blue()/(double)255); + rendering_program_p_l.setAttributeValue("color",color); + glPointSize(m_size_points); + glDrawArrays(GL_POINTS, 0, static_cast(arrays[POS_MONO_POINTS].size()/3)); + vao[VAO_MONO_POINTS].release(); + + vao[VAO_COLORED_POINTS].bind(); + if (m_use_mono_color) + { + color.setRgbF((double)m_vertices_mono_color.red()/(double)255, + (double)m_vertices_mono_color.green()/(double)255, + (double)m_vertices_mono_color.blue()/(double)255); + rendering_program_p_l.disableAttributeArray("color"); + rendering_program_p_l.setAttributeValue("color",color); + } + else + { + rendering_program_p_l.enableAttributeArray("color"); + } + glPointSize(m_size_points); + glDrawArrays(GL_POINTS, 0, static_cast(arrays[POS_COLORED_POINTS].size()/3)); + vao[VAO_COLORED_POINTS].release(); + + rendering_program_p_l.release(); + } + + if(m_draw_edges) + { + rendering_program_p_l.bind(); + + vao[VAO_MONO_SEGMENTS].bind(); + color.setRgbF((double)m_edges_mono_color.red()/(double)255, + (double)m_edges_mono_color.green()/(double)255, + (double)m_edges_mono_color.blue()/(double)255); + rendering_program_p_l.setAttributeValue("color",color); + glLineWidth(m_size_edges); + glDrawArrays(GL_LINES, 0, static_cast(arrays[POS_MONO_SEGMENTS].size()/3)); + vao[VAO_MONO_SEGMENTS].release(); + + vao[VAO_COLORED_SEGMENTS].bind(); + if (m_use_mono_color) + { + color.setRgbF((double)m_edges_mono_color.red()/(double)255, + (double)m_edges_mono_color.green()/(double)255, + (double)m_edges_mono_color.blue()/(double)255); + rendering_program_p_l.disableAttributeArray("color"); + rendering_program_p_l.setAttributeValue("color",color); + } + else + { + rendering_program_p_l.enableAttributeArray("color"); + } + glLineWidth(m_size_edges); + glDrawArrays(GL_LINES, 0, static_cast(arrays[POS_COLORED_SEGMENTS].size()/3)); + vao[VAO_COLORED_SEGMENTS].release(); + + rendering_program_p_l.release(); + } + + if (m_draw_faces) + { + rendering_program_face.bind(); + + vao[VAO_MONO_FACES].bind(); + color.setRgbF((double)m_faces_mono_color.red()/(double)255, + (double)m_faces_mono_color.green()/(double)255, + (double)m_faces_mono_color.blue()/(double)255); + rendering_program_face.setAttributeValue("color",color); + glDrawArrays(GL_TRIANGLES, 0, static_cast(arrays[POS_MONO_FACES].size()/3)); + vao[VAO_MONO_FACES].release(); + + vao[VAO_COLORED_FACES].bind(); + if (m_use_mono_color) + { + color.setRgbF((double)m_faces_mono_color.red()/(double)255, + (double)m_faces_mono_color.green()/(double)255, + (double)m_faces_mono_color.blue()/(double)255); + rendering_program_face.disableAttributeArray("color"); + rendering_program_face.setAttributeValue("color",color); + } + else + { + rendering_program_face.enableAttributeArray("color"); + } + glDrawArrays(GL_TRIANGLES, 0, static_cast(arrays[POS_COLORED_FACES].size()/3)); + vao[VAO_COLORED_FACES].release(); + + rendering_program_face.release(); + } + } + + virtual void redraw() + { + initialize_buffers(); + update(); + } + + virtual void init() + { + // Restore previous viewer state. + restoreStateFromFile(); + initializeOpenGLFunctions(); + + // Define 'Control+Q' as the new exit shortcut (default was 'Escape') + setShortcut(qglviewer::EXIT_VIEWER, ::Qt::CTRL+::Qt::Key_Q); + + // Add custom key description (see keyPressEvent). + setKeyDescription(::Qt::Key_E, "Toggles edges display"); + setKeyDescription(::Qt::Key_F, "Toggles faces display"); + setKeyDescription(::Qt::Key_G, "Switch between flat/Gouraud shading display"); + setKeyDescription(::Qt::Key_M, "Toggles mono color for all faces"); + setKeyDescription(::Qt::Key_N, "Inverse direction of normals"); + setKeyDescription(::Qt::Key_V, "Toggles vertices display"); + setKeyDescription(::Qt::Key_Plus, "Increase size of edges"); + setKeyDescription(::Qt::Key_Minus, "Decrease size of edges"); + setKeyDescription(::Qt::Key_Plus+::Qt::ControlModifier, "Increase size of vertices"); + setKeyDescription(::Qt::Key_Minus+::Qt::ControlModifier, "Decrease size of vertices"); + setKeyDescription(::Qt::Key_PageDown, "Increase light (all colors, use shift/alt/ctrl for one rgb component)"); + setKeyDescription(::Qt::Key_PageUp, "Decrease light (all colors, use shift/alt/ctrl for one rgb component)"); + + // Light default parameters + glLineWidth(m_size_edges); + glPointSize(m_size_points); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.f,1.f); + glClearColor(1.0f,1.0f,1.0f,0.0f); + glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + glEnable(GL_LIGHTING); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); + glShadeModel(GL_FLAT); + glDisable(GL_BLEND); + glEnable(GL_LINE_SMOOTH); + glDisable(GL_POLYGON_SMOOTH_HINT); + glBlendFunc(GL_ONE, GL_ZERO); + glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST); + + compile_shaders(); + + CGAL::Bbox_3 bb; + if (bb==bounding_box()) // Case of "empty" bounding box + { + bb=Local_point(CGAL::ORIGIN).bbox(); + bb=bb + Local_point(1,1,1).bbox(); // To avoid a warning from Qglviewer + } + else + { bb=bounding_box(); } + this->camera()->setSceneBoundingBox(CGAL::qglviewer::Vec(bb.xmin(), + bb.ymin(), + bb.zmin()), + CGAL::qglviewer::Vec(bb.xmax(), + bb.ymax(), + bb.zmax())); + + this->showEntireScene(); + } + + void negate_all_normals() + { + for (unsigned int k=BEGIN_NORMAL; kmodifiers(); + + if ((e->key()==::Qt::Key_E) && (modifiers==::Qt::NoButton)) + { + m_draw_edges=!m_draw_edges; + displayMessage(QString("Draw edges=%1.").arg(m_draw_edges?"true":"false")); + update(); + } + else if ((e->key()==::Qt::Key_F) && (modifiers==::Qt::NoButton)) + { + m_draw_faces=!m_draw_faces; + displayMessage(QString("Draw faces=%1.").arg(m_draw_faces?"true":"false")); + update(); + } + else if ((e->key()==::Qt::Key_G) && (modifiers==::Qt::NoButton)) + { + m_flatShading=!m_flatShading; + if (m_flatShading) + displayMessage("Flat shading."); + else + displayMessage("Gouraud shading."); + redraw(); + } + else if ((e->key()==::Qt::Key_M) && (modifiers==::Qt::NoButton)) + { + m_use_mono_color=!m_use_mono_color; + displayMessage(QString("Mono color=%1.").arg(m_use_mono_color?"true":"false")); + update(); + } + else if ((e->key()==::Qt::Key_N) && (modifiers==::Qt::NoButton)) + { + m_inverse_normal=!m_inverse_normal; + displayMessage(QString("Inverse normal=%1.").arg(m_inverse_normal?"true":"false")); + negate_all_normals(); + redraw(); + } + else if ((e->key()==::Qt::Key_V) && (modifiers==::Qt::NoButton)) + { + m_draw_vertices=!m_draw_vertices; + displayMessage(QString("Draw vertices=%1.").arg(m_draw_vertices?"true":"false")); + update(); + } + else if ((e->key()==::Qt::Key_Plus) && (!modifiers.testFlag(::Qt::ControlModifier))) // No ctrl + { + m_size_edges+=.5; + displayMessage(QString("Size of edges=%1.").arg(m_size_edges)); + update(); + } + else if ((e->key()==::Qt::Key_Minus) && (!modifiers.testFlag(::Qt::ControlModifier))) // No ctrl + { + if (m_size_edges>.5) m_size_edges-=.5; + displayMessage(QString("Size of edges=%1.").arg(m_size_edges)); + update(); + } + else if ((e->key()==::Qt::Key_Plus) && (modifiers.testFlag(::Qt::ControlModifier))) + { + m_size_points+=.5; + displayMessage(QString("Size of points=%1.").arg(m_size_points)); + update(); + } + else if ((e->key()==::Qt::Key_Minus) && (modifiers.testFlag(::Qt::ControlModifier))) + { + if (m_size_points>.5) m_size_points-=.5; + displayMessage(QString("Size of points=%1.").arg(m_size_points)); + update(); + } + else if ((e->key()==::Qt::Key_PageUp) && (modifiers==::Qt::NoButton)) + { + m_ambient_color.setX(m_ambient_color.x()+.1); + if (m_ambient_color.x()>1.) m_ambient_color.setX(1.); + m_ambient_color.setY(m_ambient_color.x()+.1); + if (m_ambient_color.y()>1.) m_ambient_color.setY(1.); + m_ambient_color.setZ(m_ambient_color.x()+.1); + if (m_ambient_color.z()>1.) m_ambient_color.setZ(1.); + displayMessage(QString("Light color=(%1 %2 %3)."). + arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); + update(); + } + else if ((e->key()==::Qt::Key_PageDown) && (modifiers==::Qt::NoButton)) + { + m_ambient_color.setX(m_ambient_color.x()-.1); + if (m_ambient_color.x()<0.) m_ambient_color.setX(0.); + m_ambient_color.setY(m_ambient_color.y()-.1); + if (m_ambient_color.y()<0.) m_ambient_color.setY(0.); + m_ambient_color.setZ(m_ambient_color.z()-.1); + if (m_ambient_color.z()<0.) m_ambient_color.setZ(0.); + displayMessage(QString("Light color=(%1 %2 %3)."). + arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); + update(); + } + else if ((e->key()==::Qt::Key_PageUp) && (modifiers==::Qt::ShiftModifier)) + { + m_ambient_color.setX(m_ambient_color.x()+.1); + if (m_ambient_color.x()>1.) m_ambient_color.setX(1.); + displayMessage(QString("Light color=(%1 %2 %3)."). + arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); + update(); + } + else if ((e->key()==::Qt::Key_PageUp) && (modifiers==::Qt::AltModifier)) + { + m_ambient_color.setY(m_ambient_color.y()+.1); + if (m_ambient_color.y()>1.) m_ambient_color.setY(1.); + displayMessage(QString("Light color=(%1 %2 %3)."). + arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); + update(); + } + else if ((e->key()==::Qt::Key_PageUp) && (modifiers==::Qt::ControlModifier)) + { + m_ambient_color.setZ(m_ambient_color.z()+.1); + if (m_ambient_color.z()>1.) m_ambient_color.setZ(1.); + displayMessage(QString("Light color=(%1 %2 %3)."). + arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); + update(); + } + else if ((e->key()==::Qt::Key_PageDown) && (modifiers==::Qt::ShiftModifier)) + { + m_ambient_color.setX(m_ambient_color.x()-.1); + if (m_ambient_color.x()<0.) m_ambient_color.setX(0.); + displayMessage(QString("Light color=(%1 %2 %3)."). + arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); + update(); + } + else if ((e->key()==::Qt::Key_PageDown) && (modifiers==::Qt::AltModifier)) + { + m_ambient_color.setY(m_ambient_color.y()-.1); + if (m_ambient_color.y()<0.) m_ambient_color.setY(0.); + displayMessage(QString("Light color=(%1 %2 %3)."). + arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); + update(); + } + else if ((e->key()==::Qt::Key_PageDown) && (modifiers==::Qt::ControlModifier)) + { + m_ambient_color.setZ(m_ambient_color.z()-.1); + if (m_ambient_color.z()<0.) m_ambient_color.setZ(0.); + displayMessage(QString("Light color=(%1 %2 %3)."). + arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); + update(); + } + else + CGAL::QGLViewer::keyPressEvent(e); + } + + virtual QString helpString() const + { + QString text("

C G A L B a s i c V i e w e r

"); + text += "Use the mouse to move the camera around the object. "; + text += "You can respectively revolve around, zoom and translate with " + "the three mouse buttons. "; + text += "Left and middle buttons pressed together rotate around the " + "camera view direction axis

"; + text += "Pressing Alt and one of the function keys " + "(F1..F12) defines a camera keyFrame. "; + text += "Simply press the function key again to restore it. " + "Several keyFrames define a "; + text += "camera path. Paths are saved when you quit the application " + "and restored at next start.

"; + text += "Press F to display the frame rate, A for the " + "world axis, "; + text += "Alt+Return for full screen mode and Control+S " + "to save a snapshot. "; + text += "See the Keyboard tab in this window for a complete " + "shortcut list.

"; + text += "Double clicks automates single click actions: A left button " + "double click aligns the closer axis with the camera (if close enough). "; + text += "A middle button double click fits the zoom of the camera and " + "the right button re-centers the scene.

"; + text += "A left button double click while holding right button pressed " + "defines the camera Revolve Around Point. "; + text += "See the Mouse tab and the documentation web pages for " + "details.

"; + text += "Press Escape to exit the viewer."; + return text; + } + +private: + bool m_draw_vertices; + bool m_draw_edges; + bool m_draw_faces; + bool m_flatShading; + bool m_use_mono_color; + bool m_inverse_normal; + + double m_size_points; + double m_size_edges; + + CGAL::Color m_vertices_mono_color; + CGAL::Color m_edges_mono_color; + CGAL::Color m_faces_mono_color; + QVector4D m_ambient_color; + + bool m_are_buffers_initialized; + CGAL::Bbox_3 m_bounding_box; + + // The following enum gives the indices of different elements of arrays vectors. + enum + { + BEGIN_POS=0, + POS_MONO_POINTS=BEGIN_POS, + POS_COLORED_POINTS, + POS_MONO_SEGMENTS, + POS_COLORED_SEGMENTS, + POS_MONO_FACES, + POS_COLORED_FACES, + END_POS, + BEGIN_COLOR=END_POS, + COLOR_POINTS=BEGIN_COLOR, + COLOR_SEGMENTS, + COLOR_FACES, + END_COLOR, + BEGIN_NORMAL=END_COLOR, + SMOOTH_NORMAL_MONO_FACES=BEGIN_NORMAL, + FLAT_NORMAL_MONO_FACES, + SMOOTH_NORMAL_COLORED_FACES, + FLAT_NORMAL_COLORED_FACES, + END_NORMAL, + LAST_INDEX=END_NORMAL + }; + std::vector arrays[LAST_INDEX]; + + Buffer_for_vao m_buffer_for_mono_points; + Buffer_for_vao m_buffer_for_colored_points; + Buffer_for_vao m_buffer_for_mono_segments; + Buffer_for_vao m_buffer_for_colored_segments; + Buffer_for_vao m_buffer_for_mono_faces; + Buffer_for_vao m_buffer_for_colored_faces; + + static const unsigned int NB_VBO_BUFFERS=(END_POS-BEGIN_POS)+ + (END_COLOR-BEGIN_COLOR)+2; // +2 for 2 vectors of normals + + QGLBuffer buffers[NB_VBO_BUFFERS]; + + // The following enum gives the indices of the differents vao. + enum + { VAO_MONO_POINTS=0, + VAO_COLORED_POINTS, + VAO_MONO_SEGMENTS, + VAO_COLORED_SEGMENTS, + VAO_MONO_FACES, + VAO_COLORED_FACES, + NB_VAO_BUFFERS + }; + QOpenGLVertexArrayObject vao[NB_VAO_BUFFERS]; + + QOpenGLShaderProgram rendering_program_face; + QOpenGLShaderProgram rendering_program_p_l; +}; + +} // End namespace CGAL + +#else // CGAL_USE_BASIC_VIEWER + +namespace CGAL +{ + +template +void draw(const T&, const char*, bool, const ColorFunctor&) +{ + std::cerr<<"Impossible to draw because CGAL_USE_BASIC_VIEWER is not defined." + < +void draw(const T&, const char*, bool) +{ + std::cerr<<"Impossible to draw because CGAL_USE_BASIC_VIEWER is not defined." + < +void draw(const T&, const char*) +{ + std::cerr<<"Impossible to draw because CGAL_USE_BASIC_VIEWER is not defined." + < +void draw(const T&) +{ + std::cerr<<"Impossible to draw because CGAL_USE_BASIC_VIEWER is not defined." + < +void draw(const LCC& alcc); + +} /* namespace CGAL */ + diff --git a/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt b/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt index 0f00181c9a7..30e3be293e6 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt @@ -241,7 +241,7 @@ point: 1 0 0, color: 19 Before applying the sew operation, the eight vertices of the first cube are colored by `1`, and the eight vertices of the second cube by `19`. After the sew operation, there are eight vertices which are merged two by two, and due to the average functor, the color of the four resulting vertices is now 10. Then we insert a vertex in the center of the common 2-cell between the two cubes. The coordinates of this vertex are initialized with the barycenter of the 2-cell (-1,0.5,0.5), and its color is not initialized by the method, thus we set its color manually by using the result of \link LinearCellComplex::insert_barycenter_in_cell `insert_barycenter_in_cell<2>`\endlink which is a dart incident to the new vertex. -\subsection Linear_cell_complexAutomaticAttributesManagement Automatic attributes management +\subsection Linear_cell_complexAutomaticAttributesManagement Automatic Attribute Management \anchor ssecAttributesManagement The following example illustrates the use of the automatic attributes management for a linear cell complex. An off file is loaded into a 2D linear cell complex embedded in 3D. Then, a certain percentage of edges is removed from the linear cell complex. The same method is applied twice: the first time by using the automatic attributes management (which is the default behaviour) and the second time by calling first \link GenericMap::set_automatic_attributes_management `set_automatic_attributes_management(false)`\endlink to disable the automatic updating of attributes. @@ -250,6 +250,19 @@ We can observe that the second run is faster than the first one. Indeed, updatin \cgalExample{Linear_cell_complex/linear_cell_complex_3_attributes_management.cpp} +\subsection Linear_cell_complexDraw Draw a Linear Cell Complex +\anchor ssecDrawLCC + +A linear cell complex can be visualized by calling the `CGAL::draw()` function as shown in the following example. This function opens a new window showing the given linear cell complex. The function is blocking, that is the program continues as soon as the user closes the window. + +\cgalExample{Linear_cell_complex/draw_linear_cell_complex.cpp} + +This function requires CGAL_Qt5, and is only available if the flag CGAL_USE_BASIC_VIEWER is defined at compile time. + +\cgalFigureBegin{fig_draw_lcc,draw_lcc.png} +Result of the run of the draw_linear_cell_complex program. A window shows two 3D cubes and allows to navigate through the 3D scene. +\cgalFigureEnd + \section Linear_cell_complexDesign Design and Implementation History This package was developed by Guillaume Damiand, with the help of Andreas Fabri, Sébastien Loriot and Laurent Rineau. Monique Teillaud and Bernd Gärtner contributed to the manual. diff --git a/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt b/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt index 4d9a112c79a..8eb6f42e7dc 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt @@ -19,6 +19,14 @@ /// \defgroup PkgLinearCellComplexOperations Operations for Linear Cell Complex /// \ingroup PkgLinearCellComplex +/*! Draw. + \code + #include + \endcode +*/ +/// \defgroup PkgDrawLinearCellComplex Draw a Linear Cell Complex +/// \ingroup PkgLinearCellComplex + /*! \addtogroup PkgLinearCellComplex @@ -57,14 +65,17 @@ - `CGAL::Linear_cell_complex` ## Global Functions ## -### Constructions for Linear cell complex ### +### Constructions for Linear Cell Complex ### - `CGAL::import_from_plane_graph` - `CGAL::import_from_triangulation_3` - `CGAL::import_from_polyhedron_3` -### Operations for Linear cell complex ### +### Operations for Linear Cell Complex ### - `CGAL::compute_normal_of_cell_0` - `CGAL::compute_normal_of_cell_2` +### Draw a Linear cell complex ### +- `CGAL::draw` + */ diff --git a/Linear_cell_complex/doc/Linear_cell_complex/examples.txt b/Linear_cell_complex/doc/Linear_cell_complex/examples.txt index 081c08d5da3..f41e9b41af0 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/examples.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/examples.txt @@ -3,4 +3,5 @@ \example Linear_cell_complex/linear_cell_complex_3.cpp \example Linear_cell_complex/linear_cell_complex_4.cpp \example Linear_cell_complex/linear_cell_complex_3_attributes_management.cpp +\example Linear_cell_complex/draw_linear_cell_complex.cpp */ diff --git a/Linear_cell_complex/doc/Linear_cell_complex/fig/draw_lcc.png b/Linear_cell_complex/doc/Linear_cell_complex/fig/draw_lcc.png new file mode 100644 index 00000000000..5ae0ccbb570 Binary files /dev/null and b/Linear_cell_complex/doc/Linear_cell_complex/fig/draw_lcc.png differ diff --git a/Linear_cell_complex/examples/Linear_cell_complex/CMakeBasicViewerQt.inc b/Linear_cell_complex/examples/Linear_cell_complex/CMakeBasicViewerQt.inc deleted file mode 100644 index 5dd94c1e7f9..00000000000 --- a/Linear_cell_complex/examples/Linear_cell_complex/CMakeBasicViewerQt.inc +++ /dev/null @@ -1,33 +0,0 @@ -# This file must be included in your CMakeLists.txt to use the basic viewer -# You need to link the libraries in your executable by using -# TARGET_LINK_LIBRARIES( myexec ${BASIC_VIEWER_LIBRARIES}) - -if ( NOT CGAL_FOUND OR NOT CGAL_Qt5_FOUND) - message(STATUS "NOTICE: Libraries for basic viewer not found " - "(CGAL, Qt5, QGLViewer).") -endif( NOT CGAL_FOUND OR NOT CGAL_Qt5_FOUND) - -include( ${CGAL_USE_FILE} ) -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -FIND_PACKAGE(Qt5 REQUIRED COMPONENTS OpenGL Xml) -find_package(QGLViewer REQUIRED) -find_package(OpenGL REQUIRED) - -add_definitions(${QT_DEFINITIONS}) -add_definitions(-DQT_NO_KEYWORDS) - -include_directories( ${QGLVIEWER_INCLUDE_DIR} ) -add_definitions(${QGLVIEWER_DEFINITIONS}) - -set (BASIC_VIEWER_LIBRARIES ${QT_LIBRARIES} ${QGLVIEWER_LIBRARIES} - ${OPENGL_gl_LIBRARY}) # ${OPENGL_glu_LIBRARY} - -set(BASIC_VIEWER_MODULES Xml OpenGL) - -ADD_DEFINITIONS("-DCGAL_USE_BASIC_VIEWER") -message(STATUS "Libraries for lcc_viewer found. You need to link them " - "in your executable by using " - "TARGET_LINK_LIBRARIES( myexec \${BASIC_VIEWER_LIBRARIES})") - -set(USE_BASIC_VIEWER true) diff --git a/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt b/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt index 0d26a50dbff..9c0372c277d 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt +++ b/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt @@ -9,14 +9,11 @@ if(NOT POLICY CMP0070 AND POLICY CMP0053) cmake_policy(SET CMP0053 OLD) endif() -# If you want to visualize a linear cell complex, you can use the following viewer -# based on qt. Just uncomment the following two lines, plus the lines qt5_use_modules below +find_package(CGAL COMPONENTS Qt5) -# find_package(CGAL COMPONENTS Qt5) -# include("CMakeBasicViewerQt.inc") - -# If you don't want to visualize, use the following line (otherwise comment it) -find_package(CGAL QUIET) +if(CGAL_Qt5_FOUND) + add_definitions(-DCGAL_USE_BASIC_VIEWER -DQT_NO_KEYWORDS) +endif() # For Gprof. # ADD_DEFINITIONS("-pg") @@ -25,50 +22,31 @@ find_package(CGAL QUIET) # To use valgrind, we must disable rounding math ckeck. # add_definition(-DCGAL_DISABLE_ROUNDING_MATH_CHECK) -if ( CGAL_FOUND ) +if (CGAL_FOUND) include( ${CGAL_USE_FILE} ) - include( CGAL_CreateSingleSourceCGALProgram ) + include(CGAL_CreateSingleSourceCGALProgram) include_directories(BEFORE ../../include) - create_single_source_cgal_program( "linear_cell_complex_3.cpp" ) - create_single_source_cgal_program( "linear_cell_complex_4.cpp" ) - create_single_source_cgal_program( - "linear_cell_complex_3_with_colored_vertices.cpp" ) - create_single_source_cgal_program( - "linear_cell_complex_3_with_mypoint.cpp" ) - - create_single_source_cgal_program("plane_graph_to_lcc_2.cpp") + create_single_source_cgal_program("gmap_linear_cell_complex_3.cpp") + create_single_source_cgal_program("linear_cell_complex_3.cpp") create_single_source_cgal_program("linear_cell_complex_3_attributes_management.cpp") + create_single_source_cgal_program("linear_cell_complex_3_operations.cpp") + create_single_source_cgal_program("linear_cell_complex_3_with_colored_vertices.cpp") + create_single_source_cgal_program("linear_cell_complex_3_with_mypoint.cpp") + create_single_source_cgal_program("linear_cell_complex_4.cpp") + create_single_source_cgal_program("plane_graph_to_lcc_2.cpp") + create_single_source_cgal_program("voronoi_2.cpp") + create_single_source_cgal_program("voronoi_3.cpp") - add_executable(voronoi_2 voronoi_2.cpp) - target_link_libraries(voronoi_2 ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} - ${BASIC_VIEWER_LIBRARIES}) - if (USE_BASIC_VIEWER) - qt5_use_modules(voronoi_2 ${BASIC_VIEWER_MODULES}) - endif(USE_BASIC_VIEWER) + create_single_source_cgal_program("draw_linear_cell_complex.cpp") + if(CGAL_Qt5_FOUND) + target_link_libraries(draw_linear_cell_complex PUBLIC CGAL::CGAL_Qt5) + endif() - add_executable(voronoi_3 voronoi_3.cpp) - target_link_libraries(voronoi_3 ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} - ${BASIC_VIEWER_LIBRARIES}) - - if (USE_BASIC_VIEWER) - qt5_use_modules(voronoi_3 ${BASIC_VIEWER_MODULES}) - endif(USE_BASIC_VIEWER) - - create_single_source_cgal_program( "gmap_linear_cell_complex_3.cpp" ) - - add_executable(linear_cell_complex_3_operations linear_cell_complex_3_operations.cpp) - target_link_libraries(linear_cell_complex_3_operations ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} - ${BASIC_VIEWER_LIBRARIES}) - if (USE_BASIC_VIEWER) - qt5_use_modules(linear_cell_complex_3_operations ${BASIC_VIEWER_MODULES}) - endif(USE_BASIC_VIEWER) - else() - message(STATUS "This program requires the CGAL library, " - "and will not be compiled.") + message(STATUS "This program requires the CGAL library, and will not be compiled.") endif() diff --git a/Linear_cell_complex/examples/Linear_cell_complex/draw_linear_cell_complex.cpp b/Linear_cell_complex/examples/Linear_cell_complex/draw_linear_cell_complex.cpp new file mode 100644 index 00000000000..7888bba129d --- /dev/null +++ b/Linear_cell_complex/examples/Linear_cell_complex/draw_linear_cell_complex.cpp @@ -0,0 +1,29 @@ +#include +#include + +typedef CGAL::Linear_cell_complex_for_combinatorial_map<3> LCC; +typedef LCC::Dart_handle Dart_handle; +typedef LCC::Point Point; + +int main() +{ + LCC lcc; + Dart_handle dh1= + lcc.make_hexahedron(Point(0,0,0), Point(5,0,0), + Point(5,5,0), Point(0,5,0), + Point(0,5,4), Point(0,0,4), + Point(5,0,4), Point(5,5,4)); + Dart_handle dh2= + lcc.make_hexahedron(Point(5,0,0), Point(10,0,0), + Point(10,5,0), Point(5,5,0), + Point(5,5,4), Point(5,0,4), + Point(10,0,4), Point(10,5,4)); + + lcc.sew<3>(lcc.beta(dh1, 1, 1, 2), lcc.beta(dh2, 2)); + + lcc.display_characteristics(std::cout)<<", valid=" + < #include -/* If you want to use a viewer, you can use qglviewer. */ -#ifdef CGAL_USE_BASIC_VIEWER -#include "linear_cell_complex_3_viewer_qt.h" -#endif - typedef CGAL::Linear_cell_complex_for_combinatorial_map<3> LCC_3_cmap; typedef CGAL::Linear_cell_complex_for_generalized_map<3> LCC_3_gmap; @@ -54,10 +49,6 @@ void run_test() lcc.template sew<3>(lcc.template opposite<2>(lcc.next(dh1)), lcc.other_orientation(lcc.template opposite<2>(lcc.previous(dh3)))); -#ifdef CGAL_USE_BASIC_VIEWER - display_lcc(lcc); -#endif // CGAL_USE_BASIC_VIEWER - lcc.insert_cell_1_in_cell_2(lcc.next(dh1), Alpha1::run(lcc, lcc.previous(dh1))); dh2=lcc.template opposite<2>(lcc.next(lcc.next @@ -73,14 +64,9 @@ void run_test() lcc.insert_cell_2_in_cell_3(path.begin(),path.end()); lcc.display_characteristics(std::cout) << ", valid=" - << lcc.is_valid() << std::endl; - -#ifdef CGAL_USE_BASIC_VIEWER - display_lcc(lcc); -#endif // CGAL_USE_BASIC_VIEWER + << lcc.is_valid() << std::endl; } - int main() { run_test(); diff --git a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_viewer_qt.h b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_viewer_qt.h deleted file mode 100644 index 4e6d5e37077..00000000000 --- a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_viewer_qt.h +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright (c) 2011 CNRS and LIRIS' Establishments (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 Lesser 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: LGPL-3.0+ -// -// Author(s) : Guillaume Damiand - -#ifndef CGAL_LCC_3_VIEWER_QT_H -#define CGAL_LCC_3_VIEWER_QT_H - -#include "basic_viewer.h" -#include -#include -#include - -typedef CGAL::Exact_predicates_inexact_constructions_kernel Local_kernel; -typedef Local_kernel::Point_3 Local_point; -typedef Local_kernel::Vector_3 Local_vector; - -// Default color functor; user can change it to have its own face color -struct DefaultColorFunctor -{ - template - static CGAL::Color run(const LCC& alcc, - typename LCC::Dart_const_handle dh) - { - if (dh==alcc.null_handle) // use to get the mono color - return CGAL::Color(100, 125, 200); // R G B between 0-255 - - // Here dh is the smaller dart of its face - CGAL::Random random(alcc.darts().index(dh)); - CGAL::Color res; - do - { - res=CGAL::Color(random.get_int(0,256), - random.get_int(0,256), - random.get_int(0,256)); - } - while(res.red()==255 && res.green()==255 && res.blue()==255); - return res; - } -}; - -template -struct Geom_utils; - -template -struct Geom_utils -{ - Local_point get_point(const LCC& lcc, - typename LCC::Vertex_attribute_const_handle vh) - { return converter(lcc.point_of_vertex_attribute(vh)); } - - Local_point get_point(const LCC& lcc, typename LCC::Dart_const_handle dh) - { return converter(lcc.point(dh)); } - - Local_vector get_vertex_normal(const LCC& lcc, - typename LCC::Dart_const_handle dh) - { - Local_vector n = converter(CGAL::compute_normal_of_cell_0(lcc,dh)); - n = n/(CGAL::sqrt(n*n)); - return n; - } -protected: - CGAL::Cartesian_converter converter; -}; - -template -struct Geom_utils -{ - Local_point get_point(const LCC& lcc, - typename LCC::Vertex_attribute_const_handle vh) - { - Local_point p(converter(lcc.point_of_vertex_attribute(vh).x()),0, - converter(lcc.point_of_vertex_attribute(vh).y())); - return p; - } - - Local_point get_point(const LCC& lcc, typename LCC::Dart_const_handle dh) - { return get_point(lcc, lcc.vertex_attribute(dh)); } - - Local_vector get_vertex_normal(const LCC&, typename LCC::Dart_const_handle) - { - Local_vector n(0,-1,0); - return n; - } -protected: - CGAL::Cartesian_converter converter; -}; - -// Viewer class for LCC -template -class SimpleLCCViewerQt : public Basic_viewer -{ - typedef Basic_viewer Base; - typedef typename LCC::Dart_const_handle Dart_const_handle; - -public: - /// Construct the viewer. - /// @param alcc the lcc 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 LCC where this time could be long) - SimpleLCCViewerQt(const LCC& alcc, const char* title="", bool anofaces=false) : - Base(title), - lcc(alcc), - m_nofaces(anofaces) - { - compute_elements(); - } - -protected: - - 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(lcc, it, markfaces); - } - - if ( !lcc.is_marked(it, markedges) ) - { - compute_edge(it); - CGAL::mark_cell(lcc, it, markedges); - } - - if ( !lcc.is_marked(it, markvertices) ) - { - compute_vertex(it, empty); - CGAL::mark_cell(lcc, it, markvertices); - } - } - - lcc.free_mark(markfaces); - lcc.free_mark(markedges); - lcc.free_mark(markvertices); - } - - virtual void keyPressEvent(QKeyEvent *e) - { - const Qt::KeyboardModifiers modifiers = e->modifiers(); - Base::keyPressEvent(e); - } - -protected: - const LCC& lcc; - bool m_nofaces; - Geom_utils geomutils; -}; - - -template -void display_lcc(const LCC& alcc, - const char* title="", - bool nofill=false) -{ - int argc=1; - - const char* argv[2]={"lccviewer","\0"}; - QApplication app(argc,const_cast(argv)); - - SimpleLCCViewerQt mainwindow(alcc, title, nofill); - mainwindow.show(); - - app.exec(); -} - -#endif // CGAL_LCC_3_VIEWER_QT_H diff --git a/Linear_cell_complex/examples/Linear_cell_complex/voronoi_2.cpp b/Linear_cell_complex/examples/Linear_cell_complex/voronoi_2.cpp index 43ac93a3327..64fe08e3b42 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/voronoi_2.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/voronoi_2.cpp @@ -6,10 +6,6 @@ #include #include -/* If you want to use a viewer, you can use qglviewer. */ -#ifdef CGAL_USE_BASIC_VIEWER -#include "linear_cell_complex_3_viewer_qt.h" -#endif // This example works both with cmap and gmap as combinatorial data structure. //typedef CGAL::Linear_cell_complex_for_combinatorial_map<2> LCC_2; @@ -56,10 +52,6 @@ void display_voronoi(LCC_2& alcc, Dart_handle adart) alcc.display_characteristics(std::cout) << ", valid=" << alcc.is_valid() << std::endl; - -#ifdef CGAL_USE_BASIC_VIEWER - display_lcc(alcc); -#endif // CGAL_USE_BASIC_VIEWER } template diff --git a/Linear_cell_complex/examples/Linear_cell_complex/voronoi_3.cpp b/Linear_cell_complex/examples/Linear_cell_complex/voronoi_3.cpp index 28bf93b0f12..30f94107b00 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/voronoi_3.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/voronoi_3.cpp @@ -5,11 +5,6 @@ #include #include -/* If you want to use a viewer, you can use one qglviewer. */ -#ifdef CGAL_USE_BASIC_VIEWER -#include "linear_cell_complex_3_viewer_qt.h" -#endif - /* // If you want to use exact constructions. #include typedef CGAL::Linear_cell_complex<3,3, @@ -59,10 +54,6 @@ void display_voronoi(LCC_3& alcc, Dart_handle adart) alcc.display_characteristics(std::cout) << ", valid=" << alcc.is_valid() << std::endl; - -#ifdef CGAL_USE_BASIC_VIEWER - display_lcc(alcc); -#endif // CGAL_USE_BASIC_VIEWER } template diff --git a/Linear_cell_complex/include/CGAL/draw_linear_cell_complex.h b/Linear_cell_complex/include/CGAL/draw_linear_cell_complex.h new file mode 100644 index 00000000000..e792b745282 --- /dev/null +++ b/Linear_cell_complex/include/CGAL/draw_linear_cell_complex.h @@ -0,0 +1,247 @@ +// Copyright (c) 2018 CNRS and LIRIS' Establishments (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 Lesser 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: LGPL-3.0+ +// +// Author(s) : Guillaume Damiand + +#ifndef CGAL_DRAW_LCC_H +#define CGAL_DRAW_LCC_H + +#include + +#ifdef CGAL_USE_BASIC_VIEWER + +#include + +namespace CGAL +{ + +// Default color functor; user can change it to have its own face color +struct DefaultColorFunctorLCC +{ + template + static CGAL::Color run(const LCC& alcc, + typename LCC::Dart_const_handle dh) + { + if (dh==alcc.null_handle) // use to get the mono color + return CGAL::Color(100, 125, 200); // R G B between 0-255 + + CGAL::Random random((unsigned int)(alcc.darts().index(dh))); + return get_random_color(random); + } +}; + +template +struct Geom_utils; + +template +struct Geom_utils +{ + static typename LCC::Vector get_vertex_normal(const LCC& lcc, + typename LCC::Dart_const_handle dh) + { + typename LCC::Vector n = CGAL::compute_normal_of_cell_0(lcc,dh); + n = n/(CGAL::sqrt(n*n)); + return n; + } +}; + +template +struct Geom_utils +{ + static typename LCC::Vector get_vertex_normal(const LCC&, + typename LCC::Dart_const_handle) + { + typename LCC::Vector res=CGAL::NULL_VECTOR; + return res; + } +}; + +// Viewer class for LCC +template +class SimpleLCCViewerQt : public Basic_viewer_qt +{ + typedef Basic_viewer_qt Base; + typedef typename LCC::Dart_const_handle Dart_const_handle; + typedef typename LCC::Traits Kernel; + typedef typename Kernel::Point Point; + typedef typename Kernel::Vector Vector; + +public: + /// Construct the viewer. + /// @param alcc the lcc 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) + SimpleLCCViewerQt(QWidget* parent, + const LCC& alcc, + const char* title="Basic LCC Viewer", + bool anofaces=false, + const ColorFunctor& fcolor=ColorFunctor()) : + // First draw: vertices; edges, faces; multi-color; inverse normal + Base(parent, title, true, true, true, false, true), + lcc(alcc), + m_nofaces(anofaces), + m_fcolor(fcolor) + { + compute_elements(); + } + +protected: + 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::get_vertex_normal(lcc, cur)); + cur=lcc.next(cur); + } + while(cur!=dh); + + face_end(); + } + + void compute_edge(Dart_const_handle dh) + { + Point p1 = lcc.point(dh); + Dart_const_handle d2 = lcc.other_extremity(dh); + if (d2!=NULL) + { add_segment(p1, lcc.point(d2)); } + } + + void compute_vertex(Dart_const_handle dh) + { add_point(lcc.point(dh)); } + + void compute_elements() + { + clear(); + + typename LCC::size_type markfaces = lcc.get_new_mark(); + typename LCC::size_type markedges = lcc.get_new_mark(); + typename LCC::size_type markvertices = lcc.get_new_mark(); + + for (typename LCC::Dart_range::const_iterator it=lcc.darts().begin(), + itend=lcc.darts().end(); it!=itend; ++it ) + { + if ( !m_nofaces && !lcc.is_marked(it, markfaces) ) + { + compute_face(it); + CGAL::mark_cell(lcc, it, markfaces); + } + + if ( !lcc.is_marked(it, markedges) ) + { + compute_edge(it); + CGAL::mark_cell(lcc, it, markedges); + } + + if ( !lcc.is_marked(it, markvertices) ) + { + compute_vertex(it); + CGAL::mark_cell(lcc, it, markvertices); + } + } + + lcc.free_mark(markfaces); + lcc.free_mark(markedges); + lcc.free_mark(markvertices); + } + + 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: + const LCC& lcc; + bool m_nofaces; + const ColorFunctor& m_fcolor; +}; + +template +void draw(const LCC& alcc, + const char* title, + bool nofill, + const ColorFunctor& fcolor) +{ +#if defined(CGAL_TEST_SUITE) + bool cgal_test_suite=true; +#else + bool cgal_test_suite=false; +#endif + + if (!cgal_test_suite) + { + int argc=1; + const char* argv[2]={"lccviewer","\0"}; + QApplication app(argc,const_cast(argv)); + SimpleLCCViewerQt mainwindow(app.activeWindow(), + alcc, + title, + nofill, + fcolor); + mainwindow.show(); + app.exec(); + } +} + +template +void draw(const LCC& alcc, const char* title, bool nofill) +{ + DefaultColorFunctorLCC c; + draw(alcc, title, nofill, c); +} + +template +void draw(const LCC& alcc, const char* title) +{ draw(alcc, title, false); } + +template +void draw(const LCC& alcc) +{ draw(alcc, "Basic LCC Viewer"); } + +} // End namespace CGAL + +#endif // CGAL_USE_BASIC_VIEWER + +#endif // CGAL_DRAW_LCC_H diff --git a/Linear_cell_complex/package_info/Linear_cell_complex/dependencies b/Linear_cell_complex/package_info/Linear_cell_complex/dependencies index d3c90923a14..4a46d8312a8 100644 --- a/Linear_cell_complex/package_info/Linear_cell_complex/dependencies +++ b/Linear_cell_complex/package_info/Linear_cell_complex/dependencies @@ -8,6 +8,7 @@ Distance_2 Distance_3 Filtered_kernel Generalized_map +GraphicsView HalfedgeDS Hash_map Homogeneous_kernel diff --git a/Polyhedron/doc/Polyhedron/CGAL/draw_polyhedron.h b/Polyhedron/doc/Polyhedron/CGAL/draw_polyhedron.h new file mode 100644 index 00000000000..8ac1c401b79 --- /dev/null +++ b/Polyhedron/doc/Polyhedron/CGAL/draw_polyhedron.h @@ -0,0 +1,15 @@ +namespace CGAL { + +/*! +\ingroup PkgDrawPolyhedron + +Open a new window and draw `apoly`, an instance of the `CGAL::Polyhedron_3` class. The function is blocking, that is the program continues as soon as the user closes the window. This function requires CGAL_Qt5, and is only available if the flag CGAL_USE_BASIC_VIEWER is defined at compile time. +\tparam POLY an instance of the `CGAL::Polyhedron_3` class. +\param apoly the polyhedron to draw. + +*/ +template +void draw(const POLY& apoly); + +} /* namespace CGAL */ + diff --git a/Polyhedron/doc/Polyhedron/PackageDescription.txt b/Polyhedron/doc/Polyhedron/PackageDescription.txt index aa9cf8ed001..05972f40034 100644 --- a/Polyhedron/doc/Polyhedron/PackageDescription.txt +++ b/Polyhedron/doc/Polyhedron/PackageDescription.txt @@ -4,6 +4,15 @@ /// \defgroup PkgPolyhedronIOFunc I/O Functions /// \ingroup PkgPolyhedron + +/*! Draw. + \code + #include + \endcode +*/ +/// \defgroup PkgDrawPolyhedron Draw a Polyhedron 3 +/// \ingroup PkgPolyhedron + /*! \addtogroup PkgPolyhedron \todo check generated documentation @@ -62,5 +71,9 @@ surface can be used without knowing the halfedge data structure. - \link PkgPolyhedronIOFunc `CGAL::operator>>()` \endlink - \link PkgPolyhedronIOFunc `write_off()` \endlink - \link PkgPolyhedronIOFunc `read_off()` \endlink + +### Draw a Polyhedron 3 ### +- `CGAL::draw` + */ diff --git a/Polyhedron/doc/Polyhedron/Polyhedron.txt b/Polyhedron/doc/Polyhedron/Polyhedron.txt index 7e39194363e..b960089fa00 100644 --- a/Polyhedron/doc/Polyhedron/Polyhedron.txt +++ b/Polyhedron/doc/Polyhedron/Polyhedron.txt @@ -275,6 +275,19 @@ are also marked in the program code. \cgalExample{Polyhedron/polyhedron_prog_cube.cpp} +\subsection PolyhedronDraw Draw a Polyhedron +\anchor ssecDrawPolyhedron + +A polyhedron can be visualized by calling the `CGAL::draw()` function as shown in the following example. This function opens a new window showing the given polyhedron. The function is blocking, that is the program continues as soon as the user closes the window. + +\cgalExample{Polyhedron/draw_polyhedron.cpp} + +This function requires CGAL_Qt5, and is only available if the flag CGAL_USE_BASIC_VIEWER is defined at compile time. + +\cgalFigureBegin{fig_draw_polyhedron,draw_polyhedron.png} +Result of the run of the draw_polyhedron program. A window shows the polyhedron and allows to navigate through the 3D scene. +\cgalFigureEnd + \section PolyhedronFile File I/O \anchor sectionPolyIO diff --git a/Polyhedron/doc/Polyhedron/examples.txt b/Polyhedron/doc/Polyhedron/examples.txt index 8fc56694e39..e106785f37d 100644 --- a/Polyhedron/doc/Polyhedron/examples.txt +++ b/Polyhedron/doc/Polyhedron/examples.txt @@ -10,4 +10,5 @@ \example Polyhedron/polyhedron_prog_subdiv.cpp \example Polyhedron/polyhedron_prog_tetra.cpp \example Polyhedron/polyhedron_prog_vector.cpp +\example Polyhedron/draw_polyhedron.cpp */ diff --git a/Polyhedron/doc/Polyhedron/fig/draw_polyhedron.png b/Polyhedron/doc/Polyhedron/fig/draw_polyhedron.png new file mode 100644 index 00000000000..0d711aef842 Binary files /dev/null and b/Polyhedron/doc/Polyhedron/fig/draw_polyhedron.png differ diff --git a/Polyhedron/examples/Polyhedron/CMakeLists.txt b/Polyhedron/examples/Polyhedron/CMakeLists.txt index f2b82769342..d191da8a473 100644 --- a/Polyhedron/examples/Polyhedron/CMakeLists.txt +++ b/Polyhedron/examples/Polyhedron/CMakeLists.txt @@ -4,9 +4,18 @@ project( Polyhedron_Examples ) -cmake_minimum_required(VERSION 2.8.10) +cmake_minimum_required(VERSION 3.1) -find_package(CGAL QUIET) +if(NOT POLICY CMP0070 AND POLICY CMP0053) + # Only set CMP0053 to OLD with CMake<3.10, otherwise there is a warning. + cmake_policy(SET CMP0053 OLD) +endif() + +find_package(CGAL COMPONENTS Qt5) + +if(CGAL_Qt5_FOUND) + add_definitions(-DCGAL_USE_BASIC_VIEWER -DQT_NO_KEYWORDS) +endif() if ( CGAL_FOUND ) @@ -16,12 +25,17 @@ if ( CGAL_FOUND ) include_directories (BEFORE "../../include") + # create a target per cppfile file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) create_single_source_cgal_program( "${cppfile}" ) endforeach() + if(CGAL_Qt5_FOUND ) + target_link_libraries(draw_polyhedron PUBLIC CGAL::CGAL_Qt5) + endif() + else() message(STATUS "This program requires the CGAL library, and will not be compiled.") diff --git a/Polyhedron/examples/Polyhedron/corner.off b/Polyhedron/examples/Polyhedron/data/corner.off similarity index 100% rename from Polyhedron/examples/Polyhedron/corner.off rename to Polyhedron/examples/Polyhedron/data/corner.off diff --git a/Polyhedron/examples/Polyhedron/corner_with_hole.off b/Polyhedron/examples/Polyhedron/data/corner_with_hole.off similarity index 100% rename from Polyhedron/examples/Polyhedron/corner_with_hole.off rename to Polyhedron/examples/Polyhedron/data/corner_with_hole.off diff --git a/Polyhedron/examples/Polyhedron/corner_with_sharp_edge.off b/Polyhedron/examples/Polyhedron/data/corner_with_sharp_edge.off similarity index 100% rename from Polyhedron/examples/Polyhedron/corner_with_sharp_edge.off rename to Polyhedron/examples/Polyhedron/data/corner_with_sharp_edge.off diff --git a/Polyhedron/examples/Polyhedron/cross.off b/Polyhedron/examples/Polyhedron/data/cross.off similarity index 100% rename from Polyhedron/examples/Polyhedron/cross.off rename to Polyhedron/examples/Polyhedron/data/cross.off diff --git a/Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv.cin b/Polyhedron/examples/Polyhedron/data/cube.off similarity index 100% rename from Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv.cin rename to Polyhedron/examples/Polyhedron/data/cube.off diff --git a/Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv_with_boundary.cin b/Polyhedron/examples/Polyhedron/data/lshape_with_boundary.off similarity index 100% rename from Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv_with_boundary.cin rename to Polyhedron/examples/Polyhedron/data/lshape_with_boundary.off diff --git a/Polyhedron/examples/Polyhedron/polyhedron_self_intersection.cin b/Polyhedron/examples/Polyhedron/data/tetra_intersected_by_triangle.off similarity index 100% rename from Polyhedron/examples/Polyhedron/polyhedron_self_intersection.cin rename to Polyhedron/examples/Polyhedron/data/tetra_intersected_by_triangle.off diff --git a/Polyhedron/examples/Polyhedron/draw_polyhedron.cpp b/Polyhedron/examples/Polyhedron/draw_polyhedron.cpp new file mode 100644 index 00000000000..a41fc79cc02 --- /dev/null +++ b/Polyhedron/examples/Polyhedron/draw_polyhedron.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef CGAL::Polyhedron_3 Polyhedron; + +int main(int argc, char* argv[]) +{ + Polyhedron P; + std::ifstream in1((argc>1)?argv[1]:"data/cross.off"); + in1 >> P; + CGAL::draw(P); + + return EXIT_SUCCESS; +} diff --git a/Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv.cpp b/Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv.cpp index bf1104c3c3b..b7d997bcfc1 100644 --- a/Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv.cpp +++ b/Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv.cpp @@ -4,6 +4,7 @@ #include #include #include +#include typedef CGAL::Simple_cartesian Kernel; typedef Kernel::Vector_3 Vector; @@ -90,9 +91,10 @@ void subdiv( Polyhedron& P) { CGAL_postcondition( P.is_valid()); } -int main() { +int main(int argc, char* argv[]) { Polyhedron P; - std::cin >> P; + std::ifstream in1((argc>1)?argv[1]:"data/cube.off"); + in1 >> P; P.normalize_border(); if ( P.size_of_border_edges() != 0) { std::cerr << "The input object has border edges. Cannot subdivide." diff --git a/Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv_with_boundary.cpp b/Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv_with_boundary.cpp index 744440fd123..296c910239a 100644 --- a/Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv_with_boundary.cpp +++ b/Polyhedron/examples/Polyhedron/polyhedron_prog_subdiv_with_boundary.cpp @@ -6,6 +6,7 @@ #include #include #include +#include typedef CGAL::Simple_cartesian Kernel; typedef Kernel::Vector_3 Vector; @@ -172,21 +173,22 @@ void subdiv_border( Polyhedron& P) { using namespace std; int main( int argc, char* argv[]) { - if ( argc > 2 || (argc == 2 && ! isdigit( argv[1][0]))) { - cerr << "Usage: " << argv[0] << " []" << endl; - cerr << " subdivides times the polyhedron read from stdin." + if ( argc > 3 || (argc == 3 && ! isdigit( argv[2][0]))) { + cerr << "Usage: " << argv[0] << " [offfile] []]" << endl; + cerr << " subdivides times the polyhedron read from offfile." << endl; exit(1); } int n = 1; - if ( argc >= 2) - n = atoi( argv[1]); + std::ifstream in1((argc>1)?argv[1]:"data/lshape_with_boundary.off"); + if ( argc == 3) + n = atoi( argv[2]); if ( n < 1 || n > 12) { cerr << "Error: Choose reasonable value for in [1..12]" << endl; exit(1); } Polyhedron P; - cin >> P; + in1 >> P; for ( int i = 0; i != n; ++i) { cerr << "Subdivision " << i+1 << " ..." << endl; diff --git a/Polyhedron/examples/Polyhedron/polyhedron_self_intersection.cpp b/Polyhedron/examples/Polyhedron/polyhedron_self_intersection.cpp index a70ee0fd0e2..5bfc3f0ced6 100644 --- a/Polyhedron/examples/Polyhedron/polyhedron_self_intersection.cpp +++ b/Polyhedron/examples/Polyhedron/polyhedron_self_intersection.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using std::cerr; using std::endl; @@ -138,12 +139,13 @@ void intersection( const Polyhedron& P) { Intersect_facets(), std::ptrdiff_t(2000)); } -int main() { +int main(int argc, char* argv[]) { CGAL::Timer user_time; cerr << "Loading OFF file ... " << endl; user_time.start(); Polyhedron P; - cin >> P; + std::ifstream in1((argc>1)?argv[1]:"data/tetra_intersected_by_triangle.off"); + in1 >> P; cerr << "Loading OFF file : " << user_time.time() << " seconds." << endl; if ( ! P.is_pure_triangle()) { cerr << "The input object is not triangulated. Cannot intersect." @@ -155,5 +157,6 @@ int main() { intersection( P); cerr << "Intersection : " << user_time.time() << " seconds." << endl; write_off(); + return 0; } diff --git a/Polyhedron/include/CGAL/draw_polyhedron.h b/Polyhedron/include/CGAL/draw_polyhedron.h new file mode 100644 index 00000000000..b8464757097 --- /dev/null +++ b/Polyhedron/include/CGAL/draw_polyhedron.h @@ -0,0 +1,240 @@ +// Copyright (c) 2018 ETH Zurich (Switzerland). +// 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_POLYHEDRON_H +#define CGAL_DRAW_POLYHEDRON_H + +#include +#include + +#ifdef CGAL_USE_BASIC_VIEWER + +#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: + typename Kernel::Vector_3 get_face_normal(Halfedge_const_handle he) + { + typename Kernel::Vector_3 normal=CGAL::NULL_VECTOR; + Halfedge_const_handle end=he; + unsigned int nb=0; + do + { + internal::newell_single_step_3(he->vertex()->point(), + he->next()->vertex()->point(), + normal); + ++nb; + he=he->next(); + } + 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_const_handle he) + { + typename Kernel::Vector_3 normal=CGAL::NULL_VECTOR; + Halfedge_const_handle end=he; + do + { + if (!he->is_border()) + { + typename Kernel::Vector_3 n=get_face_normal(he); + normal=typename Kernel::Construct_sum_of_vectors_3()(normal, n); + } + he=he->next()->opposite(); + } + 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: + const Polyhedron& poly; + bool m_nofaces; + const ColorFunctor& m_fcolor; +}; + +template +void draw(const Polyhedron& apoly, + const char* title, + bool nofill, + const ColorFunctor& fcolor) +{ +#if defined(CGAL_TEST_SUITE) + bool cgal_test_suite=true; +#else + bool cgal_test_suite=false; +#endif + + if (!cgal_test_suite) + { + int argc=1; + const char* argv[2]={"polyhedron_viewer","\0"}; + QApplication app(argc,const_cast(argv)); + SimplePolyhedronViewerQt + mainwindow(app.activeWindow(), apoly, title, nofill, fcolor); + mainwindow.show(); + app.exec(); + } +} + +template +void draw(const Polyhedron& apoly, const char* title, bool nofill) +{ + DefaultColorFunctorPolyhedron c; + draw(apoly, title, nofill, c); +} + +template +void draw(const Polyhedron& apoly, const char* title) +{ draw(apoly, title, false); } + +template +void draw(const Polyhedron& apoly) +{ draw(apoly, "Basic Polyhedron Viewer"); } + +} // End namespace CGAL + +#endif // CGAL_USE_BASIC_VIEWER + +#endif // CGAL_DRAW_POLYHEDRON_H diff --git a/Polyhedron/package_info/Polyhedron/dependencies b/Polyhedron/package_info/Polyhedron/dependencies index 47699a9637a..70c007e409d 100644 --- a/Polyhedron/package_info/Polyhedron/dependencies +++ b/Polyhedron/package_info/Polyhedron/dependencies @@ -2,6 +2,7 @@ Algebraic_foundations BGL Circulator Distance_2 +GraphicsView HalfedgeDS Hash_map Installation diff --git a/Scripts/developer_scripts/cgal_check_dependencies.sh b/Scripts/developer_scripts/cgal_check_dependencies.sh index b3290f8a5a8..65b989a8ca2 100644 --- a/Scripts/developer_scripts/cgal_check_dependencies.sh +++ b/Scripts/developer_scripts/cgal_check_dependencies.sh @@ -57,7 +57,7 @@ echo " Checks finished" cd $CGAL_ROOT rm -r dep_check_build if [ -n "$TOTAL_RES" ]; then - echo "$TOTAL_RES" + printf "$TOTAL_RES" echo " You can run cmake with options CGAL_ENABLE_CHECK_HEADERS and CGAL_COPY_DEPENDENCIES ON, make the target packages_dependencies and commit the new dependencies files," echo " or simply manually edit the problematic files." exit 1 diff --git a/Surface_mesh/doc/Surface_mesh/PackageDescription.txt b/Surface_mesh/doc/Surface_mesh/PackageDescription.txt index 58ead2eda6c..1707c8a7a3f 100644 --- a/Surface_mesh/doc/Surface_mesh/PackageDescription.txt +++ b/Surface_mesh/doc/Surface_mesh/PackageDescription.txt @@ -1,6 +1,14 @@ /// \defgroup PkgSurface_mesh Surface Mesh Reference +/*! Draw. + \code + #include + \endcode +*/ +/// \defgroup PkgDrawSurfaceMesh Draw a Surface Mesh +/// \ingroup PkgSurface_mesh + /*! \addtogroup PkgSurface_mesh \cgalPkgDescriptionBegin{Surface Mesh,PkgSurfaceMeshSummary} @@ -31,5 +39,8 @@ and faces is much simpler and can be used at runtime and not at compile time.} - `CGAL::Surface_mesh

` +### Draw a Surface Mesh ### +- `CGAL::draw` + */ diff --git a/Surface_mesh/doc/Surface_mesh/Surface_mesh.txt b/Surface_mesh/doc/Surface_mesh/Surface_mesh.txt index 395ec2ca8b1..06b7c0dc14d 100644 --- a/Surface_mesh/doc/Surface_mesh/Surface_mesh.txt +++ b/Surface_mesh/doc/Surface_mesh/Surface_mesh.txt @@ -344,6 +344,20 @@ refering to the right vertices. \subsection SubsectionSurfaceMeshMemoryManagementExample Example \cgalExample{Surface_mesh/sm_memory.cpp} +\section SurfaceMeshDraw Draw a Surface Mesh +\anchor ssecDrawSurfaceMesh + +A surface mesh can be visualized by calling the `CGAL::draw()` function as shown in the following example. This function opens a new window showing the given surface mesh. The function is blocking, that is the program continues as soon as the user closes the window. + +\cgalExample{Surface_mesh/draw_surface_mesh.cpp} + +This function requires CGAL_Qt5, and is only available if the flag CGAL_USE_BASIC_VIEWER is defined at compile time. + +\cgalFigureBegin{fig_draw_surface_mesh,draw_surface_mesh.png} +Result of the run of the draw_surface_mesh program. A window shows the surface mesh and allows to navigate through the 3D scene. +\cgalFigureEnd + + \section sectionSurfaceMeshImplementation Implementation Details As integer type for the indices we have chosen `boost::uint32_t`. On 64 bit operating systems they diff --git a/Surface_mesh/doc/Surface_mesh/examples.txt b/Surface_mesh/doc/Surface_mesh/examples.txt index 7d76ae3218a..b19e4dfa646 100644 --- a/Surface_mesh/doc/Surface_mesh/examples.txt +++ b/Surface_mesh/doc/Surface_mesh/examples.txt @@ -10,4 +10,5 @@ \example Surface_mesh/sm_do_intersect.cpp \example Surface_mesh/sm_aabbtree.cpp @endcond +\example Surface_mesh/draw_surface_mesh.cpp */ diff --git a/Surface_mesh/doc/Surface_mesh/fig/draw_surface_mesh.png b/Surface_mesh/doc/Surface_mesh/fig/draw_surface_mesh.png new file mode 100644 index 00000000000..1c0800bfe46 Binary files /dev/null and b/Surface_mesh/doc/Surface_mesh/fig/draw_surface_mesh.png differ diff --git a/Surface_mesh/examples/Surface_mesh/CMakeLists.txt b/Surface_mesh/examples/Surface_mesh/CMakeLists.txt index cdd0587bf7f..6170d1bb2b7 100644 --- a/Surface_mesh/examples/Surface_mesh/CMakeLists.txt +++ b/Surface_mesh/examples/Surface_mesh/CMakeLists.txt @@ -6,8 +6,16 @@ project( Surface_mesh_Examples ) cmake_minimum_required(VERSION 2.8.11) +if(NOT POLICY CMP0070 AND POLICY CMP0053) + # Only set CMP0053 to OLD with CMake<3.10, otherwise there is a warning. + cmake_policy(SET CMP0053 OLD) +endif() -find_package(CGAL QUIET) +find_package(CGAL COMPONENTS Qt5) + +if(CGAL_Qt5_FOUND) + add_definitions(-DCGAL_USE_BASIC_VIEWER -DQT_NO_KEYWORDS) +endif() if ( CGAL_FOUND ) @@ -28,6 +36,11 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "sm_memory.cpp" ) create_single_source_cgal_program( "sm_properties.cpp" ) + create_single_source_cgal_program("draw_surface_mesh.cpp") + if(CGAL_Qt5_FOUND ) + target_link_libraries(draw_surface_mesh PUBLIC CGAL::CGAL_Qt5) + endif() + else() message(STATUS "This program requires the CGAL library, and will not be compiled.") diff --git a/Surface_mesh/examples/Surface_mesh/cube.off b/Surface_mesh/examples/Surface_mesh/cube.off deleted file mode 100644 index b1afa5a6858..00000000000 --- a/Surface_mesh/examples/Surface_mesh/cube.off +++ /dev/null @@ -1,22 +0,0 @@ -OFF -8 12 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 -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 -3 1 5 6 -3 2 1 6 diff --git a/Surface_mesh/examples/Surface_mesh/draw_surface_mesh.cpp b/Surface_mesh/examples/Surface_mesh/draw_surface_mesh.cpp new file mode 100644 index 00000000000..4735193c89f --- /dev/null +++ b/Surface_mesh/examples/Surface_mesh/draw_surface_mesh.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point; +typedef CGAL::Surface_mesh Mesh; + +int main(int argc, char* argv[]) +{ + Mesh sm1; + std::ifstream in1((argc>1)?argv[1]:"data/triangle.off"); + in1 >> sm1; + + CGAL::draw(sm1); + + return EXIT_SUCCESS; +} diff --git a/Surface_mesh/examples/Surface_mesh/sm_join.cpp b/Surface_mesh/examples/Surface_mesh/sm_join.cpp index c892bfc4cd9..e787eb66c70 100644 --- a/Surface_mesh/examples/Surface_mesh/sm_join.cpp +++ b/Surface_mesh/examples/Surface_mesh/sm_join.cpp @@ -36,5 +36,4 @@ int main(int argc, char* argv[]) std::cout << sm1 << std::endl; - } diff --git a/Surface_mesh/include/CGAL/draw_surface_mesh.h b/Surface_mesh/include/CGAL/draw_surface_mesh.h new file mode 100644 index 00000000000..3e5f602d94c --- /dev/null +++ b/Surface_mesh/include/CGAL/draw_surface_mesh.h @@ -0,0 +1,252 @@ +// 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_H +#define CGAL_DRAW_SURFACE_MESH_H + +#ifdef DOXYGEN_RUNNING + +/*! +\ingroup PkgDrawSurfaceMesh + +Open a new window and draw `asm`, an instance of the `CGAL::Surface_mesh` class. The function is blocking, that is the program continues as soon as the user closes the window. This function requires CGAL_Qt5, and is only available if the flag CGAL_USE_BASIC_VIEWER is defined at compile time. +\tparam SM an instance of the `CGAL::Surface_mesh` class. +\param asm the surface mesh to draw. + +*/ +template +void draw(const SM& asm); + +#else // DOXYGEN_RUNNING + +#include +#include + +#ifdef CGAL_USE_BASIC_VIEWER + +#include + +namespace CGAL +{ + +// Default color functor; user can change it to have its own face color +struct DefaultColorFunctorSM +{ + template + static CGAL::Color run(const SM&, + typename SM::Face_index 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)fh); + return get_random_color(random); + } +}; + +template +class SimpleSurfaceMeshViewerQt : public Basic_viewer_qt +{ + typedef 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; + +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) + SimpleSurfaceMeshViewerQt(QWidget* parent, + const SM& amesh, + const char* title="Basic Surface_mesh 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), + sm(amesh), + m_nofaces(anofaces), + m_fcolor(fcolor) + { + compute_elements(); + } + +protected: + void compute_face(face_descriptor fh) + { + CGAL::Color c=m_fcolor.run(sm, fh); + 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(); + } + + void compute_edge(edge_descriptor e) + { + add_segment(sm.point(sm.source(sm.halfedge(e))), + sm.point(sm.target(sm.halfedge(e)))); + } + + void compute_vertex(vertex_descriptor vh) + { add_point(sm.point(vh)); } + + void compute_elements() + { + clear(); + + if (!m_nofaces) + { + for (typename SM::Face_range::iterator f=sm.faces().begin(); + f!=sm.faces().end(); ++f) + { + if (*f!=boost::graph_traits::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); } + } + + 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: + 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 + { + 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: + const SM& sm; + bool m_nofaces; + const ColorFunctor& m_fcolor; +}; + +template +void draw(const SM& amesh, + const char* title, + bool nofill, + const ColorFunctor& fcolor) +{ +#if defined(CGAL_TEST_SUITE) + bool cgal_test_suite=true; +#else + bool cgal_test_suite=false; +#endif + + if (!cgal_test_suite) + { + int argc=1; + const char* argv[2]={"surface_mesh_viewer","\0"}; + QApplication app(argc,const_cast(argv)); + SimpleSurfaceMeshViewerQt mainwindow(app.activeWindow(), + amesh, + title, + nofill, + fcolor); + mainwindow.show(); + app.exec(); + } +} + +template +void draw(const SM& amesh, const char* title, bool nofill) +{ + DefaultColorFunctorSM c; + draw(amesh, title, nofill, c); +} + +template +void draw(const SM& amesh, const char* title) +{ draw(amesh, title, false); } + +template +void draw(const SM& amesh) +{ draw(amesh, "Basic Surface_mesh Viewer"); } + +} // End namespace CGAL + +#endif // CGAL_USE_BASIC_VIEWER + +#endif // DOXYGEN_RUNNING + +#endif // CGAL_DRAW_SURFACE_MESH_H diff --git a/Surface_mesh/package_info/Surface_mesh/dependencies b/Surface_mesh/package_info/Surface_mesh/dependencies index c34f3a297ff..474db4e6713 100644 --- a/Surface_mesh/package_info/Surface_mesh/dependencies +++ b/Surface_mesh/package_info/Surface_mesh/dependencies @@ -4,6 +4,7 @@ Cartesian_kernel Circulator Distance_2 Distance_3 +GraphicsView Hash_map Installation Interval_support diff --git a/Triangulation_2/doc/Triangulation_2/CGAL/draw_triangulation_2.h b/Triangulation_2/doc/Triangulation_2/CGAL/draw_triangulation_2.h new file mode 100644 index 00000000000..11d13a005a1 --- /dev/null +++ b/Triangulation_2/doc/Triangulation_2/CGAL/draw_triangulation_2.h @@ -0,0 +1,15 @@ +namespace CGAL { + +/*! +\ingroup PkgDrawTriangulation2 + +Open a new window and draw `at2`, a model of the `TriangulationDataStructure_2` concept. The function is blocking, that is the program continues as soon as the user closes the window. This function requires CGAL_Qt5, and is only available if the flag CGAL_USE_BASIC_VIEWER is defined at compile time. +\tparam T2 a model of the `TriangulationDataStructure_2` concept. +\param at2 the triangulation to draw. + +*/ +template +void draw(const T2& at2); + +} /* namespace CGAL */ + diff --git a/Triangulation_2/doc/Triangulation_2/PackageDescription.txt b/Triangulation_2/doc/Triangulation_2/PackageDescription.txt index a5d99c7a98b..0984fbd61b3 100644 --- a/Triangulation_2/doc/Triangulation_2/PackageDescription.txt +++ b/Triangulation_2/doc/Triangulation_2/PackageDescription.txt @@ -16,6 +16,14 @@ /// \defgroup PkgTriangulation2Miscellaneous Miscellaneous /// \ingroup PkgTriangulation2 +/*! Draw. + \code + #include + \endcode +*/ +/// \defgroup PkgDrawTriangulation2 Draw a Triangulation 2 +/// \ingroup PkgTriangulation2 + /*! \addtogroup PkgTriangulation2 \todo check generated documentation @@ -104,5 +112,8 @@ are described in Chapter \ref PkgTDS2 "2D Triangulation Data Structure". ## Enum ## - \link CGAL::Triangulation_2::Locate_type `CGAL::Triangulation_2::Locate_type` \endlink +### Draw a Triangulation 2 ### +- `CGAL::draw` + */ diff --git a/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt b/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt index eb0daf0d94a..65688e950b0 100644 --- a/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt +++ b/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt @@ -472,6 +472,19 @@ and inserted in the triangulation. Finally points on the convex hull are written to cout. \cgalExample{Triangulation_2/triangulation_prog1.cpp} +\subsection Triangulation2Draw Draw a 2D Triangulation +\anchor ssecDrawT2 + +A 2D triangulation can be visualized by calling the `CGAL::draw()` function as shown in the following example. This function opens a new window showing the given 2D triangulation. The function is blocking, that is the program continues as soon as the user closes the window. + +\cgalExample{Triangulation_2/draw_triangulation_2.cpp} + +This function requires CGAL_Qt5, and is only available if the flag CGAL_USE_BASIC_VIEWER is defined at compile time. + +\cgalFigureBegin{fig_draw_triangulation_2,draw_triangulation_2.png} +Result of the run of the draw_triangulation_2 program. A window shows the 2D triangulation and allows to navigate through the scene. +\cgalFigureEnd + \section Section_2D_Triangulations_Delaunay Delaunay Triangulations \subsection Subsection_2D_Triangulations_Delaunay_Description Description diff --git a/Triangulation_2/doc/Triangulation_2/examples.txt b/Triangulation_2/doc/Triangulation_2/examples.txt index 86a3c4fd016..9bff70297db 100644 --- a/Triangulation_2/doc/Triangulation_2/examples.txt +++ b/Triangulation_2/doc/Triangulation_2/examples.txt @@ -18,4 +18,5 @@ \example Triangulation_2/voronoi.cpp \example Triangulation_2/copy_triangulation_2.cpp \example Triangulation_2/polylines_triangulation.cpp +\example Triangulation_2/draw_triangulation_2.cpp */ diff --git a/Triangulation_2/doc/Triangulation_2/fig/draw_triangulation_2.png b/Triangulation_2/doc/Triangulation_2/fig/draw_triangulation_2.png new file mode 100644 index 00000000000..fee87844199 Binary files /dev/null and b/Triangulation_2/doc/Triangulation_2/fig/draw_triangulation_2.png differ diff --git a/Triangulation_2/examples/Triangulation_2/CMakeLists.txt b/Triangulation_2/examples/Triangulation_2/CMakeLists.txt index 5eb6e369b69..f1a119e58b6 100644 --- a/Triangulation_2/examples/Triangulation_2/CMakeLists.txt +++ b/Triangulation_2/examples/Triangulation_2/CMakeLists.txt @@ -4,9 +4,18 @@ project( Triangulation_2_Examples ) -cmake_minimum_required(VERSION 2.8.10) +cmake_minimum_required(VERSION 3.1) -find_package(CGAL QUIET) +if(NOT POLICY CMP0070 AND POLICY CMP0053) + # Only set CMP0053 to OLD with CMake<3.10, otherwise there is a warning. + cmake_policy(SET CMP0053 OLD) +endif() + +find_package(CGAL COMPONENTS Qt5) + +if(CGAL_Qt5_FOUND) + add_definitions(-DCGAL_USE_BASIC_VIEWER -DQT_NO_KEYWORDS) +endif() if ( CGAL_FOUND ) @@ -22,6 +31,10 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "${cppfile}" ) endforeach() + if(CGAL_Qt5_FOUND) + target_link_libraries(draw_triangulation_2 PUBLIC CGAL::CGAL_Qt5) + endif() + else() message(STATUS "This program requires the CGAL library, and will not be compiled.") diff --git a/Triangulation_2/examples/Triangulation_2/draw_triangulation_2.cpp b/Triangulation_2/examples/Triangulation_2/draw_triangulation_2.cpp new file mode 100644 index 00000000000..ec8f03b0e3b --- /dev/null +++ b/Triangulation_2/examples/Triangulation_2/draw_triangulation_2.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Triangulation_2 Triangulation; +typedef Triangulation::Point Point; + +int main() { + std::ifstream in("data/triangulation_prog1.cin"); + std::istream_iterator begin(in); + std::istream_iterator end; + + Triangulation t; + t.insert(begin, end); + + CGAL::draw(t); + + return EXIT_SUCCESS; +} diff --git a/Triangulation_2/examples/Triangulation_2/regular.cpp b/Triangulation_2/examples/Triangulation_2/regular.cpp index 2bbfe11e823..4cc0a1857ad 100644 --- a/Triangulation_2/examples/Triangulation_2/regular.cpp +++ b/Triangulation_2/examples/Triangulation_2/regular.cpp @@ -24,5 +24,6 @@ int main() std::cout << rt.number_of_vertices() << std::endl; std::cout << "number of hidden vertices : " ; std::cout << rt.number_of_hidden_vertices() << std::endl; + return 0; } diff --git a/Triangulation_2/include/CGAL/draw_triangulation_2.h b/Triangulation_2/include/CGAL/draw_triangulation_2.h new file mode 100644 index 00000000000..a1cfc460fdb --- /dev/null +++ b/Triangulation_2/include/CGAL/draw_triangulation_2.h @@ -0,0 +1,185 @@ +// Copyright(c) 2018 INRIA Sophia-Antipolis (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_T2_H +#define CGAL_DRAW_T2_H + +#include +#include + +#ifdef CGAL_USE_BASIC_VIEWER + +#include + +namespace CGAL +{ + +// Default color functor; user can change it to have its own face color +struct DefaultColorFunctorT2 +{ + template + static CGAL::Color run(const T2&, + const typename T2::Finite_faces_iterator fh) + { + CGAL::Random random((unsigned int)(std::size_t)(&*fh)); + return get_random_color(random); + } +}; + +// Viewer class for T2 +template +class SimpleTriangulation2ViewerQt : public Basic_viewer_qt +{ + typedef Basic_viewer_qt Base; + typedef typename T2::Vertex_handle Vertex_const_handle; + typedef typename T2::Finite_edges_iterator Edge_const_handle; + typedef typename T2::Finite_faces_iterator Facet_const_handle; + typedef typename T2::Point Point; + +public: + /// Construct the viewer. + /// @param at2 the t2 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) + SimpleTriangulation2ViewerQt(QWidget* parent, const T2& at2, + const char* title="Basic T2 Viewer", + bool anofaces=false, + const ColorFunctor& fcolor=ColorFunctor()) : + // First draw: vertices; edges, faces; multi-color; no inverse normal + Base(parent, title, true, true, true, false, false), + t2(at2), + m_nofaces(anofaces), + m_fcolor(fcolor) + { + compute_elements(); + } + +protected: + void compute_face(Facet_const_handle fh) + { + CGAL::Color c=m_fcolor.run(t2, fh); + face_begin(c); + + add_point_in_face(fh->vertex(0)->point()); + add_point_in_face(fh->vertex(1)->point()); + add_point_in_face(fh->vertex(2)->point()); + + face_end(); + } + + void compute_edge(Edge_const_handle eh) + { + add_segment(eh->first->vertex(eh->first->cw(eh->second))->point(), + eh->first->vertex(eh->first->ccw(eh->second))->point()); + } + + void compute_vertex(Vertex_const_handle vh) + { add_point(vh->point()); } + + void compute_elements() + { + clear(); + + if (!m_nofaces) + { + for (typename T2::Finite_faces_iterator it=t2.finite_faces_begin(); + it!=t2.finite_faces_end(); ++it) + { compute_face(it); } + } + + for (typename T2::Finite_edges_iterator it=t2.finite_edges_begin(); + it!=t2.finite_edges_end(); ++it) + { compute_edge(it); } + + for (typename T2::Finite_vertices_iterator it=t2.finite_vertices_begin(); + it!=t2.finite_vertices_end(); ++it) + { compute_vertex(it); } + } + + 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: + const T2& t2; + bool m_nofaces; + const ColorFunctor& m_fcolor; +}; + +template +void draw(const T2& at2, + const char* title, + bool nofill, + const ColorFunctor& fcolor) +{ +#if defined(CGAL_TEST_SUITE) + bool cgal_test_suite=true; +#else + bool cgal_test_suite=false; +#endif + + if (!cgal_test_suite) + { + int argc=1; + const char* argv[2]={"t2_viewer","\0"}; + QApplication app(argc,const_cast(argv)); + SimpleTriangulation2ViewerQt mainwindow(app.activeWindow(), + at2, + title, + nofill, + fcolor); + mainwindow.show(); + app.exec(); + } +} + +template +void draw(const T2& at2, const char* title, bool nofill) +{ + DefaultColorFunctorT2 c; + draw(at2, title, nofill, c); +} + +template +void draw(const T2& at2, const char* title) +{ draw(at2, title, false); } + +template +void draw(const T2& at2) +{ draw(at2, "Basic T2 Viewer"); } + +} // End namespace CGAL + +#endif // CGAL_USE_BASIC_VIEWER + +#endif // CGAL_DRAW_T2_H diff --git a/Triangulation_2/package_info/Triangulation_2/dependencies b/Triangulation_2/package_info/Triangulation_2/dependencies index b28aeef4d20..90dd0267b28 100644 --- a/Triangulation_2/package_info/Triangulation_2/dependencies +++ b/Triangulation_2/package_info/Triangulation_2/dependencies @@ -7,6 +7,7 @@ Distance_2 Distance_3 Filtered_kernel Geomview +GraphicsView Hash_map Homogeneous_kernel Installation diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/draw_triangulation_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/draw_triangulation_3.h new file mode 100644 index 00000000000..b7704903210 --- /dev/null +++ b/Triangulation_3/doc/Triangulation_3/CGAL/draw_triangulation_3.h @@ -0,0 +1,15 @@ +namespace CGAL { + +/*! +\ingroup PkgDrawTriangulation3 + +Open a new window and draw `at3`, a model of the `TriangulationDataStructure_3` concept. The function is blocking, that is the program continues as soon as the user closes the window. This function requires CGAL_Qt5, and is only available if the flag CGAL_USE_BASIC_VIEWER is defined at compile time. +\tparam T3 a model of the `TriangulationDataStructure_3` concept. +\param at3 the triangulation to draw. + +*/ +template +void draw(const T3& at3); + +} /* namespace CGAL */ + diff --git a/Triangulation_3/doc/Triangulation_3/PackageDescription.txt b/Triangulation_3/doc/Triangulation_3/PackageDescription.txt index 5af6493c805..11a1a0fe6a6 100644 --- a/Triangulation_3/doc/Triangulation_3/PackageDescription.txt +++ b/Triangulation_3/doc/Triangulation_3/PackageDescription.txt @@ -13,6 +13,13 @@ /// \defgroup PkgTriangulation3VertexCellClasses Vertex and Cell Classes /// \ingroup PkgTriangulation3 +/*! Draw. + \code + #include + \endcode +*/ +/// \defgroup PkgDrawTriangulation3 Draw a Triangulation 3 +/// \ingroup PkgTriangulation3 /*! \addtogroup PkgTriangulation3 @@ -111,6 +118,8 @@ is opposite to the vertex with the same index. See - `CGAL::Triangulation_3::Locate_type` +### Draw a Triangulation 3 ### +- `CGAL::draw` */ diff --git a/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt b/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt index 481610b3806..4d9385e07c8 100644 --- a/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt +++ b/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt @@ -535,6 +535,20 @@ removal of the first 100,000 vertices. \cgalExample{Triangulation_3/parallel_insertion_and_removal_in_regular_3.cpp} +\subsection Triangulation3Draw Draw a 3D Triangulation +\anchor ssecDrawT3 + +A 3D triangulation can be visualized by calling the `CGAL::draw()` function as shown in the following example. This function opens a new window showing the given 3D triangulation. The function is blocking, that is the program continues as soon as the user closes the window. + +\cgalExample{Triangulation_3/draw_triangulation_3.cpp} + +This function requires CGAL_Qt5, and is only available if the flag CGAL_USE_BASIC_VIEWER is defined at compile time. + +\cgalFigureBegin{fig_draw_triangulation_3,draw_triangulation_3.png} +Result of the run of the draw_triangulation_3 program. A window shows the 3D triangulation and allows to navigate through the 3D scene. +\cgalFigureEnd + + \section Triangulation3seccomplexity Complexity and Performance In 3D, the worst case complexity of a triangulation is quadratic in the number diff --git a/Triangulation_3/doc/Triangulation_3/examples.txt b/Triangulation_3/doc/Triangulation_3/examples.txt index 78ba6d23c9a..1a34261199c 100644 --- a/Triangulation_3/doc/Triangulation_3/examples.txt +++ b/Triangulation_3/doc/Triangulation_3/examples.txt @@ -13,4 +13,5 @@ \example Triangulation_3/copy_triangulation_3.cpp \example Triangulation_3/parallel_insertion_in_delaunay_3.cpp \example Triangulation_3/parallel_insertion_and_removal_in_regular_3.cpp +\example Triangulation_3/draw_triangulation_3.cpp */ diff --git a/Triangulation_3/doc/Triangulation_3/fig/draw_triangulation_3.png b/Triangulation_3/doc/Triangulation_3/fig/draw_triangulation_3.png new file mode 100644 index 00000000000..486aab9df08 Binary files /dev/null and b/Triangulation_3/doc/Triangulation_3/fig/draw_triangulation_3.png differ diff --git a/Triangulation_3/examples/Triangulation_3/CMakeLists.txt b/Triangulation_3/examples/Triangulation_3/CMakeLists.txt index c9673ba28b7..c13b8b4bbe0 100644 --- a/Triangulation_3/examples/Triangulation_3/CMakeLists.txt +++ b/Triangulation_3/examples/Triangulation_3/CMakeLists.txt @@ -2,8 +2,16 @@ project( Triangulation_3_Examples ) cmake_minimum_required(VERSION 2.8.12) +if(NOT POLICY CMP0070 AND POLICY CMP0053) + # Only set CMP0053 to OLD with CMake<3.10, otherwise there is a warning. + cmake_policy(SET CMP0053 OLD) +endif() -find_package(CGAL QUIET) +find_package(CGAL COMPONENTS Qt5) + +if(CGAL_Qt5_FOUND) + add_definitions(-DCGAL_USE_BASIC_VIEWER -DQT_NO_KEYWORDS) +endif() if ( CGAL_FOUND ) create_single_source_cgal_program( "adding_handles_3.cpp" ) @@ -20,19 +28,9 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "simple_triangulation_3.cpp" ) create_single_source_cgal_program( "simplex.cpp" ) - find_package( TBB QUIET ) - - if( TBB_FOUND ) - include( CGAL_target_use_TBB ) - - create_single_source_cgal_program( "parallel_insertion_and_removal_in_regular_3.cpp" ) - create_single_source_cgal_program( "parallel_insertion_in_delaunay_3.cpp" ) - create_single_source_cgal_program( "sequential_parallel.cpp" ) - CGAL_target_use_TBB( parallel_insertion_and_removal_in_regular_3 ) - CGAL_target_use_TBB( parallel_insertion_in_delaunay_3 ) - CGAL_target_use_TBB( sequential_parallel ) - else() - message(STATUS "NOTICE: a few examples require TBB and will not be compiled.") + create_single_source_cgal_program("draw_triangulation_3.cpp") + if(CGAL_Qt5_FOUND) + target_link_libraries(draw_triangulation_3 PUBLIC CGAL::CGAL_Qt5) endif() else() diff --git a/Triangulation_3/examples/Triangulation_3/draw_triangulation_3.cpp b/Triangulation_3/examples/Triangulation_3/draw_triangulation_3.cpp new file mode 100644 index 00000000000..3806854f938 --- /dev/null +++ b/Triangulation_3/examples/Triangulation_3/draw_triangulation_3.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Delaunay_triangulation_3 DT3; +typedef CGAL::Creator_uniform_3 Creator; + +int main() +{ + std::vector points; + CGAL::Random_points_in_sphere_3 g(1.0); + CGAL::cpp11::copy_n(g, 50, std::back_inserter(points)); + + DT3 dt3(points.begin(), points.end()); + + CGAL::draw(dt3); + + return EXIT_SUCCESS; +} diff --git a/Triangulation_3/include/CGAL/draw_triangulation_3.h b/Triangulation_3/include/CGAL/draw_triangulation_3.h new file mode 100644 index 00000000000..709bd15924f --- /dev/null +++ b/Triangulation_3/include/CGAL/draw_triangulation_3.h @@ -0,0 +1,192 @@ +// Copyright (c) 2018 INRIA Sophia-Antipolis (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_T3_H +#define CGAL_DRAW_T3_H + +#include +#include + +#ifdef CGAL_USE_BASIC_VIEWER + +#include + +namespace CGAL +{ + +// Default color functor; user can change it to have its own face color +struct DefaultColorFunctorT3 +{ + template + static CGAL::Color run(const T3&, + const typename T3::Finite_facets_iterator* fh) + { + if (fh==NULL) // 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)->first))+ + (std::size_t)((*fh)->second))); + return get_random_color(random); + } +}; + +// Viewer class for T3 +template +class SimpleTriangulation3ViewerQt : public Basic_viewer_qt +{ + typedef Basic_viewer_qt Base; + typedef typename T3::Vertex_handle Vertex_const_handle; + typedef typename T3::Finite_edges_iterator Edge_const_handle; + typedef typename T3::Finite_facets_iterator Facet_const_handle; + typedef typename T3::Cell_handle Cell_handle; + typedef typename T3::Point Point; + +public: + /// Construct the viewer. + /// @param at3 the t3 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) + SimpleTriangulation3ViewerQt(QWidget* parent, + const T3& at3, + const char* title="Basic T3 Viewer", + bool anofaces=false, + const ColorFunctor& fcolor=ColorFunctor()) : + // First draw: vertices; edges, faces; multi-color; no inverse normal + Base(parent, title, true, true, true, false, false), + t3(at3), + m_nofaces(anofaces), + m_fcolor(fcolor) + { + compute_elements(); + } + +protected: + void compute_face(Facet_const_handle fh) + { + CGAL::Color c=m_fcolor.run(t3, &fh); + face_begin(c); + + add_point_in_face(fh->first->vertex((fh->second+1)%4)->point()); + add_point_in_face(fh->first->vertex((fh->second+2)%4)->point()); + add_point_in_face(fh->first->vertex((fh->second+3)%4)->point()); + + face_end(); + } + + void compute_edge(Edge_const_handle eh) + { + add_segment(eh->first->vertex(eh->second)->point(), + eh->first->vertex(eh->third)->point()); + } + + void compute_vertex(Vertex_const_handle vh) + { add_point(vh->point()); } + + void compute_elements() + { + clear(); + + if (!m_nofaces) + { + for (typename T3::Finite_facets_iterator it=t3.finite_facets_begin(); + it!=t3.finite_facets_end(); ++it) + { compute_face(it); } + } + + for (typename T3::Finite_edges_iterator it=t3.finite_edges_begin(); + it!=t3.finite_edges_end(); ++it) + { compute_edge(it); } + + for (typename T3::Finite_vertices_iterator it=t3.finite_vertices_begin(); + it!=t3.finite_vertices_end(); ++it) + { compute_vertex(it); } + } + + 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: + const T3& t3; + bool m_nofaces; + const ColorFunctor& m_fcolor; +}; + +template +void draw(const T3& at3, + const char* title, + bool nofill, + const ColorFunctor& fcolor) +{ + +#if defined(CGAL_TEST_SUITE) + bool cgal_test_suite=true; +#else + bool cgal_test_suite=false; +#endif + + if (!cgal_test_suite) + { + int argc=1; + const char* argv[2]={"t3_viewer","\0"}; + QApplication app(argc,const_cast(argv)); + SimpleTriangulation3ViewerQt mainwindow(app.activeWindow(), + at3, + title, + nofill, + fcolor); + mainwindow.show(); + app.exec(); + } +} + +template +void draw(const T3& at3, const char* title, bool nofill) +{ + DefaultColorFunctorT3 c; + draw(at3, title, nofill, c); +} + +template +void draw(const T3& at3, const char* title) +{ draw(at3, title, false); } + +template +void draw(const T3& at3) +{ draw(at3, "Basic T3 Viewer"); } + +} // End namespace CGAL + +#endif // CGAL_USE_BASIC_VIEWER + +#endif // CGAL_DRAW_T3_H diff --git a/Triangulation_3/package_info/Triangulation_3/dependencies b/Triangulation_3/package_info/Triangulation_3/dependencies index c07b218e4eb..df63288cf1d 100644 --- a/Triangulation_3/package_info/Triangulation_3/dependencies +++ b/Triangulation_3/package_info/Triangulation_3/dependencies @@ -7,6 +7,7 @@ Distance_2 Distance_3 Filtered_kernel Geomview +GraphicsView Hash_map Homogeneous_kernel Installation