// Copyright (c) 2018 CNRS and LIRIS' Establishments (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org) // // $URL$ // $Id$ // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Guillaume Damiand // Mostafa Ashraf #ifndef CGAL_DRAW_LCC_H #define CGAL_DRAW_LCC_H #include #include #include #include #include #include namespace CGAL { namespace draw_function_for_lcc { typedef CGAL::Exact_predicates_inexact_constructions_kernel Local_kernel; typedef Local_kernel::Point_3 Local_point; typedef Local_kernel::Vector_3 Local_vector; template struct LCC_geom_utils; template struct LCC_geom_utils { static typename Local_kernel::Vector_3 get_vertex_normal(const LCC& lcc, typename LCC::Dart_const_descriptor dh) { typename Local_kernel::Vector_3 n = internal::Geom_utils:: get_local_vector(CGAL::compute_normal_of_cell_0(lcc, dh)); n = n / (CGAL::sqrt(n * n)); return n; } }; template struct LCC_geom_utils { static typename Local_kernel::Vector_3 get_vertex_normal(const LCC&, typename LCC::Dart_const_descriptor) { typename Local_kernel::Vector_3 n=CGAL::NULL_VECTOR; return n; } }; template void compute_face(const LCC& lcc, typename LCC::Dart_const_handle dh, typename LCC::Dart_const_handle voldh, CGAL::Graphics_scene& graphics_scene, const GSOptionsLCC& gso) { if(!gso.are_faces_enabled() || !gso.draw_face(lcc, dh)) { return; } // We fill only closed faces. typename LCC::Dart_const_handle cur=dh; do { if (!lcc.is_next_exist(cur)) { return; } // open face=>not filled cur = lcc.next(cur); } while (cur!=dh); if (gso.colored_volume(lcc, voldh)) { graphics_scene.face_begin(gso.volume_color(lcc, voldh)); } else if (gso.colored_face(lcc, dh)) { graphics_scene.face_begin(gso.face_color(lcc, dh)); } else { graphics_scene.face_begin(); } cur=dh; do { graphics_scene.add_point_in_face (lcc.point(cur), LCC_geom_utils::get_vertex_normal(lcc, cur)); cur=lcc.next(cur); } while (cur!=dh); graphics_scene.face_end(); } template void compute_edge(const LCC& lcc, typename LCC::Dart_const_handle dh, CGAL::Graphics_scene& graphics_scene, const GSOptions& gso) { if(!gso.are_edges_enabled() || !gso.draw_edge(lcc, dh)) { return; } const typename LCC::Point& p1=lcc.point(dh); typename LCC::Dart_const_handle d2=lcc.other_extremity(dh); if (d2!=LCC::null_descriptor) { if (gso.colored_edge(lcc, dh)) { graphics_scene.add_segment(p1, lcc.point(d2), gso.edge_color(lcc, dh)); } else { graphics_scene.add_segment(p1, lcc.point(d2)); } } } template void compute_vertex(const LCC& lcc, typename LCC::Dart_const_handle dh, CGAL::Graphics_scene& graphics_scene, const GSOptionsLCC& gso) { if (!gso.are_vertices_enabled() || !gso.draw_vertex(lcc, dh)) { return; } if (gso.colored_vertex(lcc, dh)) { graphics_scene.add_point(lcc.point(dh), gso.vertex_color(lcc, dh)); } else { graphics_scene.add_point(lcc.point(dh)); } } template struct Test_opposite_draw_lcc { template static bool run(const LCC& lcc, const GSOptions& gso, typename LCC::Dart_const_descriptor dh) { return (!lcc.template is_free<3>(dh) && !gso.volume_wireframe(lcc, lcc.template opposite<3>(dh))); } }; template struct Test_opposite_draw_lcc { template static bool run(const LCC&, const GSOptions&, typename LCC::Dart_const_descriptor) { return true; } }; template void compute_elements(const LCC& lcc, CGAL::Graphics_scene& graphics_scene, const GSOptions& gso) { typename LCC::size_type markvolumes = lcc.get_new_mark(); 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(); typename LCC::size_type oriented_mark = lcc.get_new_mark(); lcc.orient(oriented_mark); for(typename LCC::Dart_range::const_iterator it=lcc.darts().begin(), itend=lcc.darts().end(); it!=itend; ++it) { if (!lcc.is_marked(it, markvolumes) && gso.draw_volume(lcc, it)) { for(typename LCC::template Dart_of_cell_basic_range<3>::const_iterator itv=lcc.template darts_of_cell_basic<3>(it, markvolumes).begin(), itvend=lcc.template darts_of_cell_basic<3>(it, markvolumes).end(); itv!=itvend; ++itv) { lcc.mark(itv, markvolumes); if (!lcc.is_marked(itv, markfaces) && lcc.is_marked(itv, oriented_mark) && gso.draw_face(lcc, itv)) { if ((!gso.volume_wireframe(lcc, itv) || Test_opposite_draw_lcc::run(lcc, gso, itv)) && !gso.face_wireframe(lcc, itv)) { compute_face(lcc, itv, it, graphics_scene, gso); } for(typename LCC::template Dart_of_cell_basic_range<2>::const_iterator itf=lcc.template darts_of_cell_basic<2>(itv, markfaces).begin(), itfend=lcc.template darts_of_cell_basic<2>(itv, markfaces).end(); itf!=itfend; ++itf) { lcc.mark(itf, markfaces); if (!lcc.is_marked(itf, markedges) && gso.draw_edge(lcc, itf)) { compute_edge(lcc, itf, graphics_scene, gso); for(typename LCC::template Dart_of_cell_basic_range<1>::const_iterator ite=lcc.template darts_of_cell_basic<1>(itf, markedges).begin(), iteend=lcc.template darts_of_cell_basic<1>(itf, markedges).end(); ite!=iteend; ++ite) { lcc.mark(ite, markedges); if (!lcc.is_marked(ite, markvertices) && gso.draw_vertex(lcc, ite)) { compute_vertex(lcc, ite, graphics_scene, gso); CGAL::mark_cell(lcc, ite, markvertices); } } } } } } } } for (typename LCC::Dart_range::const_iterator it = lcc.darts().begin(), itend = lcc.darts().end(); it != itend; ++it) { lcc.unmark(it, markvertices); lcc.unmark(it, markedges); lcc.unmark(it, markfaces); lcc.unmark(it, markvolumes); lcc.unmark(it, oriented_mark); } lcc.free_mark(markvolumes); lcc.free_mark(markfaces); lcc.free_mark(markedges); lcc.free_mark(markvertices); lcc.free_mark(oriented_mark); } } // namespace draw_function_for_lcc #define CGAL_LCC_TYPE \ CGAL::Linear_cell_complex_base // add_to_graphics_scene: to add a LCC in the given graphic buffer, with a // graphics scene options. template class Map, class Refs, class Storage_, class GSOptions> void add_to_graphics_scene(const CGAL_LCC_TYPE& alcc, CGAL::Graphics_scene& graphics_scene, const GSOptions& gso) { draw_function_for_lcc::compute_elements(static_cast(alcc), graphics_scene, gso); } // add_to_graphics_scene: to add a LCC in the given graphic buffer, without a // graphics scene options. Use default drawing values. template class Map, class Refs, class Storage_> void add_to_graphics_scene(const CGAL_LCC_TYPE& alcc, CGAL::Graphics_scene& graphics_scene) { CGAL::Graphics_scene_options gso; gso.colored_volume = [](const CGAL_LCC_TYPE&, typename CGAL_LCC_TYPE::Dart_const_handle) -> bool { return true; }; gso.volume_color = [] (const CGAL_LCC_TYPE& alcc, typename CGAL_LCC_TYPE::Dart_const_handle dh) -> CGAL::IO::Color { CGAL::Random random((unsigned int)(alcc.darts().index(dh))); return get_random_color(random); }; add_to_graphics_scene(alcc, graphics_scene, gso); } // Specialization of draw function for a LCC, with a drawing graphics scene options. template class Map, class Refs, class Storage_, class GSOptions> void draw(const CGAL_LCC_TYPE& alcc, const GSOptions& gso, const char *title="LCC Basic Viewer") { CGAL::Graphics_scene buffer; add_to_graphics_scene(alcc, buffer, gso); draw_graphics_scene(buffer, title); } // Specialization of draw function for a LCC, without a graphics scene options. template class Map, class Refs, class Storage_> void draw(const CGAL_LCC_TYPE& alcc, const char *title="LCC Basic Viewer") { CGAL::Graphics_scene buffer; add_to_graphics_scene(alcc, buffer); draw_graphics_scene(buffer, title); } #undef CGAL_LCC_TYPE } // End namespace CGAL #endif // CGAL_DRAW_LCC_H